Skip to content

Commit 3d8d852

Browse files
committed
[gobby-#315] fix: preserve indexed grep unsupported flag errors
1 parent 6bf23ee commit 3d8d852

4 files changed

Lines changed: 142 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## [Unreleased]
1111

12+
## [0.9.7] — gcode
13+
14+
### Fixed
15+
16+
#### gcode
17+
18+
- **Indexed grep unsupported flags** — Unsupported grep/rg flags such as
19+
`--files-with-matches` now preserve the indexed-search error message while
20+
still allowing supported options like `-m/--max-count` after positional path
21+
filters.
22+
1223
## [0.9.6] — gcode
1324

1425
### Changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/gcode/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gobby-code"
3-
version = "0.9.6"
3+
version = "0.9.7"
44
edition = "2024"
55
rust-version = "1.88"
66
authors = ["Josh Wilhelmi <hello@gobby.ai>"]

crates/gcode/src/main.rs

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use clap::{ArgGroup, Parser, Subcommand};
1+
use clap::{ArgAction, ArgGroup, Parser, Subcommand};
22
use gobby_code::{commands, config, freshness, output, setup};
33

44
#[derive(Parser)]
@@ -221,6 +221,45 @@ enum Command {
221221
/// Unsupported: use -m/--max-count for indexed grep caps
222222
#[arg(long = "limit", hide = true, value_parser = reject_grep_limit)]
223223
_unsupported_limit: Option<String>,
224+
/// Unsupported: use raw rg for filesystem grep
225+
#[arg(short = 'l', long = "files-with-matches", hide = true, action = ArgAction::SetTrue)]
226+
unsupported_files_with_matches: bool,
227+
/// Unsupported: use raw rg for filesystem grep
228+
#[arg(short = 'L', long = "files-without-match", hide = true, action = ArgAction::SetTrue)]
229+
unsupported_files_without_match: bool,
230+
/// Unsupported: use raw rg for filesystem grep
231+
#[arg(short = 'c', long = "count", hide = true, action = ArgAction::SetTrue)]
232+
unsupported_count: bool,
233+
/// Unsupported: use raw rg for filesystem grep
234+
#[arg(short = 'o', long = "only-matching", hide = true, action = ArgAction::SetTrue)]
235+
unsupported_only_matching: bool,
236+
/// Unsupported: use raw rg for filesystem grep
237+
#[arg(short = 'v', long = "invert-match", hide = true, action = ArgAction::SetTrue)]
238+
unsupported_invert_match: bool,
239+
/// Unsupported: use raw rg for filesystem grep
240+
#[arg(short = 'w', long = "word-regexp", hide = true, action = ArgAction::SetTrue)]
241+
unsupported_word_regexp: bool,
242+
/// Unsupported: use raw rg for filesystem grep
243+
#[arg(short = 'e', long = "regexp", hide = true)]
244+
unsupported_regexp: Option<String>,
245+
/// Unsupported: use raw rg for filesystem grep
246+
#[arg(short = 'r', long = "recursive", hide = true, action = ArgAction::SetTrue)]
247+
unsupported_recursive: bool,
248+
/// Unsupported: use raw rg for filesystem grep
249+
#[arg(short = 't', long = "type", hide = true)]
250+
unsupported_type: Option<String>,
251+
/// Unsupported: use raw rg for filesystem grep
252+
#[arg(short = 'T', long = "type-not", hide = true)]
253+
unsupported_type_not: Option<String>,
254+
/// Unsupported: use raw rg for filesystem grep
255+
#[arg(short = 'P', long = "pcre2", hide = true, action = ArgAction::SetTrue)]
256+
unsupported_pcre2: bool,
257+
/// Unsupported: use raw rg for filesystem grep
258+
#[arg(short = 'U', long = "multiline", hide = true, action = ArgAction::SetTrue)]
259+
unsupported_multiline: bool,
260+
/// Unsupported: use --format json for structured indexed grep output
261+
#[arg(long = "json", hide = true, action = ArgAction::SetTrue)]
262+
unsupported_json: bool,
224263
},
225264

226265
// ── Symbol Retrieval (works in all modes) ────────────────────────
@@ -395,6 +434,55 @@ fn effective_format(explicit_format: Option<output::Format>, command: &Command)
395434
})
396435
}
397436

