diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c6d0fb..eda003b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Correctly determine the end of the line in UTF16LE/BE input #3369 (@keith-hall) - `--style=changes` no longer prints a two-space indent when the file is unmodified, see issue #2710 and PR #3406 (@jyn514) - Add missing shell completions, see #3411 (@keith-hall) +- Execute help/version/diagnostic commands even with invalid config/arguments present, see #3414 (@keith-hall) ## Other diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index b3d48cba..a8e1e0db 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -57,15 +57,30 @@ impl App { } fn matches(interactive_output: bool) -> Result { + // Check if we should skip config file processing for special arguments + // that don't require full application setup (help, version, diagnostic) + let should_skip_config = wild::args_os().any(|arg| { + matches!( + arg.to_str(), + Some("-h" | "--help" | "-V" | "--version" | "--diagnostic" | "--diagnostics") + ) + }); + let args = if wild::args_os().nth(1) == Some("cache".into()) { // Skip the config file and env vars wild::args_os().collect::>() - } else if wild::args_os().any(|arg| arg == "--no-config") { - // Skip the arguments in bats config file + } else if wild::args_os().any(|arg| arg == "--no-config") || should_skip_config { + // Skip the arguments in bats config file when --no-config is present + // or when user requests help, version, or diagnostic information let mut cli_args = wild::args_os(); - let mut args = get_args_from_env_vars(); + let mut args = if should_skip_config { + // For special commands, don't even try to load env vars that might fail + vec![] + } else { + get_args_from_env_vars() + }; // Put the zero-th CLI argument (program name) first args.insert(0, cli_args.next().unwrap()); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index f0ebef12..75021eb5 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1286,6 +1286,83 @@ fn diagnostic_sanity_check() { .stderr(""); } +#[test] +fn help_works_with_invalid_config() { + let tmp_dir = tempdir().expect("can create temporary directory"); + let tmp_config_path = tmp_dir.path().join("invalid-config.conf"); + + // Write an invalid config file + std::fs::write(&tmp_config_path, "--invalid-option").expect("can write config file"); + + // --help should work despite invalid config + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("--help") + .assert() + .success() + .stdout(predicate::str::contains( + "A cat(1) clone with syntax highlighting", + )); + + // -h should also work + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("-h") + .assert() + .success() + .stdout(predicate::str::contains("A cat(1) clone with wings")); +} + +#[test] +fn version_works_with_invalid_config() { + let tmp_dir = tempdir().expect("can create temporary directory"); + let tmp_config_path = tmp_dir.path().join("invalid-config.conf"); + + // Write an invalid config file + std::fs::write(&tmp_config_path, "--invalid-option").expect("can write config file"); + + // --version should work despite invalid config + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("--version") + .assert() + .success() + .stdout(predicate::str::contains("bat ")); + + // -V should also work + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("-V") + .assert() + .success() + .stdout(predicate::str::contains("bat ")); +} + +#[test] +fn diagnostic_works_with_invalid_config() { + let tmp_dir = tempdir().expect("can create temporary directory"); + let tmp_config_path = tmp_dir.path().join("invalid-config.conf"); + + // Write an invalid config file + std::fs::write(&tmp_config_path, "--invalid-option").expect("can write config file"); + + // --diagnostic should work despite invalid config + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("--diagnostic") + .assert() + .success() + .stdout(predicate::str::contains("#### Software version")); + + // --diagnostics (alias) should also work + bat_with_config() + .env("BAT_CONFIG_PATH", tmp_config_path.to_str().unwrap()) + .arg("--diagnostics") + .assert() + .success() + .stdout(predicate::str::contains("#### Software version")); +} + #[test] fn config_location_test() { bat_with_config()