forked from mirrors/jj
templater: pass diagnostics receiver around
This commit is contained in:
parent
8b1760ca5d
commit
11286b3072
8 changed files with 752 additions and 431 deletions
|
@ -122,7 +122,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
|
|||
let mut table = CommitTemplateBuildFnTable::empty();
|
||||
table.commit_methods.insert(
|
||||
"has_most_digits",
|
||||
|language, _build_context, property, call| {
|
||||
|language, _diagnostics, _build_context, property, call| {
|
||||
call.expect_no_arguments()?;
|
||||
let most_digits = language
|
||||
.cache_extension::<MostDigitsInId>()
|
||||
|
@ -135,7 +135,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
|
|||
);
|
||||
table.commit_methods.insert(
|
||||
"num_digits_in_id",
|
||||
|_language, _build_context, property, call| {
|
||||
|_language, _diagnostics, _build_context, property, call| {
|
||||
call.expect_no_arguments()?;
|
||||
Ok(L::wrap_integer(
|
||||
property.map(|commit| num_digits_in_id(commit.id())),
|
||||
|
@ -144,7 +144,7 @@ impl CommitTemplateLanguageExtension for HexCounter {
|
|||
);
|
||||
table.commit_methods.insert(
|
||||
"num_char_in_id",
|
||||
|_language, _build_context, property, call| {
|
||||
|_language, _diagnostics, _build_context, property, call| {
|
||||
let [string_arg] = call.expect_exact_arguments()?;
|
||||
let char_arg =
|
||||
template_parser::expect_string_literal_with(string_arg, |string, span| {
|
||||
|
|
|
@ -53,7 +53,7 @@ impl OperationTemplateLanguageExtension for HexCounter {
|
|||
let mut table = OperationTemplateBuildFnTable::empty();
|
||||
table.operation_methods.insert(
|
||||
"num_digits_in_id",
|
||||
|_language, _build_context, property, call| {
|
||||
|_language, _diagnostics, _build_context, property, call| {
|
||||
call.expect_no_arguments()?;
|
||||
Ok(L::wrap_integer(
|
||||
property.map(|operation| num_digits_in_id(operation.id())),
|
||||
|
@ -62,7 +62,7 @@ impl OperationTemplateLanguageExtension for HexCounter {
|
|||
);
|
||||
table.operation_methods.insert(
|
||||
"num_char_in_id",
|
||||
|_language, _build_context, property, call| {
|
||||
|_language, _diagnostics, _build_context, property, call| {
|
||||
let [string_arg] = call.expect_exact_arguments()?;
|
||||
let char_arg =
|
||||
template_parser::expect_string_literal_with(string_arg, |string, span| {
|
||||
|
|
|
@ -166,7 +166,7 @@ use crate::revset_util::RevsetExpressionEvaluator;
|
|||
use crate::template_builder;
|
||||
use crate::template_builder::TemplateLanguage;
|
||||
use crate::template_parser::TemplateAliasesMap;
|
||||
use crate::template_parser::TemplateParseResult;
|
||||
use crate::template_parser::TemplateDiagnostics;
|
||||
use crate::templater::PropertyPlaceholder;
|
||||
use crate::templater::TemplateRenderer;
|
||||
use crate::text_util;
|
||||
|
@ -343,13 +343,17 @@ impl CommandHelper {
|
|||
template_text: &str,
|
||||
wrap_self: impl Fn(PropertyPlaceholder<C>) -> L::Property,
|
||||
) -> Result<TemplateRenderer<'a, C>, CommandError> {
|
||||
let mut diagnostics = TemplateDiagnostics::new();
|
||||
let aliases = self.load_template_aliases(ui)?;
|
||||
Ok(template_builder::parse(
|
||||
let template = template_builder::parse(
|
||||
language,
|
||||
&mut diagnostics,
|
||||
template_text,
|
||||
&aliases,
|
||||
wrap_self,
|
||||
)?)
|
||||
)?;
|
||||
print_parse_diagnostics(ui, "In template expression", &diagnostics)?;
|
||||
Ok(template)
|
||||
}
|
||||
|
||||
pub fn workspace_loader(&self) -> Result<&dyn WorkspaceLoader, CommandError> {
|
||||
|
@ -780,13 +784,21 @@ impl WorkspaceCommandEnvironment {
|
|||
/// be one of the `L::wrap_*()` functions.
|
||||
pub fn parse_template<'a, C: Clone + 'a, L: TemplateLanguage<'a> + ?Sized>(
|
||||
&self,
|
||||
_ui: &Ui,
|
||||
ui: &Ui,
|
||||
language: &L,
|
||||
template_text: &str,
|
||||
wrap_self: impl Fn(PropertyPlaceholder<C>) -> L::Property,
|
||||
) -> TemplateParseResult<TemplateRenderer<'a, C>> {
|
||||
let aliases = &self.template_aliases_map;
|
||||
template_builder::parse(language, template_text, aliases, wrap_self)
|
||||
) -> Result<TemplateRenderer<'a, C>, CommandError> {
|
||||
let mut diagnostics = TemplateDiagnostics::new();
|
||||
let template = template_builder::parse(
|
||||
language,
|
||||
&mut diagnostics,
|
||||
template_text,
|
||||
&self.template_aliases_map,
|
||||
wrap_self,
|
||||
)?;
|
||||
print_parse_diagnostics(ui, "In template expression", &diagnostics)?;
|
||||
Ok(template)
|
||||
}
|
||||
|
||||
/// Creates commit template language environment for this workspace and the
|
||||
|
@ -1392,7 +1404,7 @@ impl WorkspaceCommandHelper {
|
|||
language: &L,
|
||||
template_text: &str,
|
||||
wrap_self: impl Fn(PropertyPlaceholder<C>) -> L::Property,
|
||||
) -> TemplateParseResult<TemplateRenderer<'a, C>> {
|
||||
) -> Result<TemplateRenderer<'a, C>, CommandError> {
|
||||
self.env
|
||||
.parse_template(ui, language, template_text, wrap_self)
|
||||
}
|
||||
|
@ -1404,9 +1416,14 @@ impl WorkspaceCommandHelper {
|
|||
template_text: &str,
|
||||
wrap_self: impl Fn(PropertyPlaceholder<C>) -> L::Property,
|
||||
) -> TemplateRenderer<'a, C> {
|
||||
let aliases = &self.env.template_aliases_map;
|
||||
template_builder::parse(language, template_text, aliases, wrap_self)
|
||||
.expect("parse error should be confined by WorkspaceCommandHelper::new()")
|
||||
template_builder::parse(
|
||||
language,
|
||||
&mut TemplateDiagnostics::new(),
|
||||
template_text,
|
||||
&self.env.template_aliases_map,
|
||||
wrap_self,
|
||||
)
|
||||
.expect("parse error should be confined by WorkspaceCommandHelper::new()")
|
||||
}
|
||||
|
||||
/// Parses commit template into evaluation tree.
|
||||
|
@ -1414,7 +1431,7 @@ impl WorkspaceCommandHelper {
|
|||
&self,
|
||||
ui: &Ui,
|
||||
template_text: &str,
|
||||
) -> TemplateParseResult<TemplateRenderer<'_, Commit>> {
|
||||
) -> Result<TemplateRenderer<'_, Commit>, CommandError> {
|
||||
let language = self.commit_template_language();
|
||||
self.parse_template(
|
||||
ui,
|
||||
|
@ -1429,7 +1446,7 @@ impl WorkspaceCommandHelper {
|
|||
&self,
|
||||
ui: &Ui,
|
||||
template_text: &str,
|
||||
) -> TemplateParseResult<TemplateRenderer<'_, Operation>> {
|
||||
) -> Result<TemplateRenderer<'_, Operation>, CommandError> {
|
||||
let language = self.operation_template_language();
|
||||
self.parse_template(
|
||||
ui,
|
||||
|
@ -2056,7 +2073,7 @@ impl WorkspaceCommandTransaction<'_> {
|
|||
&self,
|
||||
ui: &Ui,
|
||||
template_text: &str,
|
||||
) -> TemplateParseResult<TemplateRenderer<'_, Commit>> {
|
||||
) -> Result<TemplateRenderer<'_, Commit>, CommandError> {
|
||||
let language = self.commit_template_language();
|
||||
self.helper.env.parse_template(
|
||||
ui,
|
||||
|
|
|
@ -64,6 +64,7 @@ use crate::template_builder::TemplateLanguage;
|
|||
use crate::template_parser;
|
||||
use crate::template_parser::ExpressionNode;
|
||||
use crate::template_parser::FunctionCallNode;
|
||||
use crate::template_parser::TemplateDiagnostics;
|
||||
use crate::template_parser::TemplateParseError;
|
||||
use crate::template_parser::TemplateParseResult;
|
||||
use crate::templater;
|
||||
|
@ -142,15 +143,17 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
|
|||
|
||||
fn build_function(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<Self::Property> {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_function(self, build_ctx, function)
|
||||
table.build_function(self, diagnostics, build_ctx, function)
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
property: Self::Property,
|
||||
function: &FunctionCallNode,
|
||||
|
@ -159,24 +162,31 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
|
|||
match property {
|
||||
CommitTemplatePropertyKind::Core(property) => {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_method(self, build_ctx, property, function)
|
||||
table.build_method(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::Commit(property) => {
|
||||
let table = &self.build_fn_table.commit_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::CommitOpt(property) => {
|
||||
let type_name = "Commit";
|
||||
let table = &self.build_fn_table.commit_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
let inner_property = property.try_unwrap(type_name);
|
||||
build(self, build_ctx, Box::new(inner_property), function)
|
||||
build(
|
||||
self,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
Box::new(inner_property),
|
||||
function,
|
||||
)
|
||||
}
|
||||
CommitTemplatePropertyKind::CommitList(property) => {
|
||||
// TODO: migrate to table?
|
||||
template_builder::build_unformattable_list_method(
|
||||
self,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
property,
|
||||
function,
|
||||
|
@ -186,19 +196,26 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
|
|||
CommitTemplatePropertyKind::RefName(property) => {
|
||||
let table = &self.build_fn_table.ref_name_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::RefNameOpt(property) => {
|
||||
let type_name = "RefName";
|
||||
let table = &self.build_fn_table.ref_name_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
let inner_property = property.try_unwrap(type_name);
|
||||
build(self, build_ctx, Box::new(inner_property), function)
|
||||
build(
|
||||
self,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
Box::new(inner_property),
|
||||
function,
|
||||
)
|
||||
}
|
||||
CommitTemplatePropertyKind::RefNameList(property) => {
|
||||
// TODO: migrate to table?
|
||||
template_builder::build_formattable_list_method(
|
||||
self,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
property,
|
||||
function,
|
||||
|
@ -208,17 +225,17 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
|
|||
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
||||
let table = &self.build_fn_table.commit_or_change_id_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
||||
let table = &self.build_fn_table.shortest_id_prefix_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::TreeDiff(property) => {
|
||||
let table = &self.build_fn_table.tree_diff_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -500,7 +517,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
let mut map = CommitTemplateBuildMethodFnMap::<Commit>::new();
|
||||
map.insert(
|
||||
"description",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property =
|
||||
self_property.map(|commit| text_util::complete_newline(commit.description()));
|
||||
|
@ -509,7 +526,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"change_id",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property =
|
||||
self_property.map(|commit| CommitOrChangeId::Change(commit.change_id().to_owned()));
|
||||
|
@ -518,7 +535,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"commit_id",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property =
|
||||
self_property.map(|commit| CommitOrChangeId::Commit(commit.id().to_owned()));
|
||||
|
@ -527,7 +544,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"parents",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property =
|
||||
self_property.and_then(|commit| Ok(commit.parents().try_collect()?));
|
||||
|
@ -536,7 +553,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"author",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|commit| commit.author().clone());
|
||||
Ok(L::wrap_signature(out_property))
|
||||
|
@ -544,21 +561,24 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"committer",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|commit| commit.committer().clone());
|
||||
Ok(L::wrap_signature(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("mine", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let user_email = language.revset_parse_context.user_email().to_owned();
|
||||
let out_property = self_property.map(move |commit| commit.author().email == user_email);
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"mine",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let user_email = language.revset_parse_context.user_email().to_owned();
|
||||
let out_property = self_property.map(move |commit| commit.author().email == user_email);
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"working_copies",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| extract_working_copies(repo, &commit));
|
||||
|
@ -567,7 +587,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"current_working_copy",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let workspace_id = language.workspace_id.clone();
|
||||
|
@ -579,7 +599,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"bookmarks",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language
|
||||
.keyword_cache
|
||||
|
@ -598,7 +618,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"local_bookmarks",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language
|
||||
.keyword_cache
|
||||
|
@ -617,7 +637,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"remote_bookmarks",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language
|
||||
.keyword_cache
|
||||
|
@ -639,15 +659,18 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
map.insert("local_branches", map["local_bookmarks"]);
|
||||
map.insert("remote_branches", map["remote_bookmarks"]);
|
||||
|
||||
map.insert("tags", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language.keyword_cache.tags_index(language.repo).clone();
|
||||
let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec());
|
||||
Ok(L::wrap_ref_name_list(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"tags",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language.keyword_cache.tags_index(language.repo).clone();
|
||||
let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec());
|
||||
Ok(L::wrap_ref_name_list(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"git_refs",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let index = language.keyword_cache.git_refs_index(language.repo).clone();
|
||||
let out_property = self_property.map(move |commit| index.get(commit.id()).to_vec());
|
||||
|
@ -656,7 +679,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"git_head",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| extract_git_head(repo, &commit));
|
||||
|
@ -665,7 +688,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"divergent",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| {
|
||||
|
@ -676,18 +699,21 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("hidden", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| {
|
||||
let maybe_entries = repo.resolve_change_id(commit.change_id());
|
||||
maybe_entries.map_or(true, |entries| !entries.contains(commit.id()))
|
||||
});
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"hidden",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| {
|
||||
let maybe_entries = repo.resolve_change_id(commit.change_id());
|
||||
maybe_entries.map_or(true, |entries| !entries.contains(commit.id()))
|
||||
});
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"immutable",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let is_immutable = language
|
||||
.keyword_cache
|
||||
|
@ -699,12 +725,12 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"contained_in",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, diagnostics, _build_ctx, self_property, function| {
|
||||
let [revset_node] = function.expect_exact_arguments()?;
|
||||
|
||||
let is_contained =
|
||||
template_parser::expect_string_literal_with(revset_node, |revset, span| {
|
||||
Ok(evaluate_user_revset(language, span, revset)?.containing_fn())
|
||||
Ok(evaluate_user_revset(language, diagnostics, span, revset)?.containing_fn())
|
||||
})?;
|
||||
|
||||
let out_property = self_property.map(move |commit| is_contained(commit.id()));
|
||||
|
@ -713,39 +739,49 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
|
|||
);
|
||||
map.insert(
|
||||
"conflict",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.and_then(|commit| Ok(commit.has_conflict()?));
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("empty", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.and_then(|commit| Ok(commit.is_empty(repo)?));
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
});
|
||||
map.insert("diff", |language, _build_ctx, self_property, function| {
|
||||
let ([], [files_node]) = function.expect_arguments()?;
|
||||
let files = if let Some(node) = files_node {
|
||||
expect_fileset_literal(node, language.path_converter)?
|
||||
} else {
|
||||
// TODO: defaults to CLI path arguments?
|
||||
// https://github.com/martinvonz/jj/issues/2933#issuecomment-1925870731
|
||||
FilesetExpression::all()
|
||||
};
|
||||
let repo = language.repo;
|
||||
let matcher: Rc<dyn Matcher> = files.to_matcher().into();
|
||||
let out_property = self_property
|
||||
.and_then(move |commit| Ok(TreeDiff::from_commit(repo, &commit, matcher.clone())?));
|
||||
Ok(L::wrap_tree_diff(out_property))
|
||||
});
|
||||
map.insert("root", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.map(|commit| commit.id() == repo.store().root_commit_id());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"empty",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.and_then(|commit| Ok(commit.is_empty(repo)?));
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"diff",
|
||||
|language, diagnostics, _build_ctx, self_property, function| {
|
||||
let ([], [files_node]) = function.expect_arguments()?;
|
||||
let files = if let Some(node) = files_node {
|
||||
expect_fileset_literal(diagnostics, node, language.path_converter)?
|
||||
} else {
|
||||
// TODO: defaults to CLI path arguments?
|
||||
// https://github.com/martinvonz/jj/issues/2933#issuecomment-1925870731
|
||||
FilesetExpression::all()
|
||||
};
|
||||
let repo = language.repo;
|
||||
let matcher: Rc<dyn Matcher> = files.to_matcher().into();
|
||||
let out_property = self_property
|
||||
.and_then(move |commit| Ok(TreeDiff::from_commit(repo, &commit, matcher.clone())?));
|
||||
Ok(L::wrap_tree_diff(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"root",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property =
|
||||
self_property.map(|commit| commit.id() == repo.store().root_commit_id());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map
|
||||
}
|
||||
|
||||
|
@ -765,14 +801,20 @@ fn extract_working_copies(repo: &dyn Repo, commit: &Commit) -> String {
|
|||
}
|
||||
|
||||
fn expect_fileset_literal(
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
node: &ExpressionNode,
|
||||
path_converter: &RepoPathUiConverter,
|
||||
) -> Result<FilesetExpression, TemplateParseError> {
|
||||
template_parser::expect_string_literal_with(node, |text, span| {
|
||||
let mut inner_diagnostics = FilesetDiagnostics::new(); // TODO
|
||||
fileset::parse(&mut inner_diagnostics, text, path_converter).map_err(|err| {
|
||||
TemplateParseError::expression("In fileset expression", span).with_source(err)
|
||||
})
|
||||
let mut inner_diagnostics = FilesetDiagnostics::new();
|
||||
let expression =
|
||||
fileset::parse(&mut inner_diagnostics, text, path_converter).map_err(|err| {
|
||||
TemplateParseError::expression("In fileset expression", span).with_source(err)
|
||||
})?;
|
||||
diagnostics.extend_with(inner_diagnostics, |diag| {
|
||||
TemplateParseError::expression("In fileset expression", span).with_source(diag)
|
||||
});
|
||||
Ok(expression)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -797,16 +839,20 @@ fn evaluate_revset_expression<'repo>(
|
|||
|
||||
fn evaluate_user_revset<'repo>(
|
||||
language: &CommitTemplateLanguage<'repo>,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
span: pest::Span<'_>,
|
||||
revset: &str,
|
||||
) -> Result<Box<dyn Revset + 'repo>, TemplateParseError> {
|
||||
let mut inner_diagnostics = RevsetDiagnostics::new(); // TODO
|
||||
let mut inner_diagnostics = RevsetDiagnostics::new();
|
||||
let (expression, modifier) = revset::parse_with_modifier(
|
||||
&mut inner_diagnostics,
|
||||
revset,
|
||||
&language.revset_parse_context,
|
||||
)
|
||||
.map_err(|err| TemplateParseError::expression("In revset expression", span).with_source(err))?;
|
||||
diagnostics.extend_with(inner_diagnostics, |diag| {
|
||||
TemplateParseError::expression("In revset expression", span).with_source(diag)
|
||||
});
|
||||
let (None | Some(RevsetModifier::All)) = modifier;
|
||||
|
||||
evaluate_revset_expression(language, span, expression)
|
||||
|
@ -1003,14 +1049,17 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
// Not using maplit::hashmap!{} or custom declarative macro here because
|
||||
// code completion inside macro is quite restricted.
|
||||
let mut map = CommitTemplateBuildMethodFnMap::<Rc<RefName>>::new();
|
||||
map.insert("name", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.name.clone());
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"name",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.name.clone());
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"remote",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property =
|
||||
self_property.map(|ref_name| ref_name.remote.clone().unwrap_or_default());
|
||||
|
@ -1019,7 +1068,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"present",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.is_present());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
|
@ -1027,7 +1076,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"conflict",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.has_conflict());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
|
@ -1035,7 +1084,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"normal_target",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.and_then(|ref_name| {
|
||||
|
@ -1047,7 +1096,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"removed_targets",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.and_then(|ref_name| {
|
||||
|
@ -1059,7 +1108,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"added_targets",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property = self_property.and_then(|ref_name| {
|
||||
|
@ -1071,7 +1120,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"tracked",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.is_tracked());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
|
@ -1079,7 +1128,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"tracking_present",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|ref_name| ref_name.is_tracking_present());
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
|
@ -1087,7 +1136,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"tracking_ahead_count",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property =
|
||||
|
@ -1097,7 +1146,7 @@ fn builtin_ref_name_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Rc
|
|||
);
|
||||
map.insert(
|
||||
"tracking_behind_count",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let repo = language.repo;
|
||||
let out_property =
|
||||
|
@ -1225,7 +1274,7 @@ fn builtin_commit_or_change_id_methods<'repo>(
|
|||
let mut map = CommitTemplateBuildMethodFnMap::<CommitOrChangeId>::new();
|
||||
map.insert(
|
||||
"normal_hex",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
Ok(L::wrap_string(self_property.map(|id| {
|
||||
// Note: this is _not_ the same as id.hex() for ChangeId, which
|
||||
|
@ -1238,22 +1287,39 @@ fn builtin_commit_or_change_id_methods<'repo>(
|
|||
})))
|
||||
},
|
||||
);
|
||||
map.insert("short", |language, build_ctx, self_property, function| {
|
||||
let ([], [len_node]) = function.expect_arguments()?;
|
||||
let len_property = len_node
|
||||
.map(|node| template_builder::expect_usize_expression(language, build_ctx, node))
|
||||
.transpose()?;
|
||||
let out_property =
|
||||
(self_property, len_property).map(|(id, len)| id.short(len.unwrap_or(12)));
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"short",
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let ([], [len_node]) = function.expect_arguments()?;
|
||||
let len_property = len_node
|
||||
.map(|node| {
|
||||
template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
node,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
let out_property =
|
||||
(self_property, len_property).map(|(id, len)| id.short(len.unwrap_or(12)));
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"shortest",
|
||||
|language, build_ctx, self_property, function| {
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let id_prefix_context = &language.id_prefix_context;
|
||||
let ([], [len_node]) = function.expect_arguments()?;
|
||||
let len_property = len_node
|
||||
.map(|node| template_builder::expect_usize_expression(language, build_ctx, node))
|
||||
.map(|node| {
|
||||
template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
node,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
let out_property = (self_property, len_property)
|
||||
.map(|(id, len)| id.shortest(language.repo, id_prefix_context, len.unwrap_or(0)));
|
||||
|
@ -1299,27 +1365,36 @@ fn builtin_shortest_id_prefix_methods<'repo>(
|
|||
let mut map = CommitTemplateBuildMethodFnMap::<ShortestIdPrefix>::new();
|
||||
map.insert(
|
||||
"prefix",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.prefix);
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("rest", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.rest);
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert("upper", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.to_upper());
|
||||
Ok(L::wrap_shortest_id_prefix(out_property))
|
||||
});
|
||||
map.insert("lower", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.to_lower());
|
||||
Ok(L::wrap_shortest_id_prefix(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"rest",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.rest);
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"upper",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.to_upper());
|
||||
Ok(L::wrap_shortest_id_prefix(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"lower",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|id| id.to_lower());
|
||||
Ok(L::wrap_shortest_id_prefix(out_property))
|
||||
},
|
||||
);
|
||||
map
|
||||
}
|
||||
|
||||
|
@ -1392,10 +1467,17 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
|
|||
let mut map = CommitTemplateBuildMethodFnMap::<TreeDiff>::new();
|
||||
map.insert(
|
||||
"color_words",
|
||||
|language, build_ctx, self_property, function| {
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let ([], [context_node]) = function.expect_arguments()?;
|
||||
let context_property = context_node
|
||||
.map(|node| template_builder::expect_usize_expression(language, build_ctx, node))
|
||||
.map(|node| {
|
||||
template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
node,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
let path_converter = language.path_converter;
|
||||
let template = (self_property, context_property)
|
||||
|
@ -1419,38 +1501,61 @@ fn builtin_tree_diff_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, T
|
|||
Ok(L::wrap_template(template))
|
||||
},
|
||||
);
|
||||
map.insert("git", |language, build_ctx, self_property, function| {
|
||||
let ([], [context_node]) = function.expect_arguments()?;
|
||||
let context_property = context_node
|
||||
.map(|node| template_builder::expect_usize_expression(language, build_ctx, node))
|
||||
.transpose()?;
|
||||
let template = (self_property, context_property)
|
||||
.map(|(diff, context)| {
|
||||
let context = context.unwrap_or(diff_util::DEFAULT_CONTEXT_LINES);
|
||||
diff.into_formatted(move |formatter, store, tree_diff| {
|
||||
diff_util::show_git_diff(formatter, store, tree_diff, context)
|
||||
map.insert(
|
||||
"git",
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let ([], [context_node]) = function.expect_arguments()?;
|
||||
let context_property = context_node
|
||||
.map(|node| {
|
||||
template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
node,
|
||||
)
|
||||
})
|
||||
})
|
||||
.into_template();
|
||||
Ok(L::wrap_template(template))
|
||||
});
|
||||
map.insert("stat", |language, build_ctx, self_property, function| {
|
||||
let [width_node] = function.expect_exact_arguments()?;
|
||||
let width_property =
|
||||
template_builder::expect_usize_expression(language, build_ctx, width_node)?;
|
||||
let path_converter = language.path_converter;
|
||||
let template = (self_property, width_property)
|
||||
.map(move |(diff, width)| {
|
||||
diff.into_formatted(move |formatter, store, tree_diff| {
|
||||
diff_util::show_diff_stat(formatter, store, tree_diff, path_converter, width)
|
||||
.transpose()?;
|
||||
let template = (self_property, context_property)
|
||||
.map(|(diff, context)| {
|
||||
let context = context.unwrap_or(diff_util::DEFAULT_CONTEXT_LINES);
|
||||
diff.into_formatted(move |formatter, store, tree_diff| {
|
||||
diff_util::show_git_diff(formatter, store, tree_diff, context)
|
||||
})
|
||||
})
|
||||
})
|
||||
.into_template();
|
||||
Ok(L::wrap_template(template))
|
||||
});
|
||||
.into_template();
|
||||
Ok(L::wrap_template(template))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"stat",
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let [width_node] = function.expect_exact_arguments()?;
|
||||
let width_property = template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
width_node,
|
||||
)?;
|
||||
let path_converter = language.path_converter;
|
||||
let template = (self_property, width_property)
|
||||
.map(move |(diff, width)| {
|
||||
diff.into_formatted(move |formatter, store, tree_diff| {
|
||||
diff_util::show_diff_stat(
|
||||
formatter,
|
||||
store,
|
||||
tree_diff,
|
||||
path_converter,
|
||||
width,
|
||||
)
|
||||
})
|
||||
})
|
||||
.into_template();
|
||||
Ok(L::wrap_template(template))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"summary",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let path_converter = language.path_converter;
|
||||
let template = self_property
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::template_builder::IntoTemplateProperty;
|
|||
use crate::template_builder::TemplateLanguage;
|
||||
use crate::template_parser;
|
||||
use crate::template_parser::FunctionCallNode;
|
||||
use crate::template_parser::TemplateDiagnostics;
|
||||
use crate::template_parser::TemplateParseResult;
|
||||
use crate::templater::Template;
|
||||
use crate::templater::TemplateProperty;
|
||||
|
@ -86,15 +87,17 @@ impl<'a, C: 'a> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
|
|||
|
||||
fn build_function(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<Self::Property> {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_function(self, build_ctx, function)
|
||||
table.build_function(self, diagnostics, build_ctx, function)
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
property: Self::Property,
|
||||
function: &FunctionCallNode,
|
||||
|
@ -103,7 +106,7 @@ impl<'a, C: 'a> TemplateLanguage<'a> for GenericTemplateLanguage<'a, C> {
|
|||
match property {
|
||||
GenericTemplatePropertyKind::Core(property) => {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_method(self, build_ctx, property, function)
|
||||
table.build_method(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
GenericTemplatePropertyKind::Self_(property) => {
|
||||
let table = &self.build_fn_table.keywords;
|
||||
|
|
|
@ -32,6 +32,7 @@ use crate::template_builder::TemplateBuildMethodFnMap;
|
|||
use crate::template_builder::TemplateLanguage;
|
||||
use crate::template_parser;
|
||||
use crate::template_parser::FunctionCallNode;
|
||||
use crate::template_parser::TemplateDiagnostics;
|
||||
use crate::template_parser::TemplateParseResult;
|
||||
use crate::templater::PlainTextFormattedProperty;
|
||||
use crate::templater::Template;
|
||||
|
@ -87,15 +88,17 @@ impl TemplateLanguage<'static> for OperationTemplateLanguage {
|
|||
|
||||
fn build_function(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<Self::Property> {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_function(self, build_ctx, function)
|
||||
table.build_function(self, diagnostics, build_ctx, function)
|
||||
}
|
||||
|
||||
fn build_method(
|
||||
&self,
|
||||
diagnostics: &mut TemplateDiagnostics,
|
||||
build_ctx: &BuildContext<Self::Property>,
|
||||
property: Self::Property,
|
||||
function: &FunctionCallNode,
|
||||
|
@ -104,17 +107,17 @@ impl TemplateLanguage<'static> for OperationTemplateLanguage {
|
|||
match property {
|
||||
OperationTemplatePropertyKind::Core(property) => {
|
||||
let table = &self.build_fn_table.core;
|
||||
table.build_method(self, build_ctx, property, function)
|
||||
table.build_method(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
OperationTemplatePropertyKind::Operation(property) => {
|
||||
let table = &self.build_fn_table.operation_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
OperationTemplatePropertyKind::OperationId(property) => {
|
||||
let table = &self.build_fn_table.operation_id_methods;
|
||||
let build = template_parser::lookup_method(type_name, table, function)?;
|
||||
build(self, build_ctx, property, function)
|
||||
build(self, diagnostics, build_ctx, property, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +239,7 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
|
|||
let mut map = OperationTemplateBuildMethodFnMap::<Operation>::new();
|
||||
map.insert(
|
||||
"current_operation",
|
||||
|language, _build_ctx, self_property, function| {
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let current_op_id = language.current_op_id.clone();
|
||||
let out_property = self_property.map(move |op| Some(op.id()) == current_op_id.as_ref());
|
||||
|
@ -245,59 +248,74 @@ fn builtin_operation_methods() -> OperationTemplateBuildMethodFnMap<Operation> {
|
|||
);
|
||||
map.insert(
|
||||
"description",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| op.metadata().description.clone());
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("id", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| op.id().clone());
|
||||
Ok(L::wrap_operation_id(out_property))
|
||||
});
|
||||
map.insert("tags", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| {
|
||||
// TODO: introduce map type
|
||||
op.metadata()
|
||||
.tags
|
||||
.iter()
|
||||
.map(|(key, value)| format!("{key}: {value}"))
|
||||
.join("\n")
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"id",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| op.id().clone());
|
||||
Ok(L::wrap_operation_id(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"tags",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| {
|
||||
// TODO: introduce map type
|
||||
op.metadata()
|
||||
.tags
|
||||
.iter()
|
||||
.map(|(key, value)| format!("{key}: {value}"))
|
||||
.join("\n")
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"snapshot",
|
||||
|_language, _build_ctx, self_property, function| {
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| op.metadata().is_snapshot);
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map.insert("time", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| TimestampRange {
|
||||
start: op.metadata().start_time,
|
||||
end: op.metadata().end_time,
|
||||
});
|
||||
Ok(L::wrap_timestamp_range(out_property))
|
||||
});
|
||||
map.insert("user", |_language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| {
|
||||
// TODO: introduce dedicated type and provide accessors?
|
||||
format!("{}@{}", op.metadata().username, op.metadata().hostname)
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert("root", |language, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let root_op_id = language.root_op_id.clone();
|
||||
let out_property = self_property.map(move |op| op.id() == &root_op_id);
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"time",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| TimestampRange {
|
||||
start: op.metadata().start_time,
|
||||
end: op.metadata().end_time,
|
||||
});
|
||||
Ok(L::wrap_timestamp_range(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"user",
|
||||
|_language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let out_property = self_property.map(|op| {
|
||||
// TODO: introduce dedicated type and provide accessors?
|
||||
format!("{}@{}", op.metadata().username, op.metadata().hostname)
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"root",
|
||||
|language, _diagnostics, _build_ctx, self_property, function| {
|
||||
function.expect_no_arguments()?;
|
||||
let root_op_id = language.root_op_id.clone();
|
||||
let out_property = self_property.map(move |op| op.id() == &root_op_id);
|
||||
Ok(L::wrap_boolean(out_property))
|
||||
},
|
||||
);
|
||||
map
|
||||
}
|
||||
|
||||
|
@ -312,17 +330,27 @@ fn builtin_operation_id_methods() -> OperationTemplateBuildMethodFnMap<Operation
|
|||
// Not using maplit::hashmap!{} or custom declarative macro here because
|
||||
// code completion inside macro is quite restricted.
|
||||
let mut map = OperationTemplateBuildMethodFnMap::<OperationId>::new();
|
||||
map.insert("short", |language, build_ctx, self_property, function| {
|
||||
let ([], [len_node]) = function.expect_arguments()?;
|
||||
let len_property = len_node
|
||||
.map(|node| template_builder::expect_usize_expression(language, build_ctx, node))
|
||||
.transpose()?;
|
||||
let out_property = (self_property, len_property).map(|(id, len)| {
|
||||
let mut hex = id.hex();
|
||||
hex.truncate(len.unwrap_or(12));
|
||||
hex
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
});
|
||||
map.insert(
|
||||
"short",
|
||||
|language, diagnostics, build_ctx, self_property, function| {
|
||||
let ([], [len_node]) = function.expect_arguments()?;
|
||||
let len_property = len_node
|
||||
.map(|node| {
|
||||
template_builder::expect_usize_expression(
|
||||
language,
|
||||
diagnostics,
|
||||
build_ctx,
|
||||
node,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
let out_property = (self_property, len_property).map(|(id, len)| {
|
||||
let mut hex = id.hex();
|
||||
hex.truncate(len.unwrap_or(12));
|
||||
hex
|
||||
});
|
||||
Ok(L::wrap_string(out_property))
|
||||
},
|
||||
);
|
||||
map
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,6 +26,7 @@ use jj_lib::dsl_util::AliasExpandError;
|
|||
use jj_lib::dsl_util::AliasExpandableExpression;
|
||||
use jj_lib::dsl_util::AliasId;
|
||||
use jj_lib::dsl_util::AliasesMap;
|
||||
use jj_lib::dsl_util::Diagnostics;
|
||||
use jj_lib::dsl_util::ExpressionFolder;
|
||||
use jj_lib::dsl_util::FoldableExpression;
|
||||
use jj_lib::dsl_util::InvalidArguments;
|
||||
|
@ -84,6 +85,9 @@ impl Rule {
|
|||
}
|
||||
}
|
||||
|
||||
/// Manages diagnostic messages emitted during template parsing and building.
|
||||
pub type TemplateDiagnostics = Diagnostics<TemplateParseError>;
|
||||
|
||||
pub type TemplateParseResult<T> = Result<T, TemplateParseError>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
Loading…
Reference in a new issue