css_parse/syntax/
bang_important.rs

1use crate::{Cursor, CursorSink, Kind, Parse, Parser, Peek, Result, Span, T, ToCursors, ToSpan, diagnostics};
2
3/// Represents a two tokens, the first being [Kind::Delim] where the char is `!`, and the second being an `Ident` with
4/// the value `important`. [CSS defines this as]:
5///
6/// ```md
7/// <ws*>
8///     ╭──────────────────────────╮
9///  │├─╯─╭─ <whitespace-token> ─╮─╰─┤│
10///       ╰──────────────────────╯
11///
12/// <!important>
13///  │├─ "!" ─ <ws*> ─ <ident-token "important"> ─ <ws*> ─┤│
14/// ```
15///
16/// `<ws*>` is any number of `<whitespace-token>`s, defined as [Kind::Whitespace][Kind::Whitespace]. This is
17/// automatically skipped by default in the [Parser] anyway.
18///
19/// [1]: https://drafts.csswg.org/css-syntax-3/#!important-diagram
20///
21#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
23pub struct BangImportant {
24	pub bang: T![!],
25	pub important: T![Ident],
26}
27
28impl<'a> Peek<'a> for BangImportant {
29	fn peek(p: &Parser<'a>, c: Cursor) -> bool {
30		if c == Kind::Delim && c == '!' {
31			let c = p.peek_n(2);
32			c == Kind::Ident && p.eq_ignore_ascii_case(c, "important")
33		} else {
34			false
35		}
36	}
37}
38
39impl<'a> Parse<'a> for BangImportant {
40	fn parse(p: &mut Parser<'a>) -> Result<Self> {
41		let bang = p.parse::<T![!]>()?;
42		let important = p.parse::<T![Ident]>()?;
43		if !p.eq_ignore_ascii_case(important.into(), "important") {
44			let source_cursor = p.to_source_cursor(important.into());
45			Err(diagnostics::ExpectedIdentOf("important", source_cursor.to_string(), important.into()))?
46		}
47		Ok(Self { bang, important })
48	}
49}
50
51impl ToCursors for BangImportant {
52	fn to_cursors(&self, s: &mut impl CursorSink) {
53		s.append(self.bang.into());
54		s.append(self.important.into());
55	}
56}
57
58impl ToSpan for BangImportant {
59	fn to_span(&self) -> Span {
60		self.bang.to_span() + self.important.to_span()
61	}
62}