2020-03-01 14:53:52 -05:00
|
|
|
use std::fmt::{self, Display, Write};
|
2020-04-20 03:45:28 -04:00
|
|
|
|
|
|
|
use peekmore::{PeekMore, PeekMoreIterator};
|
2020-03-01 14:53:52 -05:00
|
|
|
|
2020-04-26 13:07:44 -04:00
|
|
|
use crate::common::{Brackets, ListSeparator, QuoteKind};
|
2020-02-17 07:18:54 -05:00
|
|
|
use crate::error::SassResult;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::scope::Scope;
|
2020-01-26 18:43:07 -05:00
|
|
|
use crate::utils::{
|
2020-04-03 13:28:37 -04:00
|
|
|
devour_whitespace, eat_comment, eat_ident_no_interpolation, parse_interpolation,
|
|
|
|
read_until_closing_paren, read_until_newline, IsWhitespace,
|
2020-01-26 18:43:07 -05:00
|
|
|
};
|
2020-04-26 13:07:44 -04:00
|
|
|
use crate::value::Value;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::Token;
|
2020-01-04 22:55:04 -05:00
|
|
|
|
2020-04-02 20:59:37 -04:00
|
|
|
use attribute::Attribute;
|
|
|
|
|
|
|
|
mod attribute;
|
|
|
|
|
2020-01-04 22:55:04 -05:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2020-04-03 13:28:37 -04:00
|
|
|
pub(crate) struct Selector(Vec<SelectorPart>);
|
2020-01-11 14:51:31 -05:00
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
struct SelectorPart {
|
|
|
|
pub inner: Vec<SelectorKind>,
|
|
|
|
pub is_invisible: bool,
|
|
|
|
pub has_newline: bool,
|
2020-04-05 02:39:38 -04:00
|
|
|
pub contains_super_selector: bool,
|
2020-04-03 13:28:37 -04:00
|
|
|
}
|
2020-01-11 14:51:31 -05:00
|
|
|
|
2020-04-26 13:07:44 -04:00
|
|
|
impl SelectorPart {
|
|
|
|
pub fn into_value(&self) -> Value {
|
|
|
|
let mut kinds = Vec::new();
|
|
|
|
let mut this_kind = Vec::new();
|
|
|
|
for kind in &self.inner {
|
|
|
|
match kind {
|
|
|
|
SelectorKind::Whitespace => {
|
|
|
|
if !this_kind.is_empty() {
|
|
|
|
kinds.push(SelectorPart {
|
|
|
|
inner: std::mem::take(&mut this_kind),
|
|
|
|
is_invisible: false,
|
|
|
|
has_newline: false,
|
|
|
|
contains_super_selector: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v => this_kind.push(v.clone()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !this_kind.is_empty() {
|
|
|
|
kinds.push(SelectorPart {
|
|
|
|
inner: std::mem::take(&mut this_kind),
|
|
|
|
is_invisible: false,
|
|
|
|
has_newline: false,
|
|
|
|
contains_super_selector: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Value::List(
|
|
|
|
kinds
|
|
|
|
.iter()
|
2020-05-22 14:35:41 -04:00
|
|
|
.map(|s| Value::String(s.to_string(), QuoteKind::None))
|
2020-04-26 13:07:44 -04:00
|
|
|
.collect(),
|
|
|
|
ListSeparator::Space,
|
|
|
|
Brackets::None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
impl Display for SelectorPart {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-04-20 03:45:28 -04:00
|
|
|
let mut iter = self.inner.iter().peekmore();
|
2020-04-03 13:28:37 -04:00
|
|
|
devour_whitespace(&mut iter);
|
2020-01-11 14:51:31 -05:00
|
|
|
while let Some(s) = iter.next() {
|
2020-04-03 13:28:37 -04:00
|
|
|
write!(f, "{}", s)?;
|
|
|
|
if devour_whitespace(&mut iter) {
|
|
|
|
match iter.peek() {
|
|
|
|
Some(SelectorKind::Universal)
|
|
|
|
| Some(SelectorKind::Following)
|
|
|
|
| Some(SelectorKind::ImmediateChild)
|
|
|
|
| Some(SelectorKind::Preceding) => {
|
|
|
|
f.write_char(' ')?;
|
|
|
|
write!(f, "{}", iter.next().unwrap())?;
|
2020-01-26 19:16:26 -05:00
|
|
|
devour_whitespace(&mut iter);
|
2020-04-03 13:28:37 -04:00
|
|
|
if iter.peek().is_some() {
|
|
|
|
f.write_char(' ')?;
|
2020-02-22 18:33:42 -05:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
Some(..) => {
|
|
|
|
f.write_char(' ')?;
|
|
|
|
}
|
|
|
|
None => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Selector {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
for (idx, part) in self.0.iter().enumerate() {
|
|
|
|
write!(f, "{}", part)?;
|
|
|
|
if idx + 1 < self.0.len() {
|
|
|
|
f.write_char(',')?;
|
|
|
|
if part.has_newline {
|
|
|
|
f.write_char('\n')?;
|
|
|
|
} else {
|
|
|
|
f.write_char(' ')?;
|
2020-01-26 19:16:26 -05:00
|
|
|
}
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
Ok(())
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2020-01-20 13:15:47 -05:00
|
|
|
pub(crate) enum SelectorKind {
|
2020-04-03 13:28:37 -04:00
|
|
|
/// Any string
|
|
|
|
///
|
|
|
|
/// `button`
|
2020-01-04 22:55:04 -05:00
|
|
|
Element(String),
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// An id selector
|
|
|
|
///
|
|
|
|
/// `#`
|
|
|
|
Id(String),
|
|
|
|
|
|
|
|
/// A class selector
|
|
|
|
///
|
|
|
|
/// `.`
|
|
|
|
Class(String),
|
|
|
|
|
|
|
|
/// A universal selector
|
|
|
|
///
|
|
|
|
/// `*`
|
2020-01-04 22:55:04 -05:00
|
|
|
Universal,
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// Select all immediate children
|
|
|
|
///
|
|
|
|
/// `>`
|
2020-01-11 14:51:31 -05:00
|
|
|
ImmediateChild,
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// Select all elements immediately following
|
|
|
|
///
|
|
|
|
/// `+`
|
2020-01-11 14:51:31 -05:00
|
|
|
Following,
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// Select elements preceeded by
|
|
|
|
///
|
|
|
|
/// `~`
|
2020-01-11 14:51:31 -05:00
|
|
|
Preceding,
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// Select elements with attribute
|
|
|
|
///
|
|
|
|
/// `[lang|=en]`
|
2020-01-04 22:55:04 -05:00
|
|
|
Attribute(Attribute),
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
Super,
|
|
|
|
|
|
|
|
/// Pseudo selector
|
|
|
|
///
|
|
|
|
/// `:hover`
|
2020-01-04 22:55:04 -05:00
|
|
|
Pseudo(String),
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
/// Pseudo element selector
|
|
|
|
///
|
|
|
|
/// `::before`
|
2020-02-02 15:06:46 -05:00
|
|
|
PseudoElement(String),
|
2020-01-04 22:55:04 -05:00
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
/// Pseudo selector with additional parens
|
|
|
|
///
|
|
|
|
/// `:any(h1, h2, h3, h4, h5, h6)`
|
|
|
|
PseudoParen(String, Selector),
|
|
|
|
|
|
|
|
/// Placeholder selector
|
|
|
|
///
|
|
|
|
/// `%`
|
|
|
|
Placeholder(String),
|
|
|
|
|
|
|
|
/// Denotes whitespace between two selectors
|
|
|
|
Whitespace,
|
2020-01-12 20:15:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl IsWhitespace for &SelectorKind {
|
|
|
|
fn is_whitespace(&self) -> bool {
|
|
|
|
self == &&SelectorKind::Whitespace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-11 14:51:31 -05:00
|
|
|
impl Display for SelectorKind {
|
2020-01-04 22:55:04 -05:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
2020-01-11 14:51:31 -05:00
|
|
|
SelectorKind::Element(s) => write!(f, "{}", s),
|
2020-04-03 13:28:37 -04:00
|
|
|
SelectorKind::Id(s) => write!(f, "#{}", s),
|
|
|
|
SelectorKind::Class(s) => write!(f, ".{}", s),
|
2020-01-11 14:51:31 -05:00
|
|
|
SelectorKind::Universal => write!(f, "*"),
|
2020-04-03 13:28:37 -04:00
|
|
|
SelectorKind::ImmediateChild => write!(f, ">"),
|
|
|
|
SelectorKind::Following => write!(f, "+"),
|
|
|
|
SelectorKind::Preceding => write!(f, "~"),
|
2020-01-11 14:51:31 -05:00
|
|
|
SelectorKind::Attribute(attr) => write!(f, "{}", attr),
|
|
|
|
SelectorKind::Pseudo(s) => write!(f, ":{}", s),
|
2020-02-02 15:06:46 -05:00
|
|
|
SelectorKind::PseudoElement(s) => write!(f, "::{}", s),
|
2020-02-02 18:01:09 -05:00
|
|
|
SelectorKind::PseudoParen(s, val) => write!(f, ":{}({})", s, val),
|
2020-04-03 13:28:37 -04:00
|
|
|
SelectorKind::Placeholder(s) => write!(f, "%{}", s),
|
2020-04-05 02:39:38 -04:00
|
|
|
SelectorKind::Super => unreachable!("& selector should not be emitted"),
|
2020-04-03 13:28:37 -04:00
|
|
|
SelectorKind::Whitespace => f.write_char(' '),
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
fn is_selector_name_char(c: char) -> bool {
|
|
|
|
c.is_ascii_alphanumeric()
|
|
|
|
|| c == '_'
|
|
|
|
|| c == '\\'
|
|
|
|
|| (!c.is_ascii() && !c.is_control())
|
|
|
|
|| c == '-'
|
2020-01-12 10:54:46 -05:00
|
|
|
}
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
impl Selector {
|
|
|
|
pub fn from_tokens<I: Iterator<Item = Token>>(
|
2020-04-20 03:45:28 -04:00
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-04-03 13:28:37 -04:00
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
2020-03-01 12:03:14 -05:00
|
|
|
) -> SassResult<Selector> {
|
2020-04-03 13:28:37 -04:00
|
|
|
let mut string = String::new();
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut span = if let Some(tok) = toks.peek() {
|
|
|
|
tok.pos()
|
|
|
|
} else {
|
|
|
|
return Ok(Selector::new());
|
|
|
|
};
|
2020-04-03 13:28:37 -04:00
|
|
|
while let Some(tok) = toks.next() {
|
2020-04-12 19:37:12 -04:00
|
|
|
span = span.merge(tok.pos());
|
2020-02-02 15:06:46 -05:00
|
|
|
match tok.kind {
|
2020-04-03 13:28:37 -04:00
|
|
|
'#' => {
|
|
|
|
if toks.peek().is_some() && toks.peek().unwrap().kind == '{' {
|
|
|
|
toks.next();
|
|
|
|
string.push_str(
|
2020-04-12 19:37:12 -04:00
|
|
|
&parse_interpolation(toks, scope, super_selector)?
|
|
|
|
.to_css_string(span)?,
|
2020-04-03 13:28:37 -04:00
|
|
|
);
|
2020-02-02 15:06:46 -05:00
|
|
|
} else {
|
2020-04-03 13:28:37 -04:00
|
|
|
string.push('#');
|
2020-01-11 19:16:59 -05:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
',' => {
|
|
|
|
while let Some(c) = string.pop() {
|
|
|
|
if c == ' ' || c == ',' {
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-03 13:33:55 -04:00
|
|
|
string.push(c);
|
|
|
|
string.push(',');
|
|
|
|
break;
|
2020-04-03 13:28:37 -04:00
|
|
|
}
|
2020-02-02 15:06:46 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
'/' => {
|
|
|
|
if toks.peek().is_none() {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err(("Expected selector.", tok.pos()).into());
|
2020-04-03 13:28:37 -04:00
|
|
|
} else if '*' == toks.peek().unwrap().kind {
|
|
|
|
toks.next();
|
|
|
|
eat_comment(toks, &Scope::new(), &Selector::new())?;
|
|
|
|
} else if '/' == toks.peek().unwrap().kind {
|
|
|
|
read_until_newline(toks);
|
|
|
|
devour_whitespace(toks);
|
|
|
|
} else {
|
2020-04-12 19:37:12 -04:00
|
|
|
return Err(("Expected selector.", tok.pos()).into());
|
2020-04-03 13:28:37 -04:00
|
|
|
}
|
|
|
|
string.push(' ');
|
|
|
|
}
|
|
|
|
c => string.push(c),
|
2020-01-11 19:16:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
while let Some(c) = string.pop() {
|
|
|
|
if c == ' ' || c == ',' || c == '\t' {
|
|
|
|
continue;
|
2020-01-11 16:12:23 -05:00
|
|
|
}
|
2020-04-03 13:33:55 -04:00
|
|
|
string.push(c);
|
|
|
|
break;
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
let mut is_invisible = false;
|
|
|
|
let mut has_newline = false;
|
2020-04-05 02:39:38 -04:00
|
|
|
let mut contains_super_selector = false;
|
2020-04-03 13:28:37 -04:00
|
|
|
let mut parts = Vec::new();
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
let mut sel_toks = Vec::new();
|
|
|
|
|
2020-05-16 17:28:30 -04:00
|
|
|
sel_toks.extend(string.chars().map(|x| Token::new(span, x)));
|
2020-04-12 19:37:12 -04:00
|
|
|
|
2020-04-20 03:45:28 -04:00
|
|
|
let mut iter = sel_toks.into_iter().peekmore();
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
while let Some(tok) = iter.peek() {
|
2020-05-24 08:56:53 -04:00
|
|
|
let Token { kind, pos } = *tok;
|
|
|
|
inner.push(match kind {
|
|
|
|
_ if is_selector_name_char(kind) => {
|
2020-04-12 19:37:12 -04:00
|
|
|
inner.push(SelectorKind::Element(
|
2020-05-24 08:56:53 -04:00
|
|
|
eat_ident_no_interpolation(&mut iter, false, pos)?.node,
|
2020-04-12 19:37:12 -04:00
|
|
|
));
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
2020-03-29 13:28:17 -04:00
|
|
|
}
|
2020-04-05 02:39:38 -04:00
|
|
|
'&' => {
|
|
|
|
contains_super_selector = true;
|
|
|
|
SelectorKind::Super
|
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
'.' => {
|
2020-04-03 13:28:37 -04:00
|
|
|
iter.next();
|
2020-04-12 19:37:12 -04:00
|
|
|
inner.push(SelectorKind::Class(
|
2020-05-24 08:56:53 -04:00
|
|
|
eat_ident_no_interpolation(&mut iter, false, pos)?.node,
|
2020-04-12 19:37:12 -04:00
|
|
|
));
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
2020-03-30 00:18:37 -04:00
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'#' => {
|
2020-04-03 13:28:37 -04:00
|
|
|
iter.next();
|
2020-04-12 19:37:12 -04:00
|
|
|
inner.push(SelectorKind::Id(
|
2020-05-24 08:56:53 -04:00
|
|
|
eat_ident_no_interpolation(&mut iter, false, pos)?.node,
|
2020-04-12 19:37:12 -04:00
|
|
|
));
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
2020-02-14 11:52:31 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
'%' => {
|
|
|
|
iter.next();
|
|
|
|
is_invisible = true;
|
2020-04-12 19:37:12 -04:00
|
|
|
inner.push(SelectorKind::Placeholder(
|
2020-05-24 08:56:53 -04:00
|
|
|
eat_ident_no_interpolation(&mut iter, false, pos)?.node,
|
2020-04-12 19:37:12 -04:00
|
|
|
));
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
2020-03-30 00:18:37 -04:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
'>' => SelectorKind::ImmediateChild,
|
|
|
|
'+' => SelectorKind::Following,
|
|
|
|
'~' => SelectorKind::Preceding,
|
|
|
|
'*' => SelectorKind::Universal,
|
2020-03-29 13:28:17 -04:00
|
|
|
',' => {
|
2020-04-03 13:28:37 -04:00
|
|
|
iter.next();
|
|
|
|
if iter.peek().is_some() && iter.peek().unwrap().kind == '\n' {
|
|
|
|
has_newline = true;
|
2020-02-22 17:26:30 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
if !inner.is_empty() {
|
|
|
|
parts.push(SelectorPart {
|
|
|
|
inner: inner.clone(),
|
|
|
|
is_invisible,
|
|
|
|
has_newline,
|
2020-04-05 02:39:38 -04:00
|
|
|
contains_super_selector,
|
2020-04-03 13:28:37 -04:00
|
|
|
});
|
|
|
|
inner.clear();
|
|
|
|
}
|
|
|
|
is_invisible = false;
|
|
|
|
has_newline = false;
|
2020-04-05 02:39:38 -04:00
|
|
|
contains_super_selector = false;
|
2020-04-03 13:28:37 -04:00
|
|
|
devour_whitespace(&mut iter);
|
|
|
|
continue;
|
2020-02-22 17:26:30 -05:00
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
'[' => {
|
2020-04-12 19:37:12 -04:00
|
|
|
let span = iter.next().unwrap().pos();
|
|
|
|
inner.push(Attribute::from_tokens(
|
|
|
|
&mut iter,
|
|
|
|
scope,
|
|
|
|
super_selector,
|
|
|
|
span,
|
|
|
|
)?);
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
':' => {
|
|
|
|
iter.next();
|
2020-04-05 02:39:38 -04:00
|
|
|
let sel = Self::consume_pseudo_selector(&mut iter, scope, super_selector)?;
|
|
|
|
match &sel {
|
|
|
|
SelectorKind::PseudoParen(_, s) => {
|
|
|
|
if s.contains_super_selector() {
|
|
|
|
contains_super_selector = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
inner.push(sel);
|
2020-04-03 13:28:37 -04:00
|
|
|
continue;
|
2020-03-30 00:18:37 -04:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
c if c.is_whitespace() => {
|
|
|
|
if devour_whitespace(&mut iter) {
|
|
|
|
inner.push(SelectorKind::Whitespace);
|
|
|
|
}
|
|
|
|
continue;
|
2020-04-02 02:14:59 -04:00
|
|
|
}
|
2020-04-12 19:37:12 -04:00
|
|
|
_ => return Err(("expected selector.", tok.pos()).into()),
|
2020-04-03 13:28:37 -04:00
|
|
|
});
|
|
|
|
iter.next();
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
|
|
|
|
if !inner.is_empty() {
|
|
|
|
parts.push(SelectorPart {
|
|
|
|
inner,
|
|
|
|
is_invisible,
|
|
|
|
has_newline,
|
2020-04-05 02:39:38 -04:00
|
|
|
contains_super_selector,
|
2020-04-03 13:28:37 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Selector(parts))
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
fn consume_pseudo_selector<I: Iterator<Item = Token>>(
|
2020-04-20 03:45:28 -04:00
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-04-03 13:28:37 -04:00
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
) -> SassResult<SelectorKind> {
|
|
|
|
let is_pseudo_element = if toks.peek().unwrap().kind == ':' {
|
|
|
|
toks.next();
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
2020-05-24 08:56:53 -04:00
|
|
|
let t = if let Some(tok) = toks.peek() {
|
|
|
|
*tok
|
|
|
|
} else {
|
|
|
|
todo!()
|
|
|
|
};
|
|
|
|
if is_selector_name_char(t.kind) {
|
|
|
|
let name = eat_ident_no_interpolation(toks, false, t.pos)?.node;
|
2020-04-03 13:28:37 -04:00
|
|
|
Ok(
|
|
|
|
if toks.peek().is_some() && toks.peek().unwrap().kind == '(' {
|
|
|
|
toks.next();
|
|
|
|
let mut inner_toks = read_until_closing_paren(toks);
|
|
|
|
inner_toks.pop();
|
|
|
|
let inner = Selector::from_tokens(
|
2020-04-20 03:45:28 -04:00
|
|
|
&mut inner_toks.into_iter().peekmore(),
|
2020-04-03 13:28:37 -04:00
|
|
|
scope,
|
|
|
|
super_selector,
|
|
|
|
)?;
|
|
|
|
SelectorKind::PseudoParen(name, inner)
|
|
|
|
} else if is_pseudo_element {
|
|
|
|
SelectorKind::PseudoElement(name)
|
|
|
|
} else {
|
|
|
|
SelectorKind::Pseudo(name)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
2020-05-24 08:56:53 -04:00
|
|
|
return Err(("Expected identifier.", t.pos).into());
|
2020-04-03 13:28:37 -04:00
|
|
|
}
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
2020-01-05 12:25:03 -05:00
|
|
|
|
2020-04-06 14:40:28 -04:00
|
|
|
pub fn replace(super_selector: &Selector, this: Selector) -> Selector {
|
2020-04-06 13:13:03 -04:00
|
|
|
if super_selector.0.is_empty() || this.0.is_empty() {
|
2020-04-05 02:39:38 -04:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
let mut parts = Vec::with_capacity(super_selector.0.len());
|
|
|
|
for (idx, part) in super_selector.clone().0.into_iter().enumerate() {
|
|
|
|
let mut found_inner = false;
|
|
|
|
for part2 in this.clone().0 {
|
|
|
|
if !part2.contains_super_selector {
|
|
|
|
if idx == 0 {
|
|
|
|
parts.push(part2);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let mut kinds = Vec::new();
|
|
|
|
for kind in part2.clone().inner {
|
|
|
|
match kind {
|
|
|
|
SelectorKind::Super => kinds.extend(part.inner.clone()),
|
|
|
|
SelectorKind::PseudoParen(name, inner) => {
|
|
|
|
if inner.contains_super_selector() {
|
|
|
|
found_inner = true;
|
|
|
|
kinds.push(SelectorKind::PseudoParen(
|
|
|
|
name,
|
2020-04-06 14:40:28 -04:00
|
|
|
Selector::replace(super_selector, inner),
|
2020-04-05 02:39:38 -04:00
|
|
|
))
|
|
|
|
} else {
|
|
|
|
kinds.push(SelectorKind::PseudoParen(name, inner));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => kinds.push(kind),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
parts.push(SelectorPart {
|
|
|
|
inner: kinds,
|
|
|
|
is_invisible: part2.is_invisible,
|
|
|
|
has_newline: part2.has_newline,
|
|
|
|
contains_super_selector: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if found_inner {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Selector(parts)
|
|
|
|
}
|
|
|
|
|
2020-01-18 21:05:26 -05:00
|
|
|
pub fn zip(&self, other: &Selector) -> Selector {
|
2020-01-11 14:51:31 -05:00
|
|
|
if self.0.is_empty() {
|
2020-01-18 21:05:26 -05:00
|
|
|
return Selector(other.0.clone());
|
2020-02-22 15:34:32 -05:00
|
|
|
} else if other.0.is_empty() {
|
|
|
|
return self.clone();
|
2020-01-05 12:25:03 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
let mut rules = Vec::with_capacity(self.0.len());
|
|
|
|
for sel1 in self.clone().0 {
|
2020-04-05 02:39:38 -04:00
|
|
|
let mut found_inner = false;
|
2020-04-03 13:28:37 -04:00
|
|
|
for sel2 in other.clone().0 {
|
2020-01-18 21:05:26 -05:00
|
|
|
let mut this_selector: Vec<SelectorKind> = Vec::with_capacity(other.0.len());
|
2020-01-11 16:12:23 -05:00
|
|
|
let mut found_super = false;
|
|
|
|
|
2020-04-03 13:28:37 -04:00
|
|
|
for sel in sel2.inner {
|
2020-04-05 02:39:38 -04:00
|
|
|
match sel {
|
|
|
|
SelectorKind::Super => {
|
|
|
|
this_selector.extend(sel1.inner.clone());
|
|
|
|
found_super = true;
|
|
|
|
}
|
|
|
|
SelectorKind::PseudoParen(s, inner_selector) => {
|
|
|
|
if inner_selector.contains_super_selector() {
|
|
|
|
found_super = true;
|
|
|
|
found_inner = true;
|
|
|
|
this_selector.push(SelectorKind::PseudoParen(
|
|
|
|
s,
|
2020-04-06 14:40:28 -04:00
|
|
|
Selector::replace(self, inner_selector),
|
2020-04-05 02:39:38 -04:00
|
|
|
))
|
|
|
|
} else {
|
|
|
|
this_selector.push(SelectorKind::PseudoParen(s, inner_selector));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => this_selector.push(sel),
|
2020-01-11 16:12:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found_super {
|
2020-04-03 13:28:37 -04:00
|
|
|
let mut x = std::mem::take(&mut this_selector);
|
|
|
|
let mut y = sel1.clone().inner;
|
|
|
|
y.push(SelectorKind::Whitespace);
|
|
|
|
y.append(&mut x);
|
|
|
|
this_selector = y;
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
2020-04-03 13:28:37 -04:00
|
|
|
rules.push(SelectorPart {
|
|
|
|
inner: this_selector,
|
|
|
|
is_invisible: sel1.is_invisible || sel2.is_invisible,
|
2020-04-05 02:39:38 -04:00
|
|
|
has_newline: (sel1.has_newline || sel2.has_newline) && !found_inner,
|
|
|
|
contains_super_selector: false,
|
2020-04-03 13:28:37 -04:00
|
|
|
});
|
2020-01-05 12:25:03 -05:00
|
|
|
}
|
2020-04-05 02:39:38 -04:00
|
|
|
if found_inner {
|
|
|
|
break;
|
|
|
|
}
|
2020-01-05 12:25:03 -05:00
|
|
|
}
|
2020-01-11 14:51:31 -05:00
|
|
|
Selector(rules)
|
2020-01-05 12:25:03 -05:00
|
|
|
}
|
2020-02-29 17:23:17 -05:00
|
|
|
|
|
|
|
pub fn remove_placeholders(self) -> Selector {
|
2020-04-05 12:35:52 -04:00
|
|
|
Selector(
|
|
|
|
self.0
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|s| {
|
|
|
|
if s.is_invisible {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
let mut last_was_whitespace = false;
|
|
|
|
let len = s.inner.len();
|
|
|
|
for kind in s.inner {
|
|
|
|
match kind {
|
|
|
|
SelectorKind::PseudoParen(name, inner_selector) => {
|
|
|
|
let inner_empty = inner_selector.is_empty();
|
|
|
|
let removed_placeholders = inner_selector.remove_placeholders();
|
|
|
|
if removed_placeholders.is_empty() && !inner_empty {
|
|
|
|
if name.to_ascii_lowercase().as_str() == "not" {
|
|
|
|
if last_was_whitespace || len == 1 {
|
|
|
|
inner.push(SelectorKind::Universal);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
inner.push(SelectorKind::PseudoParen(
|
|
|
|
name,
|
|
|
|
removed_placeholders,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SelectorKind::Whitespace => {
|
|
|
|
last_was_whitespace = true;
|
|
|
|
inner.push(kind);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
_ => inner.push(kind),
|
|
|
|
}
|
|
|
|
last_was_whitespace = false;
|
|
|
|
}
|
|
|
|
Some(SelectorPart {
|
|
|
|
inner,
|
|
|
|
is_invisible: false,
|
|
|
|
has_newline: s.has_newline,
|
|
|
|
contains_super_selector: s.contains_super_selector,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
)
|
2020-02-29 17:23:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.0.is_empty()
|
|
|
|
}
|
2020-04-06 13:30:36 -04:00
|
|
|
|
|
|
|
pub const fn new() -> Selector {
|
|
|
|
Selector(Vec::new())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains_super_selector(&self) -> bool {
|
|
|
|
self.0.iter().any(|s| s.contains_super_selector)
|
|
|
|
}
|
2020-04-26 13:07:44 -04:00
|
|
|
|
|
|
|
pub fn into_value(&self) -> Value {
|
|
|
|
Value::List(
|
|
|
|
self.0.iter().map(SelectorPart::into_value).collect(),
|
|
|
|
ListSeparator::Comma,
|
|
|
|
Brackets::None,
|
|
|
|
)
|
|
|
|
}
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|