diff options
-rw-r--r-- | formatter/formatter_test.go | 6 | ||||
-rw-r--r-- | gsp.5 | 17 | ||||
-rw-r--r-- | parser/parser.go | 29 | ||||
-rw-r--r-- | parser/parser_test.go | 6 |
4 files changed, 50 insertions, 8 deletions
diff --git a/formatter/formatter_test.go b/formatter/formatter_test.go index fe3af4d..c5f0b83 100644 --- a/formatter/formatter_test.go +++ b/formatter/formatter_test.go @@ -39,10 +39,10 @@ func TestPrintAst(t *testing.T) { >title {- My Website } - meta x="y"{} + meta .→{} x="y"{} } >body { - >div #some-id{} + >div #some-id {} div key="val" .class-1 .class-2 { p {- This is some @em{-emphatic} text } } @@ -53,7 +53,7 @@ func TestPrintAst(t *testing.T) { result := `<html lang="en"><head attr><title> My Website </title> -<meta x="y"></head> +<meta class="→{}" x="y"></head> <body><div id="some-id"> <div class="class-1 class-2" key="val"><p> This is some <em>emphatic</em> text </p></div><tags key="Some long value"></body> </html>` @@ -1,4 +1,4 @@ -.Dd $Mdocdate: October 2 2023 $ +.Dd $Mdocdate: October 28 2023 $ .Dt GSP 5 .Os .Sh NAME @@ -153,6 +153,21 @@ div id="foo" class="bar baz" { div class="bar" {} } .Ed +.Pp +It is important to note that HTML5 allows for an ID- or class name to contain +just about anything, therefor +.Ql .→Ħ{} +is a valid ID shorthand. +This is important because it means that the following doesn’t actually create a +node with no children: +.Bd -literal -offset indent +div .foo{} +.Ed +.Pp +You must instead include a space: +.Bd -literal -offset indent +div .foo {} +.Ed .Ss Document types .Nm does not support document types. diff --git a/parser/parser.go b/parser/parser.go index 648cfe7..b333506 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -255,7 +255,7 @@ loop: return nil, err } - if s, err := reader.parseNodeName(); err != nil { + if s, err := reader.parseShorthand(); err != nil { return nil, err } else { attr.Value = s @@ -298,6 +298,33 @@ loop: return attrs, nil } +// parseShorthand parses an ID- or class shorthand value. +func (reader *reader) parseShorthand() (string, error) { + sb := strings.Builder{} + + for { + r, err := reader.readRune() + if err != nil { + return "", err + } + + if unicode.IsSpace(r) { + break + } + sb.WriteRune(r) + } + + s := sb.String() + if len(s) == 0 { + return "", invalidSyntax{ + pos: reader.pos, + expected: "id- or class name", + found: "no value", + } + } + return s, nil +} + // parseString parses the double quoted strings used as attribute values. func (reader *reader) parseString() (string, error) { sb := strings.Builder{} diff --git a/parser/parser_test.go b/parser/parser_test.go index b0b9568..1851307 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -15,10 +15,10 @@ func TestParseFile(t *testing.T) { >title {- My Website } - meta x="y"{} + meta .→{} x="y"{} } >body { - >div #some-id{} + >div #some-id {} div key="val" .class-1 .class-2 { p {- This is some @em{-emphatic} text } } @@ -39,7 +39,7 @@ func TestParseFile(t *testing.T) { s = fmt.Sprintf("%+v", ast) result := `{Type:1 Text: Attrs:[] Children:[{Type:0 Text:html Attrs:[{Key:lang Value:en}] Children:[{Type:0 Text:head Attrs:[{Key:attr Value:}] Children:[{Type:0 Text:title Attrs:[] Children:[{Type:1 Text: Attrs:[] Children:[{Type:3 Text: My Website - Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:true} {Type:0 Text:meta Attrs:[{Key:x Value:y}] Children:[] Newline:false}] Newline:true} {Type:0 Text:body Attrs:[] Children:[{Type:0 Text:div Attrs:[{Key:id Value:some-id}] Children:[] Newline:true} {Type:0 Text:div Attrs:[{Key:key Value:val} {Key:class Value:class-1} {Key:class Value:class-2}] Children:[{Type:0 Text:p Attrs:[] Children:[{Type:1 Text: Attrs:[] Children:[{Type:3 Text: This is some Attrs:[] Children:[] Newline:false} {Type:0 Text:em Attrs:[] Children:[{Type:1 Text: Attrs:[] Children:[{Type:3 Text:emphatic Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:false} {Type:3 Text: text Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:false}] Newline:false} {Type:0 Text:tags Attrs:[{Key:key Value:Some long value}] Children:[] Newline:false}] Newline:true}] Newline:false}] Newline:false}` + Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:true} {Type:0 Text:meta Attrs:[{Key:class Value:→{}} {Key:x Value:y}] Children:[] Newline:false}] Newline:true} {Type:0 Text:body Attrs:[] Children:[{Type:0 Text:div Attrs:[{Key:id Value:some-id}] Children:[] Newline:true} {Type:0 Text:div Attrs:[{Key:key Value:val} {Key:class Value:class-1} {Key:class Value:class-2}] Children:[{Type:0 Text:p Attrs:[] Children:[{Type:1 Text: Attrs:[] Children:[{Type:3 Text: This is some Attrs:[] Children:[] Newline:false} {Type:0 Text:em Attrs:[] Children:[{Type:1 Text: Attrs:[] Children:[{Type:3 Text:emphatic Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:false} {Type:3 Text: text Attrs:[] Children:[] Newline:false}] Newline:false}] Newline:false}] Newline:false} {Type:0 Text:tags Attrs:[{Key:key Value:Some long value}] Children:[] Newline:false}] Newline:true}] Newline:false}] Newline:false}` if s != result { t.Fatalf("ParseFile() parsed unexpected AST ‘%s’", s) } |