templater: merge build_*_keyword_opt() functions into method builders

template_parser::expect_no_arguments(function) is copied to each method body.
We might want to add some helper macros later.
This commit is contained in:
Yuya Nishihara 2024-02-23 12:12:30 +09:00
parent e588a9babc
commit f0ce448609
2 changed files with 127 additions and 99 deletions

View file

@ -243,20 +243,6 @@ fn build_commit_method<'repo>(
self_property: impl TemplateProperty<Commit, Output = Commit> + 'repo,
function: &FunctionCallNode,
) -> TemplateParseResult<CommitTemplatePropertyKind<'repo>> {
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<Commit, Output = Commit> + 'repo,
name: &str,
) -> Option<CommitTemplatePropertyKind<'repo>> {
fn wrap_fn<'repo, O>(
property: impl TemplateProperty<Commit, Output = Commit> + '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<String>

View file

@ -130,20 +130,6 @@ fn build_operation_method(
self_property: impl TemplateProperty<Operation, Output = Operation> + 'static,
function: &FunctionCallNode,
) -> TemplateParseResult<OperationTemplatePropertyKind> {
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<Operation, Output = Operation> + 'static,
name: &str,
) -> Option<OperationTemplatePropertyKind> {
fn wrap_fn<O>(
property: impl TemplateProperty<Operation, Output = Operation>,
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 {