diff --git a/src/template_parser.rs b/src/template_parser.rs index 37eed2e79..35fa33dcc 100644 --- a/src/template_parser.rs +++ b/src/template_parser.rs @@ -58,53 +58,61 @@ fn parse_string_literal(pair: Pair) -> String { struct StringFirstLine; -impl TemplateProperty for StringFirstLine { - fn extract(&self, context: &String) -> String { +impl TemplateProperty for StringFirstLine { + type Output = String; + + fn extract(&self, context: &String) -> Self::Output { context.lines().next().unwrap().to_string() } } struct SignatureName; -impl TemplateProperty for SignatureName { - fn extract(&self, context: &Signature) -> String { +impl TemplateProperty for SignatureName { + type Output = String; + + fn extract(&self, context: &Signature) -> Self::Output { context.name.clone() } } struct SignatureEmail; -impl TemplateProperty for SignatureEmail { - fn extract(&self, context: &Signature) -> String { +impl TemplateProperty for SignatureEmail { + type Output = String; + + fn extract(&self, context: &Signature) -> Self::Output { context.email.clone() } } struct RelativeTimestampString; -impl TemplateProperty for RelativeTimestampString { - fn extract(&self, context: &Timestamp) -> String { +impl TemplateProperty for RelativeTimestampString { + type Output = String; + + fn extract(&self, context: &Timestamp) -> Self::Output { time_util::format_timestamp_relative_to_now(context) } } enum Property<'a, I> { - String(Box + 'a>), - Boolean(Box + 'a>), + String(Box + 'a>), + Boolean(Box + 'a>), CommitOrChangeId( - Box + 'a>, + Box + 'a>, RepoRef<'a>, ), - Signature(Box + 'a>), - Timestamp(Box + 'a>), + Signature(Box + 'a>), + Timestamp(Box + 'a>), } impl<'a, I: 'a> Property<'a, I> { - fn after(self, first: Box + 'a>) -> Property<'a, C> { + fn after(self, first: Box + 'a>) -> Property<'a, C> { fn chain<'a, C: 'a, I: 'a, O: 'a>( - first: Box + 'a>, - second: Box + 'a>, - ) -> Box + 'a> { + first: Box + 'a>, + second: Box + 'a>, + ) -> Box + 'a> { Box::new(TemplateFunction::new( first, Box::new(move |value| second.extract(&value)), @@ -123,7 +131,7 @@ impl<'a, I: 'a> Property<'a, I> { fn into_template(self) -> Box + 'a> { fn wrap<'a, I: 'a, O: Template<()> + 'a>( - property: Box + 'a>, + property: Box + 'a>, ) -> Box + 'a> { Box::new(FormattablePropertyTemplate::new(property)) } @@ -146,7 +154,7 @@ fn parse_method_chain<'a, I: 'a>( PropertyAndLabels(input_property, vec![]) } else { fn chain<'a, I: 'a, O: 'a>( - property: Box + 'a>, + property: Box + 'a>, parse: impl FnOnce() -> PropertyAndLabels<'a, O>, ) -> (Property<'a, I>, Vec) { let PropertyAndLabels(next_method, labels) = parse(); @@ -282,7 +290,7 @@ fn parse_boolean_commit_property<'a>( repo: RepoRef<'a>, workspace_id: &WorkspaceId, pair: Pair, -) -> Box + 'a> { +) -> Box + 'a> { let mut inner = pair.into_inner(); let pair = inner.next().unwrap(); let _method = inner.next().unwrap(); diff --git a/src/templater.rs b/src/templater.rs index 80296b1a0..b3c14b7de 100644 --- a/src/templater.rs +++ b/src/templater.rs @@ -130,8 +130,10 @@ impl<'a, C> Template for ListTemplate<'a, C> { } } -pub trait TemplateProperty { - fn extract(&self, context: &C) -> O; +pub trait TemplateProperty { + type Output; + + fn extract(&self, context: &C) -> Self::Output; } /// Adapter to drop template context. @@ -143,7 +145,9 @@ impl> Template for Literal { } } -impl TemplateProperty for Literal { +impl TemplateProperty for Literal { + type Output = O; + fn extract(&self, _context: &C) -> O { self.0.clone() } @@ -151,11 +155,11 @@ impl TemplateProperty for Literal { /// Adapter to extract context-less template value from property for displaying. pub struct FormattablePropertyTemplate<'a, C, O> { - property: Box + 'a>, + property: Box + 'a>, } impl<'a, C, O> FormattablePropertyTemplate<'a, C, O> { - pub fn new(property: Box + 'a>) -> Self { + pub fn new(property: Box + 'a>) -> Self { FormattablePropertyTemplate { property } } } @@ -172,8 +176,10 @@ where pub struct DescriptionProperty; -impl TemplateProperty for DescriptionProperty { - fn extract(&self, context: &Commit) -> String { +impl TemplateProperty for DescriptionProperty { + type Output = String; + + fn extract(&self, context: &Commit) -> Self::Output { match context.description() { s if s.is_empty() => "(no description set)\n".to_owned(), s if s.ends_with('\n') => s.to_owned(), @@ -184,16 +190,20 @@ impl TemplateProperty for DescriptionProperty { pub struct AuthorProperty; -impl TemplateProperty for AuthorProperty { - fn extract(&self, context: &Commit) -> Signature { +impl TemplateProperty for AuthorProperty { + type Output = Signature; + + fn extract(&self, context: &Commit) -> Self::Output { context.author().clone() } } pub struct CommitterProperty; -impl TemplateProperty for CommitterProperty { - fn extract(&self, context: &Commit) -> Signature { +impl TemplateProperty for CommitterProperty { + type Output = Signature; + + fn extract(&self, context: &Commit) -> Self::Output { context.committer().clone() } } @@ -202,8 +212,10 @@ pub struct WorkingCopiesProperty<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for WorkingCopiesProperty<'_> { - fn extract(&self, context: &Commit) -> String { +impl TemplateProperty for WorkingCopiesProperty<'_> { + type Output = String; + + fn extract(&self, context: &Commit) -> Self::Output { let wc_commit_ids = self.repo.view().wc_commit_ids(); if wc_commit_ids.len() <= 1 { return "".to_string(); @@ -223,8 +235,10 @@ pub struct IsWorkingCopyProperty<'a> { pub workspace_id: WorkspaceId, } -impl TemplateProperty for IsWorkingCopyProperty<'_> { - fn extract(&self, context: &Commit) -> bool { +impl TemplateProperty for IsWorkingCopyProperty<'_> { + type Output = bool; + + fn extract(&self, context: &Commit) -> Self::Output { Some(context.id()) == self.repo.view().get_wc_commit_id(&self.workspace_id) } } @@ -233,8 +247,10 @@ pub struct BranchProperty<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for BranchProperty<'_> { - fn extract(&self, context: &Commit) -> String { +impl TemplateProperty for BranchProperty<'_> { + type Output = String; + + fn extract(&self, context: &Commit) -> Self::Output { let mut names = vec![]; for (branch_name, branch_target) in self.repo.view().branches() { let local_target = branch_target.local_target.as_ref(); @@ -271,8 +287,10 @@ pub struct TagProperty<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for TagProperty<'_> { - fn extract(&self, context: &Commit) -> String { +impl TemplateProperty for TagProperty<'_> { + type Output = String; + + fn extract(&self, context: &Commit) -> Self::Output { let mut names = vec![]; for (tag_name, target) in self.repo.view().tags() { if target.has_add(context.id()) { @@ -291,8 +309,10 @@ pub struct GitRefsProperty<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for GitRefsProperty<'_> { - fn extract(&self, context: &Commit) -> String { +impl TemplateProperty for GitRefsProperty<'_> { + type Output = String; + + fn extract(&self, context: &Commit) -> Self::Output { // TODO: We should keep a map from commit to ref names so we don't have to walk // all refs here. let mut names = vec![]; @@ -319,8 +339,10 @@ impl<'a> IsGitHeadProperty<'a> { } } -impl TemplateProperty for IsGitHeadProperty<'_> { - fn extract(&self, context: &Commit) -> bool { +impl TemplateProperty for IsGitHeadProperty<'_> { + type Output = bool; + + fn extract(&self, context: &Commit) -> Self::Output { self.repo.view().git_head().as_ref() == Some(context.id()) } } @@ -350,22 +372,26 @@ impl DivergentProperty { } } -impl TemplateProperty for DivergentProperty { - fn extract(&self, context: &Commit) -> bool { +impl TemplateProperty for DivergentProperty { + type Output = bool; + + fn extract(&self, context: &Commit) -> Self::Output { self.divergent_changes.contains(context.change_id()) } } pub struct ConflictProperty; -impl TemplateProperty for ConflictProperty { - fn extract(&self, context: &Commit) -> bool { +impl TemplateProperty for ConflictProperty { + type Output = bool; + + fn extract(&self, context: &Commit) -> Self::Output { context.tree().has_conflict() } } pub struct ConditionalTemplate<'a, C> { - pub condition: Box + 'a>, + pub condition: Box + 'a>, pub true_template: Box + 'a>, pub false_template: Option + 'a>>, } @@ -373,7 +399,7 @@ pub struct ConditionalTemplate<'a, C> { // TODO: figure out why this lifetime is needed impl<'a, C> ConditionalTemplate<'a, C> { pub fn new( - condition: Box + 'a>, + condition: Box + 'a>, true_template: Box + 'a>, false_template: Option + 'a>>, ) -> Self { @@ -399,14 +425,14 @@ impl<'a, C> Template for ConditionalTemplate<'a, C> { // TODO: If needed, add a ContextualTemplateFunction where the function also // gets the context pub struct TemplateFunction<'a, C, I, O> { - pub property: Box + 'a>, + pub property: Box + 'a>, pub function: Box O + 'a>, } // TODO: figure out why this lifetime is needed impl<'a, C, I, O> TemplateFunction<'a, C, I, O> { pub fn new( - template: Box + 'a>, + template: Box + 'a>, function: Box O + 'a>, ) -> Self { TemplateFunction { @@ -416,8 +442,10 @@ impl<'a, C, I, O> TemplateFunction<'a, C, I, O> { } } -impl<'a, C, I, O> TemplateProperty for TemplateFunction<'a, C, I, O> { - fn extract(&self, context: &C) -> O { +impl<'a, C, I, O> TemplateProperty for TemplateFunction<'a, C, I, O> { + type Output = O; + + fn extract(&self, context: &C) -> Self::Output { (self.function)(self.property.extract(context)) } } @@ -473,8 +501,10 @@ pub struct CommitOrChangeIdShort<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for CommitOrChangeIdShort<'_> { - fn extract(&self, context: &CommitOrChangeId) -> String { +impl TemplateProperty for CommitOrChangeIdShort<'_> { + type Output = String; + + fn extract(&self, context: &CommitOrChangeId) -> Self::Output { context.short() } } @@ -483,32 +513,40 @@ pub struct CommitOrChangeIdShortPrefixAndBrackets<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for CommitOrChangeIdShortPrefixAndBrackets<'_> { - fn extract(&self, context: &CommitOrChangeId) -> String { +impl TemplateProperty for CommitOrChangeIdShortPrefixAndBrackets<'_> { + type Output = String; + + fn extract(&self, context: &CommitOrChangeId) -> Self::Output { context.short_prefix_and_brackets(self.repo) } } pub struct CommitIdProperty; -impl TemplateProperty for CommitIdProperty { - fn extract(&self, context: &Commit) -> CommitOrChangeId { +impl TemplateProperty for CommitIdProperty { + type Output = CommitOrChangeId; + + fn extract(&self, context: &Commit) -> Self::Output { CommitOrChangeId(context.id().to_bytes()) } } pub struct ChangeIdProperty; -impl TemplateProperty for ChangeIdProperty { - fn extract(&self, context: &Commit) -> CommitOrChangeId { +impl TemplateProperty for ChangeIdProperty { + type Output = CommitOrChangeId; + + fn extract(&self, context: &Commit) -> Self::Output { CommitOrChangeId(context.change_id().to_bytes()) } } pub struct SignatureTimestamp; -impl TemplateProperty for SignatureTimestamp { - fn extract(&self, context: &Signature) -> Timestamp { +impl TemplateProperty for SignatureTimestamp { + type Output = Timestamp; + + fn extract(&self, context: &Signature) -> Self::Output { context.timestamp.clone() } } @@ -517,8 +555,10 @@ pub struct EmptyProperty<'a> { pub repo: RepoRef<'a>, } -impl TemplateProperty for EmptyProperty<'_> { - fn extract(&self, context: &Commit) -> bool { +impl TemplateProperty for EmptyProperty<'_> { + type Output = bool; + + fn extract(&self, context: &Commit) -> Self::Output { context.tree().id() == merge_commit_trees(self.repo, &context.parents()).id() } }