From 2fc7febaefbc441a1a930c86c4c93d271cf4eded Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Mon, 18 Mar 2024 20:52:35 +0900 Subject: [PATCH] commit_templater: teach elidable (or optional) commit I think Option is the simplest encoding of the log node. The behavior of an Option type is closer to nullable types rather than the Option in Rust. I don't think we would want to write opt.map(|x| x.f()) or opt.unwrap().f(). We can of course add opt?.f() syntax, but it will be a short for "if(opt, opt.f())"? --- cli/src/commit_templater.rs | 21 ++++++++++++++++++++- docs/templates.md | 6 ++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cli/src/commit_templater.rs b/cli/src/commit_templater.rs index 6b5d33b01..c997f08f2 100644 --- a/cli/src/commit_templater.rs +++ b/cli/src/commit_templater.rs @@ -39,7 +39,7 @@ use crate::template_builder::{ use crate::template_parser::{self, FunctionCallNode, TemplateParseError, TemplateParseResult}; use crate::templater::{ self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, - TemplatePropertyExt as _, + TemplatePropertyError, TemplatePropertyExt as _, }; use crate::{revset_util, text_util}; @@ -126,6 +126,14 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> { let build = template_parser::lookup_method("Commit", table, function)?; build(self, build_ctx, property, function) } + CommitTemplatePropertyKind::CommitOpt(property) => { + let table = &self.build_fn_table.commit_methods; + let build = template_parser::lookup_method("Commit", table, function)?; + let inner_property = property.and_then(|opt| { + opt.ok_or_else(|| TemplatePropertyError("No commit available".into())) + }); + build(self, build_ctx, Box::new(inner_property), function) + } CommitTemplatePropertyKind::CommitList(property) => { // TODO: migrate to table? template_builder::build_unformattable_list_method( @@ -190,6 +198,12 @@ impl<'repo> CommitTemplateLanguage<'repo> { CommitTemplatePropertyKind::Commit(Box::new(property)) } + pub fn wrap_commit_opt( + property: impl TemplateProperty> + 'repo, + ) -> CommitTemplatePropertyKind<'repo> { + CommitTemplatePropertyKind::CommitOpt(Box::new(property)) + } + pub fn wrap_commit_list( property: impl TemplateProperty> + 'repo, ) -> CommitTemplatePropertyKind<'repo> { @@ -224,6 +238,7 @@ impl<'repo> CommitTemplateLanguage<'repo> { pub enum CommitTemplatePropertyKind<'repo> { Core(CoreTemplatePropertyKind<'repo>), Commit(Box + 'repo>), + CommitOpt(Box> + 'repo>), CommitList(Box> + 'repo>), RefName(Box + 'repo>), RefNameList(Box> + 'repo>), @@ -236,6 +251,9 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> { match self { CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(), CommitTemplatePropertyKind::Commit(_) => None, + CommitTemplatePropertyKind::CommitOpt(property) => { + Some(Box::new(property.map(|opt| opt.is_some()))) + } CommitTemplatePropertyKind::CommitList(property) => { Some(Box::new(property.map(|l| !l.is_empty()))) } @@ -269,6 +287,7 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> { match self { CommitTemplatePropertyKind::Core(property) => property.try_into_template(), CommitTemplatePropertyKind::Commit(_) => None, + CommitTemplatePropertyKind::CommitOpt(_) => None, CommitTemplatePropertyKind::CommitList(_) => None, CommitTemplatePropertyKind::RefName(property) => Some(property.into_template()), CommitTemplatePropertyKind::RefNameList(property) => Some(property.into_template()), diff --git a/docs/templates.md b/docs/templates.md index 1ab78dccd..fe4f1db41 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -137,6 +137,12 @@ The following methods are defined. * `.short([len: Integer]) -> String` +### Option type + +An option can be implicitly converted to `Boolean` denoting whether the +contained value is set. If set, all methods of the contained value can be +invoked. If not set, an error will be reported inline on method call. + ### RefName type The following methods are defined.