Skip to content

Commit

Permalink
prep towards quoted string that cross lines
Browse files Browse the repository at this point in the history
changes heredoc interpretation so that it will make sense with multi-line string scalars.
  • Loading branch information
ionous committed May 20, 2024
1 parent 945f2cb commit e441f01
Show file tree
Hide file tree
Showing 20 changed files with 375 additions and 310 deletions.
6 changes: 6 additions & 0 deletions charmed/_testdata/expectedResults
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
here are a couple of lines
specified on separate lines.

backslashes "\" might be special,
depending on the quoting style.
and same for the final newline.
9 changes: 9 additions & 0 deletions charmed/_testdata/hereDocDouble
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
here are a couple of lines
specified on separate lines.

backslashes "\\" might be \
special,
depending on the quoting style.
and same for the final newline.
"""
8 changes: 8 additions & 0 deletions charmed/_testdata/hereDocRaw
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```lang <<< END
here are a couple of lines
specified on separate lines.

backslashes "\" might be special,
depending on the quoting style.
and same for the final newline.
END
9 changes: 9 additions & 0 deletions charmed/_testdata/hereDocSingle
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'''
here are a couple of lines
specified on separate lines.

backslashes "\" might be special,
depending on the quoting style.
and same for the final newline.

'''
8 changes: 8 additions & 0 deletions charmed/_testdata/herePipeDouble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
|
here are a couple of lines
specified on separate lines.

backslashes "\\" might be special,
depending on the quoting style.
and same for the final newline.
"""
8 changes: 8 additions & 0 deletions charmed/_testdata/herePipeRaw
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
|
here are a couple of lines
specified on separate lines.

backslashes "\" might be special,
depending on the quoting style.
and same for the final newline.
```
119 changes: 119 additions & 0 deletions charmed/charmedBlock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package charmed

import (
"fmt"
"log"
"strings"

"github.com/ionous/tell/runes"
)

func KeepEnding(q rune) (okay bool) {
if q == runes.QuoteRaw || q == runes.QuoteDouble {
okay = true
} else if q != runes.QuoteSingle {
log.Panicf("unknown rune %q", q)
}
return
}

func EscapeHere(q rune) (okay bool) {
if q == runes.QuoteDouble {
okay = true
} else if q != runes.QuoteSingle &&
q != runes.QuoteRaw {
log.Panicf("unknown rune %q", q)
}
return
}

// track the indentation of each line in the heredoc
// ( to subtract the indentation of the closing marker once that's known )
type indentedLine struct {
indented int
line string
}

func (el *indentedLine) getLine(escape bool) (ret string, err error) {
if !escape || len(el.line) == 0 {
ret = el.line
} else {
var buf strings.Builder
if e := escapeString(&buf, el.line); e != nil {
err = e
} else {
ret = buf.String()
}
}
return
}

// accumulates text for line
type indentedBlock struct {
buf strings.Builder
lines []indentedLine
}

// record a rune on the current line
// ( left hand spaces are expected to be accumulated externally and add via flushLine )
func (ls *indentedBlock) WriteRune(r rune) (int, error) {
return ls.buf.WriteRune(r)
}

// record a string on the current line
func (ls *indentedBlock) WriteString(str string) (int, error) {
return ls.buf.WriteString(str)
}

func (ls *indentedBlock) addLine(lhs int, str string) {
ls.lines = append(ls.lines, indentedLine{lhs, str})
}

func (ls *indentedBlock) flushLine(lhs, rhs int) {
// if the line only had spaces
if ls.buf.Len() == 0 {
ls.addLine(-1, "")
} else {
dupe(&ls.buf, runes.Space, rhs) // as per yaml, trailing spaces are preserved
ls.buf.WriteRune(runes.Newline)
ls.addLine(lhs, ls.buf.String())
ls.buf.Reset()
}
}

// the leftEdge counts the number of leading spaces to eat
// if a line has less than that, its an underflow.
func (ls indentedBlock) writeHere(out *strings.Builder, lineType rune, leftEdge int) (err error) {
escape, keepEnding := EscapeHere(lineType), KeepEnding(lineType)
for i, end := 0, len(ls.lines)-1; i <= end; i++ {
el, atEnd := ls.lines[i], i == end
// a blank line:
if el.indented < 0 {
if !atEnd || keepEnding {
out.WriteRune(runes.Newline)
}
} else {
// a content line:
if newLhs := el.indented - leftEdge; newLhs < 0 {
err = underIndentAt(i)
break
} else if str, e := el.getLine(escape); e != nil {
err = e // ^ interprets the string, or returns it raw depending
break
} else {
dupe(out, runes.Space, newLhs) // add leading spaces
if atEnd && !keepEnding {
str = str[:len(str)-1]
}
out.WriteString(str)
}
}
}
return
}

type underIndentAt int

func (u underIndentAt) Error() string {
return fmt.Sprintf("heredoc line %d has a smaller indent than its closing tag", u)
}
7 changes: 6 additions & 1 deletion charmed/charmedEscape.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ func decodeEscape(w runes.RuneWriter) charm.State {
e := fmt.Errorf("%w is not recognized after a backslash", charm.InvalidRune(q))
ret = charm.Error(e)
} else {
w.WriteRune(v)
if v != 0 {
w.WriteRune(v)
}
ret = charm.UnhandledNext()
}
}
Expand Down Expand Up @@ -94,4 +96,7 @@ var escapes = map[rune]rune{
'v': '\v',
'\\': '\\',
'"': '"',
// a backslash followed by an actual newline
// eats the newline, joining the next line seamlessly.
'\n': 0,
}
119 changes: 0 additions & 119 deletions charmed/charmedHere.go

This file was deleted.

Loading

0 comments on commit e441f01

Please sign in to comment.