Repository navigation
feat: surface file:line anchors for symbols (find, grep --symbols, show, for/context) - #16
Conversation
slice find matched the whole needle as one literal substring, so any multi-word query (e.g. "Variable setitem values") silently returned no matches. Split the needle into whitespace terms and require every term to hit some field (per-term AND). Empty/whitespace needle preserves the prior match-all. Per-field lowercase is cached once per doc, not once per term. On an empty multi-term result, name the term(s) that hit nothing anywhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…spans slice grep returned file:line:text with no extent, so an agent had to guess a read window around each hit. Add a new src/symbols.rs heuristic (hand-rolled std scanning, no parser dependency) exposing enclosing_span/definition_span, and a --symbols flag on grep that appends a stable, uncolored '\t[span <Name> <start>-<end> approx]' suffix per hit (via rg --json, so the path/line come structurally). The flag is opt-in: the default streaming path, exit codes (0/1/2), and stderr are byte-for-byte unchanged. The heuristic is reject-on-ambiguity — decorators, nested functions, multi-line signatures, tab indent, and braces in strings/comments yield no span rather than a wrong one (a wrong span is worse than none on this surface). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slice show listed abstractions by name only, so an agent that wanted the definition had to grep for it (the card already named the symbol). Resolve each abstraction's symbol to its definition site via symbols::definition_span and append a dim '(path:line)' in the human render. Reuses normalize_abstraction (now pub(crate)) so the name is parsed exactly as check does. Human output only: the --json contract is unchanged (no new field), and a symbol defined in zero or multiple of the slice's files is left unannotated rather than guessed. Scoped to show; context has no abstractions block to annotate, so it is left unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slice for <testfile> returned 'no owning slice' even when the file was a Verification target of a slice, so test files (legitimate context) were navigationally unreachable. Add a verification-link fallback for for/context: when no files: owner matches, resolve via the slice's Verification refs. Surgical and bounded: owners_for_path is untouched (affected-docs and staleness are unaffected); the fallback is a separate helper (verification_associations) reusing parse_verification (now pub(crate)). It is human-output only — the --json contract is unchanged. Verification refs only; exclusions: is a disown signal, not ownership. Empty result now reports 'no slice association for: X (checked files and verification links)'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds opt-in symbol anchoring and improved slice resolution behaviors so CLI users (and agents) can get concrete file:line anchors and better for/context results without re-deriving spans manually.
Changes:
- Update
findto support multi-term AND matching across slice fields, with improved “unmatched term” diagnostics. - Add
grep --symbols(opt-in) and a newsymbolsmodule to heuristically annotate grep hits with enclosing symbol spans. - Annotate
showabstractions with(path:line)in human output and add a human-only verification-link fallback forfor/contextwhen nofiles:owner matches.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| rust/slice-rs/tests/cli.rs | Adds CLI tests covering multi-term find, grep --symbols, abstraction location rendering, and verification-link fallback behavior. |
| rust/slice-rs/src/symbols.rs | Introduces heuristic symbol span detection utilities for Python and brace-based languages. |
| rust/slice-rs/src/lib.rs | Exposes the new symbols module. |
| rust/slice-rs/src/commands.rs | Implements multi-term find, grep --symbols output, abstraction (path:line) rendering, and verification-link fallback for for/context. |
| rust/slice-rs/src/cli.rs | Adds the --symbols flag and help text for slice grep. |
| rust/slice-rs/src/check.rs | Makes verification parsing and abstraction normalization reusable within the crate. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if line_has_string_or_comment(line) { | ||
| return None; // a brace could be inside a string/comment → ambiguous | ||
| } |
| write!(lock, "{path}:{lineno}:{text}")?; | ||
| if let Some(lang) = crate::symbols::lang_for_path(path) { | ||
| let content = file_cache | ||
| .entry(path.to_owned()) | ||
| .or_insert_with(|| std::fs::read_to_string(ctx.repo_root().join(path)).ok()); | ||
| if let Some(content) = content | ||
| && let Some(sym) = crate::symbols::enclosing_span(content, lineno, lang) | ||
| { | ||
| write!( | ||
| lock, | ||
| "\t[span {} {}-{} approx]", | ||
| sym.name, sym.start, sym.end | ||
| )?; | ||
| } | ||
| } | ||
| writeln!(lock)?; | ||
| } |
| let file = reference.split("::").next().unwrap_or(&reference).trim(); | ||
| matches_path(&normalized, file) |
| let ids: Vec<String> = verification_associations(ctx, selector)? | ||
| .into_iter() | ||
| .map(|(slice_id, _)| slice_id) | ||
| .collect(); | ||
| targets = docs.iter().filter(|d| ids.contains(&d.slice_id)).collect(); | ||
| if targets.is_empty() { |
| for pattern in files { | ||
| for rel in expand_literal_or_existing(pattern, ctx) { | ||
| let Some(lang) = crate::symbols::lang_for_path(&rel) else { | ||
| continue; | ||
| }; | ||
| let Ok(content) = std::fs::read_to_string(repo_join(ctx, &rel)) else { | ||
| continue; | ||
| }; | ||
| if let Some((start, _)) = crate::symbols::definition_span(&content, &name, lang) { |
Greptile SummaryThis PR adds four related features to the slice CLI: multi-term
Confidence Score: 4/5The verification fallback, find multi-term, and show abstraction anchoring are correct and safe; the grep --symbols and show abstraction annotation features work as advertised for Python but are silently ineffective for most real Rust code because pub fn, pub(crate) fn, and async fn are never matched by brace_def_name. brace_def_name does not strip visibility or qualifier prefixes before matching keywords — a Rust function declared as pub fn handle or pub async fn fetch falls through all keyword checks and returns None. Neither grep --symbols annotations nor show abstraction file:line locations appear for those symbols, even though Rust is listed as supported. All tests pass because the fixtures use Python source files, masking the gap entirely. rust/slice-rs/src/symbols.rs — specifically brace_def_name and the BRACE_KEYWORDS constant Important Files Changed
Reviews (2): Last reviewed commit: "fix(commands): broken-pipe, path-norm, s..." | Re-trigger Greptile |
…times
Two correctness fixes to the brace-language span heuristic, from PR review:
- brace_enclosing aborted the backward scan on the first preceding def (via `?`
and `return None`), so a line sitting *after* a nested function but still inside
the outer one got no span instead of the outer's. It now skips non-enclosing /
unparseable defs and keeps climbing to the real encloser.
- The brace-hazard check rejected any line containing a quote/comment marker, even
braceless ones, and treated a bare `'` as a string — which nuked annotation for
most Rust fns (lifetimes like `&'a T`). It now only fires when a line actually
carries a brace, and treats single quotes as a hazard only as `'{'`/`'}'`.
Adds regression tests for all three cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions Four PR-review fixes, all preserving existing JSON contracts: - grep --symbols: a closed consumer (`… | head`) surfaced BrokenPipe as exit 2; now treated as a clean early exit (Ok(0)), matching rg's behavior. - verification_associations: normalize the verification ref's file path before matching, the same way the query path is, so `./`-style forms line up. - context verification fallback: look up slice ids via FxHashSet, not Vec::contains. - abstraction_location: read each slice file once per invocation instead of once per abstraction; the dedup also fixes a latent false-ambiguity when one file matched two patterns. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the reviews — all 7 points addressed in 7322961 (symbols) + fb3f523 (commands). fmt + clippy clean; 47 lib + 56 CLI tests green (3 new regression tests). JSON contracts unchanged throughout.
|
Four focused, additive enhancements that let agents get a concrete
file:lineanchor for a symbol straight from the slice CLI, instead of re-deriving spans by
hand after a grep hit. Each is an isolated commit; no breaking changes.
Changes
findmulti-term matching — a multi-word query now matches per-term acrossa slice's description/abstractions/body/tags, rather than as one rigid substring.
grep --symbols(opt-in) — annotates each hit with its enclosingfunction/class line span via a hand-rolled, reject-on-ambiguity heuristic
(decorators, nested functions, multi-line signatures, tab indentation, and
braces-in-strings are left unannotated rather than guessed). New
symbols.rsmodule behind two small functions, so an AST backend can replace it later
without touching callers.
showabstraction anchoring — abstractions are annotated with theirdefinition
file:linein human output.for/contexttest resolution — test files resolve to their owningslices via verification links.
Test plan
cargo fmt --check— cleancargo clippy --all-targets -- -D warnings— cleancargo test— 56 passed, 0 failed (incl. newsymbols.rsunits + CLI snapshots)🤖 Generated with Claude Code