mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
cli: add ui.color = "debug"
When using `ui.color = "debug"`, changes in the output style additionally include delimiters << and >>, as well as all active labels at this point separated by ::. The output is otherwise unformatted and the delimiters and labels inherit the style of the content they apply to.
This commit is contained in:
parent
de4ea5bc5a
commit
d0a29a831d
12 changed files with 194 additions and 39 deletions
|
@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
* Conflict markers now include an explanation of what each part of the conflict
|
||||
represents.
|
||||
|
||||
* `ui.color = "debug"` prints active labels alongside the regular colored output.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
## [0.17.1] - 2024-05-07
|
||||
|
|
|
@ -2411,7 +2411,7 @@ pub struct GlobalArgs {
|
|||
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
pub struct EarlyArgs {
|
||||
/// When to colorize output (always, never, auto)
|
||||
/// When to colorize output (always, never, debug, auto)
|
||||
#[arg(long, value_name = "WHEN", global = true)]
|
||||
pub color: Option<ColorChoice>,
|
||||
/// Silence non-primary command output
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
"enum": [
|
||||
"always",
|
||||
"never",
|
||||
"debug",
|
||||
"auto"
|
||||
],
|
||||
"default": "auto"
|
||||
|
|
|
@ -132,18 +132,19 @@ pub struct FormatterFactory {
|
|||
enum FormatterFactoryKind {
|
||||
PlainText,
|
||||
Sanitized,
|
||||
Color { rules: Arc<Rules> },
|
||||
Color { rules: Arc<Rules>, debug: bool },
|
||||
}
|
||||
|
||||
impl FormatterFactory {
|
||||
pub fn prepare(
|
||||
config: &config::Config,
|
||||
debug: bool,
|
||||
color: bool,
|
||||
sanitized: bool,
|
||||
) -> Result<Self, config::ConfigError> {
|
||||
let kind = if color {
|
||||
let rules = Arc::new(rules_from_config(config)?);
|
||||
FormatterFactoryKind::Color { rules }
|
||||
FormatterFactoryKind::Color { rules, debug }
|
||||
} else if sanitized {
|
||||
FormatterFactoryKind::Sanitized
|
||||
} else {
|
||||
|
@ -159,8 +160,8 @@ impl FormatterFactory {
|
|||
match &self.kind {
|
||||
FormatterFactoryKind::PlainText => Box::new(PlainTextFormatter::new(output)),
|
||||
FormatterFactoryKind::Sanitized => Box::new(SanitizingFormatter::new(output)),
|
||||
FormatterFactoryKind::Color { rules } => {
|
||||
Box::new(ColorFormatter::new(output, rules.clone()))
|
||||
FormatterFactoryKind::Color { rules, debug } => {
|
||||
Box::new(ColorFormatter::new(output, rules.clone(), *debug))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,6 +256,7 @@ impl Style {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct ColorFormatter<W: Write> {
|
||||
output: W,
|
||||
debug: bool,
|
||||
rules: Arc<Rules>,
|
||||
/// The stack of currently applied labels. These determine the desired
|
||||
/// style.
|
||||
|
@ -265,19 +267,24 @@ pub struct ColorFormatter<W: Write> {
|
|||
}
|
||||
|
||||
impl<W: Write> ColorFormatter<W> {
|
||||
pub fn new(output: W, rules: Arc<Rules>) -> ColorFormatter<W> {
|
||||
pub fn new(output: W, rules: Arc<Rules>, debug: bool) -> ColorFormatter<W> {
|
||||
ColorFormatter {
|
||||
output,
|
||||
rules,
|
||||
debug,
|
||||
labels: vec![],
|
||||
cached_styles: HashMap::new(),
|
||||
current_style: Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_config(output: W, config: &config::Config) -> Result<Self, config::ConfigError> {
|
||||
pub fn for_config(
|
||||
output: W,
|
||||
config: &config::Config,
|
||||
debug: bool,
|
||||
) -> Result<Self, config::ConfigError> {
|
||||
let rules = rules_from_config(config)?;
|
||||
Ok(Self::new(output, Arc::new(rules)))
|
||||
Ok(Self::new(output, Arc::new(rules), debug))
|
||||
}
|
||||
|
||||
fn requested_style(&mut self) -> Style {
|
||||
|
@ -473,19 +480,43 @@ impl<W: Write> Write for ColorFormatter<W> {
|
|||
* Some tools (like `less -R`) get confused and lose coloring of lines
|
||||
after a newline.
|
||||
*/
|
||||
|
||||
for line in data.split_inclusive(|b| *b == b'\n') {
|
||||
if line.ends_with(b"\n") {
|
||||
self.write_new_style()?;
|
||||
write_sanitized(&mut self.output, &line[..line.len() - 1])?;
|
||||
write_line_exclusive(
|
||||
&mut self.output,
|
||||
&line[..line.len() - 1],
|
||||
&self.labels,
|
||||
self.debug,
|
||||
)?;
|
||||
let labels = mem::take(&mut self.labels);
|
||||
self.write_new_style()?;
|
||||
self.output.write_all(b"\n")?;
|
||||
self.labels = labels;
|
||||
} else {
|
||||
self.write_new_style()?;
|
||||
write_sanitized(&mut self.output, line)?;
|
||||
write_line_exclusive(&mut self.output, line, &self.labels, self.debug)?;
|
||||
}
|
||||
}
|
||||
|
||||
fn write_line_exclusive<W: Write>(
|
||||
output: &mut W,
|
||||
buf: &[u8],
|
||||
labels: &[String],
|
||||
debug: bool,
|
||||
) -> io::Result<()> {
|
||||
if debug {
|
||||
write!(output, "<<{}::", labels.join(" "))?;
|
||||
write_sanitized(output, buf)?;
|
||||
write!(output, ">>")?;
|
||||
} else {
|
||||
write_sanitized(output, buf)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(data.len())
|
||||
}
|
||||
|
||||
|
@ -699,7 +730,8 @@ mod tests {
|
|||
}
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter =
|
||||
ColorFormatter::for_config(&mut output, &config_builder.build().unwrap()).unwrap();
|
||||
ColorFormatter::for_config(&mut output, &config_builder.build().unwrap(), false)
|
||||
.unwrap();
|
||||
for color in colors {
|
||||
formatter.push_label(&color.replace(' ', "-")).unwrap();
|
||||
write!(formatter, " {color} ").unwrap();
|
||||
|
@ -744,7 +776,8 @@ mod tests {
|
|||
}
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter =
|
||||
ColorFormatter::for_config(&mut output, &config_builder.build().unwrap()).unwrap();
|
||||
ColorFormatter::for_config(&mut output, &config_builder.build().unwrap(), false)
|
||||
.unwrap();
|
||||
for [label, _] in labels_and_colors {
|
||||
formatter.push_label(&label.replace(' ', "-")).unwrap();
|
||||
write!(formatter, " {label} ").unwrap();
|
||||
|
@ -769,7 +802,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
write!(formatter, " before ").unwrap();
|
||||
formatter.push_label("inside").unwrap();
|
||||
write!(formatter, " inside ").unwrap();
|
||||
|
@ -793,7 +826,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("red_fg").unwrap();
|
||||
write!(formatter, " fg only ").unwrap();
|
||||
formatter.pop_label().unwrap();
|
||||
|
@ -841,7 +874,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("not_bold").unwrap();
|
||||
write!(formatter, " not bold ").unwrap();
|
||||
formatter.push_label("bold_font").unwrap();
|
||||
|
@ -863,7 +896,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
write!(formatter, "before").unwrap();
|
||||
formatter.push_label("red").unwrap();
|
||||
write!(formatter, "first").unwrap();
|
||||
|
@ -885,7 +918,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("red").unwrap();
|
||||
write!(formatter, "\x1b[1mnot actually bold\x1b[0m").unwrap();
|
||||
formatter.pop_label().unwrap();
|
||||
|
@ -906,7 +939,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
write!(formatter, " before outer ").unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
write!(formatter, " before inner ").unwrap();
|
||||
|
@ -930,7 +963,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
write!(formatter, " not colored ").unwrap();
|
||||
formatter.push_label("inner").unwrap();
|
||||
|
@ -953,7 +986,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let err = ColorFormatter::for_config(&mut output, &config)
|
||||
let err = ColorFormatter::for_config(&mut output, &config, false)
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
insta::assert_snapshot!(err,
|
||||
|
@ -970,7 +1003,7 @@ mod tests {
|
|||
"##,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let err = ColorFormatter::for_config(&mut output, &config)
|
||||
let err = ColorFormatter::for_config(&mut output, &config, false)
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
insta::assert_snapshot!(err,
|
||||
|
@ -989,7 +1022,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
write!(formatter, "Blue on yellow, ").unwrap();
|
||||
formatter.push_label("default_fg").unwrap();
|
||||
|
@ -1018,7 +1051,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("outer1").unwrap();
|
||||
formatter.push_label("inner2").unwrap();
|
||||
write!(formatter, " hello ").unwrap();
|
||||
|
@ -1038,7 +1071,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
formatter.push_label("inner").unwrap();
|
||||
write!(formatter, " hello ").unwrap();
|
||||
|
@ -1060,7 +1093,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("a").unwrap();
|
||||
write!(formatter, " a1 ").unwrap();
|
||||
formatter.push_label("b").unwrap();
|
||||
|
@ -1087,7 +1120,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
formatter.push_label("inner").unwrap();
|
||||
write!(formatter, " inside ").unwrap();
|
||||
|
@ -1095,6 +1128,26 @@ mod tests {
|
|||
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @"[38;5;2m inside [39m");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_color_formatter_debug() {
|
||||
// Behaves like the color formatter, but surrounds each write with <<...>>,
|
||||
// adding the active labels before the actual content separated by a ::.
|
||||
let config = config_from_string(
|
||||
r#"
|
||||
colors.outer = "green"
|
||||
"#,
|
||||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, true).unwrap();
|
||||
formatter.push_label("outer").unwrap();
|
||||
formatter.push_label("inner").unwrap();
|
||||
write!(formatter, " inside ").unwrap();
|
||||
formatter.pop_label().unwrap();
|
||||
formatter.pop_label().unwrap();
|
||||
drop(formatter);
|
||||
insta::assert_snapshot!(String::from_utf8(output).unwrap(), @"[38;5;2m<<outer inner:: inside >>[39m");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_heading_labeled_writer() {
|
||||
let config = config_from_string(
|
||||
|
@ -1105,7 +1158,7 @@ mod tests {
|
|||
);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter: Box<dyn Formatter> =
|
||||
Box::new(ColorFormatter::for_config(&mut output, &config).unwrap());
|
||||
Box::new(ColorFormatter::for_config(&mut output, &config, false).unwrap());
|
||||
HeadingLabeledWriter::new(formatter.as_mut(), "inner", "Should be noop: ");
|
||||
let mut writer = HeadingLabeledWriter::new(formatter.as_mut(), "inner", "Heading: ");
|
||||
write!(writer, "Message").unwrap();
|
||||
|
@ -1146,7 +1199,7 @@ mod tests {
|
|||
// Replayed output should be labeled.
|
||||
let config = config_from_string(r#" colors.inner = "red" "#);
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
recorder.replay(&mut formatter).unwrap();
|
||||
drop(formatter);
|
||||
insta::assert_snapshot!(
|
||||
|
@ -1155,7 +1208,7 @@ mod tests {
|
|||
|
||||
// Replayed output should be split at push/pop_label() call.
|
||||
let mut output: Vec<u8> = vec![];
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
recorder
|
||||
.replay_with(&mut formatter, |formatter, range| {
|
||||
let data = &recorder.data()[range];
|
||||
|
|
|
@ -1292,7 +1292,8 @@ mod tests {
|
|||
fn render_ok(&self, template: &str) -> String {
|
||||
let template = self.parse(template).unwrap();
|
||||
let mut output = Vec::new();
|
||||
let mut formatter = ColorFormatter::new(&mut output, self.color_rules.clone().into());
|
||||
let mut formatter =
|
||||
ColorFormatter::new(&mut output, self.color_rules.clone().into(), false);
|
||||
template.format(&(), &mut formatter).unwrap();
|
||||
drop(formatter);
|
||||
String::from_utf8(output).unwrap()
|
||||
|
|
|
@ -275,7 +275,7 @@ mod tests {
|
|||
.build()
|
||||
.unwrap();
|
||||
let mut output = Vec::new();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
|
||||
let mut formatter = ColorFormatter::for_config(&mut output, &config, false).unwrap();
|
||||
write(&mut formatter).unwrap();
|
||||
drop(formatter);
|
||||
String::from_utf8(output).unwrap()
|
||||
|
|
|
@ -179,6 +179,7 @@ fn progress_indicator_setting(config: &config::Config) -> bool {
|
|||
pub enum ColorChoice {
|
||||
Always,
|
||||
Never,
|
||||
Debug,
|
||||
#[default]
|
||||
Auto,
|
||||
}
|
||||
|
@ -190,6 +191,7 @@ impl FromStr for ColorChoice {
|
|||
match s {
|
||||
"always" => Ok(ColorChoice::Always),
|
||||
"never" => Ok(ColorChoice::Never),
|
||||
"debug" => Ok(ColorChoice::Debug),
|
||||
"auto" => Ok(ColorChoice::Auto),
|
||||
_ => Err("must be one of always, never, or auto"),
|
||||
}
|
||||
|
@ -201,6 +203,7 @@ impl fmt::Display for ColorChoice {
|
|||
let s = match self {
|
||||
ColorChoice::Always => "always",
|
||||
ColorChoice::Never => "never",
|
||||
ColorChoice::Debug => "debug",
|
||||
ColorChoice::Auto => "auto",
|
||||
};
|
||||
write!(f, "{s}")
|
||||
|
@ -215,10 +218,15 @@ fn color_setting(config: &config::Config) -> ColorChoice {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn debug_color(choice: ColorChoice) -> bool {
|
||||
matches!(choice, ColorChoice::Debug)
|
||||
}
|
||||
|
||||
fn use_color(choice: ColorChoice) -> bool {
|
||||
match choice {
|
||||
ColorChoice::Always => true,
|
||||
ColorChoice::Never => false,
|
||||
ColorChoice::Debug => true,
|
||||
ColorChoice::Auto => io::stdout().is_terminal(),
|
||||
}
|
||||
}
|
||||
|
@ -249,12 +257,14 @@ fn pager_setting(config: &config::Config) -> Result<CommandNameAndArgs, CommandE
|
|||
|
||||
impl Ui {
|
||||
pub fn with_config(config: &config::Config) -> Result<Ui, CommandError> {
|
||||
let color = use_color(color_setting(config));
|
||||
let color = color_setting(config);
|
||||
let debug = debug_color(color);
|
||||
let color = use_color(color);
|
||||
let quiet = be_quiet(config);
|
||||
// Sanitize ANSI escape codes if we're printing to a terminal. Doesn't affect
|
||||
// ANSI escape codes that originate from the formatter itself.
|
||||
let sanitize = io::stdout().is_terminal();
|
||||
let formatter_factory = FormatterFactory::prepare(config, color, sanitize)?;
|
||||
let formatter_factory = FormatterFactory::prepare(config, debug, color, sanitize)?;
|
||||
let progress_indicator = progress_indicator_setting(config);
|
||||
Ok(Ui {
|
||||
color,
|
||||
|
@ -268,13 +278,15 @@ impl Ui {
|
|||
}
|
||||
|
||||
pub fn reset(&mut self, config: &config::Config) -> Result<(), CommandError> {
|
||||
self.color = use_color(color_setting(config));
|
||||
let color = color_setting(config);
|
||||
let debug = debug_color(color);
|
||||
self.color = use_color(color);
|
||||
self.quiet = be_quiet(config);
|
||||
self.paginate = pagination_setting(config)?;
|
||||
self.pager_cmd = pager_setting(config)?;
|
||||
self.progress_indicator = progress_indicator_setting(config);
|
||||
let sanitize = io::stdout().is_terminal();
|
||||
self.formatter_factory = FormatterFactory::prepare(config, self.color, sanitize)?;
|
||||
self.formatter_factory = FormatterFactory::prepare(config, debug, self.color, sanitize)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ To get started, see the tutorial at https://github.com/martinvonz/jj/blob/main/d
|
|||
|
||||
Possible values: `true`, `false`
|
||||
|
||||
* `--color <WHEN>` — When to colorize output (always, never, auto)
|
||||
* `--color <WHEN>` — When to colorize output (always, never, debug, auto)
|
||||
* `--quiet` — Silence non-primary command output
|
||||
|
||||
Possible values: `true`, `false`
|
||||
|
|
|
@ -360,6 +360,75 @@ fn test_log_builtin_templates_colored() {
|
|||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_builtin_templates_colored_debug() {
|
||||
let test_env = TestEnvironment::default();
|
||||
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
|
||||
let repo_path = test_env.env_root().join("repo");
|
||||
let render =
|
||||
|template| test_env.jj_cmd_success(&repo_path, &["--color=debug", "log", "-T", template]);
|
||||
|
||||
test_env.jj_cmd_ok(
|
||||
&repo_path,
|
||||
&[
|
||||
"--config-toml=user.email=''",
|
||||
"--config-toml=user.name=''",
|
||||
"new",
|
||||
],
|
||||
);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "my-branch"]);
|
||||
|
||||
insta::assert_snapshot!(render(r#"builtin_log_oneline"#), @r###"
|
||||
<<node::@>> [1m[38;5;13m<<log working_copy change_id shortest prefix::r>>[38;5;8m<<log working_copy change_id shortest rest::lvkpnrz>>[39m<<log working_copy:: >>[38;5;9m<<log working_copy email placeholder::(no email set)>>[39m<<log working_copy:: >>[38;5;14m<<log working_copy committer timestamp local format::2001-02-03 08:05:08>>[39m<<log working_copy:: >>[38;5;13m<<log working_copy branches name::my-branch>>[39m<<log working_copy:: >>[38;5;12m<<log working_copy commit_id shortest prefix::d>>[38;5;8m<<log working_copy commit_id shortest rest::c315397>>[39m<<log working_copy:: >>[38;5;10m<<log working_copy empty::(empty)>>[39m<<log working_copy:: >>[38;5;10m<<log working_copy empty description placeholder::(no description set)>>[39m<<log working_copy::>>[0m
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::q>>[0m[38;5;8m<<log change_id shortest rest::pvuntsm>>[39m<<log:: >>[38;5;3m<<log author username::test.user>>[39m<<log:: >>[38;5;6m<<log committer timestamp local format::2001-02-03 08:05:07>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::2>>[0m[38;5;8m<<log commit_id shortest rest::30dd059>>[39m<<log:: >>[38;5;2m<<log empty::(empty)>>[39m<<log:: >>[38;5;2m<<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::z>>[0m[38;5;8m<<log change_id shortest rest::zzzzzzz>>[39m<<log:: >>[38;5;2m<<log root::root()>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::0>>[0m[38;5;8m<<log commit_id shortest rest::0000000>>[39m<<log::>>
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render(r#"builtin_log_compact"#), @r###"
|
||||
<<node::@>> [1m[38;5;13m<<log working_copy change_id shortest prefix::r>>[38;5;8m<<log working_copy change_id shortest rest::lvkpnrz>>[39m<<log working_copy:: >>[38;5;9m<<log working_copy email placeholder::(no email set)>>[39m<<log working_copy:: >>[38;5;14m<<log working_copy committer timestamp local format::2001-02-03 08:05:08>>[39m<<log working_copy:: >>[38;5;13m<<log working_copy branches name::my-branch>>[39m<<log working_copy:: >>[38;5;12m<<log working_copy commit_id shortest prefix::d>>[38;5;8m<<log working_copy commit_id shortest rest::c315397>>[39m<<log working_copy::>>[0m
|
||||
│ [1m[38;5;10m<<log working_copy empty::(empty)>>[39m<<log working_copy:: >>[38;5;10m<<log working_copy empty description placeholder::(no description set)>>[39m<<log working_copy::>>[0m
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::q>>[0m[38;5;8m<<log change_id shortest rest::pvuntsm>>[39m<<log:: >>[38;5;3m<<log author email::test.user@example.com>>[39m<<log:: >>[38;5;6m<<log committer timestamp local format::2001-02-03 08:05:07>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::2>>[0m[38;5;8m<<log commit_id shortest rest::30dd059>>[39m<<log::>>
|
||||
│ [38;5;2m<<log empty::(empty)>>[39m<<log:: >>[38;5;2m<<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::z>>[0m[38;5;8m<<log change_id shortest rest::zzzzzzz>>[39m<<log:: >>[38;5;2m<<log root::root()>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::0>>[0m[38;5;8m<<log commit_id shortest rest::0000000>>[39m<<log::>>
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render(r#"builtin_log_comfortable"#), @r###"
|
||||
<<node::@>> [1m[38;5;13m<<log working_copy change_id shortest prefix::r>>[38;5;8m<<log working_copy change_id shortest rest::lvkpnrz>>[39m<<log working_copy:: >>[38;5;9m<<log working_copy email placeholder::(no email set)>>[39m<<log working_copy:: >>[38;5;14m<<log working_copy committer timestamp local format::2001-02-03 08:05:08>>[39m<<log working_copy:: >>[38;5;13m<<log working_copy branches name::my-branch>>[39m<<log working_copy:: >>[38;5;12m<<log working_copy commit_id shortest prefix::d>>[38;5;8m<<log working_copy commit_id shortest rest::c315397>>[39m<<log working_copy::>>[0m
|
||||
│ [1m[38;5;10m<<log working_copy empty::(empty)>>[39m<<log working_copy:: >>[38;5;10m<<log working_copy empty description placeholder::(no description set)>>[39m<<log working_copy::>>[0m
|
||||
│ <<log::>>
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::q>>[0m[38;5;8m<<log change_id shortest rest::pvuntsm>>[39m<<log:: >>[38;5;3m<<log author email::test.user@example.com>>[39m<<log:: >>[38;5;6m<<log committer timestamp local format::2001-02-03 08:05:07>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::2>>[0m[38;5;8m<<log commit_id shortest rest::30dd059>>[39m<<log::>>
|
||||
│ [38;5;2m<<log empty::(empty)>>[39m<<log:: >>[38;5;2m<<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
│ <<log::>>
|
||||
<<node::◉>> [1m[38;5;5m<<log change_id shortest prefix::z>>[0m[38;5;8m<<log change_id shortest rest::zzzzzzz>>[39m<<log:: >>[38;5;2m<<log root::root()>>[39m<<log:: >>[1m[38;5;4m<<log commit_id shortest prefix::0>>[0m[38;5;8m<<log commit_id shortest rest::0000000>>[39m<<log::>>
|
||||
<<log::>>
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render(r#"builtin_log_detailed"#), @r###"
|
||||
<<node::@>> <<log::Commit ID: >>[38;5;4m<<log commit_id::dc31539712c7294d1d712cec63cef4504b94ca74>>[39m<<log::>>
|
||||
│ <<log::Change ID: >>[38;5;5m<<log change_id::rlvkpnrzqnoowoytxnquwvuryrwnrmlp>>[39m<<log::>>
|
||||
│ <<log::Branches: >>[38;5;5m<<log local_branches name::my-branch>>[39m<<log::>>
|
||||
│ <<log::Author: >>[38;5;1m<<log name placeholder::(no name set)>>[39m<<log:: <>>[38;5;1m<<log email placeholder::(no email set)>>[39m<<log::>>><<log:: (>>[38;5;6m<<log author timestamp local format::2001-02-03 08:05:08>>[39m<<log::)>><<log::>>
|
||||
│ <<log::Committer: >>[38;5;1m<<log name placeholder::(no name set)>>[39m<<log:: <>>[38;5;1m<<log email placeholder::(no email set)>>[39m<<log::>>><<log:: (>>[38;5;6m<<log committer timestamp local format::2001-02-03 08:05:08>>[39m<<log::)>><<log::>>
|
||||
│ <<log::>>
|
||||
│ [38;5;2m<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
│ <<log::>>
|
||||
<<node::◉>> <<log::Commit ID: >>[38;5;4m<<log commit_id::230dd059e1b059aefc0da06a2e5a7dbf22362f22>>[39m<<log::>>
|
||||
│ <<log::Change ID: >>[38;5;5m<<log change_id::qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu>>[39m<<log::>>
|
||||
│ <<log::Author: >><<log author name::Test User>><<log:: <>>[38;5;3m<<log author email::test.user@example.com>>[39m<<log::>>><<log:: (>>[38;5;6m<<log author timestamp local format::2001-02-03 08:05:07>>[39m<<log::)>><<log::>>
|
||||
│ <<log::Committer: >><<log committer name::Test User>><<log:: <>>[38;5;3m<<log committer email::test.user@example.com>>[39m<<log::>>><<log:: (>>[38;5;6m<<log committer timestamp local format::2001-02-03 08:05:07>>[39m<<log::)>><<log::>>
|
||||
│ <<log::>>
|
||||
│ [38;5;2m<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
│ <<log::>>
|
||||
<<node::◉>> <<log::Commit ID: >>[38;5;4m<<log commit_id::0000000000000000000000000000000000000000>>[39m<<log::>>
|
||||
<<log::Change ID: >>[38;5;5m<<log change_id::zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz>>[39m<<log::>>
|
||||
<<log::Author: >>[38;5;1m<<log name placeholder::(no name set)>>[39m<<log:: <>>[38;5;1m<<log email placeholder::(no email set)>>[39m<<log::>>><<log:: (>>[38;5;6m<<log author timestamp local format::1970-01-01 11:00:00>>[39m<<log::)>><<log::>>
|
||||
<<log::Committer: >>[38;5;1m<<log name placeholder::(no name set)>>[39m<<log:: <>>[38;5;1m<<log email placeholder::(no email set)>>[39m<<log::>>><<log:: (>>[38;5;6m<<log committer timestamp local format::1970-01-01 11:00:00>>[39m<<log::)>><<log::>>
|
||||
<<log::>>
|
||||
[38;5;2m<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>>[39m<<log::>>
|
||||
<<log::>>
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_obslog_divergence() {
|
||||
let test_env = TestEnvironment::default();
|
||||
|
|
|
@ -486,6 +486,14 @@ fn test_color_ui_messages() {
|
|||
[39m [1m[38;5;5mq[0m[38;5;8mpvuntsm[39m [1m[38;5;4m2[0m[38;5;8m30dd059[39m [38;5;2m(empty)[39m [38;5;2m(no description set)[39m[39m
|
||||
[1m[38;5;6mHint: [0m[39mPrefix the expression with 'all:' to allow any number of revisions (i.e. 'all:..').[39m
|
||||
"###);
|
||||
|
||||
// debugging colors
|
||||
let (stdout, _stderr) = test_env.jj_cmd_ok(&repo_path, &["st", "--color", "debug"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
<<::The working copy is clean>>
|
||||
<<::Working copy : >>[1m[38;5;13m<<working_copy change_id shortest prefix::m>>[38;5;8m<<working_copy change_id shortest rest::zvwutvl>>[39m<<working_copy:: >>[38;5;12m<<working_copy commit_id shortest prefix::1>>[38;5;8m<<working_copy commit_id shortest rest::67f90e7>>[39m<<working_copy:: >>[38;5;10m<<working_copy empty::(empty)>>[39m<<working_copy:: >>[38;5;10m<<working_copy empty description placeholder::(no description set)>>[0m<<::>>
|
||||
<<::Parent commit: >>[1m[38;5;5m<<change_id shortest prefix::q>>[0m[38;5;8m<<change_id shortest rest::pvuntsm>>[39m<<:: >>[1m[38;5;4m<<commit_id shortest prefix::2>>[0m[38;5;8m<<commit_id shortest rest::30dd059>>[39m<<:: >>[38;5;2m<<empty::(empty)>>[39m<<:: >>[38;5;2m<<empty description placeholder::(no description set)>>[39m<<::>>
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -595,7 +603,7 @@ fn test_help() {
|
|||
--ignore-immutable Allow rewriting immutable commits
|
||||
--at-operation <AT_OPERATION> Operation to load the repo at [default: @] [aliases: at-op]
|
||||
--debug Enable debug logging
|
||||
--color <WHEN> When to colorize output (always, never, auto)
|
||||
--color <WHEN> When to colorize output (always, never, debug, auto)
|
||||
--quiet Silence non-primary command output
|
||||
--no-pager Disable the pager
|
||||
--config-toml <TOML> Additional configuration options (can be repeated)
|
||||
|
|
|
@ -1161,6 +1161,14 @@ fn test_graph_template_color() {
|
|||
│ [38;5;1mthird line[39m
|
||||
◉
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["--color=debug", "log", "-T", template]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
<<node::@>> [1m[38;5;2m<<log working_copy description::single line>>[0m
|
||||
<<node::◉>> [38;5;1m<<log description::first line>>[39m
|
||||
│ [38;5;1m<<log description::second line>>[39m
|
||||
│ [38;5;1m<<log description::third line>>[39m
|
||||
<<node::◉>>
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -80,8 +80,9 @@ Don't forget to change these to your own details!
|
|||
|
||||
### Colorizing output
|
||||
|
||||
Possible values are `always`, `never` and `auto` (default: `auto`).
|
||||
`auto` will use color only when writing to a terminal.
|
||||
Possible values are `always`, `never`, `debug` and `auto` (default: `auto`).
|
||||
`auto` will use color only when writing to a terminal. `debug` will print the
|
||||
active labels alongside the regular colorized output.
|
||||
|
||||
This setting overrides the `NO_COLOR` environment variable (if set).
|
||||
|
||||
|
|
Loading…
Reference in a new issue