Skip to main content

css_ast/selector/
functional_pseudo_element.rs

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	/// <https://drafts.csswg.org/css-highlight-api/#custom-highlight-pseudo>
16	Highlight(HighlightPseudoElement),
17	/// <https://drafts.csswg.org/css-shadow-parts/#part>
18	Part(PartPseudoElement<'a>),
19	/// <https://drafts.csswg.org/css-forms-1/#picker-pseudo>
20	Picker(PickerPseudoElement),
21	/// <https://drafts.csswg.org/css-scoping/#slotted-pseudo>
22	Slotted(SlottedPseudoElement<'a>),
23	/// <https://drafts.csswg.org/css-view-transitions-2/#view-transition-pseudo>
24	/// <https://drafts.csswg.org/css-view-transitions-2/#::view-transition-group>
25	ViewTransitionGroup(ViewTransitionGroupPseudoElement<'a>),
26	/// <https://drafts.csswg.org/css-view-transitions-2/#::view-transition-image-pair>
27	ViewTransitionImagePair(ViewTransitionImagePairPseudoElement<'a>),
28	/// <https://drafts.csswg.org/css-view-transitions-2/#::view-transition-new>
29	ViewTransitionNew(ViewTransitionNewPseudoElement<'a>),
30	/// <https://drafts.csswg.org/css-view-transitions-2/#::view-transition-old>
31	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}