Skip to content

Commit c0273f1

Browse files
authored
caddyfile: Add heredoc support to fmt command (#6056)
1 parent dba556f commit c0273f1

File tree

3 files changed

+145
-1
lines changed

3 files changed

+145
-1
lines changed

caddyconfig/caddyfile/formatter.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ func Format(input []byte) []byte {
3131
out := new(bytes.Buffer)
3232
rdr := bytes.NewReader(input)
3333

34+
type heredocState int
35+
36+
const (
37+
heredocClosed heredocState = 0
38+
heredocOpening heredocState = 1
39+
heredocOpened heredocState = 2
40+
)
41+
3442
var (
3543
last rune // the last character that was written to the result
3644

@@ -47,6 +55,11 @@ func Format(input []byte) []byte {
4755
quoted bool // whether we're in a quoted segment
4856
escaped bool // whether current char is escaped
4957

58+
heredoc heredocState // whether we're in a heredoc
59+
heredocEscaped bool // whether heredoc is escaped
60+
heredocMarker []rune
61+
heredocClosingMarker []rune
62+
5063
nesting int // indentation level
5164
)
5265

@@ -75,6 +88,58 @@ func Format(input []byte) []byte {
7588
panic(err)
7689
}
7790

91+
// detect whether we have the start of a heredoc
92+
if !quoted && !(heredoc != heredocClosed || heredocEscaped) &&
93+
space && last == '<' && ch == '<' {
94+
write(ch)
95+
heredoc = heredocOpening
96+
space = false
97+
continue
98+
}
99+
100+
if heredoc == heredocOpening {
101+
if ch == '\n' {
102+
if len(heredocMarker) > 0 && heredocMarkerRegexp.MatchString(string(heredocMarker)) {
103+
heredoc = heredocOpened
104+
} else {
105+
heredocMarker = nil
106+
heredoc = heredocClosed
107+
nextLine()
108+
continue
109+
}
110+
write(ch)
111+
continue
112+
}
113+
if unicode.IsSpace(ch) {
114+
// a space means it's just a regular token and not a heredoc
115+
heredocMarker = nil
116+
heredoc = heredocClosed
117+
} else {
118+
heredocMarker = append(heredocMarker, ch)
119+
write(ch)
120+
continue
121+
}
122+
}
123+
// if we're in a heredoc, all characters are read&write as-is
124+
if heredoc == heredocOpened {
125+
write(ch)
126+
heredocClosingMarker = append(heredocClosingMarker, ch)
127+
if len(heredocClosingMarker) > len(heredocMarker) {
128+
heredocClosingMarker = heredocClosingMarker[1:]
129+
}
130+
// check if we're done
131+
if string(heredocClosingMarker) == string(heredocMarker) {
132+
heredocMarker = nil
133+
heredocClosingMarker = nil
134+
heredoc = heredocClosed
135+
}
136+
continue
137+
}
138+
139+
if last == '<' && space {
140+
space = false
141+
}
142+
78143
if comment {
79144
if ch == '\n' {
80145
comment = false
@@ -98,6 +163,9 @@ func Format(input []byte) []byte {
98163
}
99164

100165
if escaped {
166+
if ch == '<' {
167+
heredocEscaped = true
168+
}
101169
write(ch)
102170
escaped = false
103171
continue
@@ -117,6 +185,7 @@ func Format(input []byte) []byte {
117185

118186
if unicode.IsSpace(ch) {
119187
space = true
188+
heredocEscaped = false
120189
if ch == '\n' {
121190
newLines++
122191
}
@@ -205,6 +274,11 @@ func Format(input []byte) []byte {
205274
write('{')
206275
openBraceWritten = true
207276
}
277+
278+
if spacePrior && ch == '<' {
279+
space = true
280+
}
281+
208282
write(ch)
209283

210284
beginningOfLine = false

caddyconfig/caddyfile/formatter_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,76 @@ block {
362362
363363
block {
364364
}
365+
`,
366+
},
367+
{
368+
description: "keep heredoc as-is",
369+
input: `block {
370+
heredoc <<HEREDOC
371+
Here's more than one space Here's more than one space
372+
HEREDOC
373+
}
374+
`,
375+
expect: `block {
376+
heredoc <<HEREDOC
377+
Here's more than one space Here's more than one space
378+
HEREDOC
379+
}
380+
`,
381+
},
382+
{
383+
description: "Mixing heredoc with regular part",
384+
input: `block {
385+
heredoc <<HEREDOC
386+
Here's more than one space Here's more than one space
387+
HEREDOC
388+
respond "More than one space will be eaten" 200
389+
}
390+
391+
block2 {
392+
heredoc <<HEREDOC
393+
Here's more than one space Here's more than one space
394+
HEREDOC
395+
respond "More than one space will be eaten" 200
396+
}
397+
`,
398+
expect: `block {
399+
heredoc <<HEREDOC
400+
Here's more than one space Here's more than one space
401+
HEREDOC
402+
respond "More than one space will be eaten" 200
403+
}
404+
405+
block2 {
406+
heredoc <<HEREDOC
407+
Here's more than one space Here's more than one space
408+
HEREDOC
409+
respond "More than one space will be eaten" 200
410+
}
411+
`,
412+
},
413+
{
414+
description: "Heredoc as regular token",
415+
input: `block {
416+
heredoc <<HEREDOC "More than one space will be eaten"
417+
}
418+
`,
419+
expect: `block {
420+
heredoc <<HEREDOC "More than one space will be eaten"
421+
}
422+
`,
423+
},
424+
{
425+
description: "Escape heredoc",
426+
input: `block {
427+
heredoc \<<HEREDOC
428+
respond "More than one space will be eaten" 200
429+
}
430+
`,
431+
expect: `block {
432+
heredoc \<<HEREDOC
433+
respond "More than one space will be eaten" 200
434+
}
365435
`,
366436
},
367437
} {

caddyconfig/caddyfile/lexer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ func (l *lexer) finalizeHeredoc(val []rune, marker string) ([]rune, error) {
313313
// iterate over each line and strip the whitespace from the front
314314
var out string
315315
for lineNum, lineText := range lines[:len(lines)-1] {
316-
if lineText == "" {
316+
if lineText == "" || lineText == "\r" {
317317
out += "\n"
318318
continue
319319
}

0 commit comments

Comments
 (0)