Repository: CloudyKit/jet
Pull request #212 (2024-02-18 17:07:14)

Adds option for custom comment delimiters
Fixes: https://github.com/CloudyKit/jet/issues/187


Patch:
diff --git a/lex.go b/lex.go
index dc37b6c..3711bfa 100644
--- a/lex.go
+++ b/lex.go
@@ -141,8 +141,8 @@ const eof = -1
 const (
 	defaultLeftDelim  = "{{"
 	defaultRightDelim = "}}"
-	leftComment       = "{*"
-	rightComment      = "*}"
+	defaultLeftComment       = "{*"
+	defaultRightComment      = "*}"
 	leftTrimMarker    = "- "
 	rightTrimMarker   = " -"
 	trimMarkerLen     = Pos(len(leftTrimMarker))
@@ -165,6 +165,8 @@ type lexer struct {
 	lastType       itemType
 	leftDelim      string
 	rightDelim     string
+	leftComment      string
+	rightComment     string
 	trimRightDelim string
 }
 
@@ -177,6 +179,15 @@ func (l *lexer) setDelimiters(leftDelim, rightDelim string) {
 	}
 }
 
+func (l *lexer) setCommentDelimiters(leftDelim, rightDelim string) {
+	if leftDelim != "" {
+		l.leftComment = leftDelim
+	}
+	if rightDelim != "" {
+		l.rightComment = rightDelim
+	}
+}
+
 // next returns the next rune in the input.
 func (l *lexer) next() rune {
 	if int(l.pos) >= len(l.input) {
@@ -266,6 +277,8 @@ func lex(name, input string, run bool) *lexer {
 		items:          make(chan item),
 		leftDelim:      defaultLeftDelim,
 		rightDelim:     defaultRightDelim,
+		leftComment:    defaultLeftComment,
+		rightComment:   defaultRightComment,
 		trimRightDelim: rightTrimMarker + defaultRightDelim,
 	}
 	if run {
@@ -289,7 +302,7 @@ func lexText(l *lexer) stateFn {
 	for {
 		// without breaking the API, this seems like a reasonable workaround to correctly parse comments
 		i := strings.IndexByte(l.input[l.pos:], l.leftDelim[0])  // index of suspected left delimiter
-		ic := strings.IndexByte(l.input[l.pos:], leftComment[0]) // index of suspected left comment marker
+		ic := strings.IndexByte(l.input[l.pos:], l.leftComment[0]) // index of suspected left comment marker
 		if ic > -1 && ic < i {                                   // use whichever is lower for future lexing
 			i = ic
 		}
@@ -313,7 +326,7 @@ func lexText(l *lexer) stateFn {
 				l.ignore()
 				return lexLeftDelim
 			}
-			if strings.HasPrefix(l.input[l.pos:], leftComment) {
+			if strings.HasPrefix(l.input[l.pos:], l.leftComment) {
 				if l.pos > l.start {
 					l.emit(itemText)
 				}
@@ -346,12 +359,12 @@ func lexLeftDelim(l *lexer) stateFn {
 
 // lexComment scans a comment. The left comment marker is known to be present.
 func lexComment(l *lexer) stateFn {
-	l.pos += Pos(len(leftComment))
-	i := strings.Index(l.input[l.pos:], rightComment)
+	l.pos += Pos(len(l.leftComment))
+	i := strings.Index(l.input[l.pos:], l.rightComment)
 	if i < 0 {
 		return l.errorf("unclosed comment")
 	}
-	l.pos += Pos(i + len(rightComment))
+	l.pos += Pos(i + len(l.rightComment))
 	l.ignore()
 	return lexText
 }
diff --git a/parse.go b/parse.go
index 4f0166d..7bcaa4e 100644
--- a/parse.go
+++ b/parse.go
@@ -225,6 +225,7 @@ func (s *Set) parse(name, text string, cacheAfterParsing bool) (t *Template, err
 
 	lexer := lex(name, text, false)
 	lexer.setDelimiters(s.leftDelim, s.rightDelim)
+	lexer.setCommentDelimiters(s.leftComment, s.rightComment)
 	lexer.run()
 	t.startParse(lexer)
 	t.parseTemplate(cacheAfterParsing)
diff --git a/set.go b/set.go
index 67b7871..1340606 100644
--- a/set.go
+++ b/set.go
@@ -23,6 +23,8 @@ type Set struct {
 	developmentMode bool
 	leftDelim       string
 	rightDelim      string
+	leftComment       string
+	rightComment     string
 }
 
 // Option is the type of option functions that can be used in NewSet().
@@ -84,6 +86,15 @@ func WithDelims(left, right string) Option {
 	}
 }
 
+// WithCommentDelims returns an option function that sets the comment delimiters to the specified strings.
+// Parsed templates will inherit the settings. Not setting them leaves them at the default: `{*` and `*}`.
+func WithCommentDelims(left, right string) Option {
+	return func(s *Set) {
+		s.leftComment = left
+		s.rightComment = right
+	}
+}
+
 // WithTemplateNameExtensions returns an option function that sets the extensions to try when looking
 // up template names in the cache or loader. Default extensions are `""` (no extension), `".jet"`,
 // `".html.jet"`, `".jet.html"`. Extensions will be tried in the order they are defined in the slice.


Test patch:
diff --git a/parse_test.go b/parse_test.go
index a6baf34..a78993b 100644
--- a/parse_test.go
+++ b/parse_test.go
@@ -131,6 +131,7 @@ func TestParseTemplateWithCustomDelimiters(t *testing.T) {
 		NewOSFileSystemLoader("./testData"),
 		WithSafeWriter(nil),
 		WithDelims("[[", "]]"),
+		WithCommentDelims("[*", "*]"),
 	)
 	p := ParserTestCase{T: t, set: set}
 	p.TestPrintFile("custom_delimiters.jet")
diff --git a/testData/custom_delimiters.jet b/testData/custom_delimiters.jet
index 00d92ad..739d761 100644
--- a/testData/custom_delimiters.jet
+++ b/testData/custom_delimiters.jet
@@ -1,4 +1,4 @@
-{* comment *}[[ . ]]
+[* comment *][[ . ]]
 [[ singleValue ]]
 [[ nil ]]
 [[ "" ]]