implement @content inside mixins
This commit is contained in:
parent
907ac3390c
commit
415b19fc47
@ -1,6 +1,8 @@
|
||||
use std::iter::Peekable;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use super::eat_stmts;
|
||||
|
||||
use crate::args::{eat_call_args, eat_func_args, CallArgs, FuncArgs};
|
||||
use crate::atrule::AtRule;
|
||||
use crate::common::Symbol;
|
||||
@ -15,12 +17,18 @@ pub(crate) struct Mixin {
|
||||
scope: Scope,
|
||||
args: FuncArgs,
|
||||
body: Peekable<IntoIter<Token>>,
|
||||
content: Vec<Stmt>,
|
||||
}
|
||||
|
||||
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();
|
||||
Mixin { scope, args, body }
|
||||
Mixin {
|
||||
scope,
|
||||
args,
|
||||
body,
|
||||
content,
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -98,7 +111,7 @@ impl Mixin {
|
||||
while let Some(expr) = eat_expr(&mut self.body, &mut self.scope, super_selector)? {
|
||||
match expr {
|
||||
Expr::AtRule(a) => match a {
|
||||
AtRule::Content => todo!("@content in mixin"),
|
||||
AtRule::Content => stmts.extend(self.content.clone()),
|
||||
_ => stmts.push(Stmt::AtRule(a)),
|
||||
},
|
||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||
@ -146,6 +159,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
||||
|
||||
devour_whitespace(toks);
|
||||
|
||||
let mut has_include = false;
|
||||
|
||||
let mut args = if let Some(tok) = toks.next() {
|
||||
match tok.kind {
|
||||
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)?;
|
||||
devour_whitespace(toks);
|
||||
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
|
||||
}
|
||||
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
||||
has_include = true;
|
||||
CallArgs::new()
|
||||
}
|
||||
_ => return Err("expected \"{\".".into()),
|
||||
}
|
||||
} else {
|
||||
@ -165,8 +188,24 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
||||
|
||||
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 rules = mixin.args(&mut args)?.call(super_selector)?;
|
||||
let rules = mixin
|
||||
.args(&mut args)?
|
||||
.content(content)
|
||||
.call(super_selector)?;
|
||||
Ok(rules)
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ use std::iter::Peekable;
|
||||
|
||||
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::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
@ -13,13 +11,15 @@ use crate::unit::Unit;
|
||||
use crate::utils::{devour_whitespace, devour_whitespace_or_comment};
|
||||
use crate::value::{Number, Value};
|
||||
use crate::{Stmt, Token, TokenKind};
|
||||
pub(crate) use function::Function;
|
||||
pub(crate) use mixin::{eat_include, Mixin};
|
||||
|
||||
use parse::eat_stmts;
|
||||
use unknown::UnknownAtRule;
|
||||
|
||||
mod function;
|
||||
mod parse;
|
||||
mod mixin;
|
||||
mod parse;
|
||||
mod unknown;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -164,7 +164,7 @@ pub(crate) fn register(f: &mut HashMap<String, Builtin>) {
|
||||
} else {
|
||||
sep1
|
||||
}
|
||||
},
|
||||
}
|
||||
"comma" => ListSeparator::Comma,
|
||||
"space" => ListSeparator::Space,
|
||||
_ => {
|
||||
|
@ -84,7 +84,7 @@ use std::io::Write;
|
||||
use std::iter::{Iterator, Peekable};
|
||||
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::css::Css;
|
||||
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::Error(pos, err) => Err(SassError::new(err, pos)),
|
||||
AtRule::Return(_) => Err("This at-rule is not allowed here.".into()),
|
||||
AtRule::Content => {
|
||||
return Err("@content is only allowed within mixin declarations.".into())
|
||||
}
|
||||
c @ AtRule::Content => Ok(Some(Expr::AtRule(c))),
|
||||
f @ AtRule::If(..) => Ok(Some(Expr::AtRule(f))),
|
||||
f @ AtRule::For(..) => Ok(Some(Expr::AtRule(f))),
|
||||
u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))),
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::atrule::{Function, Mixin};
|
||||
use crate::error::SassResult;
|
||||
use crate::value::Value;
|
||||
|
||||
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",
|
||||
"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