1use crate::{DirValue, diagnostics};
2use css_parse::{
3 Build, Cursor, Parse, Parser, Result as ParserResult, T, function_set, pseudo_class, pseudo_element,
4 syntax::CommaSeparated,
5};
6use csskit_derives::{ToCursors, Visitable};
7
8pseudo_element!(
9 #[derive(Visitable)]
11 #[visit(self)]
12 pub enum MozPseudoElement {
13 AnonymousBlock: "-moz-anonymous-block",
14 AnonymousItem: "-moz-anonymous-item",
15 AnonymousPositionedBlock: "-moz-anonymous-positioned-block",
16 BlockInsideInlineWrapper: "-moz-block-inside-inline-wrapper",
17 BlockRubyContent: "-moz-block-ruby-content",
18 ButtonContent: "-moz-button-content",
19 Canvas: "-moz-canvas",
20 CellContent: "-moz-cell-content",
21 ColorSwatch: "-moz-color-swatch",
22 ColumnContent: "-moz-column-content",
23 ColumnSet: "-moz-column-set",
24 ColumnSpanWrapper: "-moz-column-span-wrapper",
25 DropdownList: "-moz-dropdown-list",
26 FieldsetContent: "-moz-fieldset-content",
27 FirstLetterContinuation: "-moz-first-letter-continuation",
28 FocusInner: "-moz-focus-inner",
29 FocusOuter: "-moz-focus-outer",
30 FramesetBlank: "-moz-frameset-blank",
31 HframesetBorder: "-moz-hframeset-border",
32 HtmlCanvasContent: "-moz-html-canvas-content",
33 InlineTable: "-moz-inline-table",
34 LineFrame: "-moz-line-frame",
35 ListBullet: "-moz-list-bullet",
36 ListNumber: "-moz-list-number",
37 MathmlAnonymousBlock: "-moz-mathml-anonymous-block",
38 NumberSpinBox: "-moz-number-spin-box",
39 NumberSpinDown: "-moz-number-spin-down",
40 NumberSpinUp: "-moz-number-spin-up",
41 OofPlaceholder: "-moz-oof-placeholder",
42 Page: "-moz-page",
43 PageBreak: "-moz-page-break",
44 PageContent: "-moz-page-content",
45 PageSequence: "-moz-page-sequence",
46 Pagebreak: "-moz-pagebreak",
47 Pagecontent: "-moz-pagecontent",
48 Placeholder: "-moz-placeholder",
49 PrintedSheet: "-moz-printed-sheet",
50 ProgressBar: "-moz-progress-bar",
51 RangeProgress: "-moz-range-progress",
52 RangeThumb: "-moz-range-thumb",
53 RangeTrack: "-moz-range-track",
54 Reveal: "-moz-reveal",
55 Ruby: "-moz-ruby",
56 RubyBase: "-moz-ruby-base",
57 RubyBaseContainer: "-moz-ruby-base-container",
58 RubyText: "-moz-ruby-text",
59 RubyTextContainer: "-moz-ruby-text-container",
60 ScrolledCanvas: "-moz-scrolled-canvas",
61 ScrolledContent: "-moz-scrolled-content",
62 ScrolledPageSequence: "-moz-scrolled-page-sequence",
63 SearchClearButton: "-moz-search-clear-button",
64 Selection: "-moz-selection",
65 SvgForeignContent: "-moz-svg-foreign-content",
66 SvgMarkerAnonChild: "-moz-svg-marker-anon-child",
67 SvgMarkerOuterSvgAnonChild: "-moz-svg-marker-outer-svg-anon-child",
68 SvgText: "-moz-svg-text",
69 Table: "-moz-table",
70 TableCell: "-moz-table-cell",
71 TableColumn: "-moz-table-column",
72 TableColumnGroup: "-moz-table-column-group",
73 TableOuter: "-moz-table-outer",
74 TableRow: "-moz-table-row",
75 TableRowGroup: "-moz-table-row-group",
76 TableWrapper: "-moz-table-wrapper",
77 TextControlEditingRoot: "-moz-text-control-editing-root",
78 TextControlPreview: "-moz-text-control-preview",
79 TreeCell: "-moz-tree-cell",
80 TreeCheckbox: "-moz-tree-checkbox",
81 TreeDropFeedback: "-moz-tree-drop-feedback",
82 TreeIndentation: "-moz-tree-indentation",
83 TreeSeparator: "-moz-tree-separator",
84 VframesetBorder: "-moz-vframeset-border",
85 Viewport: "-moz-viewport",
86 ViewportScroll: "-moz-viewport-scroll",
87 }
88);
89
90#[derive(ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(rename_all = "kebab-case"))]
92#[visit(self)]
93pub enum MozFunctionalPseudoElement<'a> {
94 TreeCell(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
95 TreeCellText(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
96 TreeCheckbox(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
97 TreeColumn(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
98 TreeImage(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
99 TreeLine(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
100 TreeRow(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
101 TreeSeparator(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
102 TreeTwisty(T![::], T![Function], CommaSeparated<'a, T![Ident]>, T![')']),
103}
104
105function_set!(
106 pub enum MozFunctionalPseudoElementKeyword {
107 TreeCell: "-moz-tree-cell",
108 TreeCellText: "-moz-tree-cell-text",
109 TreeCheckbox: "-moz-tree-checkbox",
110 TreeColumn: "-moz-tree-column",
111 TreeImage: "-moz-tree-image",
112 TreeLine: "-moz-tree-line",
113 TreeRow: "-moz-tree-row",
114 TreeSeparator: "-moz-tree-separator",
115 TreeTwisty: "-moz-tree-twisty",
116 }
117);
118
119impl<'a> Parse<'a> for MozFunctionalPseudoElement<'a> {
120 fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
121 let colons = p.parse::<T![::]>()?;
122 let keyword = p.parse::<MozFunctionalPseudoElementKeyword>()?;
123 let function = <T![Function]>::build(p, keyword.into());
124 let items = p.parse::<CommaSeparated<'a, T![Ident]>>()?;
125 let close = p.parse::<T![')']>()?;
126 Ok(match keyword {
127 MozFunctionalPseudoElementKeyword::TreeCell(_) => Self::TreeCell(colons, function, items, close),
128 MozFunctionalPseudoElementKeyword::TreeCellText(_) => Self::TreeCellText(colons, function, items, close),
129 MozFunctionalPseudoElementKeyword::TreeCheckbox(_) => Self::TreeCheckbox(colons, function, items, close),
130 MozFunctionalPseudoElementKeyword::TreeColumn(_) => Self::TreeColumn(colons, function, items, close),
131 MozFunctionalPseudoElementKeyword::TreeImage(_) => Self::TreeImage(colons, function, items, close),
132 MozFunctionalPseudoElementKeyword::TreeLine(_) => Self::TreeLine(colons, function, items, close),
133 MozFunctionalPseudoElementKeyword::TreeRow(_) => Self::TreeRow(colons, function, items, close),
134 MozFunctionalPseudoElementKeyword::TreeSeparator(_) => Self::TreeSeparator(colons, function, items, close),
135 MozFunctionalPseudoElementKeyword::TreeTwisty(_) => Self::TreeTwisty(colons, function, items, close),
136 })
137 }
138}
139
140pseudo_class!(
141 #[derive(Visitable)]
143 #[visit(self)]
144 pub enum MozPseudoClass {
145 Any: "-moz-any",
146 AnyLink: "-moz-any-link",
147 Broken: "-moz-broken",
148 DragOver: "-moz-drag-over",
149 FirstNode: "-moz-first-node",
150 FocusRing: "-moz-focusring",
151 FullScreen: "-moz-full-screen",
152 FullScreenAncestor: "-moz-full-screen-ancestor",
153 HandlerBlocked: "-moz-handler-blocked",
154 HandlerCrashed: "-moz-handler-crashed",
155 HandlerDisabled: "-moz-handler-disabled",
156 LastNode: "-moz-last-node",
157 Loading: "-moz-loading",
158 LwTheme: "-moz-lwtheme",
159 LwThemeBrighttext: "-moz-lwtheme-brighttext",
160 LwThemeDarktext: "-moz-lwtheme-darktext",
161 NativeAnonymous: "-moz-native-anonymous",
162 OnlyWhitespace: "-moz-only-whitespace",
163 PlaceholderShown: "-moz-placeholder-shown",
164 ReadOnly: "-moz-read-only",
165 ReadWrite: "-moz-read-write",
166 SubmitInvalid: "-moz-submit-invalid",
167 Suppressed: "-moz-suppressed",
168 UiInvalid: "-moz-ui-invalid",
169 UiValid: "-moz-ui-valid",
170 UserDisabled: "-moz-user-disabled",
171 WindowInactive: "-moz-window-inactive",
172 }
173);
174
175#[derive(ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
176#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(rename_all = "kebab-case"))]
177#[visit]
178pub enum MozFunctionalPseudoClass {
179 LocaleDir(MozLocaleDirFunctionalPseudoClass),
180}
181
182impl<'a> Parse<'a> for MozFunctionalPseudoClass {
183 fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
184 let colon = p.parse::<T![:]>()?;
185 let function = p.parse::<T![Function]>()?;
186 let c: Cursor = function.into();
187 if p.eq_ignore_ascii_case(c, "-moz-locale-dir") {
188 let value = p.parse::<DirValue>()?;
189 let close = p.parse_if_peek::<T![')']>()?;
190 Ok(Self::LocaleDir(MozLocaleDirFunctionalPseudoClass { colon, function, value, close }))
191 } else {
192 Err(diagnostics::UnexpectedFunction(p.parse_str(c).into(), c))?
193 }
194 }
195}
196
197#[derive(ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
198#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(rename_all = "kebab-case"))]
199#[visit(self)]
200pub struct MozLocaleDirFunctionalPseudoClass {
201 pub colon: T![:],
202 pub function: T![Function],
203 pub value: DirValue,
204 pub close: Option<T![')']>,
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use css_parse::assert_parse;
211
212 #[test]
213 fn size_test() {
214 assert_eq!(std::mem::size_of::<MozPseudoElement>(), 40);
215 assert_eq!(std::mem::size_of::<MozFunctionalPseudoElement>(), 88);
216 assert_eq!(std::mem::size_of::<MozPseudoClass>(), 28);
217 assert_eq!(std::mem::size_of::<MozFunctionalPseudoClass>(), 56);
218 }
219
220 #[test]
221 fn test_writes() {
222 assert_parse!(MozPseudoElement, "::-moz-anonymous-block");
223 assert_parse!(MozFunctionalPseudoElement, "::-moz-tree-twisty(selected,focus)");
224 }
225}