ok/jj
1
0
Fork 0
forked from mirrors/jj

templater: add string.len() and list.len() methods

This commit is contained in:
Yuya Nishihara 2024-02-29 13:17:04 +09:00
parent 0656409904
commit 82b3017fda
3 changed files with 32 additions and 5 deletions

View file

@ -488,6 +488,11 @@ fn builtin_string_methods<'a, L: TemplateLanguage<'a>>() -> TemplateBuildMethodF
// Not using maplit::hashmap!{} or custom declarative macro here because // Not using maplit::hashmap!{} or custom declarative macro here because
// code completion inside macro is quite restricted. // code completion inside macro is quite restricted.
let mut map = TemplateBuildMethodFnMap::<L, String>::new(); let mut map = TemplateBuildMethodFnMap::<L, String>::new();
map.insert("len", |language, _build_ctx, self_property, function| {
template_parser::expect_no_arguments(function)?;
let out_property = TemplateFunction::new(self_property, |s| Ok(s.len().try_into()?));
Ok(language.wrap_integer(out_property))
});
map.insert( map.insert(
"contains", "contains",
|language, build_ctx, self_property, function| { |language, build_ctx, self_property, function| {
@ -762,6 +767,12 @@ where
O: Template<()> + Clone + 'a, O: Template<()> + Clone + 'a,
{ {
let property = match function.name { let property = match function.name {
"len" => {
template_parser::expect_no_arguments(function)?;
let out_property =
TemplateFunction::new(self_property, |items| Ok(items.len().try_into()?));
language.wrap_integer(out_property)
}
"join" => { "join" => {
let [separator_node] = template_parser::expect_exact_arguments(function)?; let [separator_node] = template_parser::expect_exact_arguments(function)?;
let separator = expect_template_expression(language, build_ctx, separator_node)?; let separator = expect_template_expression(language, build_ctx, separator_node)?;
@ -789,6 +800,12 @@ where
O: Clone + 'a, O: Clone + 'a,
{ {
let property = match function.name { let property = match function.name {
"len" => {
template_parser::expect_no_arguments(function)?;
let out_property =
TemplateFunction::new(self_property, |items| Ok(items.len().try_into()?));
language.wrap_integer(out_property)
}
// No "join" // No "join"
"map" => build_map_operation(language, build_ctx, self_property, function, wrap_item)?, "map" => build_map_operation(language, build_ctx, self_property, function, wrap_item)?,
_ => return Err(TemplateParseError::no_such_method("List", function)), _ => return Err(TemplateParseError::no_such_method("List", function)),
@ -1536,6 +1553,9 @@ mod tests {
language.wrap_string(Literal("sep".to_owned())) language.wrap_string(Literal("sep".to_owned()))
}); });
insta::assert_snapshot!(env.render_ok(r#""".lines().len()"#), @"0");
insta::assert_snapshot!(env.render_ok(r#""a\nb\nc".lines().len()"#), @"3");
insta::assert_snapshot!(env.render_ok(r#""".lines().join("|")"#), @""); insta::assert_snapshot!(env.render_ok(r#""".lines().join("|")"#), @"");
insta::assert_snapshot!(env.render_ok(r#""a\nb\nc".lines().join("|")"#), @"a|b|c"); insta::assert_snapshot!(env.render_ok(r#""a\nb\nc".lines().join("|")"#), @"a|b|c");
// Null separator // Null separator
@ -1633,6 +1653,10 @@ mod tests {
language.wrap_string(Literal("description 1".to_owned())) language.wrap_string(Literal("description 1".to_owned()))
}); });
insta::assert_snapshot!(env.render_ok(r#""".len()"#), @"0");
insta::assert_snapshot!(env.render_ok(r#""foo".len()"#), @"3");
insta::assert_snapshot!(env.render_ok(r#""💩".len()"#), @"4");
insta::assert_snapshot!(env.render_ok(r#""fooo".contains("foo")"#), @"true"); insta::assert_snapshot!(env.render_ok(r#""fooo".contains("foo")"#), @"true");
insta::assert_snapshot!(env.render_ok(r#""foo".contains("fooo")"#), @"false"); insta::assert_snapshot!(env.render_ok(r#""foo".contains("fooo")"#), @"false");
insta::assert_snapshot!(env.render_ok(r#"description.contains("description")"#), @"true"); insta::assert_snapshot!(env.render_ok(r#"description.contains("description")"#), @"true");

View file

@ -26,17 +26,18 @@ fn test_log_parents() {
test_env.jj_cmd_ok(&repo_path, &["new", "@-"]); test_env.jj_cmd_ok(&repo_path, &["new", "@-"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@", "@-"]); test_env.jj_cmd_ok(&repo_path, &["new", "@", "@-"]);
let template = r#"commit_id ++ "\nP: " ++ parents.map(|c| c.commit_id()) ++ "\n""#; let template =
r#"commit_id ++ "\nP: " ++ parents.len() ++ " " ++ parents.map(|c| c.commit_id()) ++ "\n""#;
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]); let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stdout, @r###" insta::assert_snapshot!(stdout, @r###"
@ c067170d4ca1bc6162b64f7550617ec809647f84 @ c067170d4ca1bc6162b64f7550617ec809647f84
P: 4db490c88528133d579540b6900b8098f0c17701 230dd059e1b059aefc0da06a2e5a7dbf22362f22 P: 2 4db490c88528133d579540b6900b8098f0c17701 230dd059e1b059aefc0da06a2e5a7dbf22362f22
4db490c88528133d579540b6900b8098f0c17701 4db490c88528133d579540b6900b8098f0c17701
P: 230dd059e1b059aefc0da06a2e5a7dbf22362f22 P: 1 230dd059e1b059aefc0da06a2e5a7dbf22362f22
230dd059e1b059aefc0da06a2e5a7dbf22362f22 230dd059e1b059aefc0da06a2e5a7dbf22362f22
P: 0000000000000000000000000000000000000000 P: 1 0000000000000000000000000000000000000000
0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
P: P: 0
"###); "###);
let template = r#"parents.map(|c| c.commit_id().shortest(4))"#; let template = r#"parents.map(|c| c.commit_id().shortest(4))"#;

View file

@ -105,6 +105,7 @@ No methods are defined.
A list can be implicitly converted to `Boolean`. The following methods are A list can be implicitly converted to `Boolean`. The following methods are
defined. defined.
* `.len() -> Integer`: Number of elements in the list.
* `.join(separator: Template) -> Template`: Concatenate elements with * `.join(separator: Template) -> Template`: Concatenate elements with
the given `separator`. the given `separator`.
* `.map(|item| expression) -> ListTemplate`: Apply template `expression` * `.map(|item| expression) -> ListTemplate`: Apply template `expression`
@ -164,6 +165,7 @@ The following methods are defined.
A string can be implicitly converted to `Boolean`. The following methods are A string can be implicitly converted to `Boolean`. The following methods are
defined. defined.
* `.len() -> Integer`: Length in UTF-8 bytes.
* `.contains(needle: Template) -> Boolean` * `.contains(needle: Template) -> Boolean`
* `.first_line() -> String` * `.first_line() -> String`
* `.lines() -> List<String>`: Split into lines excluding newline characters. * `.lines() -> List<String>`: Split into lines excluding newline characters.