diff --git a/src/templater.rs b/src/templater.rs index f19b15c44..c2ffec9b3 100644 --- a/src/templater.rs +++ b/src/templater.rs @@ -17,7 +17,7 @@ use std::io; use jujutsu_lib::backend::{Signature, Timestamp}; use crate::formatter::{FormatRecorder, Formatter, PlainTextFormatter}; -use crate::time_util; +use crate::{text_util, time_util}; pub trait Template { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>; @@ -139,18 +139,14 @@ where fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> { let mut recorder = FormatRecorder::new(); self.content.format(context, &mut recorder)?; - let mut new_line = true; - recorder.replay_with(formatter, |formatter, data| { - for line in data.split_inclusive(|&c| c == b'\n') { - if new_line && line != b"\n" { - // Prefix inherits the current labels. This is implementation detail - // and may be fixed later. - self.prefix.format(context, formatter)?; - } - formatter.write_all(line)?; - new_line = line.ends_with(b"\n"); - } - Ok(()) + text_util::write_indented(formatter, &recorder, |formatter| { + // If Template::format() returned a custom error type, we would need to + // handle template evaluation error out of this closure: + // prefix.format(context, &mut prefix_recorder)?; + // write_indented(formatter, recorded, |formatter| { + // prefix_recorder.replay(formatter) + // }) + self.prefix.format(context, formatter) }) } } diff --git a/src/text_util.rs b/src/text_util.rs index 6d4e5ff2e..41ee89d6b 100644 --- a/src/text_util.rs +++ b/src/text_util.rs @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::io; + +use crate::formatter::{FormatRecorder, Formatter}; + pub fn complete_newline(s: impl Into) -> String { let mut s = s.into(); if !s.is_empty() && !s.ends_with('\n') { @@ -19,3 +23,24 @@ pub fn complete_newline(s: impl Into) -> String { } s } + +/// Indents each line by the given prefix preserving labels. +pub fn write_indented( + formatter: &mut dyn Formatter, + recorded_content: &FormatRecorder, + mut write_prefix: impl FnMut(&mut dyn Formatter) -> io::Result<()>, +) -> io::Result<()> { + let mut new_line = true; + recorded_content.replay_with(formatter, |formatter, data| { + for line in data.split_inclusive(|&c| c == b'\n') { + if new_line && line != b"\n" { + // Prefix inherits the current labels. This is implementation detail + // and may be fixed later. + write_prefix(formatter)?; + } + formatter.write_all(line)?; + new_line = line.ends_with(b"\n"); + } + Ok(()) + }) +}