Skip to content

refactor completions into a backend based architecture - #5

Merged
Revantark merged 15 commits into
Revantark:mainfrom
azeemshaik025:refactor/completion-backends
Aug 28, 2026
Merged

refactor completions into a backend based architecture#5
Revantark merged 15 commits into
Revantark:mainfrom
azeemshaik025:refactor/completion-backends

Conversation

@azeemshaik025

@azeemshaik025 azeemshaik025 commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Completion moves behind a CompletionBackend trait so slash commands can slot in beside @ paths without the editor learning a second syntax.

  • The character a token starts with picks the backend. CompletionController keys them on trigger(), and one shared tokenizer means no backend parses the line or handles byte offsets itself.
  • matcher.rs ranks every backend the same way. A pattern's /-separated parts may skip directories, so @crates/main.rs finds crates/alan/src/main.rs, and the last part ranks against the file name rather than anywhere in the path.
  • The file backend holds one flat workspace index instead of per-directory scans, dropping DirEntry, refilter and dir_part.
  • One scan runs at a time, so the generation counter, cancel epoch and delivery channel are gone — the in-flight JoinHandle is also where the result arrives.
  • Accepting a directory inserts it and closes, adding a separator so the next keystroke is prose rather than more of the mention.
  • The footer's key hints follow an Activity the controller derives, so "Enter send" no longer shows while Enter would accept a completion.

MAX_INDEXED_PATHS is 10,000 where the old CANDIDATE_LIMIT was 5,000. That one truncated after sorting by depth, so on a repo the size of zed (5,117 entries) the deepest files were silently uncompletable. MAX_PATH_DEPTH went 32 to 10, and suggestions built per keystroke are capped at 100.

The last commit touches crates/agent: the first session on a machine failed with "No such file or directory", because the root was chmodded before create_dir_all made it and every test pre-created it. Happy to split that out if you'd rather keep this to completion.

Paths is the only backend so far; a Commands backend on / is the intended second one.

azeemshaik025 and others added 15 commits August 23, 2026 22:35
- Add a CompletionBackend trait: one `complete(request) -> result` method, so
  each backend decides for itself whether a request is its own.
- Add matcher.rs, a pure ranking function shared by every backend. Ranking now
  follows the typed pattern rather than the order the scan happened to produce.
- Fold the file-path scanner behind the trait: one flat workspace index in
  place of per-directory scans, dropping DirEntry, refilter and dir_part.
- Backends declare a trigger character and the controller keys them in a
  map, so the trait is dispatched rather than only declared
- Token parsing moves into token.rs, shared by every backend; fixes a panic
  when the cursor sat inside a multi-byte character
- Only one scan runs at a time, so the generation counter, cancel epoch and
  delivery channel are gone
- Paths::new takes its root and no longer scans from the constructor
- Scan limits collapse to MAX_INDEXED_PATHS and MAX_PATH_DEPTH, plus a cap
  on suggestions built per keystroke
- @crates/main.rs matched nothing; pattern parts may now skip directories
- Accepting a directory replaced it with itself forever, and left no
  separator so the next keystroke reopened the popup
- One unreadable directory failed the entire scan
- Brightness now tracks what Enter will take; the trailing `/` already says
  an entry is a directory
- Pull the row styling out of the render loop into item_line
- matcher moves inside completion/, where its only caller lives, and stops
  being crate-public
- Re-export CompletionItem from core alongside the other completion types
- Drop CompletionItem::description: nothing sets it, so it can come back
  with the slash-command backend that will
- replace_range bails instead of panicking if a range outlives its line
- CompletionRequest carries `pattern` and `range` rather than the line and a
  token span, so no backend slices and the same span has one name
- Fix Event::Paste syncing completion before inserting, which left the popup
  shut after pasting a mention
`@src/s` ranked every `.rs` file above `skill.rs`, because the name check
looked for the whole pattern inside the name. `src` never appears in a
filename, so nothing ever matched on its name and the trailing `s` of `.rs`
satisfied the rest.

The last part is the name being typed; the parts before it only locate it.
`@src/s` put skill.rs third behind sse.rs and selection.rs. Every candidate
matched on its name, so only the tie-break separated them, and the first
field compared was the offset of the pattern's first part — effectively
"how few directories precede src", which says nothing about match quality.

Comparing length first is what fzf does by default.
- Add an Activity the controller derives, so the footer stops assembling the
  status line out of booleans: thinking, suggesting, or idle
- The status line becomes a table keyed on that, with plan mode and cost as
  badges layered on top
- Anchor the completion popup above the prompt rather than the cursor, which
  had it painting over the status line describing it
- Drop Controller::is_busy, which activity folds in
The first session on a machine failed with "No such file or directory",
because `create` chmodded the root before `create_dir_all` had made it.
Every test pre-created the root, so the first-run path was never exercised.
@Revantark
Revantark merged commit ef9da27 into Revantark:main Aug 28, 2026
1 check passed
@azeemshaik025
azeemshaik025 deleted the refactor/completion-backends branch August 29, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants