simplify declaration of other color fns

This commit is contained in:
ConnorSkees 2020-04-30 18:59:27 -04:00
parent 11e0d523b2
commit 4cfa29c971

View File

@ -3,8 +3,12 @@ use super::GlobalFunctionMap;
use num_traits::{One, Signed, Zero};
use super::Builtin;
use crate::args::CallArgs;
use crate::color::Color;
use crate::common::QuoteKind;
use crate::error::SassResult;
use crate::scope::Scope;
use crate::selector::Selector;
use crate::unit::Unit;
use crate::value::{Number, Value};
@ -51,7 +55,11 @@ macro_rules! opt_hsl {
}
pub(crate) fn register(f: &mut GlobalFunctionMap) {
f.insert("change-color", Builtin::new(|mut args, scope, super_selector| {
fn change_color(
mut args: CallArgs,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Value> {
if args.get_positional(1, scope, super_selector).is_some() {
return Err(
("Only one positional argument is allowed. All other arguments must be passed by name.", args.span()
@ -60,9 +68,13 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => return Err(
(format!("$color: {} is not a color.", v.to_css_string(args.span())?), args.span()
).into()),
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_rgba!(args, alpha, "alpha", 0, 1, scope, super_selector);
@ -71,24 +83,46 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
opt_rgba!(args, blue, "blue", 0, 255, scope, super_selector);
if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba(red.unwrap_or(color.red()), green.unwrap_or(color.green()), blue.unwrap_or(color.blue()), alpha.unwrap_or(color.alpha())))))
return Ok(Value::Color(Box::new(Color::from_rgba(
red.unwrap_or(color.red()),
green.unwrap_or(color.green()),
blue.unwrap_or(color.blue()),
alpha.unwrap_or(color.alpha()),
))));
}
let hue = match named_arg!(args, scope, super_selector, "hue"=Value::Null) {
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
Value::Dimension(n, _) => Some(n),
Value::Null => None,
v => return Err(
(format!("$hue: {} is not a number.", v.to_css_string(args.span())?), args.span()
).into()),
v => {
return Err((
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_hsl!(args, saturation, "saturation", 0, 100, scope, super_selector);
opt_hsl!(
args,
saturation,
"saturation",
0,
100,
scope,
super_selector
);
opt_hsl!(args, luminance, "lightness", 0, 100, scope, super_selector);
if hue.is_some() || saturation.is_some() || luminance.is_some() {
// Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Box::new(Color::from_hsla(hue.unwrap_or(this_hue), saturation.unwrap_or(this_saturation), luminance.unwrap_or(this_luminance), alpha.unwrap_or(this_alpha)))))
return Ok(Value::Color(Box::new(Color::from_hsla(
hue.unwrap_or(this_hue),
saturation.unwrap_or(this_saturation),
luminance.unwrap_or(this_luminance),
alpha.unwrap_or(this_alpha),
))));
}
Ok(Value::Color(if let Some(a) = alpha {
@ -96,197 +130,242 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
} else {
color
}))
}));
f.insert(
"adjust-color",
Builtin::new(|mut args, scope, super_selector| {
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_rgba!(args, alpha, "alpha", -1, 1, scope, super_selector);
opt_rgba!(args, red, "red", -255, 255, scope, super_selector);
opt_rgba!(args, green, "green", -255, 255, scope, super_selector);
opt_rgba!(args, blue, "blue", -255, 255, scope, super_selector);
if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba(
color.red() + red.unwrap_or(Number::zero()),
color.green() + green.unwrap_or(Number::zero()),
color.blue() + blue.unwrap_or(Number::zero()),
color.alpha() + alpha.unwrap_or(Number::zero()),
))));
}
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
Value::Dimension(n, _) => Some(n),
Value::Null => None,
v => {
return Err((
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_hsl!(
args,
saturation,
"saturation",
-100,
100,
scope,
super_selector
);
opt_hsl!(
args,
luminance,
"lightness",
-100,
100,
scope,
super_selector
);
if hue.is_some() || saturation.is_some() || luminance.is_some() {
// Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Box::new(Color::from_hsla(
this_hue + hue.unwrap_or(Number::zero()),
this_saturation + saturation.unwrap_or(Number::zero()),
this_luminance + luminance.unwrap_or(Number::zero()),
this_alpha + alpha.unwrap_or(Number::zero()),
))));
}
Ok(Value::Color(if let Some(a) = alpha {
let temp_alpha = color.alpha();
Box::new(color.with_alpha(temp_alpha + a))
} else {
color
}))
}),
);
f.insert(
"scale-color",
Builtin::new(|mut args, scope, super_selector| {
let span = args.span();
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => return Err(
(format!("$color: {} is not a color.", v.to_css_string(span)?), span
).into()),
};
macro_rules! opt_scale_arg {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $scope:ident, $super_selector:ident) => {
let $name = match named_arg!($args, $scope, $super_selector, $arg = Value::Null) {
Value::Dimension(n, Unit::Percent) => {
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
}
v @ Value::Dimension(..) => {
return Err(
(format!("${}: Expected {} to have unit \"%\".", $arg, v.to_css_string($args.span())?), $args.span()).into()
)
}
Value::Null => None,
v => return Err(
(format!("${}: {} is not a number.", $arg, v.to_css_string($args.span())?), $args.span()
).into()),
};
};
}
opt_scale_arg!(args, alpha, "alpha", -100, 100, scope, super_selector);
opt_scale_arg!(args, red, "red", -100, 100, scope, super_selector);
opt_scale_arg!(args, green, "green", -100, 100, scope, super_selector);
opt_scale_arg!(args, blue, "blue", -100, 100, scope, super_selector);
if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba(
scale(
color.red(),
red.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.green(),
green.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.blue(),
blue.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.alpha(),
alpha.unwrap_or(Number::zero()),
Number::one(),
),
))));
}
opt_scale_arg!(args, saturation, "saturation", -100, 100, scope, super_selector);
opt_scale_arg!(args, luminance, "lightness", -100, 100, scope, super_selector);
if saturation.is_some() || luminance.is_some() {
// Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Box::new(Color::from_hsla(
scale(this_hue, Number::zero(), Number::from(360)),
scale(
this_saturation,
saturation.unwrap_or(Number::zero()),
Number::one(),
),
scale(
this_luminance,
luminance.unwrap_or(Number::zero()),
Number::one(),
),
scale(this_alpha, alpha.unwrap_or(Number::zero()), Number::one()),
))));
}
Ok(Value::Color(if let Some(a) = alpha {
let temp_alpha = color.alpha();
Box::new(color.with_alpha(scale(temp_alpha, a, Number::one())))
} else {
color
}))
}),
);
f.insert(
"ie-hex-str",
Builtin::new(|mut args, scope, super_selector| {
args.max_args(1)?;
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
}),
);
}
fn scale(val: Number, by: Number, max: Number) -> Number {
if by.is_zero() {
return val;
}
val.clone() + (if by.is_positive() { max - val } else { val }) * by
fn adjust_color(
mut args: CallArgs,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Value> {
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_rgba!(args, alpha, "alpha", -1, 1, scope, super_selector);
opt_rgba!(args, red, "red", -255, 255, scope, super_selector);
opt_rgba!(args, green, "green", -255, 255, scope, super_selector);
opt_rgba!(args, blue, "blue", -255, 255, scope, super_selector);
if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba(
color.red() + red.unwrap_or(Number::zero()),
color.green() + green.unwrap_or(Number::zero()),
color.blue() + blue.unwrap_or(Number::zero()),
color.alpha() + alpha.unwrap_or(Number::zero()),
))));
}
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
Value::Dimension(n, _) => Some(n),
Value::Null => None,
v => {
return Err((
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
opt_hsl!(
args,
saturation,
"saturation",
-100,
100,
scope,
super_selector
);
opt_hsl!(
args,
luminance,
"lightness",
-100,
100,
scope,
super_selector
);
if hue.is_some() || saturation.is_some() || luminance.is_some() {
// Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Box::new(Color::from_hsla(
this_hue + hue.unwrap_or(Number::zero()),
this_saturation + saturation.unwrap_or(Number::zero()),
this_luminance + luminance.unwrap_or(Number::zero()),
this_alpha + alpha.unwrap_or(Number::zero()),
))));
}
Ok(Value::Color(if let Some(a) = alpha {
let temp_alpha = color.alpha();
Box::new(color.with_alpha(temp_alpha + a))
} else {
color
}))
}
fn scale_color(
mut args: CallArgs,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Value> {
fn scale(val: Number, by: Number, max: Number) -> Number {
if by.is_zero() {
return val;
}
val.clone() + (if by.is_positive() { max - val } else { val }) * by
}
let span = args.span();
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(span)?),
span,
)
.into())
}
};
macro_rules! opt_scale_arg {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $scope:ident, $super_selector:ident) => {
let $name = match named_arg!($args, $scope, $super_selector, $arg = Value::Null) {
Value::Dimension(n, Unit::Percent) => {
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
}
v @ Value::Dimension(..) => {
return Err((
format!(
"${}: Expected {} to have unit \"%\".",
$arg,
v.to_css_string($args.span())?
),
$args.span(),
)
.into())
}
Value::Null => None,
v => {
return Err((
format!(
"${}: {} is not a number.",
$arg,
v.to_css_string($args.span())?
),
$args.span(),
)
.into())
}
};
};
}
opt_scale_arg!(args, alpha, "alpha", -100, 100, scope, super_selector);
opt_scale_arg!(args, red, "red", -100, 100, scope, super_selector);
opt_scale_arg!(args, green, "green", -100, 100, scope, super_selector);
opt_scale_arg!(args, blue, "blue", -100, 100, scope, super_selector);
if red.is_some() || green.is_some() || blue.is_some() {
return Ok(Value::Color(Box::new(Color::from_rgba(
scale(
color.red(),
red.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.green(),
green.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.blue(),
blue.unwrap_or(Number::zero()),
Number::from(255),
),
scale(
color.alpha(),
alpha.unwrap_or(Number::zero()),
Number::one(),
),
))));
}
opt_scale_arg!(
args,
saturation,
"saturation",
-100,
100,
scope,
super_selector
);
opt_scale_arg!(
args,
luminance,
"lightness",
-100,
100,
scope,
super_selector
);
if saturation.is_some() || luminance.is_some() {
// Color::as_hsla() returns more exact values than Color::hue(), etc.
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
return Ok(Value::Color(Box::new(Color::from_hsla(
scale(this_hue, Number::zero(), Number::from(360)),
scale(
this_saturation,
saturation.unwrap_or(Number::zero()),
Number::one(),
),
scale(
this_luminance,
luminance.unwrap_or(Number::zero()),
Number::one(),
),
scale(this_alpha, alpha.unwrap_or(Number::zero()), Number::one()),
))));
}
Ok(Value::Color(if let Some(a) = alpha {
let temp_alpha = color.alpha();
Box::new(color.with_alpha(scale(temp_alpha, a, Number::one())))
} else {
color
}))
}
fn ie_hex_str(
mut args: CallArgs,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Value> {
args.max_args(1)?;
let color = match arg!(args, scope, super_selector, 0, "color") {
Value::Color(c) => c,
v => {
return Err((
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
args.span(),
)
.into())
}
};
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
}
f.insert("change-color", Builtin::new(change_color));
f.insert("adjust-color", Builtin::new(adjust_color));
f.insert("scale-color", Builtin::new(scale_color));
f.insert("ie-hex-str", Builtin::new(ie_hex_str));
}