Handle uppercase I
in attribute selectors
This commit is contained in:
parent
3e45f05d97
commit
65030eb7ea
33
src/lexer.rs
33
src/lexer.rs
@ -4,7 +4,7 @@ use std::str::Chars;
|
||||
|
||||
use crate::atrule::AtRuleKind;
|
||||
use crate::common::{Keyword, Op, Pos, Symbol};
|
||||
use crate::selector::{Attribute, AttributeKind};
|
||||
use crate::selector::{Attribute, AttributeKind, CaseKind};
|
||||
use crate::{Token, TokenKind, Whitespace};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -243,7 +243,7 @@ impl<'a> Lexer<'a> {
|
||||
kind: AttributeKind::Any,
|
||||
attr,
|
||||
value: String::new(),
|
||||
case_sensitive: true,
|
||||
case_sensitive: CaseKind::Sensitive,
|
||||
})
|
||||
}
|
||||
'i' => {
|
||||
@ -253,7 +253,17 @@ impl<'a> Lexer<'a> {
|
||||
kind: AttributeKind::Any,
|
||||
attr,
|
||||
value: String::new(),
|
||||
case_sensitive: false,
|
||||
case_sensitive: CaseKind::InsensitiveLowercase,
|
||||
});
|
||||
}
|
||||
'I' => {
|
||||
self.devour_whitespace();
|
||||
assert!(self.buf.next() == Some(']'));
|
||||
return TokenKind::Attribute(Attribute {
|
||||
kind: AttributeKind::Any,
|
||||
attr,
|
||||
value: String::new(),
|
||||
case_sensitive: CaseKind::InsensitiveCapital,
|
||||
});
|
||||
}
|
||||
'=' => AttributeKind::Equals,
|
||||
@ -272,14 +282,19 @@ impl<'a> Lexer<'a> {
|
||||
self.devour_whitespace();
|
||||
|
||||
let mut value = String::with_capacity(99);
|
||||
let mut case_sensitive = true;
|
||||
let mut case_sensitive = CaseKind::Sensitive;
|
||||
|
||||
while let Some(c) = self.buf.peek() {
|
||||
if !c.is_alphabetic() && c != &'-' && c != &'_' && c != &'"' && c != &'\'' {
|
||||
break;
|
||||
}
|
||||
|
||||
if c == &'i' || c == &'I' {
|
||||
if c == &'i' {
|
||||
case_sensitive = CaseKind::InsensitiveLowercase;
|
||||
} else if c == &'I' {
|
||||
case_sensitive = CaseKind::InsensitiveCapital;
|
||||
}
|
||||
let tok = self
|
||||
.buf
|
||||
.next()
|
||||
@ -287,7 +302,14 @@ impl<'a> Lexer<'a> {
|
||||
self.pos.next_char();
|
||||
self.devour_whitespace();
|
||||
match self.buf.next() {
|
||||
Some(']') => case_sensitive = false,
|
||||
Some(']') => {
|
||||
return TokenKind::Attribute(Attribute {
|
||||
kind,
|
||||
attr,
|
||||
value,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
Some(val) => {
|
||||
self.pos.next_char();
|
||||
value.push(tok);
|
||||
@ -304,6 +326,7 @@ impl<'a> Lexer<'a> {
|
||||
.expect("this is impossible because we have already peeked");
|
||||
self.pos.next_char();
|
||||
value.push(tok);
|
||||
self.devour_whitespace();
|
||||
}
|
||||
|
||||
self.devour_whitespace();
|
||||
|
@ -329,38 +329,51 @@ impl Selector {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Attribute {
|
||||
pub(crate) struct Attribute {
|
||||
pub attr: String,
|
||||
pub value: String,
|
||||
pub case_sensitive: bool,
|
||||
pub case_sensitive: CaseKind,
|
||||
pub kind: AttributeKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum CaseKind {
|
||||
InsensitiveCapital,
|
||||
InsensitiveLowercase,
|
||||
Sensitive,
|
||||
}
|
||||
|
||||
impl Display for CaseKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InsensitiveCapital => write!(f, " I"),
|
||||
Self::InsensitiveLowercase => write!(f, " i"),
|
||||
Self::Sensitive => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Attribute {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.case_sensitive {
|
||||
match self.kind {
|
||||
AttributeKind::Any => write!(f, "[{}]", self.attr),
|
||||
AttributeKind::Equals => write!(f, "[{}={}]", self.attr, self.value),
|
||||
AttributeKind::InList => write!(f, "[{}~={}]", self.attr, self.value),
|
||||
AttributeKind::Any => write!(f, "[{}{}]", self.attr, self.case_sensitive),
|
||||
AttributeKind::Equals => {
|
||||
write!(f, "[{}={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
AttributeKind::InList => {
|
||||
write!(f, "[{}~={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
AttributeKind::BeginsWithHyphenOrExact => {
|
||||
write!(f, "[{}|={}]", self.attr, self.value)
|
||||
write!(f, "[{}|={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
AttributeKind::StartsWith => write!(f, "[{}^={}]", self.attr, self.value),
|
||||
AttributeKind::EndsWith => write!(f, "[{}$={}]", self.attr, self.value),
|
||||
AttributeKind::Contains => write!(f, "[{}*={}]", self.attr, self.value),
|
||||
AttributeKind::StartsWith => {
|
||||
write!(f, "[{}^={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
} else {
|
||||
match self.kind {
|
||||
AttributeKind::Any => write!(f, "[{} i]", self.attr),
|
||||
AttributeKind::Equals => write!(f, "[{}={} i]", self.attr, self.value),
|
||||
AttributeKind::InList => write!(f, "[{}~={} i]", self.attr, self.value),
|
||||
AttributeKind::BeginsWithHyphenOrExact => {
|
||||
write!(f, "[{}|={} i]", self.attr, self.value)
|
||||
AttributeKind::EndsWith => {
|
||||
write!(f, "[{}$={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
AttributeKind::StartsWith => write!(f, "[{}^={} i]", self.attr, self.value),
|
||||
AttributeKind::EndsWith => write!(f, "[{}$={} i]", self.attr, self.value),
|
||||
AttributeKind::Contains => write!(f, "[{}*={} i]", self.attr, self.value),
|
||||
AttributeKind::Contains => {
|
||||
write!(f, "[{}*={}{}]", self.attr, self.value, self.case_sensitive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +127,14 @@ mod test_selectors {
|
||||
);
|
||||
|
||||
test!(selector_attribute_any, "[attr] {\n color: red;\n}\n");
|
||||
test!(
|
||||
selector_attribute_any_lower_case_insensitive,
|
||||
"[attr i] {\n color: red;\n}\n"
|
||||
);
|
||||
test!(
|
||||
selector_attribute_any_upper_case_insensitive,
|
||||
"[attr I] {\n color: red;\n}\n"
|
||||
);
|
||||
test!(
|
||||
selector_attribute_equals,
|
||||
"[attr=val] {\n color: red;\n}\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user