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

cli: error out if colors section isn't of map type

This commit is contained in:
Yuya Nishihara 2023-01-18 10:20:27 +09:00
parent 7b24df25e4
commit 797189b106
3 changed files with 76 additions and 71 deletions

View file

@ -1717,7 +1717,7 @@ fn handle_early_args(
} }
if !args.config_toml.is_empty() { if !args.config_toml.is_empty() {
layered_configs.parse_config_args(&args.config_toml)?; layered_configs.parse_config_args(&args.config_toml)?;
ui.reset(&layered_configs.merge()); ui.reset(&layered_configs.merge())?;
} }
Ok(()) Ok(())
} }
@ -1899,7 +1899,7 @@ impl CliRunner {
let cwd = env::current_dir().unwrap(); // TODO: maybe map_err to CommandError? let cwd = env::current_dir().unwrap(); // TODO: maybe map_err to CommandError?
layered_configs.read_user_config()?; layered_configs.read_user_config()?;
let config = layered_configs.merge(); let config = layered_configs.merge();
ui.reset(&config); ui.reset(&config)?;
let string_args = expand_args(&self.app, std::env::args_os(), &config)?; let string_args = expand_args(&self.app, std::env::args_os(), &config)?;
let (matches, args) = parse_args( let (matches, args) = parse_args(
ui, ui,
@ -1915,7 +1915,7 @@ impl CliRunner {
layered_configs.read_repo_config(loader.repo_path())?; layered_configs.read_repo_config(loader.repo_path())?;
} }
let config = layered_configs.merge(); let config = layered_configs.merge();
ui.reset(&config); ui.reset(&config)?;
let settings = UserSettings::from_config(config); let settings = UserSettings::from_config(config);
let command_helper = CommandHelper::new( let command_helper = CommandHelper::new(
self.app, self.app,
@ -1932,7 +1932,8 @@ impl CliRunner {
#[must_use] #[must_use]
pub fn run(self) -> ExitCode { pub fn run(self) -> ExitCode {
let layered_configs = LayeredConfigs::from_environment(); let layered_configs = LayeredConfigs::from_environment();
let mut ui = Ui::with_config(&layered_configs.merge()); let mut ui = Ui::with_config(&layered_configs.merge())
.expect("default config should be valid, env vars are stringly typed");
let result = self.run_internal(&mut ui, layered_configs); let result = self.run_internal(&mut ui, layered_configs);
let exit_code = handle_command_result(&mut ui, result); let exit_code = handle_command_result(&mut ui, result);
ui.finalize_writes(); ui.finalize_writes();

View file

@ -98,16 +98,20 @@ enum FormatterFactoryKind {
} }
impl FormatterFactory { impl FormatterFactory {
pub fn prepare(config: &config::Config, color: bool, sanitized: bool) -> Self { pub fn prepare(
config: &config::Config,
color: bool,
sanitized: bool,
) -> Result<Self, config::ConfigError> {
let kind = if color { let kind = if color {
let rules = Arc::new(rules_from_config(config)); let rules = Arc::new(rules_from_config(config)?);
FormatterFactoryKind::Color { rules } FormatterFactoryKind::Color { rules }
} else if sanitized { } else if sanitized {
FormatterFactoryKind::Sanitized FormatterFactoryKind::Sanitized
} else { } else {
FormatterFactoryKind::PlainText FormatterFactoryKind::PlainText
}; };
FormatterFactory { kind } Ok(FormatterFactory { kind })
} }
pub fn new_formatter<'output, W: Write + 'output>( pub fn new_formatter<'output, W: Write + 'output>(
@ -232,9 +236,9 @@ impl<W: Write> ColorFormatter<W> {
} }
} }
pub fn for_config(output: W, config: &config::Config) -> ColorFormatter<W> { pub fn for_config(output: W, config: &config::Config) -> Result<Self, config::ConfigError> {
let rules = rules_from_config(config); let rules = rules_from_config(config)?;
Self::new(output, Arc::new(rules)) Ok(Self::new(output, Arc::new(rules)))
} }
fn requested_style(&mut self) -> Style { fn requested_style(&mut self) -> Style {
@ -316,53 +320,52 @@ impl<W: Write> ColorFormatter<W> {
} }
} }
fn rules_from_config(config: &config::Config) -> Rules { fn rules_from_config(config: &config::Config) -> Result<Rules, config::ConfigError> {
let mut result = vec![]; let mut result = vec![];
if let Ok(table) = config.get_table("colors") { let table = config.get_table("colors")?;
for (key, value) in table { for (key, value) in table {
let labels = key let labels = key
.split_whitespace() .split_whitespace()
.map(ToString::to_string) .map(ToString::to_string)
.collect_vec(); .collect_vec();
match value.kind { match value.kind {
config::ValueKind::String(color_name) => { config::ValueKind::String(color_name) => {
let style = Style { let style = Style {
fg_color: color_for_name(&color_name), fg_color: color_for_name(&color_name),
bg_color: None, bg_color: None,
bold: None, bold: None,
underlined: None, underlined: None,
}; };
result.push((labels, style)); result.push((labels, style));
}
config::ValueKind::Table(style_table) => {
let mut style = Style::default();
if let Some(value) = style_table.get("fg") {
if let config::ValueKind::String(color_name) = &value.kind {
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);
}
}
if let Some(value) = style_table.get("bold") {
if let config::ValueKind::Boolean(value) = &value.kind {
style.bold = Some(*value);
}
}
if let Some(value) = style_table.get("underlined") {
if let config::ValueKind::Boolean(value) = &value.kind {
style.underlined = Some(*value);
}
}
result.push((labels, style));
}
_ => {}
} }
config::ValueKind::Table(style_table) => {
let mut style = Style::default();
if let Some(value) = style_table.get("fg") {
if let config::ValueKind::String(color_name) = &value.kind {
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);
}
}
if let Some(value) = style_table.get("bold") {
if let config::ValueKind::Boolean(value) = &value.kind {
style.bold = Some(*value);
}
}
if let Some(value) = style_table.get("underlined") {
if let config::ValueKind::Boolean(value) = &value.kind {
style.underlined = Some(*value);
}
}
result.push((labels, style));
}
_ => {}
} }
} }
result Ok(result)
} }
fn color_for_name(color_name: &str) -> Option<Color> { fn color_for_name(color_name: &str) -> Option<Color> {
@ -540,7 +543,7 @@ mod tests {
} }
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = let mut formatter =
ColorFormatter::for_config(&mut output, &config_builder.build().unwrap()); ColorFormatter::for_config(&mut output, &config_builder.build().unwrap()).unwrap();
for color in colors { for color in colors {
formatter.push_label(&color.replace(' ', "-")).unwrap(); formatter.push_label(&color.replace(' ', "-")).unwrap();
formatter.write_str(&format!(" {color} ")).unwrap(); formatter.write_str(&format!(" {color} ")).unwrap();
@ -577,7 +580,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.write_str(" before ").unwrap(); formatter.write_str(" before ").unwrap();
formatter.push_label("inside").unwrap(); formatter.push_label("inside").unwrap();
formatter.write_str(" inside ").unwrap(); formatter.write_str(" inside ").unwrap();
@ -600,7 +603,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("red_fg").unwrap(); formatter.push_label("red_fg").unwrap();
formatter.write_str(" fg only ").unwrap(); formatter.write_str(" fg only ").unwrap();
formatter.pop_label().unwrap(); formatter.pop_label().unwrap();
@ -647,7 +650,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("not_bold").unwrap(); formatter.push_label("not_bold").unwrap();
formatter.write_str(" not bold ").unwrap(); formatter.write_str(" not bold ").unwrap();
formatter.push_label("bold_font").unwrap(); formatter.push_label("bold_font").unwrap();
@ -668,7 +671,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.write_str("before").unwrap(); formatter.write_str("before").unwrap();
formatter.push_label("red").unwrap(); formatter.push_label("red").unwrap();
formatter.write_str("first").unwrap(); formatter.write_str("first").unwrap();
@ -689,7 +692,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("red").unwrap(); formatter.push_label("red").unwrap();
formatter formatter
.write_str("\x1b[1mnot actually bold\x1b[0m") .write_str("\x1b[1mnot actually bold\x1b[0m")
@ -711,7 +714,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.write_str(" before outer ").unwrap(); formatter.write_str(" before outer ").unwrap();
formatter.push_label("outer").unwrap(); formatter.push_label("outer").unwrap();
formatter.write_str(" before inner ").unwrap(); formatter.write_str(" before inner ").unwrap();
@ -734,7 +737,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("outer").unwrap(); formatter.push_label("outer").unwrap();
formatter.write_str(" not colored ").unwrap(); formatter.write_str(" not colored ").unwrap();
formatter.push_label("inner").unwrap(); formatter.push_label("inner").unwrap();
@ -756,7 +759,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("outer").unwrap(); formatter.push_label("outer").unwrap();
formatter.write_str(" red before ").unwrap(); formatter.write_str(" red before ").unwrap();
formatter.push_label("inner").unwrap(); formatter.push_label("inner").unwrap();
@ -778,7 +781,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("outer1").unwrap(); formatter.push_label("outer1").unwrap();
formatter.push_label("inner2").unwrap(); formatter.push_label("inner2").unwrap();
formatter.write_str(" hello ").unwrap(); formatter.write_str(" hello ").unwrap();
@ -797,7 +800,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("outer").unwrap(); formatter.push_label("outer").unwrap();
formatter.push_label("inner").unwrap(); formatter.push_label("inner").unwrap();
formatter.write_str(" hello ").unwrap(); formatter.write_str(" hello ").unwrap();
@ -818,7 +821,7 @@ mod tests {
"#, "#,
); );
let mut output: Vec<u8> = vec![]; let mut output: Vec<u8> = vec![];
let mut formatter = ColorFormatter::for_config(&mut output, &config); let mut formatter = ColorFormatter::for_config(&mut output, &config).unwrap();
formatter.push_label("a").unwrap(); formatter.push_label("a").unwrap();
formatter.write_str(" a1 ").unwrap(); formatter.write_str(" a1 ").unwrap();
formatter.push_label("b").unwrap(); formatter.push_label("b").unwrap();

View file

@ -107,29 +107,30 @@ fn pager_setting(config: &config::Config) -> FullCommandArgs {
} }
impl Ui { impl Ui {
pub fn with_config(config: &config::Config) -> Ui { pub fn with_config(config: &config::Config) -> Result<Ui, config::ConfigError> {
let color = use_color(color_setting(config)); let color = use_color(color_setting(config));
// Sanitize ANSI escape codes if we're printing to a terminal. Doesn't affect // Sanitize ANSI escape codes if we're printing to a terminal. Doesn't affect
// ANSI escape codes that originate from the formatter itself. // ANSI escape codes that originate from the formatter itself.
let sanitize = io::stdout().is_tty(); let sanitize = io::stdout().is_tty();
let formatter_factory = FormatterFactory::prepare(config, color, sanitize); let formatter_factory = FormatterFactory::prepare(config, color, sanitize)?;
let progress_indicator = progress_indicator_setting(config); let progress_indicator = progress_indicator_setting(config);
Ui { Ok(Ui {
color, color,
formatter_factory, formatter_factory,
pager_cmd: pager_setting(config), pager_cmd: pager_setting(config),
paginate: PaginationChoice::Auto, paginate: PaginationChoice::Auto,
progress_indicator, progress_indicator,
output: UiOutput::new_terminal(), output: UiOutput::new_terminal(),
} })
} }
pub fn reset(&mut self, config: &config::Config) { pub fn reset(&mut self, config: &config::Config) -> Result<(), config::ConfigError> {
self.color = use_color(color_setting(config)); self.color = use_color(color_setting(config));
self.pager_cmd = pager_setting(config); self.pager_cmd = pager_setting(config);
self.progress_indicator = progress_indicator_setting(config); self.progress_indicator = progress_indicator_setting(config);
let sanitize = io::stdout().is_tty(); let sanitize = io::stdout().is_tty();
self.formatter_factory = FormatterFactory::prepare(config, self.color, sanitize); self.formatter_factory = FormatterFactory::prepare(config, self.color, sanitize)?;
Ok(())
} }
/// Sets the pagination value. /// Sets the pagination value.