feat(tui): completion dropdown for slash and @path - #576
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9b4ba7089
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| draw_input(frame, chunks[6], app); | ||
| if let Some(menu) = app.completion.as_ref() { | ||
| // Float above the composer within the full frame. | ||
| super::completion::draw(frame, chunks[6], menu); |
There was a problem hiding this comment.
Render the completion menu above the composer
For the default one-line fullscreen composer, chunks[6] is only four rows high, so passing it as the menu's clipping area makes the dropdown clear and overwrite the composer itself; after borders, menus with three or more matches display only two rows, and cycling can leave the selected row invisible. The menu needs an area extending above the composer while retaining the composer position as its anchor.
Useful? React with 👍 / 👎.
| // Completion dropdown captures navigation / accept / dismiss. | ||
| if app.completion.is_some() && app.phase != super::app::Phase::Permission { | ||
| match key.code { |
There was a problem hiding this comment.
Dismiss completion before opening another overlay
When a completion is open and the user presses Ctrl+P, Ctrl+F, or another overlay chord, this block leaves the completion alive and the later dispatch opens the requested overlay. Because completion handling runs before all picker/search handlers, the next plain Enter or arrow key operates on the hidden completion instead of the visible overlay; for example, Ctrl+P followed by Enter accepts the old slash candidate while leaving the command palette open.
Useful? React with 👍 / 👎.
| // Typing rebuilds the menu from the new input on next Tab; | ||
| // dismiss so characters land in the composer. | ||
| KeyCode::Char(_) | KeyCode::Backspace if key.modifiers.is_empty() => { | ||
| app.dismiss_completion(); |
There was a problem hiding this comment.
Invalidate completion after pasted composer edits
The menu is dismissed only for character and Backspace key events, but bracketed paste bypasses this branch and calls insert_str directly. If a user opens completion for /se, pastes more text, and presses Enter, the old menu still replaces only its original byte range, potentially inserting a stale command and leaving the pasted suffix attached; any composer mutation, including paste and Delete, should dismiss or rebuild the menu.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9b4ba7089
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| draw_input(frame, chunks[6], app); | ||
| if let Some(menu) = app.completion.as_ref() { | ||
| // Float above the composer within the full frame. | ||
| super::completion::draw(frame, chunks[6], menu); |
There was a problem hiding this comment.
Render the completion menu outside the composer
Passing chunks[6] gives the dropdown only the composer rectangle, so completion::draw clips its height to that rectangle and then clears and redraws the same area. With the normal single-line fullscreen composer this hides the prompt and leaves only two menu rows inside the border, even though window() assumes six rows are visible; after cycling past the second item, the highlighted selection is therefore off-screen. Pass an area that extends above the composer or calculate the floating rectangle from the full frame.
Useful? React with 👍 / 👎.
| insert.push(' '); | ||
| } | ||
| } | ||
| self.input.replace_range(start..end, &insert); |
There was a problem hiding this comment.
Invalidate completion ranges after pasted edits
The menu stores byte offsets from when Tab was pressed, but bracketed paste edits the composer without dismissing or rebuilding the menu. For example, after opening a menu, moving the cursor inside its token, and pasting a multibyte character such as é, the saved replace_end can fall inside that character; pressing Enter then panics at this replace_range (or the earlier path-only slice) because the index is no longer a UTF-8 boundary. Dismiss completion on paste and other composer mutations, or recompute and validate the token range before accepting.
Useful? React with 👍 / 👎.
| // Completion dropdown captures navigation / accept / dismiss. | ||
| if app.completion.is_some() && app.phase != super::app::Phase::Permission { |
There was a problem hiding this comment.
Close completion before opening another overlay
Completion routing runs before search and picker routing but allows chords such as Ctrl+P to fall through without closing the menu. Starting from an ambiguous completion, Ctrl+P therefore opens the command palette while leaving completion set; the next Up/Down, Enter, or Esc is consumed here by the hidden completion instead of the visible palette, and Enter can rewrite the composer behind it. Ensure overlays are mutually exclusive or only route completion keys when no higher-level overlay is open.
Useful? React with 👍 / 👎.
Tab with multiple matches opens a shared dropdown (label + description, Tab cycle, Enter accept, Esc dismiss) instead of dumping names into the transcript. Unique name-prefix slash hits still complete inline. Includes the fuzzy matcher and palette ranking so providers share one scorer.
- Anchor the dropdown to the region above the composer so it no longer overwrites the input row. - Dismiss completion when opening palette/search/theme/model/session pickers or the shortcuts overlay. - Dismiss on paste so Enter cannot apply a stale replace range.
5dce377 to
02bbca9
Compare
Summary
completiondropdown for slash commands and@pathmentions (MAX_VISIBLE_ROWS=6, label/description columns)./hel→/help).ui/fuzzy+ palette ranking (overlaps feat(tui): add fuzzy subsequence matcher and rank the command palette #573; can supersede it).Addresses #560.
Test plan
tab_opens_slash_dropdown_for_ambiguous_prefix