Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1@precedence {
2 attribute @left,
3 structure @left,
4 call,
5 valueCompareOp,
6 valueOp @left,
7 layerName
8}
9
10@skip { whitespace | Comment }
11
12@top StyleSheet { item* }
13
14@top Styles { blockContent }
15
16item {
17 RuleSet |
18 ImportStatement |
19 MediaStatement |
20 CharsetStatement |
21 NamespaceStatement |
22 KeyframesStatement |
23 SupportsStatement |
24 ScopeStatement |
25 AtRule
26}
27
28RuleSet {
29 selector ("," selector)* Block
30}
31
32ImportStatement {
33 atKw<"import">
34 value
35 Layer {
36 queryCalleeKw<"layer"> (!layerName "(" LayerName ("." LayerName)* ")")? |
37 queryKw<"layer">
38 }?
39 commaSep<query> ";"
40}
41
42LayerName { identifier }
43
44MediaStatement {
45 atKw<"media"> commaSep<query> Block
46}
47
48CharsetStatement {
49 atKw<"charset"> value ";"
50}
51
52NamespaceStatement {
53 atKw<"namespace">
54 NamespaceName { identifier }?
55 (StringLiteral | CallLiteral) ";"
56}
57
58KeyframesStatement {
59 atKw<"keyframes">
60 KeyframeName { identifier | StringLiteral }
61 KeyframeList
62}
63
64KeyframeSelector {
65 KeyframeRangeName { identifier } NumberLiteral? |
66 NumberLiteral
67}
68
69KeyframeList {
70 "{" (KeyframeSelector ("," KeyframeSelector)* Block)* "}"
71}
72
73SupportsStatement {
74 atKw<"supports"> query Block
75}
76
77ScopeStatement {
78 atKw<"scope">
79 ParenthesizedSelector?
80 (@extend[@name=to]<identifier, "to"> ParenthesizedSelector)?
81 Block
82}
83
84AtRule { AtKeyword commaSep<query> (";" | Block) }
85
86Block[@dynamicPrecedence=1] { "{" blockContent "}" }
87
88blockContent { ~item item* (Declaration (";" ~item item* Declaration?)*)? }
89
90selector {
91 UniversalSelector |
92 TagSelector { ~item TagName { identifier ~item } } |
93 NestingSelector |
94 ClassSelector { selector? !attribute "." ClassName { identifier } } |
95 PseudoClassSelector {
96 selector? !attribute (":" | "::") (
97 PseudoClassName { identifier } |
98 pseudoClassWithArg ArgList<value+> |
99 PseudoClassName { callee } ArgList<selector>)
100 } |
101 IdSelector { selector? !attribute "#" IdName { identifier } } |
102 AttributeSelector { selector? !attribute "[" AttributeName { identifier } (MatchOp value)? "]" } |
103 ChildSelector { selector? !structure ChildOp selector } |
104 DescendantSelector { selector !structure descendantOp selector } |
105 SiblingSelector { selector? !structure SiblingOp selector }
106}
107
108pseudoClassWithArg {
109 @specialize[@name=PseudoClassName]<callee, "lang" | "nth-child" | "nth-last-child" | "nth-of-type" | "nth-last-of-type" | "nth-of-type" | "dir" | "host-context">
110}
111
112NumberLiteral {
113 numberLiteralInner Unit?
114}
115
116ArgList<content> { "(" commaSep<content> ")" }
117
118Declaration {
119 (PropertyName { identifier ~item } | VariableName)
120 ":" (value (","? value)*)? Important?
121}
122
123query {
124 KeywordQuery { queryIdentifier } |
125 FeatureQuery { "(" FeatureName ":" value+ ")" } |
126 BinaryQuery { query !valueOp @specialize[@name=LogicOp]<queryIdentifier, "or" | "and"> query } |
127 ComparisonQuery {
128 "("
129 (queryValue | FeatureName) !valueCompareOp CompareOp (queryValue | FeatureName)
130 (!valueCompareOp CompareOp (queryValue | FeatureName))?
131 ")"
132 } |
133 UnaryQuery { @specialize[@name=UnaryQueryOp]<queryIdentifier, "not" | "only"> query } |
134 ParenthesizedQuery { "(" query ")" } |
135 SelectorQuery { queryCalleeKw<"selector"> ParenthesizedSelector } |
136 CallQuery { QueryCallee ArgList<FeatureName ":" value+ | query> }
137}
138
139ParenthesizedSelector { "(" selector ")" }
140
141FeatureName { queryIdentifier }
142
143value {
144 VariableName |
145 ValueName { identifier } |
146 ParenthesizedValue { "(" token* ")" } |
147 BracketedValue { "[" token* "]" } |
148 BracedValue { "{" token* "}" } |
149 ColorLiteral |
150 NumberLiteral |
151 StringLiteral |
152 BinaryExpression { value !valueOp BinOp value } |
153 CallExpression |
154 IfExpression |
155 CallLiteral
156}
157
158token {
159 value |
160 AtKeyword |
161 "#" | ";" | "." | ":"
162}
163
164queryValue {
165 queryVariableName |
166 ColorLiteral |
167 NumberLiteral |
168 StringLiteral
169}
170
171IfExpression {
172 @specialize[@name=if]<callee, "if"> ArgList {
173 "(" (IfBranch ";")* IfBranch ";"? ")"
174 }
175}
176
177IfBranch { query ":" value }
178
179CallLiteral {
180 @specialize[@name=CallTag]<callee, "url" | "url-prefix" | "domain" | "regexp">
181 "(" (ParenthesizedContent | StringLiteral)? ")"
182}
183
184CallExpression {
185 (Callee { callee } | VariableName) !call ArgList<value+>
186}
187
188@skip {} {
189 Comment[isolate] { "/*" (commentContent | commentLineBreak)* commentEnd }
190}
191
192@local tokens {
193 commentEnd { "*/" | @eof }
194 commentLineBreak { "\n" }
195 @else commentContent
196}
197
198commaSep<value> { "" | value ("," value?)* }
199
200queryKw<name> { @specialize[@name={name}]<queryIdentifier, name> }
201queryCalleeKw<name> { @specialize[@name={name}]<QueryCallee, name> }
202
203atKw<name> { @specialize[@name={name}]<AtKeyword, "@" name> }
204
205@external tokens descendant from "./tokens" {
206 descendantOp
207}
208
209@external tokens unitToken from "./tokens" {
210 Unit
211}
212
213@external tokens identifiers from "./tokens" {
214 identifier,
215 callee,
216 VariableName
217}
218
219@external tokens queryIdentifiers from "./tokens" {
220 @conflict { identifier, VariableName, callee }
221 queryIdentifier,
222 queryVariableName[@name=VariableName],
223 QueryCallee
224}
225
226@tokens {
227 UniversalSelector { "*" }
228
229 NestingSelector { "&" }
230
231 AtKeyword { "@" "-"? @asciiLetter (@asciiLetter | @digit | "-")* }
232
233 MatchOp { $[~^|*$]? "=" }
234
235 ChildOp { ">" ">"? }
236
237 CompareOp { $[<>] "="? | "=" }
238
239 SiblingOp { "~" | "+" }
240
241 BinOp { $[+\-*/] }
242
243 Important { "!important" }
244
245 whitespace { @whitespace+ }
246
247 hexDigit { @digit | $[a-fA-F] }
248
249 ParenthesizedContent { !['")] ![)]+ }
250
251 @precedence { whitespace, ParenthesizedContent, "/*" }
252
253 ColorLiteral {
254 "#" hexDigit hexDigit hexDigit (hexDigit (hexDigit hexDigit (hexDigit hexDigit)?)?)?
255 }
256
257 numberLiteralInner { ("+" | "-")? (@digit+ ("." @digit*)? | "." @digit+) (("e" | "E") ("+" | "-")? @digit+)? }
258
259 @precedence { numberLiteralInner, BinOp, SiblingOp }
260
261 @precedence { numberLiteralInner, "." }
262
263 StringLiteral[isolate] { "\"" (!["\n\\] | "\\" _)* "\"" | "'" (!['\n\\] | "\\" _)* "'" }
264
265 "#" "."
266
267 ":" "::" ";" ","
268
269 "(" ")" "[" "]" "{" "}"
270}
271
272@external propSource cssHighlighting from "./highlight"
273
274@detectDelim