Preserve newlines after , in selectors

This commit is contained in:
ConnorSkees 2020-02-22 17:26:30 -05:00
parent 686c3f0a51
commit 4ee9cc72a6
3 changed files with 24 additions and 10 deletions

View File

@ -115,7 +115,7 @@ impl<'a> Iterator for Lexer<'a> {
} }
'\r' => { '\r' => {
self.buf.next(); self.buf.next();
TokenKind::Whitespace(Whitespace::CarriageReturn) TokenKind::Whitespace(Whitespace::Newline)
} }
'#' => self.lex_hash(), '#' => self.lex_hash(),
'{' => symbol!(self, OpenCurlyBrace), '{' => symbol!(self, OpenCurlyBrace),

View File

@ -1,10 +1,10 @@
use crate::common::{Scope, Symbol}; use crate::common::{Scope, Symbol, Whitespace};
use crate::error::SassResult; use crate::error::SassResult;
use crate::utils::{ use crate::utils::{
devour_whitespace, devour_whitespace_or_comment, parse_interpolation, IsWhitespace, devour_whitespace, devour_whitespace_or_comment, parse_interpolation, IsWhitespace,
}; };
use crate::{Token, TokenKind}; use crate::{Token, TokenKind};
use std::fmt::{self, Display}; use std::fmt::{self, Display, Write};
use std::iter::Peekable; use std::iter::Peekable;
use std::string::ToString; use std::string::ToString;
use std::vec::IntoIter; use std::vec::IntoIter;
@ -56,7 +56,10 @@ impl Display for Selector {
devour_whitespace(&mut iter); devour_whitespace(&mut iter);
while let Some(sel) = iter.peek() { while let Some(sel) = iter.peek() {
if sel != &&SelectorKind::Multiple { if sel != &&SelectorKind::Multiple {
write!(f, ", ")?; write!(f, ",")?;
if sel != &&SelectorKind::Newline {
f.write_char(' ')?;
}
break; break;
} }
iter.next(); iter.next();
@ -82,6 +85,8 @@ pub(crate) enum SelectorKind {
Universal, Universal,
/// Multiple unrelated selectors: `button, .active` /// Multiple unrelated selectors: `button, .active`
Multiple, Multiple,
/// Newline (significant if after `SelectorKind::Multiple`)
Newline,
/// Select all immediate children: `ul > li` /// Select all immediate children: `ul > li`
ImmediateChild, ImmediateChild,
/// Select all elements immediately following: `div + p` /// Select all elements immediately following: `div + p`
@ -102,8 +107,6 @@ pub(crate) enum SelectorKind {
InterpolatedSuper, InterpolatedSuper,
/// Placeholder selector: `%alert` /// Placeholder selector: `%alert`
Placeholder, Placeholder,
/// Used to signify no selector (when there is no super_selector of a rule)
None,
Whitespace, Whitespace,
} }
@ -128,6 +131,7 @@ impl Display for SelectorKind {
SelectorKind::Universal => write!(f, "*"), SelectorKind::Universal => write!(f, "*"),
SelectorKind::Whitespace => write!(f, " "), SelectorKind::Whitespace => write!(f, " "),
SelectorKind::Multiple => write!(f, ", "), SelectorKind::Multiple => write!(f, ", "),
SelectorKind::Newline => writeln!(f),
SelectorKind::ImmediateChild => write!(f, " > "), SelectorKind::ImmediateChild => write!(f, " > "),
SelectorKind::Following => write!(f, " + "), SelectorKind::Following => write!(f, " + "),
SelectorKind::Preceding => write!(f, " ~ "), SelectorKind::Preceding => write!(f, " ~ "),
@ -135,9 +139,7 @@ impl Display for SelectorKind {
SelectorKind::Pseudo(s) => write!(f, ":{}", s), SelectorKind::Pseudo(s) => write!(f, ":{}", s),
SelectorKind::PseudoElement(s) => write!(f, "::{}", s), SelectorKind::PseudoElement(s) => write!(f, "::{}", s),
SelectorKind::PseudoParen(s, val) => write!(f, ":{}({})", s, val), SelectorKind::PseudoParen(s, val) => write!(f, ":{}({})", s, val),
SelectorKind::Super | SelectorKind::None | SelectorKind::InterpolatedSuper => { SelectorKind::Super | SelectorKind::InterpolatedSuper => write!(f, ""),
write!(f, "")
}
SelectorKind::Placeholder => write!(f, "%"), SelectorKind::Placeholder => write!(f, "%"),
} }
} }
@ -246,7 +248,13 @@ impl<'a> SelectorParser<'a> {
TokenKind::Symbol(Symbol::Period) => self.selectors.push(SelectorKind::Class), TokenKind::Symbol(Symbol::Period) => self.selectors.push(SelectorKind::Class),
TokenKind::Symbol(Symbol::Hash) => self.selectors.push(SelectorKind::Id), TokenKind::Symbol(Symbol::Hash) => self.selectors.push(SelectorKind::Id),
TokenKind::Symbol(Symbol::Colon) => self.consume_pseudo_selector(tokens)?, TokenKind::Symbol(Symbol::Colon) => self.consume_pseudo_selector(tokens)?,
TokenKind::Symbol(Symbol::Comma) => self.selectors.push(SelectorKind::Multiple), TokenKind::Symbol(Symbol::Comma) => {
self.selectors.push(SelectorKind::Multiple);
if tokens.peek().unwrap().kind == TokenKind::Whitespace(Whitespace::Newline) {
self.selectors.push(SelectorKind::Newline);
devour_whitespace(tokens);
}
}
TokenKind::Symbol(Symbol::Gt) => self.selectors.push(SelectorKind::ImmediateChild), TokenKind::Symbol(Symbol::Gt) => self.selectors.push(SelectorKind::ImmediateChild),
TokenKind::Symbol(Symbol::Plus) => self.selectors.push(SelectorKind::Following), TokenKind::Symbol(Symbol::Plus) => self.selectors.push(SelectorKind::Following),
TokenKind::Symbol(Symbol::Tilde) => self.selectors.push(SelectorKind::Preceding), TokenKind::Symbol(Symbol::Tilde) => self.selectors.push(SelectorKind::Preceding),

View File

@ -255,3 +255,9 @@ test!(
"a {\n + {\n b {\n color: red;\n }\n}\n", "a {\n + {\n b {\n color: red;\n }\n}\n",
"a + b {\n color: red;\n}\n" "a + b {\n color: red;\n}\n"
); );
test!(simple_multiple_newline, "a,\nb {\n color: red;\n}\n");
test!(
nested_multiple_newline,
"a,\nb {\n c {\n color: blue;\n }\n color: red;\n}\n",
"a,\nb {\n color: red;\n}\na c,\nb c {\n color: blue;\n}\n"
);