diff --git a/crates/bashkit/src/builtins/mod.rs b/crates/bashkit/src/builtins/mod.rs index 54a9c3273..419cba741 100644 --- a/crates/bashkit/src/builtins/mod.rs +++ b/crates/bashkit/src/builtins/mod.rs @@ -289,6 +289,7 @@ pub(crate) fn check_help_version( ) -> Option { for arg in args { match arg.as_str() { + "--" => break, "--help" => return Some(ExecResult::ok(help_text.to_string())), "--version" => { if let Some(ver) = version { @@ -1108,6 +1109,13 @@ mod tests { assert!(r.is_none()); } + #[test] + fn check_help_version_stops_at_option_delimiter() { + let args = vec!["--".to_string(), "--help".to_string()]; + let r = check_help_version(&args, "usage\n", Some("v1")); + assert!(r.is_none()); + } + #[test] fn check_help_version_no_match() { let args = vec!["-c".to_string(), "filter".to_string()]; diff --git a/crates/bashkit/src/builtins/rg/mod.rs b/crates/bashkit/src/builtins/rg/mod.rs index 69a55ea53..e23f0c0be 100644 --- a/crates/bashkit/src/builtins/rg/mod.rs +++ b/crates/bashkit/src/builtins/rg/mod.rs @@ -4845,6 +4845,12 @@ fn rg_option_takes_value(arg: &str) -> bool { ) } +fn rg_arg_before_delimiter(args: &[String], needle: &str) -> bool { + args.iter() + .take_while(|arg| arg.as_str() != "--") + .any(|arg| arg == needle) +} + fn rg_generate_kind(args: &[String]) -> Result> { let mut i = 0; while i < args.len() { @@ -4989,16 +4995,16 @@ impl Builtin for Rg { " -g, --glob GLOB\tinclude/exclude paths by glob (!GLOB excludes)\n", " -g, --glob GLOB\tinclude/exclude paths by glob (!GLOB excludes)\n --iglob GLOB\tcase-insensitive include/exclude path glob\n --glob-case-insensitive\tmake -g/--glob rules case-insensitive\n --no-glob-case-insensitive\tdisable case-insensitive -g/--glob rules\n", ); - if ctx.args.iter().any(|arg| arg == "-h") { + if rg_arg_before_delimiter(ctx.args, "-h") { return Ok(ExecResult::ok(help_text)); } - if ctx.args.iter().any(|arg| arg == "-V") { + if rg_arg_before_delimiter(ctx.args, "-V") { return Ok(ExecResult::ok("rg (bashkit) 0.1\n".to_string())); } if let Some(r) = super::check_help_version(ctx.args, &help_text, Some("rg (bashkit) 0.1")) { return Ok(r); } - if ctx.args.iter().any(|arg| arg == "--pcre2-version") { + if rg_arg_before_delimiter(ctx.args, "--pcre2-version") { return Ok(ExecResult::ok( "PCRE2 10.45 is available (JIT is available)\n".to_string(), )); @@ -6862,6 +6868,10 @@ mod tests { ]; const DIFF_DASH_PATTERN_FILES: &[(&str, &[u8])] = &[("/proj/dash.txt", b"-needle\nneedle\n")]; + const DIFF_DASH_FLAG_FILES: &[(&str, &[u8])] = &[( + "/proj/dash-flags.txt", + b"-h\n-V\n--help\n--version\n--pcre2-version\nneedle\n", + )]; const DIFF_PCRE2_FILES: &[(&str, &[u8])] = &[( "/proj/pcre.txt", @@ -7412,6 +7422,46 @@ mod tests { cwd: "/", output: RgDiffOutput::Exact, }, + RgDiffCase { + name: "dash delimiter treats short help as pattern", + args: &["--", "-h", "proj/dash-flags.txt"], + stdin: None, + files: DIFF_DASH_FLAG_FILES, + cwd: "/", + output: RgDiffOutput::Exact, + }, + RgDiffCase { + name: "dash delimiter treats short version as pattern", + args: &["--", "-V", "proj/dash-flags.txt"], + stdin: None, + files: DIFF_DASH_FLAG_FILES, + cwd: "/", + output: RgDiffOutput::Exact, + }, + RgDiffCase { + name: "dash delimiter treats long help as pattern", + args: &["--", "--help", "proj/dash-flags.txt"], + stdin: None, + files: DIFF_DASH_FLAG_FILES, + cwd: "/", + output: RgDiffOutput::Exact, + }, + RgDiffCase { + name: "dash delimiter treats long version as pattern", + args: &["--", "--version", "proj/dash-flags.txt"], + stdin: None, + files: DIFF_DASH_FLAG_FILES, + cwd: "/", + output: RgDiffOutput::Exact, + }, + RgDiffCase { + name: "dash delimiter treats pcre2 version as pattern", + args: &["--", "--pcre2-version", "proj/dash-flags.txt"], + stdin: None, + files: DIFF_DASH_FLAG_FILES, + cwd: "/", + output: RgDiffOutput::Exact, + }, RgDiffCase { name: "generate bash completion", args: &["--generate=complete-bash"],