mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-01 00:50:57 +00:00
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:
parent
bd3d9309ff
commit
b363e695e4
5 changed files with 51 additions and 11 deletions
|
@ -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.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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###"
|
||||
@ [1m[38;5;13mr[38;5;8mlvkpnrz[39m [38;5;3mtest.user@example.com[39m [38;5;14m2001-02-03 08:05:09[39m [38;5;12m5[38;5;8m0aaf475[39m[0m
|
||||
|
|
|
@ -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).
|
||||
|
|
Loading…
Reference in a new issue