diff --git a/CHANGELOG.md b/CHANGELOG.md index bdfd542d43..68ad7a3a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Graph node symbols are now configurable via templates * `templates.log_node` * `templates.op_log_node` - * `templates.log_node_elided` - * `jj log` now includes synthetic nodes in the graph where some revisions were elided. diff --git a/cli/src/commands/log.rs b/cli/src/commands/log.rs index 59d7291dcd..2d2e76f8e8 100644 --- a/cli/src/commands/log.rs +++ b/cli/src/commands/log.rs @@ -25,7 +25,6 @@ use crate::cli_util::{format_template, CommandHelper, LogContentFormat, Revision use crate::command_error::CommandError; use crate::commit_templater::CommitTemplateLanguage; use crate::diff_util::{self, DiffFormatArgs}; -use crate::generic_templater::GenericTemplateLanguage; use crate::graphlog::{get_graphlog, Edge}; use crate::templater::Template as _; use crate::ui::Ui; @@ -111,7 +110,7 @@ pub(crate) fn cmd_log( let with_content_format = LogContentFormat::new(ui, command.settings())?; let template; - let commit_node_template; + let node_template; { let language = workspace_command.commit_template_language()?; let template_string = match &args.template { @@ -123,19 +122,13 @@ pub(crate) fn cmd_log( &template_string, CommitTemplateLanguage::wrap_commit, )?; - commit_node_template = workspace_command.parse_template( + node_template = workspace_command.parse_template( &language, &command.settings().commit_node_template(), - CommitTemplateLanguage::wrap_commit, + CommitTemplateLanguage::wrap_commit_opt, )?; } - let elided_node_template = workspace_command.parse_template( - &GenericTemplateLanguage::new(), - &command.settings().elided_node_template(), - GenericTemplateLanguage::wrap_self, - )?; - { ui.request_pager(); let mut formatter = ui.stdout_formatter(); @@ -201,7 +194,7 @@ pub(crate) fn cmd_log( )?; } - let node_symbol = format_template(ui, &commit, &commit_node_template); + let node_symbol = format_template(ui, &Some(commit), &node_template); graph.add_node( &key, &graphlog_edges, @@ -218,7 +211,7 @@ pub(crate) fn cmd_log( |formatter| writeln!(formatter.labeled("elided"), "(elided revisions)"), || graph.width(&elided_key, &edges), )?; - let node_symbol = format_template(ui, &(), &elided_node_template); + let node_symbol = format_template(ui, &None, &node_template); graph.add_node( &elided_key, &edges, diff --git a/cli/src/commands/obslog.rs b/cli/src/commands/obslog.rs index 14c0cfb022..6c9beda57f 100644 --- a/cli/src/commands/obslog.rs +++ b/cli/src/commands/obslog.rs @@ -73,7 +73,7 @@ pub(crate) fn cmd_obslog( let with_content_format = LogContentFormat::new(ui, command.settings())?; let template; - let commit_node_template; + let node_template; { let language = workspace_command.commit_template_language()?; let template_string = match &args.template { @@ -85,10 +85,10 @@ pub(crate) fn cmd_obslog( &template_string, CommitTemplateLanguage::wrap_commit, )?; - commit_node_template = workspace_command.parse_template( + node_template = workspace_command.parse_template( &language, &command.settings().commit_node_template(), - CommitTemplateLanguage::wrap_commit, + CommitTemplateLanguage::wrap_commit_opt, )?; } @@ -131,7 +131,7 @@ pub(crate) fn cmd_obslog( &diff_formats, )?; } - let node_symbol = format_template(ui, &commit, &commit_node_template); + let node_symbol = format_template(ui, &Some(commit.clone()), &node_template); graph.add_node( commit.id(), &edges, diff --git a/cli/src/commit_templater.rs b/cli/src/commit_templater.rs index 6b5d33b012..c997f08f23 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/cli/tests/test_log_command.rs b/cli/tests/test_log_command.rs index d2887bbcb3..e25282d940 100644 --- a/cli/tests/test_log_command.rs +++ b/cli/tests/test_log_command.rs @@ -1433,11 +1433,12 @@ fn test_log_with_custom_symbols() { }; // Simple test with showing default and elided nodes. - test_env.add_config(concat!( - "ui.log-synthetic-elided-nodes = true\n", - "templates.log_node = 'if(current_working_copy, \"$\", if(root, \"┴\", \"┝\"))'\n", - "templates.log_node_elided = '\"🮀\"'", - )); + test_env.add_config( + r###" + ui.log-synthetic-elided-nodes = true + templates.log_node = 'if(self, if(current_working_copy, "$", if(root, "┴", "┝")), "🮀")' + "###, + ); insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r###" $ merge ├─╮ @@ -1454,12 +1455,13 @@ fn test_log_with_custom_symbols() { "###); // Simple test with showing default and elided nodes, ascii style. - test_env.add_config(concat!( - "ui.log-synthetic-elided-nodes = true\n", - "ui.graph.style = 'ascii'\n", - "templates.log_node = 'if(current_working_copy, \"$\", if(root, \"^\", \"*\"))'\n", - "templates.log_node_elided = '\":\"'", - )); + test_env.add_config( + r###" + ui.log-synthetic-elided-nodes = true + ui.graph.style = 'ascii' + templates.log_node = 'if(self, if(current_working_copy, "$", if(root, "^", "*")), ":")' + "###, + ); insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r###" $ merge |\ diff --git a/docs/config.md b/docs/config.md index ba499f5242..3ec7a5a728 100644 --- a/docs/config.md +++ b/docs/config.md @@ -234,23 +234,23 @@ ui.graph.style = "square" The symbols used to represent commits or operations can be customized via templates. - * `templates.log_node` for commits (with `Commit` keywords) + * `templates.log_node` for commits (with `Option` keywords) * `templates.op_log_node` for operations (with `Operation` keywords) - * `templates.log_node_elided` for elided nodes For example: ```toml [templates] log_node = ''' +if(self, if(current_working_copy, "@", if(root, "┴", if(immutable, "●", "○") ) - ) + ), + "🮀", +) ''' op_log_node = 'if(current_operation, "@", "○")' -log_node_elided = '"🮀"' - ``` ### Wrap log content diff --git a/docs/templates.md b/docs/templates.md index 1ab78dccda..fe4f1db41a 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. diff --git a/lib/src/settings.rs b/lib/src/settings.rs index c01d8d23da..1eb572469b 100644 --- a/lib/src/settings.rs +++ b/lib/src/settings.rs @@ -245,8 +245,8 @@ impl UserSettings { pub fn commit_node_template(&self) -> String { self.node_template_for_key( "templates.log_node", - r#"if(current_working_copy, "@", "◉")"#, - r#"if(current_working_copy, "@", "o")"#, + r#"if(self, if(current_working_copy, "@", "◉"), "◌")"#, + r#"if(self, if(current_working_copy, "@", "o"), ".")"#, ) } @@ -258,10 +258,6 @@ impl UserSettings { ) } - pub fn elided_node_template(&self) -> String { - self.node_template_for_key("templates.log_node_elided", r#""◌""#, r#"".""#) - } - pub fn max_new_file_size(&self) -> Result { let cfg = self .config