From c52efd9df38df2b7b93493ab4c89a9457e254a5a Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Sat, 4 Mar 2023 23:07:14 +0900 Subject: [PATCH] templater: add fill(width, content) function The parameter order follows indent()/label() functions, but this might be a bad idea because fill() is more likely to have optional parameters. We can instead add template.fill(width) method as well as .indent(prefix). If we take this approach, we'll probably need to add string.fill()/indent() methods, and/or implicit cast at method resolution. The good thing about the method syntax is that we can add string.refill(), etc. for free, without inventing generic labeled template functions. For #1043, I think it's better to add a config like ui.log-word-wrap = true. We could add term_width/graph_width keywords to the templater, but the implementation would be more complicated, and is difficult to use for the basic use case. Unlike Mercurial, our templater doesn't have a context map to override the graph_width stub. --- docs/templates.md | 2 ++ src/template_parser.rs | 10 ++++++++++ tests/test_templater.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/docs/templates.md b/docs/templates.md index 05a6eee474..4238fd2a57 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -56,6 +56,8 @@ The following operators are supported. The following functions are defined. +* `fill(width: Integer, content: Template) -> Template`: Fill lines at + the given `width`. * `indent(prefix: Template, content: Template) -> Template`: Indent non-empty lines by the given `prefix`. * `label(label: Template, content: Template) -> Template`: Apply label to diff --git a/src/template_parser.rs b/src/template_parser.rs index 55dc4780e0..132573ee26 100644 --- a/src/template_parser.rs +++ b/src/template_parser.rs @@ -1071,6 +1071,16 @@ fn build_global_function<'a, L: TemplateLanguage<'a>>( function: &FunctionCallNode, ) -> TemplateParseResult> { let property = match function.name { + "fill" => { + let [width_node, content_node] = expect_exact_arguments(function)?; + let width = expect_integer_expression(language, width_node)?; + let content = build_expression(language, content_node)?.into_template(); + let template = ReformatTemplate::new(content, move |context, formatter, recorded| { + let width = width.extract(context).try_into().unwrap_or(0); + text_util::write_wrapped(formatter, recorded, width) + }); + language.wrap_template(template) + } "indent" => { let [prefix_node, content_node] = expect_exact_arguments(function)?; let prefix = build_expression(language, prefix_node)?.into_template(); diff --git a/tests/test_templater.rs b/tests/test_templater.rs index 7f88c69714..c3c6ebbadb 100644 --- a/tests/test_templater.rs +++ b/tests/test_templater.rs @@ -332,6 +332,45 @@ fn test_templater_signature() { insta::assert_snapshot!(render(r#"author.username()"#), @"x"); } +#[test] +fn test_templater_fill_function() { + let test_env = TestEnvironment::default(); + test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]); + let repo_path = test_env.env_root().join("repo"); + let render = |template| get_colored_template_output(&test_env, &repo_path, "@-", template); + + insta::assert_snapshot!( + render(r#"fill(20, "The quick fox jumps over the " ++ + label("error", "lazy") ++ " dog\n")"#), + @r###" + The quick fox jumps + over the lazy dog + "###); + + // Word-wrap, then indent + insta::assert_snapshot!( + render(r#""START marker to help insta\n" ++ + indent(" ", fill(20, "The quick fox jumps over the " ++ + label("error", "lazy") ++ " dog\n"))"#), + @r###" + START marker to help insta + The quick fox jumps + over the lazy dog + "###); + + // Word-wrap indented (no special handling for leading spaces) + insta::assert_snapshot!( + render(r#""START marker to help insta\n" ++ + fill(20, indent(" ", "The quick fox jumps over the " ++ + label("error", "lazy") ++ " dog\n"))"#), + @r###" + START marker to help insta + The quick fox + jumps over the lazy + dog + "###); +} + #[test] fn test_templater_indent_function() { let test_env = TestEnvironment::default();