mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-01 00:50:57 +00:00
formatter: add wrapper that writes labeled heading once with content
This will be used to label "Error: " heading and content differently. I want to see an error message in the default (white) color because it's easier to read, but I still want to highlight the "Error: " heading. We can achieve that without introducing new wrapper, but the resulting code would look something like "writeln!(ui.error("Error: ")?, ..)?", and it would get messier if the caller had to suppress io::Error.
This commit is contained in:
parent
890a8e282f
commit
894219dd77
1 changed files with 76 additions and 1 deletions
|
@ -73,9 +73,50 @@ where
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
|
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
|
||||||
|
self.with_labeled(|formatter| formatter.write_fmt(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_labeled(
|
||||||
|
&mut self,
|
||||||
|
write_inner: impl FnOnce(&mut dyn Formatter) -> io::Result<()>,
|
||||||
|
) -> io::Result<()> {
|
||||||
self.formatter
|
self.formatter
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.with_label(self.label.as_ref(), |formatter| formatter.write_fmt(args))
|
.with_label(self.label.as_ref(), write_inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `LabeledWriter`, but also prints the `heading` once.
|
||||||
|
///
|
||||||
|
/// The `heading` will be printed within the first `write!()` or `writeln!()`
|
||||||
|
/// invocation, which is handy because `io::Error` can be handled there.
|
||||||
|
pub struct HeadingLabeledWriter<T, S, H> {
|
||||||
|
writer: LabeledWriter<T, S>,
|
||||||
|
heading: Option<H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S, H> HeadingLabeledWriter<T, S, H> {
|
||||||
|
pub fn new(formatter: T, label: S, heading: H) -> Self {
|
||||||
|
HeadingLabeledWriter {
|
||||||
|
writer: LabeledWriter::new(formatter, label),
|
||||||
|
heading: Some(heading),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, S, H> HeadingLabeledWriter<T, S, H>
|
||||||
|
where
|
||||||
|
T: BorrowMut<dyn Formatter + 'a>,
|
||||||
|
S: AsRef<str>,
|
||||||
|
H: fmt::Display,
|
||||||
|
{
|
||||||
|
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
|
||||||
|
self.writer.with_labeled(|formatter| {
|
||||||
|
if let Some(heading) = self.heading.take() {
|
||||||
|
write!(formatter.labeled("heading"), "{heading}")?;
|
||||||
|
}
|
||||||
|
formatter.write_fmt(args)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,6 +1095,40 @@ mod tests {
|
||||||
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @"[38;5;2m inside [39m");
|
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @"[38;5;2m inside [39m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_heading_labeled_writer() {
|
||||||
|
let config = config_from_string(
|
||||||
|
r#"
|
||||||
|
colors.inner = "green"
|
||||||
|
colors."inner heading" = "red"
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let mut output: Vec<u8> = vec![];
|
||||||
|
let mut formatter: Box<dyn Formatter> =
|
||||||
|
Box::new(ColorFormatter::for_config(&mut output, &config).unwrap());
|
||||||
|
HeadingLabeledWriter::new(formatter.as_mut(), "inner", "Should be noop: ");
|
||||||
|
let mut writer = HeadingLabeledWriter::new(formatter.as_mut(), "inner", "Heading: ");
|
||||||
|
write!(writer, "Message").unwrap();
|
||||||
|
writeln!(writer, " continues").unwrap();
|
||||||
|
drop(formatter);
|
||||||
|
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @r###"
|
||||||
|
[38;5;1mHeading: [38;5;2mMessage[39m[38;5;2m continues[39m
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_heading_labeled_writer_empty_string() {
|
||||||
|
let mut output: Vec<u8> = vec![];
|
||||||
|
let mut formatter: Box<dyn Formatter> = Box::new(PlainTextFormatter::new(&mut output));
|
||||||
|
let mut writer = HeadingLabeledWriter::new(formatter.as_mut(), "inner", "Heading: ");
|
||||||
|
// write_fmt() is called even if the format string is empty. I don't
|
||||||
|
// know if that's guaranteed, but let's record the current behavior.
|
||||||
|
write!(writer, "").unwrap();
|
||||||
|
write!(writer, "").unwrap();
|
||||||
|
drop(formatter);
|
||||||
|
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @"Heading: ");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_recorder() {
|
fn test_format_recorder() {
|
||||||
let mut recorder = FormatRecorder::new();
|
let mut recorder = FormatRecorder::new();
|
||||||
|
|
Loading…
Reference in a new issue