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

formatter: add support for setting background color

This commit is contained in:
Martin von Zweigbergk 2023-01-07 09:34:15 -08:00 committed by Martin von Zweigbergk
parent 138798ce0a
commit 3b4ed096d0
2 changed files with 72 additions and 7 deletions

View file

@ -42,6 +42,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* The `ui.relative-timestamps` option now also affects `jj op log`.
* Background colors are now supported. You can set e.g.
`color.error = { bg = "red" }` in your `~/.jjconfig.toml`.
### Fixed bugs
* When sharing the working copy with a Git repo, we used to forget to export

View file

@ -19,7 +19,7 @@ use std::sync::Arc;
use std::{fmt, io};
use crossterm::queue;
use crossterm::style::{Attribute, Color, SetAttribute, SetForegroundColor};
use crossterm::style::{Attribute, Color, SetAttribute, SetBackgroundColor, SetForegroundColor};
use itertools::Itertools;
// Lets the caller label strings and translates the labels to colors
@ -153,11 +153,13 @@ impl<W: Write> Formatter for PlainTextFormatter<W> {
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Style {
pub fg_color: Option<Color>,
pub bg_color: Option<Color>,
}
impl Style {
fn merge(&mut self, other: &Style) {
self.fg_color = other.fg_color.or(self.fg_color);
self.bg_color = other.bg_color.or(self.bg_color);
}
}
@ -236,10 +238,18 @@ impl<W: Write> ColorFormatter<W> {
} else if !is_bright(&new_style.fg_color) && is_bright(&self.current_style.fg_color) {
queue!(self.output, SetAttribute(Attribute::Reset))?;
}
queue!(
self.output,
SetForegroundColor(new_style.fg_color.unwrap_or(Color::Reset))
)?;
if new_style.fg_color != self.current_style.fg_color {
queue!(
self.output,
SetForegroundColor(new_style.fg_color.unwrap_or(Color::Reset))
)?;
}
if new_style.bg_color != self.current_style.bg_color {
queue!(
self.output,
SetBackgroundColor(new_style.bg_color.unwrap_or(Color::Reset))
)?;
}
self.current_style = new_style;
}
Ok(())
@ -272,6 +282,7 @@ fn rules_from_config(config: &config::Config) -> HashMap<Vec<String>, Style> {
config::ValueKind::String(color_name) => {
let style = Style {
fg_color: color_for_name(&color_name),
bg_color: None,
};
result.insert(labels, style);
}
@ -282,6 +293,11 @@ fn rules_from_config(config: &config::Config) -> HashMap<Vec<String>, Style> {
style.fg_color = color_for_name(color_name);
}
}
if let Some(value) = style_table.get("bg") {
if let config::ValueKind::String(color_name) = &value.kind {
style.bg_color = color_for_name(color_name);
}
}
result.insert(labels, style);
}
_ => {}
@ -435,10 +451,13 @@ mod tests {
#[test]
fn test_color_formatter_attributes() {
// Test that each attribute of the style can be set.
// Test that each attribute of the style can be set and that they can be
// combined in a single rule or by using multiple rules.
let config = config_from_string(
r#"
colors.red_fg = { fg = "red" }
colors.blue_bg = { bg = "blue" }
colors.multiple = { fg = "green", bg = "yellow" }
"#,
);
let mut output: Vec<u8> = vec![];
@ -446,7 +465,50 @@ mod tests {
formatter.add_label("red_fg").unwrap();
formatter.write_str(" fg only ").unwrap();
formatter.remove_label().unwrap();
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @" fg only ");
formatter.write_str("\n").unwrap();
formatter.add_label("blue_bg").unwrap();
formatter.write_str(" bg only ").unwrap();
formatter.remove_label().unwrap();
formatter.write_str("\n").unwrap();
formatter.add_label("multiple").unwrap();
formatter.write_str(" single rule ").unwrap();
formatter.remove_label().unwrap();
formatter.write_str("\n").unwrap();
formatter.add_label("red_fg").unwrap();
formatter.add_label("blue_bg").unwrap();
formatter.write_str(" two rules ").unwrap();
formatter.remove_label().unwrap();
formatter.remove_label().unwrap();
formatter.write_str("\n").unwrap();
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @r###"
 fg only 
 bg only 
 single rule 
 two rules 
"###);
}
#[test]
fn test_color_formatter_bold_reset() {
// Test that we don't lose other attributes when we reset the bold attribute.
// TODO: Actually use bold instead of bright when we support that
let config = config_from_string(
r#"
colors.not_bold = { fg = "red", bg = "blue" }
colors.bold_font = { fg = "bright red" }
"#,
);
let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config);
formatter.add_label("not_bold").unwrap();
formatter.write_str(" not bold ").unwrap();
formatter.add_label("bold_font").unwrap();
formatter.write_str(" bold ").unwrap();
formatter.remove_label().unwrap();
formatter.write_str(" not bold again ").unwrap();
formatter.remove_label().unwrap();
// TODO: This loses the blue background when we reset the bold attribute.
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @" not bold  bold  not bold again ");
}
#[test]