aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2023-10-28 02:23:11 +0200
committerThomas Voss <mail@thomasvoss.com> 2023-10-28 02:23:11 +0200
commit04b07b3715a815f0140d870fb88a6822f06cf5cb (patch)
tree633b92a23a37802aae83d5f5cd6047164500ab65
parent024cd373e052db4193343b1eeb0767df98d7ea1e (diff)
Allow for true HTML ID- and class shorthandsv2.0.0
-rw-r--r--formatter/formatter_test.go6
-rw-r--r--gsp.517
-rw-r--r--parser/parser.go29
-rw-r--r--parser/parser_test.go6
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>`
diff --git a/gsp.5 b/gsp.5
index 96d8ae6..5c67bd4 100644
--- a/gsp.5
+++ b/gsp.5
@@ -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)
}