diff --git a/src/builtin/list.rs b/src/builtin/list.rs index 1333279..3b499fd 100644 --- a/src/builtin/list.rs +++ b/src/builtin/list.rs @@ -70,4 +70,44 @@ pub(crate) fn register(f: &mut HashMap) { )) }), ); + f.insert( + "set-nth".to_owned(), + Box::new(|args, _| { + max_args!(args, 3); + let (mut list, sep) = match arg!(args, 0, "list") { + Value::List(v, sep) => (v, sep), + v => (vec![v], ListSeparator::Space), + }; + let n = match arg!(args, 1, "n") { + Value::Dimension(num, _) => num, + v => return Err(format!("$n: {} is not a number.", v).into()), + }; + + if n == Number::from(0) { + return Err("$n: List index may not be 0.".into()); + } + + let len = list.len(); + + if n.abs() > Number::from(len) { + return Err( + format!("$n: Invalid index {} for a list with {} elements.", n, len).into(), + ); + } + + if n.is_decimal() { + return Err(format!("$n: {} is not an int.", n).into()); + } + + let val = arg!(args, 2, "value"); + + if n > Number::from(0) { + list[n.to_integer().to_usize().unwrap() - 1] = val; + } else { + list[len - n.abs().to_integer().to_usize().unwrap()] = val; + } + + Ok(Value::List(list, sep)) + }), + ); } diff --git a/tests/list.rs b/tests/list.rs index d481b77..b8b41b8 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -60,3 +60,23 @@ test!( // "a {\n color: list-separator(((a b, c d)));\n}\n", // "a {\n color: comma;\n}\n" // ); +test!( + set_nth_named_args, + "a {\n color: set-nth($list: 1 2 3, $n: 2, $value: foo);\n}\n", + "a {\n color: 1 foo 3;\n}\n" +); +test!( + set_nth_non_list, + "a {\n color: set-nth(c, 1, e);\n}\n", + "a {\n color: e;\n}\n" +); +test!( + set_nth_2_long, + "a {\n color: set-nth(c d, 1, e);\n}\n", + "a {\n color: e d;\n}\n" +); +test!( + set_nth_comma_separated, + "a {\n color: set-nth((a, b, c), 1, e);\n}\n", + "a {\n color: e, b, c;\n}\n" +);