mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
templater: add list.join(separator) method
The implementation is a bit tricky since we have to combine a property (of C -> Vec<Template<()>> type) and a separator of Template<C> type.
This commit is contained in:
parent
6c146de2e8
commit
e8fd12aff6
4 changed files with 72 additions and 9 deletions
|
@ -86,7 +86,10 @@ No methods are defined.
|
|||
|
||||
### List type
|
||||
|
||||
No methods are defined.
|
||||
The following methods are defined.
|
||||
|
||||
* `.join(separator: Template) -> Template`: Concatenate elements with
|
||||
the given `separator`.
|
||||
|
||||
### OperationId type
|
||||
|
||||
|
|
|
@ -25,9 +25,9 @@ use pest_derive::Parser;
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::templater::{
|
||||
ConcatTemplate, ConditionalTemplate, IndentTemplate, IntoTemplate, LabelTemplate, Literal,
|
||||
PlainTextFormattedProperty, SeparateTemplate, Template, TemplateFunction, TemplateProperty,
|
||||
TimestampRange,
|
||||
ConcatTemplate, ConditionalTemplate, FormattablePropertyListTemplate, IndentTemplate,
|
||||
IntoTemplate, LabelTemplate, Literal, PlainTextFormattedProperty, SeparateTemplate, Template,
|
||||
TemplateFunction, TemplateProperty, TimestampRange,
|
||||
};
|
||||
use crate::time_util;
|
||||
|
||||
|
@ -1048,13 +1048,22 @@ fn build_timestamp_range_method<'a, L: TemplateLanguage<'a>>(
|
|||
Ok(property)
|
||||
}
|
||||
|
||||
pub fn build_list_method<'a, L: TemplateLanguage<'a>, P>(
|
||||
_language: &L,
|
||||
_self_property: impl TemplateProperty<L::Context, Output = Vec<P>> + 'a,
|
||||
pub fn build_list_method<'a, L: TemplateLanguage<'a>, P: Template<()> + 'a>(
|
||||
language: &L,
|
||||
self_property: impl TemplateProperty<L::Context, Output = Vec<P>> + 'a,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<L::Property> {
|
||||
// TODO: .join(separator), .map(), ...
|
||||
Err(TemplateParseError::no_such_method("List", function))
|
||||
let property = match function.name {
|
||||
"join" => {
|
||||
let [separator_node] = expect_exact_arguments(function)?;
|
||||
let separator = build_expression(language, separator_node)?.into_template();
|
||||
let template = FormattablePropertyListTemplate::new(self_property, separator);
|
||||
language.wrap_template(template)
|
||||
}
|
||||
// TODO: .map()
|
||||
_ => return Err(TemplateParseError::no_such_method("List", function)),
|
||||
};
|
||||
Ok(property)
|
||||
}
|
||||
|
||||
fn build_global_function<'a, L: TemplateLanguage<'a>>(
|
||||
|
|
|
@ -378,6 +378,44 @@ impl<C, T: Template<C>> TemplateProperty<C> for PlainTextFormattedProperty<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Renders a list of template properties with the given separator.
|
||||
///
|
||||
/// Each template property can be extracted as a context-less value, but
|
||||
/// the separator takes a context of type `C`.
|
||||
pub struct FormattablePropertyListTemplate<P, S> {
|
||||
property: P,
|
||||
separator: S,
|
||||
}
|
||||
|
||||
impl<P, S> FormattablePropertyListTemplate<P, S> {
|
||||
pub fn new<C>(property: P, separator: S) -> Self
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P::Output: IntoIterator,
|
||||
<P::Output as IntoIterator>::Item: Template<()>,
|
||||
S: Template<C>,
|
||||
{
|
||||
FormattablePropertyListTemplate {
|
||||
property,
|
||||
separator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, P, S> Template<C> for FormattablePropertyListTemplate<P, S>
|
||||
where
|
||||
P: TemplateProperty<C>,
|
||||
P::Output: IntoIterator,
|
||||
<P::Output as IntoIterator>::Item: Template<()>,
|
||||
S: Template<C>,
|
||||
{
|
||||
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
let contents = self.property.extract(context);
|
||||
let contents_iter = contents.into_iter().map(Literal); // as Template<C>
|
||||
format_joined(context, formatter, contents_iter, &self.separator)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConditionalTemplate<P, T, U> {
|
||||
pub condition: P,
|
||||
pub true_template: T,
|
||||
|
|
|
@ -236,6 +236,19 @@ fn test_templater_parse_error() {
|
|||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_templater_list_method() {
|
||||
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_template_output(&test_env, &repo_path, "@-", template);
|
||||
|
||||
insta::assert_snapshot!(render(r#""".lines().join("|")"#), @"");
|
||||
insta::assert_snapshot!(render(r#""a\nb\nc".lines().join("|")"#), @"a|b|c");
|
||||
// Keyword as separator
|
||||
insta::assert_snapshot!(render(r#""a\nb\nc".lines().join(commit_id.short(2))"#), @"a00b00c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_templater_string_method() {
|
||||
let test_env = TestEnvironment::default();
|
||||
|
|
Loading…
Reference in a new issue