ok/jj
1
0
Fork 0
forked from mirrors/jj

commit_templater: make git_head return Option<RefName> instead of Vec<_>

Since we've introduced Option type, it no longer makes sense that git_head
returns a Vec<RefName>.
This commit is contained in:
Yuya Nishihara 2024-03-24 21:57:07 +09:00
parent bd3d9309ff
commit b363e695e4
5 changed files with 51 additions and 11 deletions

View file

@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Breaking changes
* The `git_head` template keyword now returns an optional value instead of a
list of 0 or 1 element.
### New features
* Config now supports rgb hex colors (in the form `#rrggbb`) wherever existing color names are supported.

View file

@ -149,6 +149,14 @@ impl<'repo> TemplateLanguage<'repo> for CommitTemplateLanguage<'repo> {
let build = template_parser::lookup_method("RefName", table, function)?;
build(self, build_ctx, property, function)
}
CommitTemplatePropertyKind::RefNameOpt(property) => {
let table = &self.build_fn_table.ref_name_methods;
let build = template_parser::lookup_method("RefName", table, function)?;
let inner_property = property.and_then(|opt| {
opt.ok_or_else(|| TemplatePropertyError("No RefName available".into()))
});
build(self, build_ctx, Box::new(inner_property), function)
}
CommitTemplatePropertyKind::RefNameList(property) => {
// TODO: migrate to table?
template_builder::build_formattable_list_method(
@ -216,6 +224,12 @@ impl<'repo> CommitTemplateLanguage<'repo> {
CommitTemplatePropertyKind::RefName(Box::new(property))
}
pub fn wrap_ref_name_opt(
property: impl TemplateProperty<Output = Option<RefName>> + 'repo,
) -> CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::RefNameOpt(Box::new(property))
}
pub fn wrap_ref_name_list(
property: impl TemplateProperty<Output = Vec<RefName>> + 'repo,
) -> CommitTemplatePropertyKind<'repo> {
@ -241,6 +255,7 @@ pub enum CommitTemplatePropertyKind<'repo> {
CommitOpt(Box<dyn TemplateProperty<Output = Option<Commit>> + 'repo>),
CommitList(Box<dyn TemplateProperty<Output = Vec<Commit>> + 'repo>),
RefName(Box<dyn TemplateProperty<Output = RefName> + 'repo>),
RefNameOpt(Box<dyn TemplateProperty<Output = Option<RefName>> + 'repo>),
RefNameList(Box<dyn TemplateProperty<Output = Vec<RefName>> + 'repo>),
CommitOrChangeId(Box<dyn TemplateProperty<Output = CommitOrChangeId> + 'repo>),
ShortestIdPrefix(Box<dyn TemplateProperty<Output = ShortestIdPrefix> + 'repo>),
@ -258,6 +273,9 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
Some(Box::new(property.map(|l| !l.is_empty())))
}
CommitTemplatePropertyKind::RefName(_) => None,
CommitTemplatePropertyKind::RefNameOpt(property) => {
Some(Box::new(property.map(|opt| opt.is_some())))
}
CommitTemplatePropertyKind::RefNameList(property) => {
Some(Box::new(property.map(|l| !l.is_empty())))
}
@ -290,6 +308,7 @@ impl<'repo> IntoTemplateProperty<'repo> for CommitTemplatePropertyKind<'repo> {
CommitTemplatePropertyKind::CommitOpt(_) => None,
CommitTemplatePropertyKind::CommitList(_) => None,
CommitTemplatePropertyKind::RefName(property) => Some(property.into_template()),
CommitTemplatePropertyKind::RefNameOpt(property) => Some(property.into_template()),
CommitTemplatePropertyKind::RefNameList(property) => Some(property.into_template()),
CommitTemplatePropertyKind::CommitOrChangeId(property) => {
Some(property.into_template())
@ -530,7 +549,7 @@ fn builtin_commit_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'repo, Comm
template_parser::expect_no_arguments(function)?;
let repo = language.repo;
let out_property = self_property.map(|commit| extract_git_head(repo, &commit));
Ok(L::wrap_ref_name_list(out_property))
Ok(L::wrap_ref_name_opt(out_property))
},
);
map.insert(
@ -764,20 +783,16 @@ fn build_ref_names_index<'a>(
index
}
// TODO: maybe add option or nullable type?
fn extract_git_head(repo: &dyn Repo, commit: &Commit) -> Vec<RefName> {
fn extract_git_head(repo: &dyn Repo, commit: &Commit) -> Option<RefName> {
let target = repo.view().git_head();
if target.added_ids().contains(commit.id()) {
let ref_name = RefName {
target.added_ids().contains(commit.id()).then(|| {
RefName {
name: "HEAD".to_owned(),
remote: Some(git::REMOTE_NAME_FOR_LOCAL_GIT_REPO.to_owned()),
conflict: target.has_conflict(),
synced: false, // has no local counterpart
};
vec![ref_name]
} else {
vec![]
}
}
})
}
#[derive(Clone, Debug, Eq, PartialEq)]

View file

@ -55,6 +55,14 @@ impl<T: Template + ?Sized> Template for Box<T> {
}
}
// All optional printable types should be printable, and it's unlikely to
// implement different formatting per type.
impl<T: Template> Template for Option<T> {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
self.as_ref().map_or(Ok(()), |t| t.format(formatter))
}
}
impl Template for Signature {
fn format(&self, formatter: &mut dyn Formatter) -> io::Result<()> {
write!(formatter.labeled("name"), "{}", self.name)?;

View file

@ -494,6 +494,20 @@ fn test_log_git_head() {
test_env.jj_cmd_ok(&repo_path, &["new", "-m=initial"]);
std::fs::write(repo_path.join("file"), "foo\n").unwrap();
let template = r#"
separate(", ",
if(git_head, "name: " ++ git_head.name()),
"remote: " ++ git_head.remote(),
) ++ "\n"
"#;
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stdout, @r###"
@ remote: <Error: No RefName available>
name: HEAD, remote: git
remote: <Error: No RefName available>
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--color=always"]);
insta::assert_snapshot!(stdout, @r###"
@ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 50aaf475

View file

@ -81,7 +81,7 @@ This type cannot be printed. The following methods are defined.
* `remote_branches() -> List<RefName>`: All remote branches pointing to the commit.
* `tags() -> List<RefName>`
* `git_refs() -> List<RefName>`
* `git_head() -> List<RefName>`
* `git_head() -> Option<RefName>`
* `divergent() -> Boolean`: True if the commit's change id corresponds to multiple
visible commits.
* `hidden() -> Boolean`: True if the commit is not visible (a.k.a. abandoned).