2020-01-12 19:56:58 -05:00
use crate ::common ::{ Scope , Symbol } ;
2020-01-14 17:39:19 -05:00
use crate ::utils ::{ devour_whitespace , eat_interpolation , IsWhitespace } ;
2020-01-12 19:56:58 -05:00
use crate ::{ Token , TokenKind } ;
2020-01-06 19:23:52 -05:00
use std ::fmt ::{ self , Display } ;
2020-01-04 22:55:04 -05:00
use std ::iter ::Peekable ;
2020-01-11 19:16:59 -05:00
use std ::string ::ToString ;
2020-01-18 20:24:28 -05:00
use std ::vec ::IntoIter ;
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
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-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-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
}
_ = > { }
}
}
}
_ = > 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-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-01-11 19:16:59 -05:00
/// Pseudo selector with additional parens: `:any(h1, h2, h3, h4, h5, h6)`
PseudoParen ( String , Vec < TokenKind > ) ,
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-05 12:25:03 -05:00
/// Used to signify no selector (when there is no super_selector of a rule)
None ,
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 , " , " ) ,
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-01-11 19:16:59 -05:00
SelectorKind ::PseudoParen ( s , toks ) = > write! (
f ,
" :{}({}) " ,
s ,
toks . iter ( ) . map ( ToString ::to_string ) . collect ::< String > ( )
) ,
2020-01-26 11:17:48 -05:00
SelectorKind ::Super | SelectorKind ::None | SelectorKind ::InterpolatedSuper = > {
2020-01-26 11:07:57 -05:00
write! ( f , " " )
}
2020-01-11 14:51:31 -05:00
}
}
}
#[ cfg(test) ]
mod test_selector_display {
use super ::* ;
use SelectorKind ::* ;
macro_rules ! test_selector_display {
( $func :ident , Selector ( $tok :tt ) , $output :literal ) = > {
#[ test ]
fn $func ( ) {
assert_eq! ( format! ( " {} " , Selector ( vec ! $tok ) ) , $output ) ;
}
2020-01-04 22:55:04 -05:00
}
}
2020-01-11 14:51:31 -05:00
test_selector_display! ( el , Selector ( ( Element ( " a " . to_string ( ) ) ) ) , " a " ) ;
test_selector_display! (
keeps_one_whitespace ,
Selector ( (
Element ( " a " . to_string ( ) ) ,
Whitespace ,
Element ( " b " . to_string ( ) ) ,
) ) ,
" a b "
) ;
test_selector_display! (
keeps_one_whitespace_with_two ,
Selector ( (
Element ( " a " . to_string ( ) ) ,
Whitespace ,
Whitespace ,
Element ( " c " . to_string ( ) ) ,
Whitespace ,
) ) ,
" a c "
) ;
2020-01-11 16:12:23 -05:00
test_selector_display! (
keeps_one_whitespace_with_three_els ,
Selector ( (
Element ( " a " . to_string ( ) ) ,
Whitespace ,
Element ( " a " . to_string ( ) ) ,
Whitespace ,
Element ( " c " . to_string ( ) ) ,
) ) ,
" a a c "
) ;
2020-01-04 22:55:04 -05:00
}
struct SelectorParser < ' a > {
2020-01-12 17:44:49 -05:00
scope : & ' a Scope ,
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-01-18 19:44:34 -05:00
const fn new ( scope : & ' a Scope ) -> SelectorParser < ' a > {
2020-01-11 14:51:31 -05:00
SelectorParser {
2020-01-12 17:44:49 -05:00
scope ,
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-01-18 20:24:28 -05:00
fn all_selectors ( mut self , tokens : & ' a mut Peekable < IntoIter < Token > > ) -> Selector {
2020-01-14 17:39:19 -05:00
self . tokens_to_selectors ( tokens ) ;
// 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-01-18 20:24:28 -05:00
Selector ( self . selectors )
2020-01-11 14:51:31 -05:00
}
2020-01-18 20:24:28 -05:00
fn consume_pseudo_selector ( & mut self , tokens : & '_ mut Peekable < IntoIter < Token > > ) {
2020-01-11 19:16:59 -05:00
if let Some ( Token {
kind : TokenKind ::Ident ( s ) ,
..
2020-01-14 17:39:19 -05:00
} ) = tokens . next ( )
2020-01-11 19:16:59 -05:00
{
if let Some ( Token {
kind : TokenKind ::Symbol ( Symbol ::OpenParen ) ,
..
2020-01-14 17:39:19 -05:00
} ) = tokens . peek ( )
2020-01-11 19:16:59 -05:00
{
2020-01-14 17:39:19 -05:00
tokens . next ( ) ;
2020-01-11 19:16:59 -05:00
let mut toks = Vec ::new ( ) ;
2020-01-14 17:39:19 -05:00
while let Some ( Token { kind , .. } ) = tokens . peek ( ) {
2020-01-11 19:16:59 -05:00
if kind = = & TokenKind ::Symbol ( Symbol ::CloseParen ) {
break ;
}
2020-01-14 17:39:19 -05:00
let tok = tokens . next ( ) . unwrap ( ) ;
2020-01-18 20:24:28 -05:00
toks . push ( tok . kind ) ;
2020-01-11 19:16:59 -05:00
}
2020-01-14 17:39:19 -05:00
tokens . next ( ) ;
2020-01-18 20:24:28 -05:00
self . selectors . push ( SelectorKind ::PseudoParen ( s , toks ) )
2020-01-11 19:16:59 -05:00
} else {
2020-01-18 20:24:28 -05:00
self . selectors . push ( SelectorKind ::Pseudo ( s ) )
2020-01-11 19:16:59 -05:00
}
} else {
todo! ( " expected ident after `:` in selector " )
}
}
2020-01-18 20:24:28 -05:00
fn tokens_to_selectors ( & mut self , tokens : & '_ mut Peekable < IntoIter < Token > > ) {
2020-01-14 17:39:19 -05:00
while tokens . peek ( ) . is_some ( ) {
self . consume_selector ( tokens )
}
}
2020-01-18 20:24:28 -05:00
fn consume_selector ( & mut self , tokens : & '_ mut Peekable < IntoIter < Token > > ) {
2020-01-14 17:39:19 -05:00
if devour_whitespace ( tokens ) {
2020-01-18 20:24:28 -05:00
if let Some ( Token {
2020-01-11 16:12:23 -05:00
kind : TokenKind ::Symbol ( Symbol ::Comma ) ,
..
2020-01-14 17:39:19 -05:00
} ) = tokens . peek ( )
2020-01-11 16:12:23 -05:00
{
2020-01-14 17:39:19 -05:00
tokens . next ( ) ;
self . selectors . push ( SelectorKind ::Multiple ) ;
return ;
2020-01-11 16:12:23 -05:00
}
2020-01-14 17:39:19 -05:00
self . selectors . push ( SelectorKind ::Whitespace ) ;
return ;
2020-01-11 14:51:31 -05:00
}
2020-01-14 17:39:19 -05:00
if let Some ( Token { kind , .. } ) = tokens . next ( ) {
2020-01-18 20:24:28 -05:00
match kind {
TokenKind ::Ident ( ident ) = > self . selectors . push ( SelectorKind ::Element ( ident ) ) ,
2020-01-14 17:39:19 -05:00
TokenKind ::Symbol ( Symbol ::Period ) = > self . selectors . push ( SelectorKind ::Class ) ,
TokenKind ::Symbol ( Symbol ::Hash ) = > self . selectors . push ( SelectorKind ::Id ) ,
TokenKind ::Symbol ( Symbol ::Colon ) = > self . consume_pseudo_selector ( tokens ) ,
TokenKind ::Symbol ( Symbol ::Comma ) = > self . selectors . push ( SelectorKind ::Multiple ) ,
TokenKind ::Symbol ( Symbol ::Gt ) = > self . selectors . push ( SelectorKind ::ImmediateChild ) ,
TokenKind ::Symbol ( Symbol ::Plus ) = > self . selectors . push ( SelectorKind ::Following ) ,
TokenKind ::Symbol ( Symbol ::Tilde ) = > self . selectors . push ( SelectorKind ::Preceding ) ,
TokenKind ::Symbol ( Symbol ::Mul ) = > self . selectors . push ( SelectorKind ::Universal ) ,
2020-01-26 11:07:57 -05:00
TokenKind ::Symbol ( Symbol ::BitAnd ) = > self . selectors . push ( if self . is_interpolated {
SelectorKind ::InterpolatedSuper
} else {
SelectorKind ::Super
} ) ,
TokenKind ::Interpolation = > {
self . is_interpolated = true ;
let v = self . tokens_to_selectors (
& mut eat_interpolation ( tokens , self . scope ) . into_iter ( ) . peekable ( ) ,
) ;
self . is_interpolated = false ;
v
}
2020-01-18 20:24:28 -05:00
TokenKind ::Attribute ( attr ) = > self . selectors . push ( SelectorKind ::Attribute ( attr ) ) ,
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
}
}
}
impl Selector {
2020-01-11 14:51:31 -05:00
pub fn from_tokens < ' a > (
2020-01-18 20:24:28 -05:00
tokens : & ' a mut Peekable < IntoIter < Token > > ,
2020-01-12 17:44:49 -05:00
scope : & ' a Scope ,
2020-01-11 14:51:31 -05:00
) -> Selector {
2020-01-18 19:44:34 -05:00
SelectorParser ::new ( scope ) . 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-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-01-04 22:55:04 -05:00
}
#[ derive(Clone, Debug, Eq, PartialEq) ]
2020-01-26 11:47:00 -05:00
pub ( crate ) struct Attribute {
2020-01-04 22:55:04 -05:00
pub attr : String ,
pub value : String ,
2020-01-26 11:47:00 -05:00
pub case_sensitive : CaseKind ,
2020-01-04 22:55:04 -05:00
pub kind : AttributeKind ,
}
2020-01-26 11:47:00 -05:00
#[ 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 , " " ) ,
}
}
}
2020-01-04 22:55:04 -05:00
impl Display for Attribute {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
2020-01-26 11:47:00 -05:00
match self . kind {
AttributeKind ::Any = > write! ( f , " [{}{}] " , self . attr , self . case_sensitive ) ,
AttributeKind ::Equals = > {
write! ( f , " [{}={}{}] " , self . attr , self . value , self . case_sensitive )
2020-01-04 22:55:04 -05:00
}
2020-01-26 11:47:00 -05:00
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 )
2020-01-04 22:55:04 -05:00
}
}
}
}
#[ derive(Copy, Clone, Debug, Eq, PartialEq) ]
pub enum AttributeKind {
/// [attr]
/// Represents elements with an attribute name of `attr`
Any ,
/// [attr=value]
/// Represents elements with an attribute name of `attr` whose value is exactly `value`
Equals ,
/// [attr~=value]
/// Represents elements with an attribute name of `attr` whose value is a whitespace-separated list of words, one of which is exactly `value`
InList ,
/// [attr|=value]
/// Represents elements with an attribute name of `attr` whose value can be exactly value or can begin with `value` immediately followed by a hyphen (`-`)
BeginsWithHyphenOrExact ,
/// [attr^=value]
StartsWith ,
/// [attr$=value]
EndsWith ,
/// [attr*=value]
/// Represents elements with an attribute name of `attr` whose value contains at least one occurrence of `value` within the string
Contains ,
}