implement @content inside mixins
This commit is contained in:
parent
907ac3390c
commit
415b19fc47
@ -1,6 +1,8 @@
|
|||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
|
use super::eat_stmts;
|
||||||
|
|
||||||
use crate::args::{eat_call_args, eat_func_args, CallArgs, FuncArgs};
|
use crate::args::{eat_call_args, eat_func_args, CallArgs, FuncArgs};
|
||||||
use crate::atrule::AtRule;
|
use crate::atrule::AtRule;
|
||||||
use crate::common::Symbol;
|
use crate::common::Symbol;
|
||||||
@ -15,12 +17,18 @@ pub(crate) struct Mixin {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
args: FuncArgs,
|
args: FuncArgs,
|
||||||
body: Peekable<IntoIter<Token>>,
|
body: Peekable<IntoIter<Token>>,
|
||||||
|
content: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mixin {
|
impl Mixin {
|
||||||
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Token>) -> Self {
|
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Token>, content: Vec<Stmt>) -> Self {
|
||||||
let body = body.into_iter().peekable();
|
let body = body.into_iter().peekable();
|
||||||
Mixin { scope, args, body }
|
Mixin {
|
||||||
|
scope,
|
||||||
|
args,
|
||||||
|
body,
|
||||||
|
content,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
||||||
@ -69,7 +77,12 @@ impl Mixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((name, Mixin::new(scope.clone(), args, body)))
|
Ok((name, Mixin::new(scope.clone(), args, body, Vec::new())))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content(mut self, content: Vec<Stmt>) -> Mixin {
|
||||||
|
self.content = content;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
pub fn args(mut self, args: &mut CallArgs) -> SassResult<Mixin> {
|
||||||
@ -98,7 +111,7 @@ impl Mixin {
|
|||||||
while let Some(expr) = eat_expr(&mut self.body, &mut self.scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.body, &mut self.scope, super_selector)? {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::AtRule(a) => match a {
|
Expr::AtRule(a) => match a {
|
||||||
AtRule::Content => todo!("@content in mixin"),
|
AtRule::Content => stmts.extend(self.content.clone()),
|
||||||
_ => stmts.push(Stmt::AtRule(a)),
|
_ => stmts.push(Stmt::AtRule(a)),
|
||||||
},
|
},
|
||||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||||
@ -146,6 +159,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
|
let mut has_include = false;
|
||||||
|
|
||||||
let mut args = if let Some(tok) = toks.next() {
|
let mut args = if let Some(tok) = toks.next() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
TokenKind::Symbol(Symbol::SemiColon) => CallArgs::new(),
|
TokenKind::Symbol(Symbol::SemiColon) => CallArgs::new(),
|
||||||
@ -153,10 +168,18 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
let tmp = eat_call_args(toks, scope, super_selector)?;
|
let tmp = eat_call_args(toks, scope, super_selector)?;
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
if let Some(tok) = toks.next() {
|
if let Some(tok) = toks.next() {
|
||||||
assert_eq!(tok.kind, TokenKind::Symbol(Symbol::SemiColon));
|
match tok.kind {
|
||||||
|
TokenKind::Symbol(Symbol::SemiColon) => {}
|
||||||
|
TokenKind::Symbol(Symbol::OpenCurlyBrace) => has_include = true,
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tmp
|
tmp
|
||||||
}
|
}
|
||||||
|
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
||||||
|
has_include = true;
|
||||||
|
CallArgs::new()
|
||||||
|
}
|
||||||
_ => return Err("expected \"{\".".into()),
|
_ => return Err("expected \"{\".".into()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -165,8 +188,24 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
|
let content = if let Some(tok) = toks.peek() {
|
||||||
|
if tok.is_symbol(Symbol::OpenCurlyBrace) {
|
||||||
|
toks.next();
|
||||||
|
eat_stmts(toks, &mut scope.clone(), super_selector)?
|
||||||
|
} else if has_include {
|
||||||
|
eat_stmts(toks, &mut scope.clone(), super_selector)?
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
let mixin = scope.get_mixin(&name)?.clone();
|
let mixin = scope.get_mixin(&name)?.clone();
|
||||||
|
|
||||||
let rules = mixin.args(&mut args)?.call(super_selector)?;
|
let rules = mixin
|
||||||
|
.args(&mut args)?
|
||||||
|
.content(content)
|
||||||
|
.call(super_selector)?;
|
||||||
Ok(rules)
|
Ok(rules)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ use std::iter::Peekable;
|
|||||||
|
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
|
||||||
pub(crate) use function::Function;
|
|
||||||
pub(crate) use mixin::{eat_include, Mixin};
|
|
||||||
use crate::common::{Keyword, Pos, Symbol};
|
use crate::common::{Keyword, Pos, Symbol};
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
@ -13,13 +11,15 @@ use crate::unit::Unit;
|
|||||||
use crate::utils::{devour_whitespace, devour_whitespace_or_comment};
|
use crate::utils::{devour_whitespace, devour_whitespace_or_comment};
|
||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
use crate::{Stmt, Token, TokenKind};
|
use crate::{Stmt, Token, TokenKind};
|
||||||
|
pub(crate) use function::Function;
|
||||||
|
pub(crate) use mixin::{eat_include, Mixin};
|
||||||
|
|
||||||
use parse::eat_stmts;
|
use parse::eat_stmts;
|
||||||
use unknown::UnknownAtRule;
|
use unknown::UnknownAtRule;
|
||||||
|
|
||||||
mod function;
|
mod function;
|
||||||
mod parse;
|
|
||||||
mod mixin;
|
mod mixin;
|
||||||
|
mod parse;
|
||||||
mod unknown;
|
mod unknown;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -164,7 +164,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
|||||||
} else {
|
} else {
|
||||||
sep1
|
sep1
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"comma" => ListSeparator::Comma,
|
"comma" => ListSeparator::Comma,
|
||||||
"space" => ListSeparator::Space,
|
"space" => ListSeparator::Space,
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -84,7 +84,7 @@ use std::io::Write;
|
|||||||
use std::iter::{Iterator, Peekable};
|
use std::iter::{Iterator, Peekable};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::atrule::{AtRule, AtRuleKind, eat_include, Mixin, Function};
|
use crate::atrule::{eat_include, AtRule, AtRuleKind, Function, Mixin};
|
||||||
use crate::common::{Pos, Symbol, Whitespace};
|
use crate::common::{Pos, Symbol, Whitespace};
|
||||||
use crate::css::Css;
|
use crate::css::Css;
|
||||||
use crate::error::SassError;
|
use crate::error::SassError;
|
||||||
@ -637,9 +637,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
||||||
AtRule::Error(pos, err) => Err(SassError::new(err, pos)),
|
AtRule::Error(pos, err) => Err(SassError::new(err, pos)),
|
||||||
AtRule::Return(_) => Err("This at-rule is not allowed here.".into()),
|
AtRule::Return(_) => Err("This at-rule is not allowed here.".into()),
|
||||||
AtRule::Content => {
|
c @ AtRule::Content => Ok(Some(Expr::AtRule(c))),
|
||||||
return Err("@content is only allowed within mixin declarations.".into())
|
|
||||||
}
|
|
||||||
f @ AtRule::If(..) => Ok(Some(Expr::AtRule(f))),
|
f @ AtRule::If(..) => Ok(Some(Expr::AtRule(f))),
|
||||||
f @ AtRule::For(..) => Ok(Some(Expr::AtRule(f))),
|
f @ AtRule::For(..) => Ok(Some(Expr::AtRule(f))),
|
||||||
u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))),
|
u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::error::SassResult;
|
|
||||||
use crate::atrule::{Function, Mixin};
|
use crate::atrule::{Function, Mixin};
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell<Scope> = RefCell::new(Scope::new()));
|
thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell<Scope> = RefCell::new(Scope::new()));
|
||||||
|
@ -174,3 +174,13 @@ test!(
|
|||||||
"@mixin foo($x) {\n color: $x;\n}\na {\n @include foo(0px 0px 0px 0px #ef8086 inset !important);\n}\n",
|
"@mixin foo($x) {\n color: $x;\n}\na {\n @include foo(0px 0px 0px 0px #ef8086 inset !important);\n}\n",
|
||||||
"a {\n color: 0px 0px 0px 0px #ef8086 inset !important;\n}\n"
|
"a {\n color: 0px 0px 0px 0px #ef8086 inset !important;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
content_without_variable,
|
||||||
|
"@mixin foo {\n @content;\n}\n\na {\n @include foo {\n color: red;\n }\n}\n",
|
||||||
|
"a {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
content_with_variable,
|
||||||
|
"@mixin foo($a) {\n @content;\n}\n\na {\n @include foo(red) {\n color: red;\n }\n}\n",
|
||||||
|
"a {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user