From 998727266cea9d39dc7deca84903b2be86f5aba6 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Tue, 14 Mar 2023 19:57:03 +0900 Subject: [PATCH] templater: add join method to mapped template --- docs/templates.md | 8 +++++++- src/template_builder.rs | 40 +++++++++++++++++++++++++++++++++++++--- tests/test_templater.rs | 4 ++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index a90429558..577d113e1 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -92,9 +92,15 @@ The following methods are defined. * `.join(separator: Template) -> Template`: Concatenate elements with the given `separator`. -* `.map(|item| expression) -> Template`: Apply template `expression` +* `.map(|item| expression) -> ListTemplate`: Apply template `expression` to each element. Example: `parent_commit_ids.map(|id| id.short())` +### ListTemplate type + +The following methods are defined. See also the `List` type. + +* `.join(separator: Template) -> Template` + ### OperationId type The following methods are defined. diff --git a/src/template_builder.rs b/src/template_builder.rs index 616e77717..a4304c52b 100644 --- a/src/template_builder.rs +++ b/src/template_builder.rs @@ -23,8 +23,8 @@ use crate::template_parser::{ }; use crate::templater::{ ConcatTemplate, ConditionalTemplate, IntoTemplate, LabelTemplate, ListPropertyTemplate, - Literal, PlainTextFormattedProperty, PropertyPlaceholder, ReformatTemplate, SeparateTemplate, - Template, TemplateFunction, TemplateProperty, TimestampRange, + ListTemplate, Literal, PlainTextFormattedProperty, PropertyPlaceholder, ReformatTemplate, + SeparateTemplate, Template, TemplateFunction, TemplateProperty, TimestampRange, }; use crate::{text_util, time_util}; @@ -61,7 +61,12 @@ pub trait TemplateLanguage<'a> { &self, property: impl TemplateProperty + 'a, ) -> Self::Property; + fn wrap_template(&self, template: Box + 'a>) -> Self::Property; + fn wrap_list_template( + &self, + template: Box + 'a>, + ) -> Self::Property; fn build_keyword(&self, name: &str, span: pest::Span) -> TemplateParseResult; fn build_method( @@ -99,6 +104,13 @@ macro_rules! impl_core_wrap_property_fns { use $crate::template_builder::CoreTemplatePropertyKind as Kind; $outer(Kind::Template(template)) } + fn wrap_list_template( + &self, + template: Box + $a>, + ) -> Self::Property { + use $crate::template_builder::CoreTemplatePropertyKind as Kind; + $outer(Kind::ListTemplate(template)) + } }; } @@ -140,6 +152,7 @@ pub enum CoreTemplatePropertyKind<'a, I> { // capture `I` to produce `Template<()>`. The context `I` would have to be cloned // to convert `Template` to `Template<()>`. Template(Box + 'a>), + ListTemplate(Box + 'a>), } impl<'a, I: 'a> IntoTemplateProperty<'a, I> for CoreTemplatePropertyKind<'a, I> { @@ -180,6 +193,7 @@ impl<'a, I: 'a> IntoTemplate<'a, I> for CoreTemplatePropertyKind<'a, I> { CoreTemplatePropertyKind::Timestamp(property) => property.into_template(), CoreTemplatePropertyKind::TimestampRange(property) => property.into_template(), CoreTemplatePropertyKind::Template(template) => template, + CoreTemplatePropertyKind::ListTemplate(template) => template.into_template(), } } } @@ -288,6 +302,9 @@ pub fn build_core_method<'a, L: TemplateLanguage<'a>>( CoreTemplatePropertyKind::Template(_) => { Err(TemplateParseError::no_such_method("Template", function)) } + CoreTemplatePropertyKind::ListTemplate(template) => { + build_list_template_method(language, build_ctx, template, function) + } } } @@ -455,6 +472,23 @@ fn build_timestamp_range_method<'a, L: TemplateLanguage<'a>>( Ok(property) } +fn build_list_template_method<'a, L: TemplateLanguage<'a>>( + language: &L, + build_ctx: &BuildContext, + self_template: Box + 'a>, + function: &FunctionCallNode, +) -> TemplateParseResult { + let property = match function.name { + "join" => { + let [separator_node] = template_parser::expect_exact_arguments(function)?; + let separator = build_expression(language, build_ctx, separator_node)?.into_template(); + language.wrap_template(self_template.join(separator)) + } + _ => return Err(TemplateParseError::no_such_method("ListTemplate", function)), + }; + Ok(property) +} + /// Builds method call expression for printable list property. pub fn build_list_method<'a, L, O>( language: &L, @@ -531,7 +565,7 @@ where item_placeholder.with_value(item, || item_template.format(context, formatter)) }, ); - Ok(language.wrap_template(Box::new(list_template))) + Ok(language.wrap_list_template(Box::new(list_template))) } fn build_global_function<'a, L: TemplateLanguage<'a>>( diff --git a/tests/test_templater.rs b/tests/test_templater.rs index 9f171379b..ae7a7b794 100644 --- a/tests/test_templater.rs +++ b/tests/test_templater.rs @@ -277,6 +277,10 @@ fn test_templater_list_method() { insta::assert_snapshot!( render(r#""a\nb\nc".lines().map(|s| "x\ny".lines().map(|t| s ++ t))"#), @"ax ay bx by cx cy"); + // Nested map/join operations + insta::assert_snapshot!( + render(r#""a\nb\nc".lines().map(|s| "x\ny".lines().map(|t| s ++ t).join(",")).join(";")"#), + @"ax,ay;bx,by;cx,cy"); // Lambda expression in alias insta::assert_snapshot!(render(r#""a\nb\nc".lines().map(identity)"#), @"a b c");