diff --git a/src/cli_util.rs b/src/cli_util.rs index cdc2f0cbc..775a5dcfb 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -1717,7 +1717,7 @@ fn handle_early_args( } if !args.config_toml.is_empty() { layered_configs.parse_config_args(&args.config_toml)?; - ui.reset(&layered_configs.merge()); + ui.reset(&layered_configs.merge())?; } Ok(()) } @@ -1899,7 +1899,7 @@ impl CliRunner { let cwd = env::current_dir().unwrap(); // TODO: maybe map_err to CommandError? layered_configs.read_user_config()?; let config = layered_configs.merge(); - ui.reset(&config); + ui.reset(&config)?; let string_args = expand_args(&self.app, std::env::args_os(), &config)?; let (matches, args) = parse_args( ui, @@ -1915,7 +1915,7 @@ impl CliRunner { layered_configs.read_repo_config(loader.repo_path())?; } let config = layered_configs.merge(); - ui.reset(&config); + ui.reset(&config)?; let settings = UserSettings::from_config(config); let command_helper = CommandHelper::new( self.app, @@ -1932,7 +1932,8 @@ impl CliRunner { #[must_use] pub fn run(self) -> ExitCode { 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 exit_code = handle_command_result(&mut ui, result); ui.finalize_writes(); diff --git a/src/formatter.rs b/src/formatter.rs index 9ad91059e..37474afba 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -98,16 +98,20 @@ enum FormatterFactoryKind { } impl FormatterFactory { - pub fn prepare(config: &config::Config, color: bool, sanitized: bool) -> Self { + pub fn prepare( + config: &config::Config, + color: bool, + sanitized: bool, + ) -> Result { let kind = if color { - let rules = Arc::new(rules_from_config(config)); + let rules = Arc::new(rules_from_config(config)?); FormatterFactoryKind::Color { rules } } else if sanitized { FormatterFactoryKind::Sanitized } else { FormatterFactoryKind::PlainText }; - FormatterFactory { kind } + Ok(FormatterFactory { kind }) } pub fn new_formatter<'output, W: Write + 'output>( @@ -232,9 +236,9 @@ impl ColorFormatter { } } - pub fn for_config(output: W, config: &config::Config) -> ColorFormatter { - let rules = rules_from_config(config); - Self::new(output, Arc::new(rules)) + pub fn for_config(output: W, config: &config::Config) -> Result { + let rules = rules_from_config(config)?; + Ok(Self::new(output, Arc::new(rules))) } fn requested_style(&mut self) -> Style { @@ -316,53 +320,52 @@ impl ColorFormatter { } } -fn rules_from_config(config: &config::Config) -> Rules { +fn rules_from_config(config: &config::Config) -> Result { let mut result = vec![]; - if let Ok(table) = config.get_table("colors") { - for (key, value) in table { - let labels = key - .split_whitespace() - .map(ToString::to_string) - .collect_vec(); - match value.kind { - config::ValueKind::String(color_name) => { - let style = Style { - fg_color: color_for_name(&color_name), - bg_color: None, - bold: None, - underlined: None, - }; - 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)); - } - _ => {} + let table = config.get_table("colors")?; + for (key, value) in table { + let labels = key + .split_whitespace() + .map(ToString::to_string) + .collect_vec(); + match value.kind { + config::ValueKind::String(color_name) => { + let style = Style { + fg_color: color_for_name(&color_name), + bg_color: None, + bold: None, + underlined: None, + }; + 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 { @@ -540,7 +543,7 @@ mod tests { } let mut output: Vec = vec![]; 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 { formatter.push_label(&color.replace(' ', "-")).unwrap(); formatter.write_str(&format!(" {color} ")).unwrap(); @@ -577,7 +580,7 @@ mod tests { "#, ); let mut output: Vec = 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.push_label("inside").unwrap(); formatter.write_str(" inside ").unwrap(); @@ -600,7 +603,7 @@ mod tests { "#, ); let mut output: Vec = 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.write_str(" fg only ").unwrap(); formatter.pop_label().unwrap(); @@ -647,7 +650,7 @@ mod tests { "#, ); let mut output: Vec = 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.write_str(" not bold ").unwrap(); formatter.push_label("bold_font").unwrap(); @@ -668,7 +671,7 @@ mod tests { "#, ); let mut output: Vec = 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.push_label("red").unwrap(); formatter.write_str("first").unwrap(); @@ -689,7 +692,7 @@ mod tests { "#, ); let mut output: Vec = 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 .write_str("\x1b[1mnot actually bold\x1b[0m") @@ -711,7 +714,7 @@ mod tests { "#, ); let mut output: Vec = 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.push_label("outer").unwrap(); formatter.write_str(" before inner ").unwrap(); @@ -734,7 +737,7 @@ mod tests { "#, ); let mut output: Vec = 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.write_str(" not colored ").unwrap(); formatter.push_label("inner").unwrap(); @@ -756,7 +759,7 @@ mod tests { "#, ); let mut output: Vec = 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.write_str(" red before ").unwrap(); formatter.push_label("inner").unwrap(); @@ -778,7 +781,7 @@ mod tests { "#, ); let mut output: Vec = 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("inner2").unwrap(); formatter.write_str(" hello ").unwrap(); @@ -797,7 +800,7 @@ mod tests { "#, ); let mut output: Vec = 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("inner").unwrap(); formatter.write_str(" hello ").unwrap(); @@ -818,7 +821,7 @@ mod tests { "#, ); let mut output: Vec = 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.write_str(" a1 ").unwrap(); formatter.push_label("b").unwrap(); diff --git a/src/ui.rs b/src/ui.rs index 7b03141c3..7ddf1a453 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -107,29 +107,30 @@ fn pager_setting(config: &config::Config) -> FullCommandArgs { } impl Ui { - pub fn with_config(config: &config::Config) -> Ui { + pub fn with_config(config: &config::Config) -> Result { let color = use_color(color_setting(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_tty(); - let formatter_factory = FormatterFactory::prepare(config, color, sanitize); + let formatter_factory = FormatterFactory::prepare(config, color, sanitize)?; let progress_indicator = progress_indicator_setting(config); - Ui { + Ok(Ui { color, formatter_factory, pager_cmd: pager_setting(config), paginate: PaginationChoice::Auto, progress_indicator, 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.pager_cmd = pager_setting(config); self.progress_indicator = progress_indicator_setting(config); 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.