437+
fn reject_unsupported_grep_flags(command: &Command) -> anyhow::Result<()> {
438+
let Command::Grep {
439+
unsupported_files_with_matches,
440+
unsupported_files_without_match,
441+
unsupported_count,
442+
unsupported_only_matching,
443+
unsupported_invert_match,
444+
unsupported_word_regexp,
445+
unsupported_regexp,
446+
unsupported_recursive,
447+
unsupported_type,
448+
unsupported_type_not,
449+
unsupported_pcre2,
450+
unsupported_multiline,
451+
unsupported_json,
452+
..
453+
} = command
454+
else {
455+
return Ok(());
456+
};
457+
458+
let flag = [
459+
(*unsupported_files_with_matches).then_some("--files-with-matches"),
460+
(*unsupported_files_without_match).then_some("--files-without-match"),
461+
(*unsupported_count).then_some("--count"),
462+
(*unsupported_only_matching).then_some("--only-matching"),
463+
(*unsupported_invert_match).then_some("--invert-match"),
464+
(*unsupported_word_regexp).then_some("--word-regexp"),
465+
unsupported_regexp.as_ref().map(|_| "--regexp"),
466+
(*unsupported_recursive).then_some("--recursive"),
467+
unsupported_type.as_ref().map(|_| "--type"),
468+
unsupported_type_not.as_ref().map(|_| "--type-not"),
469+
(*unsupported_pcre2).then_some("--pcre2"),
470+
(*unsupported_multiline).then_some("--multiline"),
471+
(*unsupported_json).then_some("--json"),
472+
]
473+
.into_iter()
474+
.flatten()
475+
.next();
476+
477+
if let Some(flag) = flag {
478+
anyhow::bail!(
479+
"gcode grep is indexed search; unsupported grep/rg flag `{flag}`. Use raw `rg` for filesystem grep."
480+
);
481+
}
482+
483+
Ok(())
484+
}
485+
398486
fn dispatch_early_command<F>(
399487
cli: &Cli,
400488
format: output::Format,
@@ -491,6 +579,7 @@ fn main() -> std::process::ExitCode {
491579
fn run() -> anyhow::Result<()> {
492580
let cli = Cli::parse();
493581
let format = effective_format(cli.format, &cli.command);
582+
reject_unsupported_grep_flags(&cli.command)?;
494583

495584
// Commands that must run before Context::resolve() (work on uninitialized projects)
496585
if dispatch_early_command(&cli, format, commands::setup::run)? {
@@ -706,6 +795,19 @@ fn run() -> anyhow::Result<()> {
706795
max_count,
707796
line_number: _,
708797
_unsupported_limit: _,
798+
unsupported_files_with_matches: _,
799+
unsupported_files_without_match: _,
800+
unsupported_count: _,
801+
unsupported_only_matching: _,
802+
unsupported_invert_match: _,
803+
unsupported_word_regexp: _,
804+
unsupported_regexp: _,
805+
unsupported_recursive: _,
806+
unsupported_type: _,
807+
unsupported_type_not: _,
808+
unsupported_pcre2: _,
809+
unsupported_multiline: _,
810+
unsupported_json: _,
709811
} => {
710812
ensure_project_fresh(&ctx, cli.no_freshness)?;
711813
commands::grep::run(
@@ -1502,14 +1604,34 @@ mod tests {
15021604

15031605
#[test]
15041606
fn parse_grep_unsupported_flag_fails_before_context_resolution() {
1505-
let err = match Cli::try_parse_from(["gcode", "grep", "needle", "--files-with-matches"]) {
1506-
Ok(_) => panic!("unsupported grep flag should fail"),
1507-
Err(err) => err,
1508-
};
1607+
let cli = Cli::try_parse_from(["gcode", "grep", "needle", "--files-with-matches"])
1608+
.expect("unsupported grep flag parses for contract rejection");
1609+
let err = reject_unsupported_grep_flags(&cli.command)
1610+
.expect_err("unsupported grep flag should fail before context resolution");
1611+
1612+
assert!(
1613+
err.to_string().contains("gcode grep is indexed search"),
1614+
"unexpected error: {err}"
1615+
);
1616+
assert!(
1617+
err.to_string().contains("--files-with-matches"),
1618+
"unexpected error: {err}"
1619+
);
1620+
assert!(
1621+
err.to_string().contains("raw `rg`"),
1622+
"unexpected error: {err}"
1623+
);
1624+
}
1625+
1626+
#[test]
1627+
fn parse_grep_unsupported_flag_after_path_fails_with_indexed_search_message() {
1628+
let cli = Cli::try_parse_from(["gcode", "grep", "needle", "src", "--files-with-matches"])
1629+
.expect("unsupported grep flag after path parses for contract rejection");
1630+
let err = reject_unsupported_grep_flags(&cli.command)
1631+
.expect_err("unsupported grep flag after path should fail");
15091632

15101633
assert!(
1511-
err.to_string()
1512-
.contains("unexpected argument '--files-with-matches'"),
1634+
err.to_string().contains("gcode grep is indexed search"),
15131635
"unexpected error: {err}"
15141636
);
15151637
}

0 commit comments

Comments
 (0)