Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1@top Document { (entity | DoctypeDecl)+ }
2
3@dialects { noMatch, selfClosing }
4
5entity[@isGroup=Entity] {
6 Text |
7 EntityReference |
8 CharacterReference |
9 InvalidEntity |
10 Element |
11 Comment |
12 ProcessingInst |
13 IncompleteTag |
14 IncompleteCloseTag |
15 MismatchedCloseTag |
16 NoMatchCloseTag
17}
18
19Element {
20 OpenScriptTag ScriptText (CloseScriptTag | missingCloseTag) |
21 OpenStyleTag StyleText (CloseStyleTag | missingCloseTag) |
22 OpenTextareaTag TextareaText (CloseTextareaTag | missingCloseTag) |
23 OpenTag entity* (CloseTag | missingCloseTag) |
24 SelfClosingTag
25}
26
27ScriptText[group="TextContent Entity"] { scriptText* }
28
29StyleText[group="TextContent Entity"] { styleText* }
30
31TextareaText[group="TextContent Entity"] { textareaText* }
32
33@skip { space } {
34 OpenTag[closedBy=CloseTag,isolate=ltr] {
35 StartTag TagName Attribute* EndTag
36 }
37
38 SelfClosingTag[isolate=ltr] {
39 StartSelfClosingTag TagName Attribute* (EndTag | SelfClosingEndTag) |
40 (StartTag | StartScriptTag | StartStyleTag | StartTextareaTag) TagName Attribute* SelfClosingEndTag
41 }
42
43 MismatchedCloseTag[isolate=ltr] {
44 MismatchedStartCloseTag TagName EndTag
45 }
46
47 NoMatchCloseTag[@name=CloseTag,isolate=ltr] {
48 NoMatchStartCloseTag TagName EndTag
49 }
50
51 CloseTag[openedBy=OpenTag,isolate=ltr] {
52 StartCloseTag TagName EndTag
53 }
54
55 OpenScriptTag[@name=OpenTag,closedBy=CloseTag,isolate=ltr] {
56 StartScriptTag TagName Attribute* EndTag
57 }
58
59 CloseScriptTag[@name=CloseTag,openedBy=OpenTag,isolate=ltr] {
60 StartCloseScriptTag TagName EndTag
61 }
62
63 OpenStyleTag[@name=OpenTag,closedBy=CloseTag,isolate=ltr] {
64 StartStyleTag TagName Attribute* EndTag
65 }
66
67 CloseStyleTag[@name=CloseTag,openedBy=OpenTag,isolate=ltr] {
68 StartCloseStyleTag TagName EndTag
69 }
70
71 OpenTextareaTag[@name=OpenTag,closedBy=CloseTag,isolate=ltr] {
72 StartTextareaTag TagName Attribute* EndTag
73 }
74
75 CloseTextareaTag[@name=CloseTag,openedBy=OpenTag,isolate=ltr] {
76 StartCloseTextareaTag TagName EndTag
77 }
78
79 Attribute {
80 AttributeName (Is (AttributeValue | UnquotedAttributeValue))?
81 }
82}
83
84AttributeValue[isolate] {
85 "\"" (attributeContentDouble | EntityReference | CharacterReference | InvalidEntity)* "\"" |
86 "\'" (attributeContentSingle | EntityReference | CharacterReference | InvalidEntity)* "\'"
87}
88
89Comment[isolate] { commentStart commentContent* commentEnd }
90
91@context elementContext from "./tokens.js"
92
93@external tokens scriptTokens from "./tokens.js" {
94 scriptText
95 StartCloseScriptTag[@name=StartCloseTag,closedBy=EndTag]
96}
97
98@external tokens styleTokens from "./tokens.js" {
99 styleText
100 StartCloseStyleTag[@name=StartCloseTag,closedBy=EndTag]
101}
102
103@external tokens textareaTokens from "./tokens.js" {
104 textareaText
105 StartCloseTextareaTag[@name=StartCloseTag,closedBy=EndTag]
106}
107
108@external tokens endTag from "./tokens.js" {
109 EndTag[openedBy="StartTag StartCloseTag"]
110 SelfClosingEndTag[openedBy=StartTag,@dialect=selfClosing]
111}
112
113@external tokens tagStart from "./tokens.js" {
114 StartTag[closedBy="EndTag SelfClosingEndTag"],
115 StartScriptTag[@name=StartTag,closedBy=EndTag],
116 StartStyleTag[@name=StartTag,closedBy=EndTag],
117 StartTextareaTag[@name=StartTag,closedBy=EndTag],
118 StartSelfClosingTag[@name=StartTag,closedBy=EndTag],
119 StartCloseTag[closedBy=EndTag],
120 NoMatchStartCloseTag[@name=StartCloseTag,closedBy=EndTag]
121 MismatchedStartCloseTag[@name=StartCloseTag,closedBy=EndTag],
122 missingCloseTag,
123 IncompleteTag,
124 IncompleteCloseTag
125}
126
127@external tokens commentContent from "./tokens.js" {
128 commentContent
129}
130
131@tokens {
132 nameStart {
133 ":" | @asciiLetter | "_" |
134 $[\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D] |
135 $[\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u{10000}-\u{EFFFF}]
136 }
137
138 nameChar {
139 nameStart | "-" | "." | @digit | $[\u00B7\u0300-\u036F\u203F-\u2040]
140 }
141
142 identifier { nameStart nameChar* }
143
144 TagName { identifier }
145
146 AttributeName { ![\u0000-\u0020\u007F-\u009F"'<>/=\uFDD0-\uFDEF\uFFFE\uFFFF]+ }
147
148 UnquotedAttributeValue[isolate] { ![ \t\n\r\u000C=<>"'`]+ }
149
150 attributeContentDouble { !["&]+ }
151
152 attributeContentSingle { !['&]+ }
153
154 Is { "=" }
155
156 EntityReference { "&" ![#; ]+ ";" }
157
158 CharacterReference { "&#" ![; ]+ ";" }
159
160 InvalidEntity { "&" }
161
162 @precedence { CharacterReference, EntityReference, InvalidEntity }
163
164 Text[group=TextContent] { ![<&]+ }
165
166 commentStart { "<!--" }
167 commentEnd { "-->" }
168
169 ProcessingInst { "<?" piContent }
170
171 piContent { ![?] piContent | "?" piQuestion }
172 piQuestion { ![>] piContent | ">" }
173
174 DoctypeDecl { "<!" ("doctype" | "DOCTYPE") ![>]* ">" }
175
176 @precedence { commentStart, ProcessingInst, DoctypeDecl }
177
178 space { (" " | "\t" | "\r" | "\n")+ }
179}
180
181@external propSource htmlHighlighting from "./highlight"