mirror of
https://github.com/martinvonz/jj.git
synced 2024-10-23 23:10:01 +00:00
templater: add "parents" keyword in place of "parent_commit_ids"
All commit keywords are mapped to nullary methods. No matter if we'll introduce .field syntax and/or self. keyword, this implementation can be reused.
This commit is contained in:
parent
f4235464c2
commit
75d68fe24c
3 changed files with 76 additions and 38 deletions
|
@ -18,7 +18,7 @@ The following keywords can be used in `jj log`/`jj obslog` templates.
|
||||||
* `description: String`
|
* `description: String`
|
||||||
* `change_id: ChangeId`
|
* `change_id: ChangeId`
|
||||||
* `commit_id: CommitId`
|
* `commit_id: CommitId`
|
||||||
* `parent_commit_ids: List<CommitId>`
|
* `parents: List<Commit>`
|
||||||
* `author: Signature`
|
* `author: Signature`
|
||||||
* `committer: Signature`
|
* `committer: Signature`
|
||||||
* `working_copies: String`: For multi-workspace repository, indicate
|
* `working_copies: String`: For multi-workspace repository, indicate
|
||||||
|
@ -75,6 +75,11 @@ The following functions are defined.
|
||||||
|
|
||||||
No methods are defined.
|
No methods are defined.
|
||||||
|
|
||||||
|
### Commit type
|
||||||
|
|
||||||
|
This type cannot be printed. All commit keywords are accessible as 0-argument
|
||||||
|
methods.
|
||||||
|
|
||||||
### CommitId / ChangeId type
|
### CommitId / ChangeId type
|
||||||
|
|
||||||
The following methods are defined.
|
The following methods are defined.
|
||||||
|
@ -93,7 +98,7 @@ The following methods are defined.
|
||||||
* `.join(separator: Template) -> Template`: Concatenate elements with
|
* `.join(separator: Template) -> Template`: Concatenate elements with
|
||||||
the given `separator`.
|
the given `separator`.
|
||||||
* `.map(|item| expression) -> ListTemplate`: Apply template `expression`
|
* `.map(|item| expression) -> ListTemplate`: Apply template `expression`
|
||||||
to each element. Example: `parent_commit_ids.map(|id| id.short())`
|
to each element. Example: `parents.map(|c| c.commit_id().short())`
|
||||||
|
|
||||||
### ListTemplate type
|
### ListTemplate type
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::template_parser::{
|
||||||
self, FunctionCallNode, TemplateAliasesMap, TemplateParseError, TemplateParseResult,
|
self, FunctionCallNode, TemplateAliasesMap, TemplateParseError, TemplateParseResult,
|
||||||
};
|
};
|
||||||
use crate::templater::{
|
use crate::templater::{
|
||||||
self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateFunction, TemplateProperty,
|
IntoTemplate, PlainTextFormattedProperty, Template, TemplateFunction, TemplateProperty,
|
||||||
TemplatePropertyFn,
|
TemplatePropertyFn,
|
||||||
};
|
};
|
||||||
use crate::text_util;
|
use crate::text_util;
|
||||||
|
@ -61,18 +61,21 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo, '_> {
|
||||||
CommitTemplatePropertyKind::Core(property) => {
|
CommitTemplatePropertyKind::Core(property) => {
|
||||||
template_builder::build_core_method(self, build_ctx, property, function)
|
template_builder::build_core_method(self, build_ctx, property, function)
|
||||||
}
|
}
|
||||||
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
CommitTemplatePropertyKind::Commit(property) => {
|
||||||
build_commit_or_change_id_method(self, build_ctx, property, function)
|
build_commit_method(self, build_ctx, property, function)
|
||||||
}
|
}
|
||||||
CommitTemplatePropertyKind::CommitOrChangeIdList(property) => {
|
CommitTemplatePropertyKind::CommitList(property) => {
|
||||||
template_builder::build_formattable_list_method(
|
template_builder::build_unformattable_list_method(
|
||||||
self,
|
self,
|
||||||
build_ctx,
|
build_ctx,
|
||||||
property,
|
property,
|
||||||
function,
|
function,
|
||||||
|item| self.wrap_commit_or_change_id(item),
|
|item| self.wrap_commit(item),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
||||||
|
build_commit_or_change_id_method(self, build_ctx, property, function)
|
||||||
|
}
|
||||||
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
||||||
build_shortest_id_prefix_method(self, build_ctx, property, function)
|
build_shortest_id_prefix_method(self, build_ctx, property, function)
|
||||||
}
|
}
|
||||||
|
@ -83,6 +86,20 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo, '_> {
|
||||||
// If we need to add multiple languages that support Commit types, this can be
|
// If we need to add multiple languages that support Commit types, this can be
|
||||||
// turned into a trait which extends TemplateLanguage.
|
// turned into a trait which extends TemplateLanguage.
|
||||||
impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
||||||
|
fn wrap_commit(
|
||||||
|
&self,
|
||||||
|
property: impl TemplateProperty<Commit, Output = Commit> + 'repo,
|
||||||
|
) -> CommitTemplatePropertyKind<'repo> {
|
||||||
|
CommitTemplatePropertyKind::Commit(Box::new(property))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_commit_list(
|
||||||
|
&self,
|
||||||
|
property: impl TemplateProperty<Commit, Output = Vec<Commit>> + 'repo,
|
||||||
|
) -> CommitTemplatePropertyKind<'repo> {
|
||||||
|
CommitTemplatePropertyKind::CommitList(Box::new(property))
|
||||||
|
}
|
||||||
|
|
||||||
fn wrap_commit_or_change_id(
|
fn wrap_commit_or_change_id(
|
||||||
&self,
|
&self,
|
||||||
property: impl TemplateProperty<Commit, Output = CommitOrChangeId> + 'repo,
|
property: impl TemplateProperty<Commit, Output = CommitOrChangeId> + 'repo,
|
||||||
|
@ -90,13 +107,6 @@ impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
||||||
CommitTemplatePropertyKind::CommitOrChangeId(Box::new(property))
|
CommitTemplatePropertyKind::CommitOrChangeId(Box::new(property))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_commit_or_change_id_list(
|
|
||||||
&self,
|
|
||||||
property: impl TemplateProperty<Commit, Output = Vec<CommitOrChangeId>> + 'repo,
|
|
||||||
) -> CommitTemplatePropertyKind<'repo> {
|
|
||||||
CommitTemplatePropertyKind::CommitOrChangeIdList(Box::new(property))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap_shortest_id_prefix(
|
fn wrap_shortest_id_prefix(
|
||||||
&self,
|
&self,
|
||||||
property: impl TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo,
|
property: impl TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo,
|
||||||
|
@ -107,8 +117,9 @@ impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
||||||
|
|
||||||
enum CommitTemplatePropertyKind<'repo> {
|
enum CommitTemplatePropertyKind<'repo> {
|
||||||
Core(CoreTemplatePropertyKind<'repo, Commit>),
|
Core(CoreTemplatePropertyKind<'repo, Commit>),
|
||||||
|
Commit(Box<dyn TemplateProperty<Commit, Output = Commit> + 'repo>),
|
||||||
|
CommitList(Box<dyn TemplateProperty<Commit, Output = Vec<Commit>> + 'repo>),
|
||||||
CommitOrChangeId(Box<dyn TemplateProperty<Commit, Output = CommitOrChangeId> + 'repo>),
|
CommitOrChangeId(Box<dyn TemplateProperty<Commit, Output = CommitOrChangeId> + 'repo>),
|
||||||
CommitOrChangeIdList(Box<dyn TemplateProperty<Commit, Output = Vec<CommitOrChangeId>> + 'repo>),
|
|
||||||
ShortestIdPrefix(Box<dyn TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo>),
|
ShortestIdPrefix(Box<dyn TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,12 +154,11 @@ impl<'repo> IntoTemplateProperty<'repo, Commit> for CommitTemplatePropertyKind<'
|
||||||
fn try_into_template(self) -> Option<Box<dyn Template<Commit> + 'repo>> {
|
fn try_into_template(self) -> Option<Box<dyn Template<Commit> + 'repo>> {
|
||||||
match self {
|
match self {
|
||||||
CommitTemplatePropertyKind::Core(property) => property.try_into_template(),
|
CommitTemplatePropertyKind::Core(property) => property.try_into_template(),
|
||||||
|
CommitTemplatePropertyKind::Commit(_) => None,
|
||||||
|
CommitTemplatePropertyKind::CommitList(_) => None,
|
||||||
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
||||||
Some(property.into_template())
|
Some(property.into_template())
|
||||||
}
|
}
|
||||||
CommitTemplatePropertyKind::CommitOrChangeIdList(property) => {
|
|
||||||
Some(property.into_template())
|
|
||||||
}
|
|
||||||
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
||||||
Some(property.into_template())
|
Some(property.into_template())
|
||||||
}
|
}
|
||||||
|
@ -171,6 +181,20 @@ fn build_commit_keyword<'repo>(
|
||||||
.ok_or_else(|| TemplateParseError::no_such_keyword(name, span))
|
.ok_or_else(|| TemplateParseError::no_such_keyword(name, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_commit_method<'repo>(
|
||||||
|
language: &CommitTemplateLanguage<'repo, '_>,
|
||||||
|
_build_ctx: &BuildContext<CommitTemplatePropertyKind<'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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_commit_keyword_opt<'repo>(
|
fn build_commit_keyword_opt<'repo>(
|
||||||
language: &CommitTemplateLanguage<'repo, '_>,
|
language: &CommitTemplateLanguage<'repo, '_>,
|
||||||
property: impl TemplateProperty<Commit, Output = Commit> + 'repo,
|
property: impl TemplateProperty<Commit, Output = Commit> + 'repo,
|
||||||
|
@ -201,15 +225,7 @@ fn build_commit_keyword_opt<'repo>(
|
||||||
"commit_id" => language.wrap_commit_or_change_id(wrap_fn(property, |commit| {
|
"commit_id" => language.wrap_commit_or_change_id(wrap_fn(property, |commit| {
|
||||||
CommitOrChangeId::Commit(commit.id().to_owned())
|
CommitOrChangeId::Commit(commit.id().to_owned())
|
||||||
})),
|
})),
|
||||||
"parent_commit_ids" => {
|
"parents" => language.wrap_commit_list(wrap_fn(property, |commit| commit.parents())),
|
||||||
language.wrap_commit_or_change_id_list(wrap_fn(property, move |commit| {
|
|
||||||
commit
|
|
||||||
.parent_ids()
|
|
||||||
.iter()
|
|
||||||
.map(|id| CommitOrChangeId::Commit(id.to_owned()))
|
|
||||||
.collect()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
"author" => language.wrap_signature(wrap_fn(property, |commit| commit.author().clone())),
|
"author" => language.wrap_signature(wrap_fn(property, |commit| commit.author().clone())),
|
||||||
"committer" => {
|
"committer" => {
|
||||||
language.wrap_signature(wrap_fn(property, |commit| commit.committer().clone()))
|
language.wrap_signature(wrap_fn(property, |commit| commit.committer().clone()))
|
||||||
|
@ -381,12 +397,6 @@ impl Template<()> for CommitOrChangeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Template<()> for Vec<CommitOrChangeId> {
|
|
||||||
fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> {
|
|
||||||
templater::format_joined(&(), formatter, self, " ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_commit_or_change_id_method<'repo>(
|
fn build_commit_or_change_id_method<'repo>(
|
||||||
language: &CommitTemplateLanguage<'repo, '_>,
|
language: &CommitTemplateLanguage<'repo, '_>,
|
||||||
build_ctx: &BuildContext<CommitTemplatePropertyKind<'repo>>,
|
build_ctx: &BuildContext<CommitTemplatePropertyKind<'repo>>,
|
||||||
|
|
|
@ -18,7 +18,7 @@ use regex::Regex;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_log_parent_commit_ids() {
|
fn test_log_parents() {
|
||||||
let test_env = TestEnvironment::default();
|
let test_env = TestEnvironment::default();
|
||||||
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||||
let repo_path = test_env.env_root().join("repo");
|
let repo_path = test_env.env_root().join("repo");
|
||||||
|
@ -27,7 +27,7 @@ fn test_log_parent_commit_ids() {
|
||||||
test_env.jj_cmd_success(&repo_path, &["new", "@-"]);
|
test_env.jj_cmd_success(&repo_path, &["new", "@-"]);
|
||||||
test_env.jj_cmd_success(&repo_path, &["new", "@", "@-"]);
|
test_env.jj_cmd_success(&repo_path, &["new", "@", "@-"]);
|
||||||
|
|
||||||
let template = r#"commit_id ++ "\nP: " ++ parent_commit_ids ++ "\n""#;
|
let template = r#"commit_id ++ "\nP: " ++ parents.map(|c| c.commit_id()) ++ "\n""#;
|
||||||
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
|
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
|
||||||
insta::assert_snapshot!(stdout, @r###"
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
@ c067170d4ca1bc6162b64f7550617ec809647f84
|
@ c067170d4ca1bc6162b64f7550617ec809647f84
|
||||||
|
@ -40,16 +40,39 @@ fn test_log_parent_commit_ids() {
|
||||||
P:
|
P:
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
let template = r#"parent_commit_ids.map(|id| id.shortest(4))"#;
|
let template = r#"parents.map(|c| c.commit_id().shortest(4))"#;
|
||||||
let stdout = test_env.jj_cmd_success(
|
let stdout = test_env.jj_cmd_success(
|
||||||
&repo_path,
|
&repo_path,
|
||||||
&["log", "-T", template, "-r@", "--color=always"],
|
&["log", "-T", template, "-r@", "--color=always"],
|
||||||
);
|
);
|
||||||
insta::assert_snapshot!(stdout, @r###"
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
@ [1m4[0m[38;5;8mdb4[39m [1m2[0m[38;5;8m30d[39m
|
@ [1m[38;5;4m4[0m[38;5;8mdb4[39m [1m[38;5;4m2[0m[38;5;8m30d[39m
|
||||||
│
|
│
|
||||||
~
|
~
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
|
// Commit object isn't printable
|
||||||
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-T", "parents"]);
|
||||||
|
insta::assert_snapshot!(stderr, @r###"
|
||||||
|
Error: Failed to parse template: --> 1:1
|
||||||
|
|
|
||||||
|
1 | parents
|
||||||
|
| ^-----^
|
||||||
|
|
|
||||||
|
= Expected expression of type "Template"
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Redundant argument passed to keyword method
|
||||||
|
let template = r#"parents.map(|c| c.commit_id(""))"#;
|
||||||
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-T", template]);
|
||||||
|
insta::assert_snapshot!(stderr, @r###"
|
||||||
|
Error: Failed to parse template: --> 1:29
|
||||||
|
|
|
||||||
|
1 | parents.map(|c| c.commit_id(""))
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= Function "commit_id": Expected 0 arguments
|
||||||
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue