diff --git a/src/commands/operation.rs b/src/commands/operation.rs index d9e6b0cea..655530b88 100644 --- a/src/commands/operation.rs +++ b/src/commands/operation.rs @@ -103,6 +103,10 @@ fn cmd_op_log( } Ok(()) } + + fn has_content(&self, _: &Operation) -> bool { + true + } } let template = OpTemplate { relative_timestamps: command.settings().relative_timestamps(), diff --git a/src/templater.rs b/src/templater.rs index 7668e536f..2c2ca7097 100644 --- a/src/templater.rs +++ b/src/templater.rs @@ -25,12 +25,18 @@ use crate::time_util; pub trait Template { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>; + /// Returns true if `format()` will generate output other than labels. + fn has_content(&self, context: &C) -> bool; } impl + ?Sized> Template for Box { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> { >::format(self, context, formatter) } + + fn has_content(&self, context: &C) -> bool { + >::has_content(self, context) + } } impl Template<()> for Signature { @@ -41,24 +47,40 @@ impl Template<()> for Signature { write!(formatter, ">")?; Ok(()) } + + fn has_content(&self, _: &()) -> bool { + true + } } impl Template<()> for String { fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> { formatter.write_str(self) } + + fn has_content(&self, _: &()) -> bool { + !self.is_empty() + } } impl Template<()> for Timestamp { fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> { formatter.write_str(&time_util::format_absolute_timestamp(self)) } + + fn has_content(&self, _: &()) -> bool { + true + } } impl Template<()> for bool { fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> { formatter.write_str(if *self { "true" } else { "false" }) } + + fn has_content(&self, _: &()) -> bool { + true + } } pub struct LabelTemplate { @@ -92,6 +114,10 @@ where } Ok(()) } + + fn has_content(&self, context: &C) -> bool { + self.content.has_content(context) + } } pub struct ListTemplate(pub Vec); @@ -103,6 +129,10 @@ impl> Template for ListTemplate { } Ok(()) } + + fn has_content(&self, context: &C) -> bool { + self.0.iter().any(|template| template.has_content(context)) + } } pub trait TemplateProperty { @@ -126,6 +156,10 @@ impl> Template for Literal { fn format(&self, _context: &C, formatter: &mut dyn Formatter) -> io::Result<()> { self.0.format(&(), formatter) } + + fn has_content(&self, _context: &C) -> bool { + self.0.has_content(&()) + } } impl TemplateProperty for Literal { @@ -171,6 +205,11 @@ where let template = self.property.extract(context); template.format(&(), formatter) } + + fn has_content(&self, context: &C) -> bool { + let template = self.property.extract(context); + template.has_content(&()) + } } /// Adapter to turn template back to string property. @@ -367,6 +406,16 @@ where } Ok(()) } + + fn has_content(&self, context: &C) -> bool { + if self.condition.extract(context) { + self.true_template.has_content(context) + } else if let Some(false_template) = &self.false_template { + false_template.has_content(context) + } else { + false + } + } } // TODO: If needed, add a ContextualTemplateFunction where the function also @@ -459,6 +508,10 @@ impl Template<()> for CommitOrChangeId<'_> { fn format(&self, _: &(), formatter: &mut dyn Formatter) -> io::Result<()> { formatter.write_str(&self.hex()) } + + fn has_content(&self, _: &()) -> bool { + !self.id_bytes.is_empty() + } } /// This function supports short `total_len` by ensuring that the entire @@ -517,4 +570,8 @@ impl Template<()> for IdWithHighlightedPrefix { formatter.with_label("prefix", |fmt| fmt.write_str(&self.prefix))?; formatter.with_label("rest", |fmt| fmt.write_str(&self.rest)) } + + fn has_content(&self, _: &()) -> bool { + !self.prefix.is_empty() || !self.rest.is_empty() + } }