mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
templater: add "parent_commit_ids" keyword
A list type isn't so useful without a map operation, but List<CommitId> is at least printable. Maybe we can experiment with it to craft a map operation. If a map operation is introduced, this keyword might be replaced with "parents.map(|commit| commit.commit_id)", where parents is of List<Commit> type, and the .map() method will probably return List<Template>.
This commit is contained in:
parent
0b27f8371a
commit
4984e611f4
4 changed files with 72 additions and 1 deletions
|
@ -18,6 +18,7 @@ The following keywords can be used in `jj log`/`jj obslog` templates.
|
|||
* `description: String`
|
||||
* `change_id: ChangeId`
|
||||
* `commit_id: CommitId`
|
||||
* `parent_commit_ids: List<CommitId>`
|
||||
* `author: Signature`
|
||||
* `committer: Signature`
|
||||
* `working_copies: String`: For multi-workspace repository, indicate
|
||||
|
@ -83,6 +84,10 @@ The following methods are defined.
|
|||
|
||||
No methods are defined.
|
||||
|
||||
### List type
|
||||
|
||||
No methods are defined.
|
||||
|
||||
### OperationId type
|
||||
|
||||
The following methods are defined.
|
||||
|
|
|
@ -30,7 +30,7 @@ use crate::template_parser::{
|
|||
TemplateLanguage, TemplateParseError, TemplateParseResult,
|
||||
};
|
||||
use crate::templater::{
|
||||
IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, TemplatePropertyFn,
|
||||
self, IntoTemplate, PlainTextFormattedProperty, Template, TemplateProperty, TemplatePropertyFn,
|
||||
};
|
||||
|
||||
struct CommitTemplateLanguage<'repo, 'b> {
|
||||
|
@ -60,6 +60,9 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo, '_> {
|
|||
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
|
||||
build_commit_or_change_id_method(self, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::CommitOrChangeIdList(property) => {
|
||||
template_parser::build_list_method(self, property, function)
|
||||
}
|
||||
CommitTemplatePropertyKind::ShortestIdPrefix(property) => {
|
||||
build_shortest_id_prefix_method(self, property, function)
|
||||
}
|
||||
|
@ -77,6 +80,13 @@ impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
|||
CommitTemplatePropertyKind::CommitOrChangeId(property)
|
||||
}
|
||||
|
||||
fn wrap_commit_or_change_id_list(
|
||||
&self,
|
||||
property: Box<dyn TemplateProperty<Commit, Output = Vec<CommitOrChangeId<'repo>>> + 'repo>,
|
||||
) -> CommitTemplatePropertyKind<'repo> {
|
||||
CommitTemplatePropertyKind::CommitOrChangeIdList(property)
|
||||
}
|
||||
|
||||
fn wrap_shortest_id_prefix(
|
||||
&self,
|
||||
property: Box<dyn TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo>,
|
||||
|
@ -88,6 +98,9 @@ impl<'repo> CommitTemplateLanguage<'repo, '_> {
|
|||
enum CommitTemplatePropertyKind<'repo> {
|
||||
Core(CoreTemplatePropertyKind<'repo, Commit>),
|
||||
CommitOrChangeId(Box<dyn TemplateProperty<Commit, Output = CommitOrChangeId<'repo>> + 'repo>),
|
||||
CommitOrChangeIdList(
|
||||
Box<dyn TemplateProperty<Commit, Output = Vec<CommitOrChangeId<'repo>>> + 'repo>,
|
||||
),
|
||||
ShortestIdPrefix(Box<dyn TemplateProperty<Commit, Output = ShortestIdPrefix> + 'repo>),
|
||||
}
|
||||
|
||||
|
@ -95,6 +108,7 @@ impl<'repo> IntoTemplateProperty<'repo, Commit> for CommitTemplatePropertyKind<'
|
|||
fn try_into_boolean(self) -> Option<Box<dyn TemplateProperty<Commit, Output = bool> + 'repo>> {
|
||||
match self {
|
||||
CommitTemplatePropertyKind::Core(property) => property.try_into_boolean(),
|
||||
// TODO: should we allow implicit cast of List type?
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +133,7 @@ impl<'repo> IntoTemplate<'repo, Commit> for CommitTemplatePropertyKind<'repo> {
|
|||
match self {
|
||||
CommitTemplatePropertyKind::Core(property) => property.into_template(),
|
||||
CommitTemplatePropertyKind::CommitOrChangeId(property) => property.into_template(),
|
||||
CommitTemplatePropertyKind::CommitOrChangeIdList(property) => property.into_template(),
|
||||
CommitTemplatePropertyKind::ShortestIdPrefix(property) => property.into_template(),
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +167,13 @@ fn build_commit_keyword<'repo>(
|
|||
"commit_id" => language.wrap_commit_or_change_id(wrap_fn(move |commit| {
|
||||
CommitOrChangeId::new(repo, IdKind::Commit(commit.id().to_owned()))
|
||||
})),
|
||||
"parent_commit_ids" => language.wrap_commit_or_change_id_list(wrap_fn(move |commit| {
|
||||
commit
|
||||
.parent_ids()
|
||||
.iter()
|
||||
.map(|id| CommitOrChangeId::new(repo, IdKind::Commit(id.to_owned())))
|
||||
.collect()
|
||||
})),
|
||||
"author" => language.wrap_signature(wrap_fn(|commit| commit.author().clone())),
|
||||
"committer" => language.wrap_signature(wrap_fn(|commit| commit.committer().clone())),
|
||||
"working_copies" => language.wrap_string(wrap_repo_fn(repo, extract_working_copies)),
|
||||
|
@ -179,6 +201,7 @@ fn build_commit_keyword<'repo>(
|
|||
Ok(property)
|
||||
}
|
||||
|
||||
// TODO: return Vec<String>
|
||||
fn extract_working_copies(repo: &dyn Repo, commit: &Commit) -> String {
|
||||
let wc_commit_ids = repo.view().wc_commit_ids();
|
||||
if wc_commit_ids.len() <= 1 {
|
||||
|
@ -193,6 +216,7 @@ fn extract_working_copies(repo: &dyn Repo, commit: &Commit) -> String {
|
|||
names.join(" ")
|
||||
}
|
||||
|
||||
// TODO: return Vec<Branch>?
|
||||
fn extract_branches(repo: &dyn Repo, commit: &Commit) -> String {
|
||||
let mut names = vec![];
|
||||
for (branch_name, branch_target) in repo.view().branches() {
|
||||
|
@ -225,6 +249,7 @@ fn extract_branches(repo: &dyn Repo, commit: &Commit) -> String {
|
|||
names.join(" ")
|
||||
}
|
||||
|
||||
// TODO: return Vec<NameRef>?
|
||||
fn extract_tags(repo: &dyn Repo, commit: &Commit) -> String {
|
||||
let mut names = vec![];
|
||||
for (tag_name, target) in repo.view().tags() {
|
||||
|
@ -239,6 +264,7 @@ fn extract_tags(repo: &dyn Repo, commit: &Commit) -> String {
|
|||
names.join(" ")
|
||||
}
|
||||
|
||||
// TODO: return Vec<NameRef>?
|
||||
fn extract_git_refs(repo: &dyn Repo, commit: &Commit) -> String {
|
||||
// TODO: We should keep a map from commit to ref names so we don't have to walk
|
||||
// all refs here.
|
||||
|
@ -255,6 +281,7 @@ fn extract_git_refs(repo: &dyn Repo, commit: &Commit) -> String {
|
|||
names.join(" ")
|
||||
}
|
||||
|
||||
// TODO: return NameRef?
|
||||
fn extract_git_head(repo: &dyn Repo, commit: &Commit) -> String {
|
||||
match repo.view().git_head() {
|
||||
Some(ref_target) if ref_target.has_add(commit.id()) => {
|
||||
|
@ -322,6 +349,12 @@ 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>(
|
||||
language: &CommitTemplateLanguage<'repo, '_>,
|
||||
self_property: impl TemplateProperty<Commit, Output = CommitOrChangeId<'repo>> + 'repo,
|
||||
|
|
|
@ -1040,6 +1040,15 @@ fn build_timestamp_range_method<'a, L: TemplateLanguage<'a>>(
|
|||
Ok(property)
|
||||
}
|
||||
|
||||
pub fn build_list_method<'a, L: TemplateLanguage<'a>, P>(
|
||||
_language: &L,
|
||||
_self_property: impl TemplateProperty<L::Context, Output = Vec<P>> + 'a,
|
||||
function: &FunctionCallNode,
|
||||
) -> TemplateParseResult<L::Property> {
|
||||
// TODO: .join(separator), .map(), ...
|
||||
Err(TemplateParseError::no_such_method("List", function))
|
||||
}
|
||||
|
||||
fn build_global_function<'a, L: TemplateLanguage<'a>>(
|
||||
language: &L,
|
||||
function: &FunctionCallNode,
|
||||
|
|
|
@ -17,6 +17,30 @@ use regex::Regex;
|
|||
|
||||
pub mod common;
|
||||
|
||||
#[test]
|
||||
fn test_log_parent_commit_ids() {
|
||||
let test_env = TestEnvironment::default();
|
||||
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||
let repo_path = test_env.env_root().join("repo");
|
||||
|
||||
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 stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
@ c067170d4ca1bc6162b64f7550617ec809647f84
|
||||
├─╮ P: 4db490c88528133d579540b6900b8098f0c17701 230dd059e1b059aefc0da06a2e5a7dbf22362f22
|
||||
o │ 4db490c88528133d579540b6900b8098f0c17701
|
||||
├─╯ P: 230dd059e1b059aefc0da06a2e5a7dbf22362f22
|
||||
o 230dd059e1b059aefc0da06a2e5a7dbf22362f22
|
||||
│ P: 0000000000000000000000000000000000000000
|
||||
o 0000000000000000000000000000000000000000
|
||||
P:
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_author_timestamp() {
|
||||
let test_env = TestEnvironment::default();
|
||||
|
|
Loading…
Reference in a new issue