1use crate::{CssAtomSet, CssDiagnostic};
2use bumpalo::collections::Vec;
3use css_lexer::Kind;
4use css_parse::{Cursor, Diagnostic, KindSet, Parse, Parser, Peek, Result as ParserResult, T};
5use csskit_derives::*;
6
7use super::CompoundSelector;
8
9#[derive(ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
11#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
12#[derive(csskit_derives::NodeWithMetadata)]
13#[cfg_attr(feature = "css_feature_data", derive(::csskit_derives::ToCSSFeature), css_feature("css.selectors"))]
14pub enum FunctionalPseudoElement<'a> {
15 Highlight(HighlightPseudoElement),
17 Part(PartPseudoElement<'a>),
19 Picker(PickerPseudoElement),
21 Slotted(SlottedPseudoElement<'a>),
23 ViewTransitionGroup(ViewTransitionGroupPseudoElement<'a>),
26 ViewTransitionImagePair(ViewTransitionImagePairPseudoElement<'a>),
28 ViewTransitionNew(ViewTransitionNewPseudoElement<'a>),
30 ViewTransitionOld(ViewTransitionOldPseudoElement<'a>),
32}
33
34impl<'a> Peek<'a> for FunctionalPseudoElement<'a> {
35 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::Colon]);
36
37 #[inline(always)]
38 fn peek<I>(p: &Parser<'a, I>, _: css_lexer::Cursor) -> bool
39 where
40 I: Iterator<Item = Cursor> + Clone,
41 {
42 p.peek::<T![::]>() && p.peek_n(3) == Kind::Function
43 }
44}
45
46impl<'a> Parse<'a> for FunctionalPseudoElement<'a> {
47 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
48 where
49 I: Iterator<Item = Cursor> + Clone,
50 {
51 match p.to_atom::<CssAtomSet>(p.peek_n(3)) {
52 CssAtomSet::Highlight => p.parse::<HighlightPseudoElement>().map(Self::Highlight),
53 CssAtomSet::Part => p.parse::<PartPseudoElement>().map(Self::Part),
54 CssAtomSet::Picker => p.parse::<PickerPseudoElement>().map(Self::Picker),
55 CssAtomSet::Slotted => p.parse::<SlottedPseudoElement>().map(Self::Slotted),
56 CssAtomSet::ViewTransitionGroup => {
57 p.parse::<ViewTransitionGroupPseudoElement>().map(Self::ViewTransitionGroup)
58 }
59 CssAtomSet::ViewTransitionImagePair => {
60 p.parse::<ViewTransitionImagePairPseudoElement>().map(Self::ViewTransitionImagePair)
61 }
62 CssAtomSet::ViewTransitionNew => p.parse::<ViewTransitionNewPseudoElement>().map(Self::ViewTransitionNew),
63 CssAtomSet::ViewTransitionOld => p.parse::<ViewTransitionOldPseudoElement>().map(Self::ViewTransitionOld),
64 _ => Err(Diagnostic::new(p.next(), Diagnostic::unexpected_pseudo_element))?,
65 }
66 }
67}
68
69#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
71#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
72#[derive(csskit_derives::NodeWithMetadata)]
73pub struct HighlightPseudoElement {
74 pub colons: T![::],
75 #[atom(CssAtomSet::Highlight)]
76 pub function: T![Function],
77 pub value: T![Ident],
78 pub close: T![')'],
79}
80
81#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
83#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
84#[derive(csskit_derives::NodeWithMetadata)]
85pub struct SlottedPseudoElement<'a> {
86 #[cfg_attr(feature = "visitable", visit(skip))]
87 pub colons: T![::],
88 #[cfg_attr(feature = "visitable", visit(skip))]
89 #[atom(CssAtomSet::Slotted)]
90 pub function: T![Function],
91 pub value: CompoundSelector<'a>,
92 #[cfg_attr(feature = "visitable", visit(skip))]
93 pub close: Option<T![')']>,
94}
95
96#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
98#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
99#[derive(csskit_derives::NodeWithMetadata)]
100pub struct PartPseudoElement<'a> {
101 pub colons: T![::],
102 #[atom(CssAtomSet::Part)]
103 pub function: T![Function],
104 pub value: Vec<'a, T![Ident]>,
105 pub close: Option<T![')']>,
106}
107
108#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
110#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
111#[derive(csskit_derives::NodeWithMetadata)]
112pub struct PickerPseudoElement {
113 pub colons: T![::],
114 #[atom(CssAtomSet::Picker)]
115 pub function: T![Function],
116 pub value: T![Ident],
117 pub close: Option<T![')']>,
118}
119
120#[derive(Parse, 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(self))]
123#[derive(csskit_derives::NodeWithMetadata)]
124pub struct ViewTransitionGroupPseudoElement<'a> {
125 pub colons: T![::],
126 #[atom(CssAtomSet::ViewTransitionGroup)]
127 pub function: T![Function],
128 pub value: PtNameAndClassSelector<'a>,
129 pub close: Option<T![')']>,
130}
131
132#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
133#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
134#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
135#[derive(csskit_derives::NodeWithMetadata)]
136pub struct ViewTransitionImagePairPseudoElement<'a> {
137 pub colons: T![::],
138 #[atom(CssAtomSet::ViewTransitionImagePair)]
139 pub function: T![Function],
140 pub value: PtNameAndClassSelector<'a>,
141 pub close: Option<T![')']>,
142}
143
144#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
146#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
147#[derive(csskit_derives::NodeWithMetadata)]
148pub struct ViewTransitionNewPseudoElement<'a> {
149 pub colons: T![::],
150 #[atom(CssAtomSet::ViewTransitionNew)]
151 pub function: T![Function],
152 pub value: PtNameAndClassSelector<'a>,
153 pub close: Option<T![')']>,
154}
155
156#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
158#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
159#[derive(csskit_derives::NodeWithMetadata)]
160pub struct ViewTransitionOldPseudoElement<'a> {
161 pub colons: T![::],
162 #[atom(CssAtomSet::ViewTransitionOld)]
163 pub function: T![Function],
164 pub value: PtNameAndClassSelector<'a>,
165 pub close: Option<T![')']>,
166}
167
168#[derive(Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
169#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
170#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
171#[derive(csskit_derives::NodeWithMetadata)]
172pub enum PtNameAndClassSelector<'a> {
173 Wildcard(T![*]),
174 Named(T![Ident], Vec<'a, (T![.], T![Ident])>),
175 Classes(Vec<'a, (T![.], T![Ident])>),
176}