feat(search): / searches diff content via a bundled search extension - #1096
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Greptile SummaryThis PR adds bundled, review-wide diff-content search and exposes visible review files through extension API 27.
Confidence Score: 5/5The PR appears safe to merge; no actionable new defects or outstanding previous findings remain. The repeated-match implementation now emits every non-overlapping occurrence, and search compilation and session state preserve surrounding whitespace. The other changes since the previous review maintain prompt and search lifecycle behavior without introducing a demonstrated regression. Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant C as Bundled search command
participant P as Status-line prompt
participant S as Search session
participant N as Review navigation
participant H as Line highlighter
U->>C: Press /
C->>P: Open prompt with previous query
P-->>C: Submitted query
C->>S: Search visible selection.files
S-->>C: Next hunk target and match ranges
C->>N: Reveal matching line
C->>H: Refresh search marks
C-->>U: Show match position on status line
U->>C: Press n or N
C->>S: Repeat from live selection
S-->>C: Next/previous target, wrapping if needed
C->>N: Reveal target
C->>H: Refresh current mark
Reviews (2): Last reviewed commit: "fix(search): keep literal whitespace in ..." | Re-trigger Greptile |
elucid
force-pushed
the
status-line-primitive
branch
from
September 11, 2026 13:45
b754d95 to
e98f224
Compare
elucid
force-pushed
the
bundled-content-search
branch
2 times, most recently
from
September 11, 2026 14:16
046a62d to
c4208e4
Compare
`ctx.selection.files` carries the visible review files in review order, the same frozen views a pane's `files` prop receives, so a whole-review command reads its corpus from the selection instead of shadow-tracking `changeset_loaded`. Bumps the extension API to 27.
… the session Bundled UI registrations were only composed for panes; commands and line highlighters a bundled factory registered were dropped. `sessionRegistrations` merges both ahead of the user registry at the App merge points, the history surface treats them as known-but-inactive ids, bundled prompts and dialogs recognize the vendor id for attribution, and the bundled registry no longer requires every factory to register a pane.
Ports elucid/hunk-less-search's patch parsing, smart-case query compiling, hunk-granular target discovery, match marks, and wrapping step logic with their tests, unchanged apart from import paths and shared test fixtures.
The session no longer shadows the changeset: search and repeat receive the visible files from the command selection and rebuild targets when that list changes identity, so hidden files never become targets and a reload keeps the query while orphaning the old current target. Adds `clear` for an empty submit and renders outcomes as status-line spans.
`hunk.review.focusFilter`, `hunk.review.nextNote`, and `hunk.review.previousNote`
keep their ids and behavior but ship without default keys so content search
can take `/`, `n`, and `N`. Tab and the menus still reach the filter, `}` / `{`
still step annotated hunks, and `"hunk.review.focusFilter" = "/"` restores the
old chord. Tests that used `/` to reach the filter now press Tab, and the PTY
slash case exercises the documented remap.
`/` opens the status-line prompt and Enter jumps to the next hunk matching the typed text; `n` / `N` repeat and wrap; the status row reports each landing and the diff marks every match with the landed line inverted. Registered as bundled UI under the `hunk` vendor id (`hunk.search.find` / `next` / `previous`), listed under Navigate and in the help dialog, and documented beside the built-in keybindings.
Its `/` search is now bundled, so a lingering install only duplicates keys (bundled commands win the chord). Startup reports one notice pointing at `hunk extension remove hunk-less-search`.
Covers the prompt, the line-exact reveal near the viewport top, n / N stepping and wrapping, the inverted current mark and tinted match marks, Tab still reaching the filter, the emptied-prompt clear, and the documented `"hunk.review.focusFilter" = "/"` remap taking the key back from search.
elucid
force-pushed
the
bundled-content-search
branch
from
September 11, 2026 18:20
c4208e4 to
a288fc0
Compare
Contributor
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
/focuses the file filter, and there is no way to search the content of a review.elucid/hunk-less-searchfills the gap as a third-party extension, but only by faking a prompt: a permanently open bottom pane, a keyboard mode re-implementing a line editor, and a store token deferring navigation to the pane'suseEffect. Review andhunk logalso disagree about what/,n, andNmean.Approach
Bring the search into Hunk as a bundled extension built on the PR 1 status-line primitive, and give it
/,n,Nby default.ctx.selection.files(extension API 27). The visible files in review order — the same frozen views a pane'sfilesprop carries — so a whole-review command reads its corpus from the selection instead of shadow-trackingchangeset_loaded. Hidden (filtered) files are therefore never search targets.getBundledUIRegistry()was only composed for panes;ui/lib/sessionRegistrations.tsnow merges bundled commands and line highlighters ahead of the user registry's at theAppmerge points (bundled first, so a user extension can never shadow them, matching the existing key-conflict rule).hunk logtreats bundled command ids as known-but-inactive, bundled prompts/dialogs omit theextattribution by vendor id, and the registry no longer requires every bundled factory to register a pane. Bundled event handlers are deliberately not composed — nothing needs them.packages/hunk/src/extensions/default/ui/search/. The pure primitives (search.ts) and their tests are ported nearly verbatim fromhunk-less-search. The session (session.ts) is rewritten to takefilesper call and rebuild targets when the list changes identity (a reload keeps the query but orphans the old current target). The registration (index.ts) is three commands plus one line highlighter:/→ctx.prompts.line({ prefix: "/" })→revealLineon the first matching line (falling back toselectHunkwhen the patch never numbered it) →ctx.highlights.refresh→ctx.statusLine.set. The store, prompt grammar, pane, and deferred-navigation token are gone./prefills the last query. Enter re-runs it; Escape clears the buffer; Escape again cancels and leaves the search (marks, status item,n/N) in place; submitting the emptied prompt ends the search and frees the status row. Smart case, literal matching, strict wrapping repeats from the live selection,[i/n] path:line (+k in hunk) • wrapped — texton the status row, every match marked in the diff with the landed line inverted.hunk.review.focusFilterandhunk.review.nextNote/previousNotekeep their ids and behavior but ship unbound. Tab and the File/Navigate menus still reach the filter;}/{still step annotated hunks.[keybindings] "hunk.review.focusFilter" = "/"restores the old chord and the exclusive-binding resolver silently takes/from search (no conflict warning). Search sits under Navigate and in the help dialog;hunk.*bundled commands are filtered out of the Extensions menu.hunk-less-searchgets one startup notice pointing athunk extension remove hunk-less-search; its stale[keybindings]line is already reported softly. The website directory entry is removed.Non-goals: no
[search] mode = "regex"config (the bundled registry is process-cached and factories run with no config); the regex branch is kept and tested for a follow-up. No bundled event composition. No changes tohunk logsearch.Stacked on #1095 (
status-line-primitive); merge that first, then this.docs/handoff-pr2-bundled-search.mdis local and not committed. Note thatdocs/status-line-extension-point.mdwas committed on the PR 1 branch despite being marked local-only there.Why bundled rather than native
Porting the search straight into
Appwould be less code, butreviewInfoalready set the precedent that bundled UI goes through the public API, and doing it this way closes the composition gap (commands and highlighters from a bundled factory were dropped on the floor) instead of leaving it as a trap for the next bundled feature.Tests
Unit (colocated):
extensionSelection.test.ts(files),sessionRegistrations.test.ts(bundled-first composition,--no-extensionsshape, vendor-id attribution),search/search.test.ts(ported),search/session.test.ts(strict wrapping, follow-the-selection, corpus change, bad regex keeps the old query, hidden files never targeted,clear),startup.test.ts(superseded-install notice),appMenus/helpContent/appCommands(Navigate rows, Extensions-menu filtering, unbound rows, docs table includes bundled ids).App-level: new
AppHost.search.test.tsx— mounted with user extensions disabled:/prompt without attribution, Enter lands near the viewport top with the inverted current mark,n/Nstep and wrap, miss / no-query / emptied-prompt reports, Escape×2 keeps the search, reload keeps the query, filtered-out file never targeted, Tab still opens the filter.PTY: new
test/pty/search-integration.test.ts(prompt, line-exact reveal,n/N, current + tinted match cell backgrounds, Tab, Escape/clear flows, and the"hunk.review.focusFilter" = "/"remap). Existing PTY/AppHost tests that pressed/for the filter now press Tab; thechromeslash case exercises the documented remap; thenotesnote-stepping case bindsn/Nback through[keybindings].Commands run
bun run typecheck,bun run lint,bun run deps:check— clean.bun run generate:skill— no diff.bun run format:check— only untracked local files flagged.bun run test— 4277 pass; 5 failures also fail onorigin/mainin this environment (packages/hunk-jj"logs unexpected source failures",test/cli/install-vm×3,AppHost.watchobserver-debounce). Reproduced on a cleanorigin/mainworktree.bun run test:integration— 173 pass; 5 failures also fail onorigin/mainhere (extensions-integrationtrust-state ×2,lifecycleSIGHUP/SIGPIPE/SIGQUIT). The one new failure the run surfaced (notesstepping withn/N) was fixed by binding the keys in that test; it passes now.bun run test:tty-smoke— skips on macOS.XDG_CONFIG_HOME,hunk diff HEAD~3 --mode unified):/prompt with cursor, Enter lands and reports[i/n] path:line,n/Nstep and wrap, Tab opens the filter beside the search item, Escape×2 keeps the search, Escape+Enter clears it andnthen says "No search yet", Navigate menu shows the three entries and help shows/andn / N.Platforms: macOS only.
Follow-ups
[search] mode = "regex"config once bundled factories can read config.ninside a single tall hunk wraps to itself; line-granular stepping within a hunk is a possible refinement.elucid/hunk-less-searchwith a README pointer (outside this repo).