Handle uppercase I in attribute selectors

This commit is contained in:
ConnorSkees 2020-01-26 11:47:00 -05:00
parent 3e45f05d97
commit 65030eb7ea
3 changed files with 74 additions and 30 deletions

View File

@ -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' {
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();

View File

@ -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::BeginsWithHyphenOrExact => {
write!(f, "[{}|={}]", self.attr, self.value)
}
AttributeKind::StartsWith => write!(f, "[{}^={}]", self.attr, self.value),
AttributeKind::EndsWith => write!(f, "[{}$={}]", self.attr, self.value),
AttributeKind::Contains => write!(f, "[{}*={}]", self.attr, self.value),
match self.kind {
AttributeKind::Any => write!(f, "[{}{}]", self.attr, self.case_sensitive),
AttributeKind::Equals => {
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::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::InList => {
write!(f, "[{}~={}{}]", self.attr, self.value, self.case_sensitive)
}
AttributeKind::BeginsWithHyphenOrExact => {
write!(f, "[{}|={}{}]", self.attr, self.value, self.case_sensitive)
}
AttributeKind::StartsWith => {
write!(f, "[{}^={}{}]", self.attr, self.value, self.case_sensitive)
}
AttributeKind::EndsWith => {
write!(f, "[{}$={}{}]", self.attr, self.value, self.case_sensitive)
}
AttributeKind::Contains => {
write!(f, "[{}*={}{}]", self.attr, self.value, self.case_sensitive)
}
}
}

View File

@ -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"