diff --git a/cli/src/commit_templater.rs b/cli/src/commit_templater.rs index dbd037b51..b7e8e6af2 100644 --- a/cli/src/commit_templater.rs +++ b/cli/src/commit_templater.rs @@ -243,20 +243,6 @@ fn build_commit_method<'repo>( self_property: impl TemplateProperty + 'repo, function: &FunctionCallNode, ) -> TemplateParseResult> { - if let Some(property) = build_commit_keyword_opt(language, self_property, function.name) { - template_parser::expect_no_arguments(function)?; - Ok(property) - } else { - Err(TemplateParseError::no_such_method("Commit", function)) - } -} - -// TODO: merge into build_commit_method() -fn build_commit_keyword_opt<'repo>( - language: &CommitTemplateLanguage<'repo, '_>, - property: impl TemplateProperty + 'repo, - name: &str, -) -> Option> { fn wrap_fn<'repo, O>( property: impl TemplateProperty + 'repo, f: impl Fn(&Commit) -> O + 'repo, @@ -273,33 +259,52 @@ fn build_commit_keyword_opt<'repo>( let repo = language.repo; let cache = &language.keyword_cache; - let property = match name { - "description" => language.wrap_string(wrap_fn(property, |commit| { - text_util::complete_newline(commit.description()) - })), - "change_id" => language.wrap_commit_or_change_id(wrap_fn(property, |commit| { - CommitOrChangeId::Change(commit.change_id().to_owned()) - })), - "commit_id" => language.wrap_commit_or_change_id(wrap_fn(property, |commit| { - CommitOrChangeId::Commit(commit.id().to_owned()) - })), - "parents" => language.wrap_commit_list(wrap_fn(property, |commit| commit.parents())), - "author" => language.wrap_signature(wrap_fn(property, |commit| commit.author().clone())), + let property = match function.name { + "description" => { + template_parser::expect_no_arguments(function)?; + language.wrap_string(wrap_fn(self_property, |commit| { + text_util::complete_newline(commit.description()) + })) + } + "change_id" => { + template_parser::expect_no_arguments(function)?; + language.wrap_commit_or_change_id(wrap_fn(self_property, |commit| { + CommitOrChangeId::Change(commit.change_id().to_owned()) + })) + } + "commit_id" => { + template_parser::expect_no_arguments(function)?; + language.wrap_commit_or_change_id(wrap_fn(self_property, |commit| { + CommitOrChangeId::Commit(commit.id().to_owned()) + })) + } + "parents" => { + template_parser::expect_no_arguments(function)?; + language.wrap_commit_list(wrap_fn(self_property, |commit| commit.parents())) + } + "author" => { + template_parser::expect_no_arguments(function)?; + language.wrap_signature(wrap_fn(self_property, |commit| commit.author().clone())) + } "committer" => { - language.wrap_signature(wrap_fn(property, |commit| commit.committer().clone())) + template_parser::expect_no_arguments(function)?; + language.wrap_signature(wrap_fn(self_property, |commit| commit.committer().clone())) } "working_copies" => { - language.wrap_string(wrap_repo_fn(repo, property, extract_working_copies)) + template_parser::expect_no_arguments(function)?; + language.wrap_string(wrap_repo_fn(repo, self_property, extract_working_copies)) } "current_working_copy" => { + template_parser::expect_no_arguments(function)?; let workspace_id = language.workspace_id.clone(); - language.wrap_boolean(wrap_fn(property, move |commit| { + language.wrap_boolean(wrap_fn(self_property, move |commit| { Some(commit.id()) == repo.view().get_wc_commit_id(&workspace_id) })) } "branches" => { + template_parser::expect_no_arguments(function)?; let index = cache.branches_index(repo).clone(); - language.wrap_ref_name_list(wrap_fn(property, move |commit| { + language.wrap_ref_name_list(wrap_fn(self_property, move |commit| { index .get(commit.id()) .iter() @@ -309,8 +314,9 @@ fn build_commit_keyword_opt<'repo>( })) } "local_branches" => { + template_parser::expect_no_arguments(function)?; let index = cache.branches_index(repo).clone(); - language.wrap_ref_name_list(wrap_fn(property, move |commit| { + language.wrap_ref_name_list(wrap_fn(self_property, move |commit| { index .get(commit.id()) .iter() @@ -320,8 +326,9 @@ fn build_commit_keyword_opt<'repo>( })) } "remote_branches" => { + template_parser::expect_no_arguments(function)?; let index = cache.branches_index(repo).clone(); - language.wrap_ref_name_list(wrap_fn(property, move |commit| { + language.wrap_ref_name_list(wrap_fn(self_property, move |commit| { index .get(commit.id()) .iter() @@ -331,43 +338,61 @@ fn build_commit_keyword_opt<'repo>( })) } "tags" => { + template_parser::expect_no_arguments(function)?; let index = cache.tags_index(repo).clone(); - language.wrap_ref_name_list(wrap_fn(property, move |commit| { + language.wrap_ref_name_list(wrap_fn(self_property, move |commit| { index.get(commit.id()).to_vec() })) } "git_refs" => { + template_parser::expect_no_arguments(function)?; let index = cache.git_refs_index(repo).clone(); - language.wrap_ref_name_list(wrap_fn(property, move |commit| { + language.wrap_ref_name_list(wrap_fn(self_property, move |commit| { index.get(commit.id()).to_vec() })) } - "git_head" => language.wrap_ref_name_list(wrap_repo_fn(repo, property, extract_git_head)), - "divergent" => language.wrap_boolean(wrap_fn(property, |commit| { - // The given commit could be hidden in e.g. obslog. - let maybe_entries = repo.resolve_change_id(commit.change_id()); - maybe_entries.map_or(0, |entries| entries.len()) > 1 - })), - "hidden" => language.wrap_boolean(wrap_fn(property, |commit| { - let maybe_entries = repo.resolve_change_id(commit.change_id()); - maybe_entries.map_or(true, |entries| !entries.contains(commit.id())) - })), - "conflict" => { - language.wrap_boolean(wrap_fn(property, |commit| commit.has_conflict().unwrap())) + "git_head" => { + template_parser::expect_no_arguments(function)?; + language.wrap_ref_name_list(wrap_repo_fn(repo, self_property, extract_git_head)) } - "empty" => language.wrap_boolean(wrap_fn(property, |commit| { - if let [parent] = &commit.parents()[..] { - return parent.tree_id() == commit.tree_id(); - } - let parent_tree = rewrite::merge_commit_trees(repo, &commit.parents()).unwrap(); - *commit.tree_id() == parent_tree.id() - })), - "root" => language.wrap_boolean(wrap_fn(property, move |commit| { - commit.id() == repo.store().root_commit_id() - })), - _ => return None, + "divergent" => { + template_parser::expect_no_arguments(function)?; + language.wrap_boolean(wrap_fn(self_property, |commit| { + // The given commit could be hidden in e.g. obslog. + let maybe_entries = repo.resolve_change_id(commit.change_id()); + maybe_entries.map_or(0, |entries| entries.len()) > 1 + })) + } + "hidden" => { + template_parser::expect_no_arguments(function)?; + language.wrap_boolean(wrap_fn(self_property, |commit| { + let maybe_entries = repo.resolve_change_id(commit.change_id()); + maybe_entries.map_or(true, |entries| !entries.contains(commit.id())) + })) + } + "conflict" => { + template_parser::expect_no_arguments(function)?; + language.wrap_boolean(wrap_fn(self_property, |commit| commit.has_conflict().unwrap())) + } + "empty" => { + template_parser::expect_no_arguments(function)?; + language.wrap_boolean(wrap_fn(self_property, |commit| { + if let [parent] = &commit.parents()[..] { + return parent.tree_id() == commit.tree_id(); + } + let parent_tree = rewrite::merge_commit_trees(repo, &commit.parents()).unwrap(); + *commit.tree_id() == parent_tree.id() + })) + } + "root" => { + template_parser::expect_no_arguments(function)?; + language.wrap_boolean(wrap_fn(self_property, move |commit| { + commit.id() == repo.store().root_commit_id() + })) + } + _ => return Err(TemplateParseError::no_such_method("Commit", function)), }; - Some(property) + Ok(property) } // TODO: return Vec diff --git a/cli/src/operation_templater.rs b/cli/src/operation_templater.rs index 32e8f2a64..622e533cc 100644 --- a/cli/src/operation_templater.rs +++ b/cli/src/operation_templater.rs @@ -130,20 +130,6 @@ fn build_operation_method( self_property: impl TemplateProperty + 'static, function: &FunctionCallNode, ) -> TemplateParseResult { - if let Some(property) = build_operation_keyword_opt(language, self_property, function.name) { - template_parser::expect_no_arguments(function)?; - Ok(property) - } else { - Err(TemplateParseError::no_such_method("Operation", function)) - } -} - -// TODO: merge into build_operation_method() -fn build_operation_keyword_opt( - language: &OperationTemplateLanguage, - property: impl TemplateProperty + 'static, - name: &str, -) -> Option { fn wrap_fn( property: impl TemplateProperty, f: impl Fn(&Operation) -> O, @@ -157,42 +143,59 @@ fn build_operation_keyword_opt( TemplateFunction::new(property, move |op| f(op.metadata())) } - let property = match name { + let property = match function.name { "current_operation" => { + template_parser::expect_no_arguments(function)?; let current_op_id = language.current_op_id.cloned(); - language.wrap_boolean(wrap_fn(property, move |op| { + language.wrap_boolean(wrap_fn(self_property, move |op| { Some(op.id()) == current_op_id.as_ref() })) } - "description" => language.wrap_string(wrap_metadata_fn(property, |metadata| { - metadata.description.clone() - })), - "id" => language.wrap_operation_id(wrap_fn(property, |op| op.id().clone())), - "tags" => language.wrap_string(wrap_metadata_fn(property, |metadata| { - // TODO: introduce map type - metadata - .tags - .iter() - .map(|(key, value)| format!("{key}: {value}")) - .join("\n") - })), - "time" => { - language.wrap_timestamp_range(wrap_metadata_fn(property, |metadata| TimestampRange { - start: metadata.start_time.clone(), - end: metadata.end_time.clone(), + "description" => { + template_parser::expect_no_arguments(function)?; + language.wrap_string(wrap_metadata_fn(self_property, |metadata| { + metadata.description.clone() })) } - "user" => language.wrap_string(wrap_metadata_fn(property, |metadata| { - // TODO: introduce dedicated type and provide accessors? - format!("{}@{}", metadata.username, metadata.hostname) - })), - "root" => { - let root_op_id = language.root_op_id.clone(); - language.wrap_boolean(wrap_fn(property, move |op| op.id() == &root_op_id)) + "id" => { + template_parser::expect_no_arguments(function)?; + language.wrap_operation_id(wrap_fn(self_property, |op| op.id().clone())) } - _ => return None, + "tags" => { + template_parser::expect_no_arguments(function)?; + language.wrap_string(wrap_metadata_fn(self_property, |metadata| { + // TODO: introduce map type + metadata + .tags + .iter() + .map(|(key, value)| format!("{key}: {value}")) + .join("\n") + })) + } + "time" => { + template_parser::expect_no_arguments(function)?; + language.wrap_timestamp_range(wrap_metadata_fn(self_property, |metadata| { + TimestampRange { + start: metadata.start_time.clone(), + end: metadata.end_time.clone(), + } + })) + } + "user" => { + template_parser::expect_no_arguments(function)?; + language.wrap_string(wrap_metadata_fn(self_property, |metadata| { + // TODO: introduce dedicated type and provide accessors? + format!("{}@{}", metadata.username, metadata.hostname) + })) + } + "root" => { + template_parser::expect_no_arguments(function)?; + let root_op_id = language.root_op_id.clone(); + language.wrap_boolean(wrap_fn(self_property, move |op| op.id() == &root_op_id)) + } + _ => return Err(TemplateParseError::no_such_method("Operation", function)), }; - Some(property) + Ok(property) } impl Template<()> for OperationId {