2020-01-12 19:56:58 -05:00
use crate ::common ::{ Scope , Symbol } ;
2020-01-12 20:15:27 -05:00
use crate ::utils ::{ devour_whitespace , 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-06 17:06:37 -05:00
use std ::slice ::Iter ;
2020-01-11 19:16:59 -05:00
use std ::string ::ToString ;
2020-01-04 22:55:04 -05:00
#[ derive(Clone, Debug, Eq, PartialEq) ]
2020-01-11 14:51:31 -05:00
pub struct Selector ( pub Vec < SelectorKind > ) ;
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
| 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 )
| 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) ]
pub 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-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-12 10:54:46 -05:00
/// Intemediate value to simplify usage with identifier interpolation
Several ( Vec < SelectorKind > ) ,
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-11 16:12:23 -05:00
SelectorKind ::Super | SelectorKind ::None = > write! ( f , " " ) ,
2020-01-12 10:54:46 -05:00
SelectorKind ::Several ( _ ) = > {
panic! ( " SelectorKind::Several should not be rendered using Display " )
}
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 > {
tokens : Peekable < Iter < ' a , Token > > ,
2020-01-11 14:51:31 -05:00
super_selector : & ' a Selector ,
2020-01-12 17:44:49 -05:00
scope : & ' a Scope ,
2020-01-12 10:54:46 -05:00
}
/// Methods to handle dealing with interpolation
impl < ' a > SelectorParser < ' a > {
fn consume_interpolation ( & mut self ) -> SelectorKind {
let mut v = Vec ::new ( ) ;
let toks = self
. tokens
. by_ref ( )
2020-01-12 19:56:58 -05:00
. take_while ( | x | x . kind ! = TokenKind ::Symbol ( Symbol ::CloseCurlyBrace ) )
2020-01-12 10:54:46 -05:00
. cloned ( )
. collect ::< Vec < Token > > ( ) ; //.iter().peekable();
let mut toks = toks . iter ( ) . peekable ( ) ;
while let Some ( Token { kind , .. } ) = toks . peek ( ) {
if let TokenKind ::Variable ( _ ) = kind {
toks . next ( ) ;
let these_toks = self . deref_variable ( kind ) ;
let mut these_toks = these_toks . iter ( ) . peekable ( ) ;
while let Some ( s ) = self . selector_from_token_stream ( & mut these_toks ) {
v . push ( s ) ;
}
} else if let Some ( s ) = self . selector_from_token_stream ( & mut toks ) {
v . push ( s ) ;
} else {
return SelectorKind ::Several ( v ) ;
}
}
SelectorKind ::Several ( v )
}
fn selector_from_token_stream (
& mut self ,
toks : & mut Peekable < Iter < '_ , Token > > ,
) -> Option < SelectorKind > {
2020-01-12 20:15:27 -05:00
if devour_whitespace ( toks ) {
2020-01-12 10:54:46 -05:00
if let Some ( & & Token {
kind : TokenKind ::Symbol ( Symbol ::Comma ) ,
..
} ) = toks . peek ( )
{
toks . next ( ) ;
return Some ( SelectorKind ::Multiple ) ;
}
return Some ( SelectorKind ::Whitespace ) ;
}
if let Some ( Token { kind , .. } ) = toks . next ( ) {
return Some ( match & kind {
TokenKind ::Ident ( tok ) = > SelectorKind ::Element ( tok . clone ( ) ) ,
TokenKind ::Symbol ( Symbol ::Period ) = > SelectorKind ::Class ,
TokenKind ::Symbol ( Symbol ::Hash ) = > SelectorKind ::Id ,
TokenKind ::Symbol ( Symbol ::Colon ) = > return self . consume_pseudo_selector ( ) ,
TokenKind ::Symbol ( Symbol ::Comma ) = > SelectorKind ::Multiple ,
TokenKind ::Symbol ( Symbol ::Gt ) = > SelectorKind ::ImmediateChild ,
TokenKind ::Symbol ( Symbol ::Plus ) = > SelectorKind ::Following ,
TokenKind ::Symbol ( Symbol ::Tilde ) = > SelectorKind ::Preceding ,
TokenKind ::Symbol ( Symbol ::Mul ) = > SelectorKind ::Universal ,
TokenKind ::Symbol ( Symbol ::BitAnd ) = > SelectorKind ::Super ,
TokenKind ::Interpolation = > self . consume_interpolation ( ) ,
TokenKind ::Attribute ( attr ) = > SelectorKind ::Attribute ( attr . clone ( ) ) ,
_ = > todo! ( " unimplemented selector " ) ,
} ) ;
}
None
}
fn deref_variable ( & mut self , variable : & TokenKind ) -> Vec < Token > {
let mut val = Vec ::with_capacity ( 25 ) ;
let v = match variable {
2020-01-12 19:56:58 -05:00
TokenKind ::Variable ( ref v ) = > self
. scope
. vars
. get ( v )
. expect ( " todo! expected variable to exist " ) ,
2020-01-12 10:54:46 -05:00
_ = > todo! ( " expected variable " ) ,
}
. iter ( )
. peekable ( ) ;
for tok in v {
match & tok . kind {
TokenKind ::Variable ( _ ) = > val . extend ( self . deref_variable ( & tok . kind ) ) ,
_ = > val . push ( tok . clone ( ) ) ,
} ;
}
val
}
2020-01-04 22:55:04 -05:00
}
impl < ' a > SelectorParser < ' a > {
2020-01-11 14:51:31 -05:00
const fn new (
tokens : Peekable < Iter < ' a , Token > > ,
super_selector : & ' a Selector ,
2020-01-12 17:44:49 -05:00
scope : & ' a Scope ,
2020-01-11 14:51:31 -05:00
) -> SelectorParser < ' a > {
SelectorParser {
tokens ,
super_selector ,
2020-01-12 17:44:49 -05:00
scope ,
2020-01-11 14:51:31 -05:00
}
2020-01-04 22:55:04 -05:00
}
fn all_selectors ( & mut self ) -> Selector {
2020-01-11 16:12:23 -05:00
let mut v = Vec ::with_capacity ( self . tokens . len ( ) ) ;
2020-01-11 14:51:31 -05:00
while let Some ( s ) = self . consume_selector ( ) {
2020-01-12 10:54:46 -05:00
if let SelectorKind ::Several ( sels ) = s {
v . extend ( sels ) ;
} else {
v . push ( s ) ;
}
2020-01-11 14:51:31 -05:00
}
2020-01-11 16:12:23 -05:00
while let Some ( x ) = v . pop ( ) {
if x ! = SelectorKind ::Whitespace {
v . push ( x ) ;
break ;
}
}
2020-01-11 14:51:31 -05:00
Selector ( v )
}
2020-01-11 19:16:59 -05:00
fn consume_pseudo_selector ( & mut self ) -> Option < SelectorKind > {
if let Some ( Token {
kind : TokenKind ::Ident ( s ) ,
..
} ) = self . tokens . next ( )
{
if let Some ( Token {
kind : TokenKind ::Symbol ( Symbol ::OpenParen ) ,
..
} ) = self . tokens . peek ( )
{
self . tokens . next ( ) ;
let mut toks = Vec ::new ( ) ;
while let Some ( Token { kind , .. } ) = self . tokens . peek ( ) {
if kind = = & TokenKind ::Symbol ( Symbol ::CloseParen ) {
break ;
}
let tok = self . tokens . next ( ) . unwrap ( ) ;
toks . push ( tok . kind . clone ( ) ) ;
}
self . tokens . next ( ) ;
Some ( SelectorKind ::PseudoParen ( s . clone ( ) , toks ) )
} else {
Some ( SelectorKind ::Pseudo ( s . clone ( ) ) )
}
} else {
todo! ( " expected ident after `:` in selector " )
}
}
2020-01-11 14:51:31 -05:00
fn consume_selector ( & mut self ) -> Option < SelectorKind > {
2020-01-12 20:15:27 -05:00
if devour_whitespace ( & mut self . tokens ) {
2020-01-11 16:12:23 -05:00
if let Some ( & & Token {
kind : TokenKind ::Symbol ( Symbol ::Comma ) ,
..
} ) = self . tokens . peek ( )
{
self . tokens . next ( ) ;
return Some ( SelectorKind ::Multiple ) ;
}
2020-01-11 14:51:31 -05:00
return Some ( SelectorKind ::Whitespace ) ;
}
if let Some ( Token { kind , .. } ) = self . tokens . next ( ) {
return Some ( match & kind {
TokenKind ::Ident ( tok ) = > SelectorKind ::Element ( tok . clone ( ) ) ,
TokenKind ::Symbol ( Symbol ::Period ) = > SelectorKind ::Class ,
TokenKind ::Symbol ( Symbol ::Hash ) = > SelectorKind ::Id ,
2020-01-11 19:16:59 -05:00
TokenKind ::Symbol ( Symbol ::Colon ) = > return self . consume_pseudo_selector ( ) ,
2020-01-11 14:51:31 -05:00
TokenKind ::Symbol ( Symbol ::Comma ) = > SelectorKind ::Multiple ,
TokenKind ::Symbol ( Symbol ::Gt ) = > SelectorKind ::ImmediateChild ,
TokenKind ::Symbol ( Symbol ::Plus ) = > SelectorKind ::Following ,
TokenKind ::Symbol ( Symbol ::Tilde ) = > SelectorKind ::Preceding ,
TokenKind ::Symbol ( Symbol ::Mul ) = > SelectorKind ::Universal ,
2020-01-11 16:12:23 -05:00
TokenKind ::Symbol ( Symbol ::BitAnd ) = > SelectorKind ::Super ,
2020-01-12 10:54:46 -05:00
TokenKind ::Interpolation = > self . consume_interpolation ( ) ,
2020-01-11 14:51:31 -05:00
TokenKind ::Attribute ( attr ) = > SelectorKind ::Attribute ( attr . clone ( ) ) ,
_ = > todo! ( " unimplemented selector " ) ,
} ) ;
2020-01-04 22:55:04 -05:00
}
2020-01-11 14:51:31 -05:00
None
2020-01-04 22:55:04 -05:00
}
}
impl Selector {
2020-01-11 14:51:31 -05:00
pub fn from_tokens < ' a > (
tokens : Peekable < Iter < ' a , Token > > ,
super_selector : & ' a Selector ,
2020-01-12 17:44:49 -05:00
scope : & ' a Scope ,
2020-01-11 14:51:31 -05:00
) -> Selector {
2020-01-12 17:44:49 -05:00
SelectorParser ::new ( tokens , super_selector , scope ) . all_selectors ( )
2020-01-04 22:55:04 -05:00
}
2020-01-05 12:25:03 -05:00
pub fn zip ( self , other : Selector ) -> Selector {
2020-01-11 14:51:31 -05:00
if self . 0. is_empty ( ) {
return Selector ( other . 0 ) ;
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-11 14:51:31 -05:00
let sel1_split : Vec < Vec < SelectorKind > > = self
. 0
. split ( | sel | sel = = & SelectorKind ::Multiple )
. map ( | x | x . to_vec ( ) )
. collect ( ) ;
let sel2_split : Vec < Vec < SelectorKind > > = other
. 0
. split ( | sel | sel = = & SelectorKind ::Multiple )
. map ( | x | x . to_vec ( ) )
. collect ( ) ;
for ( idx , sel1 ) in sel1_split . iter ( ) . enumerate ( ) {
for ( idx2 , sel2 ) in sel2_split . iter ( ) . enumerate ( ) {
2020-01-11 16:12:23 -05:00
let mut this_selector = Vec ::with_capacity ( other . 0. len ( ) ) ;
let mut found_super = false ;
for sel in sel2 {
if sel = = & SelectorKind ::Super {
this_selector . extend ( sel1 . iter ( ) . cloned ( ) ) ;
found_super = true ;
} else {
this_selector . push ( sel . clone ( ) ) ;
}
}
if ! found_super {
rules . extend ( sel1 . iter ( ) . cloned ( ) ) ;
rules . push ( SelectorKind ::Whitespace ) ;
}
rules . extend ( this_selector ) ;
2020-01-11 14:51:31 -05:00
if ! ( idx + 1 = = sel1_split . len ( ) & & idx2 + 1 = = sel2_split . len ( ) ) {
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) ]
pub struct Attribute {
pub attr : String ,
pub value : String ,
pub case_sensitive : bool ,
pub kind : AttributeKind ,
}
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 ) ,
}
} 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 ) ,
}
}
}
}
#[ 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 ,
}