2020-03-01 14:53:52 -05:00
|
|
|
use std::fmt::{self, Display, Write};
|
|
|
|
use std::iter::Peekable;
|
|
|
|
use std::string::ToString;
|
|
|
|
|
2020-02-17 07:18:54 -05:00
|
|
|
use crate::error::SassResult;
|
2020-03-01 12:03:14 -05:00
|
|
|
use crate::lexer::Lexer;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::scope::Scope;
|
2020-01-26 18:43:07 -05:00
|
|
|
use crate::utils::{
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace, devour_whitespace_or_comment, eat_ident, eat_ident_no_interpolation,
|
2020-04-02 20:59:37 -04:00
|
|
|
parse_interpolation, IsWhitespace,
|
2020-01-26 18:43:07 -05:00
|
|
|
};
|
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-01-20 13:15:47 -05:00
|
|
|
pub(crate) struct Selector(pub Vec<SelectorKind>);
|
2020-01-11 14:51:31 -05:00
|
|
|
|
2020-02-22 10:25:30 -05:00
|
|
|
impl Selector {
|
2020-02-22 17:57:13 -05:00
|
|
|
pub const fn new() -> Selector {
|
2020-02-22 10:25:30 -05:00
|
|
|
Selector(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-11 14:51:31 -05:00
|
|
|
impl Display for Selector {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
let mut iter = self.0.iter().peekable();
|
|
|
|
|
|
|
|
while let Some(s) = iter.next() {
|
|
|
|
match s {
|
|
|
|
SelectorKind::Whitespace => continue,
|
|
|
|
SelectorKind::Attribute(_)
|
|
|
|
| SelectorKind::Pseudo(_)
|
2020-02-02 15:06:46 -05:00
|
|
|
| SelectorKind::PseudoElement(_)
|
2020-01-11 19:16:59 -05:00
|
|
|
| SelectorKind::PseudoParen(..)
|
2020-01-11 14:51:31 -05:00
|
|
|
| SelectorKind::Class
|
|
|
|
| SelectorKind::Id
|
|
|
|
| SelectorKind::Universal
|
2020-01-26 11:17:48 -05:00
|
|
|
| SelectorKind::InterpolatedSuper
|
2020-01-11 14:51:31 -05:00
|
|
|
| SelectorKind::Element(_) => {
|
|
|
|
write!(f, "{}", s)?;
|
|
|
|
if devour_whitespace(&mut iter) {
|
|
|
|
match iter.peek() {
|
|
|
|
Some(SelectorKind::Attribute(_))
|
|
|
|
| Some(SelectorKind::Pseudo(_))
|
2020-02-02 15:06:46 -05:00
|
|
|
| Some(SelectorKind::PseudoElement(_))
|
2020-01-11 19:16:59 -05:00
|
|
|
| Some(SelectorKind::PseudoParen(..))
|
2020-01-11 14:51:31 -05:00
|
|
|
| Some(SelectorKind::Class)
|
|
|
|
| Some(SelectorKind::Id)
|
|
|
|
| Some(SelectorKind::Universal)
|
2020-01-26 11:17:48 -05:00
|
|
|
| Some(SelectorKind::InterpolatedSuper)
|
2020-01-11 14:51:31 -05:00
|
|
|
| Some(SelectorKind::Element(_)) => {
|
2020-01-11 16:12:23 -05:00
|
|
|
write!(f, " ")?;
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-26 19:16:26 -05:00
|
|
|
SelectorKind::Multiple => {
|
|
|
|
devour_whitespace(&mut iter);
|
|
|
|
while let Some(sel) = iter.peek() {
|
|
|
|
if sel != &&SelectorKind::Multiple {
|
2020-02-22 17:26:30 -05:00
|
|
|
write!(f, ",")?;
|
2020-02-22 18:33:42 -05:00
|
|
|
if sel == &&SelectorKind::Newline {
|
|
|
|
iter.next();
|
|
|
|
f.write_char('\n')?;
|
|
|
|
} else {
|
2020-02-22 17:26:30 -05:00
|
|
|
f.write_char(' ')?;
|
|
|
|
}
|
2020-01-26 19:16:26 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
iter.next();
|
|
|
|
devour_whitespace(&mut iter);
|
|
|
|
}
|
2020-02-22 18:33:42 -05:00
|
|
|
while let Some(sel) = iter.peek() {
|
|
|
|
if sel != &&SelectorKind::Multiple
|
|
|
|
&& sel != &&SelectorKind::Newline
|
|
|
|
&& !sel.is_whitespace()
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
iter.next();
|
|
|
|
}
|
2020-01-26 19:16:26 -05:00
|
|
|
}
|
2020-01-11 14:51:31 -05:00
|
|
|
_ => write!(f, "{}", s)?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write!(f, "")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2020-01-20 13:15:47 -05:00
|
|
|
pub(crate) enum SelectorKind {
|
2020-01-04 22:55:04 -05:00
|
|
|
/// An element selector: `button`
|
|
|
|
Element(String),
|
|
|
|
/// An id selector: `#footer`
|
2020-01-11 14:51:31 -05:00
|
|
|
Id,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// A single class selector: `.button-active`
|
2020-01-11 14:51:31 -05:00
|
|
|
Class,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// A universal selector: `*`
|
|
|
|
Universal,
|
|
|
|
/// Multiple unrelated selectors: `button, .active`
|
2020-01-11 14:51:31 -05:00
|
|
|
Multiple,
|
2020-02-22 17:26:30 -05:00
|
|
|
/// Newline (significant if after `SelectorKind::Multiple`)
|
|
|
|
Newline,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// Select all immediate children: `ul > li`
|
2020-01-11 14:51:31 -05:00
|
|
|
ImmediateChild,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// Select all elements immediately following: `div + p`
|
2020-01-11 14:51:31 -05:00
|
|
|
Following,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// Select elements preceeded by: `p ~ ul`
|
2020-01-11 14:51:31 -05:00
|
|
|
Preceding,
|
2020-01-04 22:55:04 -05:00
|
|
|
/// Select elements with attribute: `html[lang|=en]`
|
|
|
|
Attribute(Attribute),
|
|
|
|
/// Pseudo selector: `:hover`
|
|
|
|
Pseudo(String),
|
2020-02-02 15:06:46 -05:00
|
|
|
/// Pseudo element selector: `::before`
|
|
|
|
PseudoElement(String),
|
2020-01-11 19:16:59 -05:00
|
|
|
/// Pseudo selector with additional parens: `:any(h1, h2, h3, h4, h5, h6)`
|
2020-02-02 15:21:47 -05:00
|
|
|
PseudoParen(String, String),
|
2020-01-11 14:51:31 -05:00
|
|
|
/// Use the super selector: `&.red`
|
2020-01-11 16:12:23 -05:00
|
|
|
Super,
|
2020-01-26 11:07:57 -05:00
|
|
|
/// Super selector in an interpolated context: `a #{&}`
|
|
|
|
InterpolatedSuper,
|
2020-01-29 20:02:02 -05:00
|
|
|
/// Placeholder selector: `%alert`
|
|
|
|
Placeholder,
|
2020-01-11 14:51:31 -05:00
|
|
|
Whitespace,
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
|
|
|
|
2020-01-12 20:15:27 -05:00
|
|
|
impl IsWhitespace for SelectorKind {
|
|
|
|
fn is_whitespace(&self) -> bool {
|
|
|
|
self == &Self::Whitespace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
|
|
|
SelectorKind::Id => write!(f, "#"),
|
|
|
|
SelectorKind::Class => write!(f, "."),
|
|
|
|
SelectorKind::Universal => write!(f, "*"),
|
|
|
|
SelectorKind::Whitespace => write!(f, " "),
|
|
|
|
SelectorKind::Multiple => write!(f, ", "),
|
2020-02-22 17:26:30 -05:00
|
|
|
SelectorKind::Newline => writeln!(f),
|
2020-01-11 14:51:31 -05:00
|
|
|
SelectorKind::ImmediateChild => write!(f, " > "),
|
|
|
|
SelectorKind::Following => write!(f, " + "),
|
|
|
|
SelectorKind::Preceding => write!(f, " ~ "),
|
|
|
|
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-02-22 17:26:30 -05:00
|
|
|
SelectorKind::Super | SelectorKind::InterpolatedSuper => write!(f, ""),
|
2020-01-29 20:02:02 -05:00
|
|
|
SelectorKind::Placeholder => write!(f, "%"),
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-04 22:55:04 -05:00
|
|
|
struct SelectorParser<'a> {
|
2020-01-12 17:44:49 -05:00
|
|
|
scope: &'a Scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector: &'a Selector,
|
2020-01-14 17:39:19 -05:00
|
|
|
selectors: Vec<SelectorKind>,
|
2020-01-26 11:07:57 -05:00
|
|
|
is_interpolated: bool,
|
2020-01-12 10:54:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> SelectorParser<'a> {
|
2020-03-01 12:03:14 -05:00
|
|
|
const fn new(scope: &'a Scope, super_selector: &'a Selector) -> SelectorParser<'a> {
|
2020-01-11 14:51:31 -05:00
|
|
|
SelectorParser {
|
2020-01-12 17:44:49 -05:00
|
|
|
scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector,
|
2020-01-14 17:39:19 -05:00
|
|
|
selectors: Vec::new(),
|
2020-01-26 11:07:57 -05:00
|
|
|
is_interpolated: false,
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
|
|
|
|
2020-03-01 12:03:14 -05:00
|
|
|
fn all_selectors<I: Iterator<Item = Token>>(
|
|
|
|
mut self,
|
|
|
|
tokens: &'a mut Peekable<I>,
|
|
|
|
) -> SassResult<Selector> {
|
2020-02-17 07:18:54 -05:00
|
|
|
self.tokens_to_selectors(tokens)?;
|
2020-01-14 17:39:19 -05:00
|
|
|
// remove trailing whitespace
|
|
|
|
while let Some(x) = self.selectors.pop() {
|
2020-01-11 16:12:23 -05:00
|
|
|
if x != SelectorKind::Whitespace {
|
2020-01-14 17:39:19 -05:00
|
|
|
self.selectors.push(x);
|
2020-01-11 16:12:23 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-02-17 07:18:54 -05:00
|
|
|
Ok(Selector(self.selectors))
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
|
|
|
|
2020-03-01 12:03:14 -05:00
|
|
|
fn consume_pseudo_selector<I: Iterator<Item = Token>>(
|
2020-02-17 09:40:30 -05:00
|
|
|
&mut self,
|
2020-03-01 12:03:14 -05:00
|
|
|
tokens: &'_ mut Peekable<I>,
|
2020-02-17 09:40:30 -05:00
|
|
|
) -> SassResult<()> {
|
2020-02-02 15:06:46 -05:00
|
|
|
if let Some(tok) = tokens.next() {
|
|
|
|
match tok.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
v @ 'a'..='z' | v @ 'A'..='Z' | v @ '-' | v @ '_' => {
|
|
|
|
let s = format!(
|
|
|
|
"{}{}",
|
|
|
|
v,
|
2020-03-30 17:06:23 -04:00
|
|
|
eat_ident(tokens, self.scope, self.super_selector)?
|
2020-03-29 13:28:17 -04:00
|
|
|
);
|
|
|
|
if let Some(Token { kind: '(', .. }) = tokens.peek() {
|
2020-02-02 15:06:46 -05:00
|
|
|
tokens.next();
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(tokens);
|
2020-02-02 15:21:47 -05:00
|
|
|
let mut toks = String::new();
|
2020-02-02 15:06:46 -05:00
|
|
|
while let Some(Token { kind, .. }) = tokens.peek() {
|
2020-03-29 13:28:17 -04:00
|
|
|
if kind == &')' {
|
2020-02-02 15:21:47 -05:00
|
|
|
tokens.next();
|
2020-02-02 15:06:46 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
let tok = tokens.next().unwrap();
|
2020-02-02 15:21:47 -05:00
|
|
|
toks.push_str(&tok.kind.to_string());
|
|
|
|
if devour_whitespace(tokens) {
|
|
|
|
toks.push(' ');
|
|
|
|
}
|
2020-02-02 15:06:46 -05:00
|
|
|
}
|
2020-02-02 18:01:09 -05:00
|
|
|
self.selectors
|
|
|
|
.push(SelectorKind::PseudoParen(s, toks.trim_end().to_owned()))
|
2020-02-02 15:06:46 -05:00
|
|
|
} else {
|
|
|
|
self.selectors.push(SelectorKind::Pseudo(s))
|
2020-01-11 19:16:59 -05:00
|
|
|
}
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
':' => {
|
2020-03-30 17:06:23 -04:00
|
|
|
let s = eat_ident(tokens, self.scope, self.super_selector)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
self.selectors.push(SelectorKind::PseudoElement(s))
|
2020-02-02 15:06:46 -05:00
|
|
|
}
|
2020-02-17 09:40:30 -05:00
|
|
|
_ => return Err("Expected identifier.".into()),
|
2020-01-11 19:16:59 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-17 09:40:30 -05:00
|
|
|
Ok(())
|
2020-01-11 19:16:59 -05:00
|
|
|
}
|
|
|
|
|
2020-03-01 12:03:14 -05:00
|
|
|
fn tokens_to_selectors<I: Iterator<Item = Token>>(
|
|
|
|
&mut self,
|
|
|
|
tokens: &'_ mut Peekable<I>,
|
|
|
|
) -> SassResult<()> {
|
2020-01-14 17:39:19 -05:00
|
|
|
while tokens.peek().is_some() {
|
2020-02-17 07:18:54 -05:00
|
|
|
self.consume_selector(tokens)?;
|
2020-01-14 17:39:19 -05:00
|
|
|
}
|
2020-02-17 07:18:54 -05:00
|
|
|
Ok(())
|
2020-01-14 17:39:19 -05:00
|
|
|
}
|
|
|
|
|
2020-03-01 12:03:14 -05:00
|
|
|
fn consume_selector<I: Iterator<Item = Token>>(
|
|
|
|
&mut self,
|
|
|
|
tokens: &'_ mut Peekable<I>,
|
|
|
|
) -> SassResult<()> {
|
2020-03-29 13:28:17 -04:00
|
|
|
if devour_whitespace_or_comment(tokens)? {
|
|
|
|
if let Some(Token { kind: ',', .. }) = tokens.peek() {
|
2020-01-14 17:39:19 -05:00
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Multiple);
|
2020-02-17 07:18:54 -05:00
|
|
|
return Ok(());
|
2020-01-11 16:12:23 -05:00
|
|
|
}
|
2020-01-14 17:39:19 -05:00
|
|
|
self.selectors.push(SelectorKind::Whitespace);
|
2020-02-17 07:18:54 -05:00
|
|
|
return Ok(());
|
2020-01-11 14:51:31 -05:00
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
if let Some(Token { kind, .. }) = tokens.peek() {
|
2020-01-18 20:24:28 -05:00
|
|
|
match kind {
|
2020-03-30 00:18:37 -04:00
|
|
|
'a'..='z' | 'A'..='Z' | '-' | '_' | '0'..='9' | '\\' => {
|
|
|
|
let s = eat_ident_no_interpolation(tokens)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
self.selectors.push(SelectorKind::Element(s))
|
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
'.' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Class)
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'#' => {
|
2020-03-30 00:18:37 -04:00
|
|
|
tokens.next();
|
2020-03-30 02:30:44 -04:00
|
|
|
if tokens.peek().is_some() && tokens.peek().unwrap().kind == '{' {
|
2020-03-29 13:28:17 -04:00
|
|
|
tokens.next();
|
|
|
|
self.is_interpolated = true;
|
|
|
|
self.tokens_to_selectors(
|
|
|
|
&mut Lexer::new(
|
|
|
|
&parse_interpolation(tokens, self.scope, self.super_selector)?
|
|
|
|
.to_string(),
|
|
|
|
)
|
|
|
|
.peekable(),
|
|
|
|
)?;
|
|
|
|
self.is_interpolated = false;
|
|
|
|
} else {
|
|
|
|
self.selectors.push(SelectorKind::Id)
|
|
|
|
}
|
2020-02-14 11:52:31 -05:00
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
':' => {
|
|
|
|
tokens.next();
|
|
|
|
self.consume_pseudo_selector(tokens)?
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
',' => {
|
2020-03-30 00:18:37 -04:00
|
|
|
tokens.next();
|
2020-02-22 17:26:30 -05:00
|
|
|
self.selectors.push(SelectorKind::Multiple);
|
2020-03-29 13:28:17 -04:00
|
|
|
if tokens.peek().unwrap().kind == '\n' {
|
2020-02-22 17:26:30 -05:00
|
|
|
self.selectors.push(SelectorKind::Newline);
|
|
|
|
devour_whitespace(tokens);
|
|
|
|
}
|
|
|
|
}
|
2020-03-30 00:18:37 -04:00
|
|
|
'>' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::ImmediateChild)
|
|
|
|
}
|
|
|
|
'+' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Following)
|
|
|
|
}
|
|
|
|
'~' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Preceding)
|
|
|
|
}
|
|
|
|
'*' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Universal)
|
|
|
|
}
|
|
|
|
'%' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(SelectorKind::Placeholder)
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'&' => self.selectors.push(if self.is_interpolated {
|
2020-03-30 00:18:37 -04:00
|
|
|
tokens.next();
|
2020-01-26 11:07:57 -05:00
|
|
|
SelectorKind::InterpolatedSuper
|
|
|
|
} else {
|
2020-03-30 00:18:37 -04:00
|
|
|
tokens.next();
|
2020-01-26 11:07:57 -05:00
|
|
|
SelectorKind::Super
|
|
|
|
}),
|
2020-03-30 00:18:37 -04:00
|
|
|
'[' => {
|
|
|
|
tokens.next();
|
|
|
|
self.selectors.push(Attribute::from_tokens(
|
|
|
|
tokens,
|
|
|
|
self.scope,
|
|
|
|
self.super_selector,
|
|
|
|
)?)
|
|
|
|
}
|
2020-04-02 02:14:59 -04:00
|
|
|
c if c.is_control() => {
|
|
|
|
return Err("expected selector.".into());
|
|
|
|
}
|
2020-04-02 02:23:48 -04:00
|
|
|
'`' => return Err("expected selector.".into()),
|
2020-01-11 14:51:31 -05:00
|
|
|
_ => todo!("unimplemented selector"),
|
2020-01-14 17:39:19 -05:00
|
|
|
};
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
2020-02-17 07:18:54 -05:00
|
|
|
Ok(())
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Selector {
|
2020-03-01 12:03:14 -05:00
|
|
|
pub fn from_tokens<'a, I: Iterator<Item = Token>>(
|
|
|
|
tokens: &'a mut Peekable<I>,
|
2020-01-12 17:44:49 -05:00
|
|
|
scope: &'a Scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
super_selector: &'a Selector,
|
2020-02-17 07:18:54 -05:00
|
|
|
) -> SassResult<Selector> {
|
2020-03-01 12:03:14 -05:00
|
|
|
SelectorParser::new(scope, super_selector).all_selectors(tokens)
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|
2020-01-05 12:25:03 -05:00
|
|
|
|
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-01-11 16:12:23 -05:00
|
|
|
let mut rules: Vec<SelectorKind> = Vec::with_capacity(self.0.len() + other.0.len());
|
2020-01-18 21:05:26 -05:00
|
|
|
let sel1_split: Vec<&[SelectorKind]> =
|
|
|
|
self.0.split(|sel| sel == &SelectorKind::Multiple).collect();
|
|
|
|
let sel2_split: Vec<&[SelectorKind]> = other
|
2020-01-11 14:51:31 -05:00
|
|
|
.0
|
|
|
|
.split(|sel| sel == &SelectorKind::Multiple)
|
|
|
|
.collect();
|
2020-01-18 21:05:26 -05:00
|
|
|
let len1 = sel1_split.len();
|
|
|
|
let len2 = sel2_split.len();
|
|
|
|
for (idx, sel1) in sel1_split.into_iter().enumerate() {
|
2020-01-11 14:51:31 -05:00
|
|
|
for (idx2, sel2) in sel2_split.iter().enumerate() {
|
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-01-18 21:05:26 -05:00
|
|
|
for sel in *sel2 {
|
2020-01-11 16:12:23 -05:00
|
|
|
if sel == &SelectorKind::Super {
|
2020-01-18 21:05:26 -05:00
|
|
|
this_selector.extend(sel1.to_vec());
|
2020-01-11 16:12:23 -05:00
|
|
|
found_super = true;
|
2020-01-26 11:07:57 -05:00
|
|
|
} else if sel == &SelectorKind::InterpolatedSuper {
|
|
|
|
this_selector.extend(sel1.to_vec());
|
2020-01-11 16:12:23 -05:00
|
|
|
} else {
|
|
|
|
this_selector.push(sel.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found_super {
|
2020-01-18 21:05:26 -05:00
|
|
|
rules.extend(sel1.to_vec());
|
2020-01-11 16:12:23 -05:00
|
|
|
rules.push(SelectorKind::Whitespace);
|
|
|
|
}
|
|
|
|
rules.extend(this_selector);
|
|
|
|
|
2020-01-18 21:05:26 -05:00
|
|
|
if !(idx + 1 == len1 && idx2 + 1 == len2) {
|
2020-01-11 14:51:31 -05:00
|
|
|
rules.push(SelectorKind::Multiple);
|
|
|
|
}
|
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 {
|
|
|
|
let mut selectors = Vec::with_capacity(self.0.len());
|
|
|
|
let mut temp_sels = Vec::new();
|
|
|
|
let mut found_placeholder = false;
|
|
|
|
for sel in self.0 {
|
|
|
|
match sel {
|
|
|
|
SelectorKind::Placeholder => found_placeholder = true,
|
|
|
|
SelectorKind::Multiple => {
|
|
|
|
temp_sels.push(SelectorKind::Multiple);
|
|
|
|
if !found_placeholder {
|
|
|
|
selectors.extend(temp_sels.clone());
|
|
|
|
}
|
|
|
|
temp_sels.clear();
|
|
|
|
found_placeholder = false;
|
|
|
|
}
|
|
|
|
_ => temp_sels.push(sel),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found_placeholder {
|
|
|
|
selectors.extend(temp_sels);
|
|
|
|
}
|
|
|
|
Selector(selectors)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.0.is_empty()
|
|
|
|
}
|
2020-01-04 22:55:04 -05:00
|
|
|
}
|