Skip to content

Commit

Permalink
templater: add fill(width, content) function
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
yuja committed Mar 10, 2023
1 parent ec554f6 commit c52efd9
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/template_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,16 @@ fn build_global_function<'a, L: TemplateLanguage<'a>>(
function: &FunctionCallNode,
) -> TemplateParseResult<Expression<L::Property>> {
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();
Expand Down
39 changes: 39 additions & 0 deletions tests/test_templater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit c52efd9

Please sign in to comment.