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

templater: migrate trivial commit keywords to closure wrapper

Perhaps, non-trivial keywords can be extracted to free functions, and both
parsing and property functions can be eventually moved to a commit templater
module?
This commit is contained in:
Yuya Nishihara 2023-01-31 12:48:38 +09:00
parent 846be15132
commit 6da43734cb
2 changed files with 32 additions and 113 deletions

View file

@ -17,20 +17,19 @@ use jujutsu_lib::backend::{Signature, Timestamp};
use jujutsu_lib::commit::Commit;
use jujutsu_lib::op_store::WorkspaceId;
use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::rewrite;
use pest::iterators::{Pair, Pairs};
use pest::Parser;
use pest_derive::Parser;
use crate::formatter::PlainTextFormatter;
use crate::templater::{
AuthorProperty, BranchProperty, ChangeIdProperty, CommitIdProperty, CommitOrChangeId,
CommitterProperty, ConditionalTemplate, ConflictProperty, DescriptionProperty,
DivergentProperty, DynamicLabelTemplate, EmptyProperty, FormattablePropertyTemplate,
GitHeadProperty, GitRefsProperty, IdWithHighlightedPrefix, IsWorkingCopyProperty,
LabelTemplate, ListTemplate, Literal, TagProperty, Template, TemplateFunction,
TemplateProperty, TemplatePropertyFn, WorkingCopiesProperty,
BranchProperty, CommitOrChangeId, ConditionalTemplate, DynamicLabelTemplate,
FormattablePropertyTemplate, GitHeadProperty, GitRefsProperty, IdWithHighlightedPrefix,
IsWorkingCopyProperty, LabelTemplate, ListTemplate, Literal, TagProperty, Template,
TemplateFunction, TemplateProperty, TemplatePropertyFn, WorkingCopiesProperty,
};
use crate::time_util;
use crate::{cli_util, time_util};
#[derive(Parser)]
#[grammar = "template.pest"]
@ -258,13 +257,24 @@ fn parse_commit_keyword<'a>(
workspace_id: &WorkspaceId,
pair: Pair<Rule>,
) -> PropertyAndLabels<'a, Commit> {
fn wrap_fn<'a, O>(
f: impl Fn(&Commit) -> O + 'a,
) -> Box<dyn TemplateProperty<Commit, Output = O> + 'a> {
Box::new(TemplatePropertyFn(f))
}
assert_eq!(pair.as_rule(), Rule::identifier);
let property = match pair.as_str() {
"description" => Property::String(Box::new(DescriptionProperty)),
"change_id" => Property::CommitOrChangeId(Box::new(ChangeIdProperty { repo })),
"commit_id" => Property::CommitOrChangeId(Box::new(CommitIdProperty { repo })),
"author" => Property::Signature(Box::new(AuthorProperty)),
"committer" => Property::Signature(Box::new(CommitterProperty)),
"description" => Property::String(wrap_fn(|commit| {
cli_util::complete_newline(commit.description())
})),
"change_id" => Property::CommitOrChangeId(wrap_fn(move |commit| {
CommitOrChangeId::new(repo, commit.change_id())
})),
"commit_id" => Property::CommitOrChangeId(wrap_fn(move |commit| {
CommitOrChangeId::new(repo, commit.id())
})),
"author" => Property::Signature(wrap_fn(|commit| commit.author().clone())),
"committer" => Property::Signature(wrap_fn(|commit| commit.committer().clone())),
"working_copies" => Property::String(Box::new(WorkingCopiesProperty { repo })),
"current_working_copy" => Property::Boolean(Box::new(IsWorkingCopyProperty {
repo,
@ -274,9 +284,15 @@ fn parse_commit_keyword<'a>(
"tags" => Property::String(Box::new(TagProperty { repo })),
"git_refs" => Property::String(Box::new(GitRefsProperty { repo })),
"git_head" => Property::String(Box::new(GitHeadProperty::new(repo))),
"divergent" => Property::Boolean(Box::new(DivergentProperty::new(repo))),
"conflict" => Property::Boolean(Box::new(ConflictProperty)),
"empty" => Property::Boolean(Box::new(EmptyProperty { repo })),
"divergent" => Property::Boolean(wrap_fn(move |commit| {
// The given commit could be hidden in e.g. obslog.
let maybe_entries = repo.resolve_change_id(commit.change_id());
maybe_entries.map_or(0, |entries| entries.len()) > 1
})),
"conflict" => Property::Boolean(wrap_fn(|commit| commit.tree().has_conflict())),
"empty" => Property::Boolean(wrap_fn(move |commit| {
commit.tree().id() == rewrite::merge_commit_trees(repo, &commit.parents()).id()
})),
name => panic!("unexpected identifier: {name}"),
};
PropertyAndLabels(property, vec![pair.as_str().to_string()])

View file

@ -20,10 +20,9 @@ use jujutsu_lib::backend::{ObjectId, Signature, Timestamp};
use jujutsu_lib::commit::Commit;
use jujutsu_lib::op_store::WorkspaceId;
use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::rewrite::merge_commit_trees;
use crate::formatter::Formatter;
use crate::{cli_util, time_util};
use crate::time_util;
pub trait Template<C> {
fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>;
@ -205,36 +204,6 @@ where
}
}
pub struct DescriptionProperty;
impl TemplateProperty<Commit> for DescriptionProperty {
type Output = String;
fn extract(&self, context: &Commit) -> Self::Output {
cli_util::complete_newline(context.description())
}
}
pub struct AuthorProperty;
impl TemplateProperty<Commit> for AuthorProperty {
type Output = Signature;
fn extract(&self, context: &Commit) -> Self::Output {
context.author().clone()
}
}
pub struct CommitterProperty;
impl TemplateProperty<Commit> for CommitterProperty {
type Output = Signature;
fn extract(&self, context: &Commit) -> Self::Output {
context.committer().clone()
}
}
pub struct WorkingCopiesProperty<'a> {
pub repo: RepoRef<'a>,
}
@ -383,36 +352,6 @@ impl TemplateProperty<Commit> for GitHeadProperty<'_> {
}
}
pub struct DivergentProperty<'a> {
repo: RepoRef<'a>,
}
impl<'a> DivergentProperty<'a> {
pub fn new(repo: RepoRef<'a>) -> Self {
DivergentProperty { repo }
}
}
impl TemplateProperty<Commit> for DivergentProperty<'_> {
type Output = bool;
fn extract(&self, context: &Commit) -> Self::Output {
// The given commit could be hidden in e.g. obslog.
let maybe_entries = self.repo.resolve_change_id(context.change_id());
maybe_entries.map_or(0, |entries| entries.len()) > 1
}
}
pub struct ConflictProperty;
impl TemplateProperty<Commit> for ConflictProperty {
type Output = bool;
fn extract(&self, context: &Commit) -> Self::Output {
context.tree().has_conflict()
}
}
pub struct ConditionalTemplate<P, T, U> {
pub condition: P,
pub true_template: T,
@ -599,39 +538,3 @@ impl Template<()> for IdWithHighlightedPrefix {
formatter.with_label("rest", |fmt| fmt.write_str(&self.rest))
}
}
pub struct CommitIdProperty<'a> {
pub repo: RepoRef<'a>,
}
impl<'a> TemplateProperty<Commit> for CommitIdProperty<'a> {
type Output = CommitOrChangeId<'a>;
fn extract(&self, context: &Commit) -> Self::Output {
CommitOrChangeId::new(self.repo, context.id())
}
}
pub struct ChangeIdProperty<'a> {
pub repo: RepoRef<'a>,
}
impl<'a> TemplateProperty<Commit> for ChangeIdProperty<'a> {
type Output = CommitOrChangeId<'a>;
fn extract(&self, context: &Commit) -> Self::Output {
CommitOrChangeId::new(self.repo, context.change_id())
}
}
pub struct EmptyProperty<'a> {
pub repo: RepoRef<'a>,
}
impl TemplateProperty<Commit> for EmptyProperty<'_> {
type Output = bool;
fn extract(&self, context: &Commit) -> Self::Output {
context.tree().id() == merge_commit_trees(self.repo, &context.parents()).id()
}
}