1use super::prelude::*;
2use crate::{Angle, CalcableValue, LengthPercentage};
3use css_parse::Box;
4
5#[syntax(
13 " <move-command> | <line-command> | close | <horizontal-line-command> | <vertical-line-command> | <curve-command> | <smooth-command> | <arc-command> "
14)]
15#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
17#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
18#[derive(csskit_derives::NodeWithMetadata)]
19pub enum ShapeCommand<'a> {}
20
21#[syntax(" <length-percentage>{2} ")]
27#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
29#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
30#[derive(csskit_derives::NodeWithMetadata)]
31pub struct CoordinatePair<'a>;
32
33#[syntax(" to <position> | by <coordinate-pair> ")]
39#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
41#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
42#[derive(csskit_derives::NodeWithMetadata)]
43pub enum CommandEndPoint<'a> {}
44
45#[syntax(" <position> | <relative-control-point> ")]
51#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
53#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
54#[derive(csskit_derives::NodeWithMetadata)]
55pub enum ControlPoint<'a> {}
56
57#[syntax(" <coordinate-pair> [ from [ start | end | origin ] ]? ")]
63#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
65#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
66#[derive(csskit_derives::NodeWithMetadata)]
67pub struct RelativeControlPoint<'a>;
68
69#[syntax(" cw | ccw ")]
75#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
76#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
77#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
78#[derive(csskit_derives::NodeWithMetadata)]
79pub enum ArcSweep<'a> {}
80
81#[syntax(" large | small ")]
87#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
89#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
90#[derive(csskit_derives::NodeWithMetadata)]
91pub enum ArcSize<'a> {}
92
93#[node]
104#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
106#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
107#[derive(csskit_derives::NodeWithMetadata)]
108pub struct MoveCommand<'a> {
109 #[atom(CssAtomSet::Move)]
110 pub keyword: T![Ident],
111 pub point: CommandEndPoint<'a>,
112}
113
114#[node]
120#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
122#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
123#[derive(csskit_derives::NodeWithMetadata)]
124pub struct LineCommand<'a> {
125 #[atom(CssAtomSet::Line)]
126 pub keyword: T![Ident],
127 pub point: CommandEndPoint<'a>,
128}
129
130#[syntax(" <length-percentage> | left | center | right | x-start | x-end ")]
138#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
140#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
141#[derive(csskit_derives::NodeWithMetadata)]
142pub enum HorizontalLineValue<'a> {}
143
144#[syntax(" to <horizontal-line-value> | by <length-percentage> ")]
145#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
147#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
148#[derive(csskit_derives::NodeWithMetadata)]
149pub enum HorizontalLineClause<'a> {}
150
151#[node]
152#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
153#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
154#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
155#[derive(csskit_derives::NodeWithMetadata)]
156pub struct HorizontalLineCommand<'a> {
157 #[atom(CssAtomSet::Hline)]
158 pub keyword: T![Ident],
159 pub clause: HorizontalLineClause<'a>,
160}
161
162#[syntax(" <length-percentage> | top | center | bottom | y-start | y-end ")]
171#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
172#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
173#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
174#[derive(csskit_derives::NodeWithMetadata)]
175pub enum VerticalLineValue<'a> {}
176
177#[syntax(" to <vertical-line-value> | by <length-percentage> ")]
178#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
180#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
181#[derive(csskit_derives::NodeWithMetadata)]
182pub enum VerticalLineClause<'a> {}
183
184#[node]
185#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
186#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
187#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
188#[derive(csskit_derives::NodeWithMetadata)]
189pub struct VerticalLineCommand<'a> {
190 #[atom(CssAtomSet::Vline)]
191 pub keyword: T![Ident],
192 pub clause: VerticalLineClause<'a>,
193}
194
195#[syntax(
203 " to <position> with <control-point> [ / <control-point> ]? | by <coordinate-pair> with <relative-control-point> [ / <relative-control-point> ]? "
204)]
205#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
206#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
207#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
208#[derive(csskit_derives::NodeWithMetadata)]
209pub enum CurveTarget<'a> {}
210
211#[node]
212#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
214#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
215#[derive(csskit_derives::NodeWithMetadata)]
216pub struct CurveCommand<'a> {
217 #[atom(CssAtomSet::Curve)]
218 pub keyword: T![Ident],
219 pub target: Box<'a, CurveTarget<'a>>,
220}
221
222#[syntax(" to <position> [ with <control-point> ]? | by <coordinate-pair> [ with <relative-control-point> ]? ")]
230#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
232#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
233#[derive(csskit_derives::NodeWithMetadata)]
234pub enum SmoothTarget<'a> {}
235
236#[node]
237#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
238#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
239#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
240#[derive(csskit_derives::NodeWithMetadata)]
241pub struct SmoothCommand<'a> {
242 #[atom(CssAtomSet::Smooth)]
243 pub keyword: T![Ident],
244 pub target: Box<'a, SmoothTarget<'a>>,
245}
246
247#[node]
255#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
256#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
257#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
258#[derive(csskit_derives::NodeWithMetadata)]
259pub struct ArcRadii<'a> {
260 #[atom(CssAtomSet::Of)]
261 pub keyword: T![Ident],
262 pub horizontal: CalcableValue<'a, LengthPercentage>,
263 pub vertical: Option<CalcableValue<'a, LengthPercentage>>,
264}
265
266#[node]
267#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
268#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
269#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
270#[derive(csskit_derives::NodeWithMetadata)]
271pub struct ArcRotate<'a> {
272 #[atom(CssAtomSet::Rotate)]
273 pub keyword: T![Ident],
274 pub angle: CalcableValue<'a, Angle>,
275}
276
277#[node]
278#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
279#[parse(all_must_occur)]
280#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
281#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
282#[derive(csskit_derives::NodeWithMetadata)]
283pub struct ArcCommandParams<'a> {
284 pub radii: ArcRadii<'a>,
285 pub sweep: Option<ArcSweep<'a>>,
286 pub size: Option<ArcSize<'a>>,
287 pub rotate: Option<ArcRotate<'a>>,
288}
289
290#[node]
291#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
292#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
293#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
294#[derive(csskit_derives::NodeWithMetadata)]
295pub struct ArcCommand<'a> {
296 #[atom(CssAtomSet::Arc)]
297 pub keyword: T![Ident],
298 pub point: CommandEndPoint<'a>,
299 pub params: Box<'a, ArcCommandParams<'a>>,
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 use crate::CssAtomSet;
306 use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
307
308 #[test]
309 fn test_parses() {
310 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "close");
311 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "move to 10px 10px");
312 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "line by 10px 10px");
313 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "hline to 50%");
314 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "hline by 10px");
315 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "vline to bottom");
316 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "curve to 100% 5% with 100% 0%");
317 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "curve by 10px 10px with 5px 5px / 8px 8px");
318 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "smooth to 100% 5%");
319 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "smooth by 10px 10px with 5px 5px");
320 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "arc to 10px 10px of 5px 5px");
321 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "arc to 10px 10px of 5px cw large rotate 10deg");
322 assert_parse!(CssAtomSet::ATOMS, ShapeCommand, "arc to 10px 10px of calc(5px) rotate var(--a)");
323 }
324
325 #[test]
326 fn test_errors() {
327 assert_peek_false!(CssAtomSet::ATOMS, ShapeCommand, "foo");
328 assert_parse_error!(CssAtomSet::ATOMS, ShapeCommand, "move");
329 assert_parse_error!(CssAtomSet::ATOMS, ShapeCommand, "arc to 10px 10px");
330 }
331}