1use super::prelude::*;
2use crate::{LineNames, NonEmpty, PositiveNonZeroInt};
3
4#[node]
12#[derive(Parse, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
14#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
15#[derive(csskit_derives::NodeWithMetadata)]
16pub struct RepeatFunction<Items, Count = PositiveNonZeroInt> {
17 #[cfg_attr(feature = "visitable", visit(skip))]
18 #[atom(CssAtomSet::Repeat)]
19 pub name: css_parse::token_macros::Function,
20 #[cfg_attr(feature = "visitable", visit(skip))]
21 pub count: Count,
22 #[cfg_attr(feature = "visitable", visit(skip))]
23 #[semantic_eq(skip)]
24 pub comma: css_parse::token_macros::Comma,
25 pub items: Items,
26 #[cfg_attr(feature = "visitable", visit(skip))]
27 #[semantic_eq(skip)]
28 pub close: css_parse::token_macros::RightParen,
29}
30
31impl<'a, Items, Count: Peek<'a>> Peek<'a> for RepeatFunction<Items, Count> {
32 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Function]);
33
34 #[inline(always)]
35 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
36 where
37 I: Iterator<Item = Cursor> + Clone,
38 {
39 <css_parse::token_macros::Function>::peek(p, c)
40 && p.equals_atom(c, &CssAtomSet::Repeat)
41 && Count::peek(p, p.peek_n(2))
42 }
43}
44
45#[node]
46#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
48#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
49#[derive(csskit_derives::NodeWithMetadata)]
50pub struct NamedRepeatItems<'a, Item> {
51 pub leading_names: Option<LineNames<'a>>,
52 pub items: NonEmpty<Vec<'a, (Item, Option<LineNames<'a>>)>>,
53}
54
55#[node]
56#[derive(
57 Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
58)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
60#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
61#[derive(csskit_derives::NodeWithMetadata)]
62pub enum AutoFillOrFit {
63 #[atom(CssAtomSet::AutoFill)]
64 AutoFill(T![Ident]),
65 #[atom(CssAtomSet::AutoFit)]
66 AutoFit(T![Ident]),
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::{CssAtomSet, FixedSize};
73 use css_parse::{assert_parse, assert_peek_false};
74
75 type FixedRepeat<'a> = RepeatFunction<NamedRepeatItems<'a, FixedSize<'a>>>;
76 type AutoRepeat<'a> = RepeatFunction<NamedRepeatItems<'a, FixedSize<'a>>, AutoFillOrFit>;
77
78 #[test]
79 fn test_count_disambiguates_same_named_function() {
80 assert_parse!(CssAtomSet::ATOMS, FixedRepeat, "repeat(2,10px)");
81 assert_peek_false!(CssAtomSet::ATOMS, FixedRepeat, "repeat(auto-fill,10px)");
82 assert_parse!(CssAtomSet::ATOMS, AutoRepeat, "repeat(auto-fill,10px)");
83 assert_peek_false!(CssAtomSet::ATOMS, AutoRepeat, "repeat(2,10px)");
84 }
85}