diff --git a/src/format.rs b/src/format.rs index d328af7..0636ea0 100644 --- a/src/format.rs +++ b/src/format.rs @@ -84,7 +84,7 @@ impl PrettyPrinter { s: &StyleSheet, ) -> io::Result<()> { for rule in &s.rules { - self.pretty_print_stmt(rule)?; + self.pretty_print_stmt_preserve_super_selectors(rule)?; } writeln!(self.buf)?; Ok(()) diff --git a/src/main.rs b/src/main.rs index f1813ce..b96809b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,7 @@ use crate::css::Css; use crate::format::PrettyPrinter; use crate::lexer::Lexer; use crate::selector::Selector; +use crate::style::Style; use crate::units::Unit; mod color; @@ -46,6 +47,7 @@ mod error; mod format; mod lexer; mod selector; +mod style; mod units; #[derive(Clone, Debug, Eq, PartialEq)] @@ -95,130 +97,6 @@ pub struct StyleSheet { rules: Vec, } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Style { - property: String, - value: String, -} - -impl Display for Style { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{};", self.property, self.value) - } -} - -impl Style { - pub fn from_tokens(tokens: &[Token], vars: &HashMap>) -> Result { - Ok(StyleParser::new(tokens, vars)?.parse()) - } -} - -struct StyleParser<'a> { - tokens: Peekable>, - vars: &'a HashMap>, -} - -impl<'a> StyleParser<'a> { - fn new(tokens: &'a [Token], vars: &'a HashMap>) -> Result { - if tokens.is_empty() { - return Err(()); - } - let tokens = tokens.iter().peekable(); - Ok(StyleParser { tokens, vars }) - } - - fn deref_variable(&mut self, variable: &TokenKind) -> String { - let mut val = String::with_capacity(25); - let mut v = match variable { - TokenKind::Variable(ref v) => { - self.vars.get(v).expect("todo! expected variable to exist") - } - _ => panic!("expected variable"), - } - .iter() - .peekable(); - while let Some(tok) = v.next() { - match &tok.kind { - TokenKind::Variable(_) => val.push_str(&self.deref_variable(&tok.kind)), - TokenKind::Whitespace(_) => { - while let Some(w) = v.peek() { - if let TokenKind::Whitespace(_) = w.kind { - v.next(); - } else { - val.push(' '); - break; - } - } - } - _ => val.push_str(&tok.kind.to_string()), - }; - } - val - } - - fn devour_whitespace(&mut self) { - while let Some(tok) = self.tokens.peek() { - if let TokenKind::Whitespace(_) = tok.kind { - self.tokens.next(); - } else { - break; - } - } - } - - fn parse(&mut self) -> Style { - let mut property = String::new(); - // read property - while let Some(tok) = self.tokens.next() { - match tok.kind { - TokenKind::Whitespace(_) => continue, - TokenKind::Ident(ref s) => { - property = s.clone(); - break; - } - _ => todo!(), - }; - } - - // read until `:` - while let Some(tok) = self.tokens.next() { - match tok.kind { - TokenKind::Whitespace(_) => continue, - TokenKind::Symbol(Symbol::Colon) => break, - _ => todo!("found tokens before style value"), - } - } - - let mut value = String::new(); - - // read styles - while let Some(tok) = self.tokens.next() { - match &tok.kind { - TokenKind::Whitespace(_) => { - while let Some(w) = self.tokens.peek() { - if let TokenKind::Whitespace(_) = w.kind { - self.tokens.next(); - continue; - } else if let TokenKind::Ident(ref s) = w.kind { - if s == &String::from("-") { - self.tokens.next(); - value.push('-'); - self.devour_whitespace(); - break; - } - } - value.push(' '); - break; - } - } - TokenKind::Variable(_) => value.push_str(&self.deref_variable(&tok.kind)), - _ => value.push_str(&tok.kind.to_string()), - } - } - Style { property, value } - } -} - #[derive(Clone, Debug, Eq, PartialEq)] pub enum Stmt { Style(Style), diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000..085e877 --- /dev/null +++ b/src/style.rs @@ -0,0 +1,130 @@ +use crate::{Token, TokenKind}; +use crate::common::Symbol; +use std::fmt::{self, Display}; +use std::collections::HashMap; +use std::slice::Iter; +use std::iter::Peekable; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Style { + property: String, + value: String, +} + +impl Display for Style { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{};", self.property, self.value) + } +} + +impl Style { + pub fn from_tokens(tokens: &[Token], vars: &HashMap>) -> Result { + Ok(StyleParser::new(tokens, vars)?.parse()) + } +} + +struct StyleParser<'a> { + tokens: Peekable>, + vars: &'a HashMap>, +} + +impl<'a> StyleParser<'a> { + fn new(tokens: &'a [Token], vars: &'a HashMap>) -> Result { + if tokens.is_empty() { + return Err(()); + } + let tokens = tokens.iter().peekable(); + Ok(StyleParser { tokens, vars }) + } + + fn deref_variable(&mut self, variable: &TokenKind) -> String { + let mut val = String::with_capacity(25); + let mut v = match variable { + TokenKind::Variable(ref v) => { + self.vars.get(v).expect("todo! expected variable to exist") + } + _ => panic!("expected variable"), + } + .iter() + .peekable(); + while let Some(tok) = v.next() { + match &tok.kind { + TokenKind::Variable(_) => val.push_str(&self.deref_variable(&tok.kind)), + TokenKind::Whitespace(_) => { + while let Some(w) = v.peek() { + if let TokenKind::Whitespace(_) = w.kind { + v.next(); + } else { + val.push(' '); + break; + } + } + } + _ => val.push_str(&tok.kind.to_string()), + }; + } + val + } + + fn devour_whitespace(&mut self) { + while let Some(tok) = self.tokens.peek() { + if let TokenKind::Whitespace(_) = tok.kind { + self.tokens.next(); + } else { + break; + } + } + } + + fn parse(&mut self) -> Style { + let mut property = String::new(); + // read property + while let Some(tok) = self.tokens.next() { + match tok.kind { + TokenKind::Whitespace(_) => continue, + TokenKind::Ident(ref s) => { + property = s.clone(); + break; + } + _ => todo!(), + }; + } + + // read until `:` + while let Some(tok) = self.tokens.next() { + match tok.kind { + TokenKind::Whitespace(_) => continue, + TokenKind::Symbol(Symbol::Colon) => break, + _ => todo!("found tokens before style value"), + } + } + + let mut value = String::new(); + + // read styles + while let Some(tok) = self.tokens.next() { + match &tok.kind { + TokenKind::Whitespace(_) => { + while let Some(w) = self.tokens.peek() { + if let TokenKind::Whitespace(_) = w.kind { + self.tokens.next(); + continue; + } else if let TokenKind::Ident(ref s) = w.kind { + if s == &String::from("-") { + self.tokens.next(); + value.push('-'); + self.devour_whitespace(); + break; + } + } + value.push(' '); + break; + } + } + TokenKind::Variable(_) => value.push_str(&self.deref_variable(&tok.kind)), + _ => value.push_str(&tok.kind.to_string()), + } + } + Style { property, value } + } +}