Repository navigation
Conversation
The completion menu, its overlay and its key routing existed only for
`EditorState`: `present_completion_items`, `dismiss_completion_overlay` and
`insert_completion` were defined on `InputBaseState<EditorMode>`, and
`CompletionMenu` and `CaretAnchoredPopup` took an `Entity<EditorState>`. An
application that wants autocomplete in a one-line field, such as a URL bar
that completes `{{variables}}`, had no way to get it without turning the
field into a multi-line code editor.
`InputState` now hosts the same host-driven menu. The application decides
when to complete and what to offer; the field only shows the items, routes
keys to the menu and applies the chosen edit.
Base (`gpui-base`)
- `InputMode` gets `FieldExtras`, which holds a `CompletionMenuState`, in
place of `()`. A plain input pays for one small struct; textareas are
unchanged.
- New `InputState` methods mirroring the editor's: `present_completion_items`,
`dismiss_completion_overlay`, `insert_completion`, `completion_menu_state`,
`set_overlay_action_handler`, `has_overlay_action_handler` and
`route_overlay_action`.
- `InputMode` overrides `hide_context_menu`, `is_context_menu_open` and
`handle_context_menu_action`, so an edit, caret move or blur closes the
menu and Enter/Escape reach it first, exactly as in the editor.
- The text-edit resolution in `insert_completion` moves into a shared
`apply_completion_item` on `InputBaseState<M>`, used by both modes, so the
two cannot drift. `CompletionMenuState::bump` becomes `pub(crate)` for it.
- Register `up`/`down` handlers on single-line inputs. They were registered
only for multi-line ones, so the arrow keys never reached an open menu.
`menu_up`/`menu_down` give the open menu the key and otherwise call
`cx.propagate()`, so single-line inputs without a menu behave as before
and parents (for example a command palette) still see the key.
Component (`gpui-component`)
- `CompletionMenu` and `CaretAnchoredPopup` become generic over the input
kind. A crate-private `CompletionMode` trait carries the three things that
differ: inserting an item, dismissing the overlay and the maximum width
(the editor reads its LSP option; a field uses the default 320 px).
`CompletionMenu<M = EditorMode>` keeps existing call sites inferring.
- `OverlayMode` gains an associated `Lsp` type and a `collect_floating`
hook, so each kind declares the popovers it builds. The editor keeps its
completion, code-action, hover and diagnostic set, a field builds only the
completion menu, and a textarea builds none.
- The completion sync that diffed signatures and re-showed the menu is
extracted into `sync_completion` and shared by the editor and the field.
Tests
- `single_line_input_hosts_a_completion_menu` presents items on an
`InputState`, checks the menu is materialized as a floating overlay, that
Escape closes it, that actions fall through when no menu is open, and that
`insert_completion` replaces the typed prefix.
- gpui-base (1333) and gpui-component (666) lib tests pass; clippy is clean.
The menus consumed `MoveUp`, `MoveDown`, `Enter` and `Escape` directly, so
an application could not rebind the menu keys without also changing caret
movement and editing in the input, and had no way to say "only while a menu
is open". Single-line inputs additionally needed ad hoc `menu_up` and
`menu_down` handlers because they never registered `up`/`down` at all.
Add four dedicated actions: `OverlayMenuNext`, `OverlayMenuPrevious`,
`OverlayMenuAccept` and `OverlayMenuDismiss`.
- The input adds a `menu_open` key context while a completion or
code-action menu is open (`M::is_context_menu_open`), so bindings can
target `Input && menu_open`.
- Default bindings in that context: `up`, `down`, `enter`, `shift-enter`
and `escape`. They are registered last because GPUI breaks ties between
equally deep contexts by registration order, so they win over the plain
`MoveUp`/`Enter`/... bindings only while a menu is open. Nothing changes
for caret or editing keys when no menu is open.
- A single generic `overlay_menu_action` handler is registered for every
input kind and hands the action to the open menu through
`handle_context_menu_action`; an unclaimed action bubbles to the host.
It replaces the single-line `menu_up`/`menu_down` handlers.
- `CompletionMenu` and `CodeActionMenu` accept the new actions in addition
to the old ones, so existing custom bindings keep working. Accept and
dismiss close the overlay like Enter and Escape do.
- The new actions are exported from `gpui_component::input`.
An application rebinds the keys with the ordinary keymap:
cx.bind_keys([
KeyBinding::new("ctrl-n", OverlayMenuNext, Some("Input && menu_open")),
KeyBinding::new("ctrl-p", OverlayMenuPrevious, Some("Input && menu_open")),
]);
`tab` is deliberately not bound by default: it indents in editors and moves
focus in inputs, so accepting on it is left to the application.
Tests
- `menu_keys_follow_the_keymap_and_can_be_rebound` drives the real keymap
on an `InputState`: Escape dismisses, Enter accepts, and an added
`ctrl-y` binding accepts only while the menu is open.
- gpui-base (1333) and gpui-component (667) lib tests pass; clippy is clean.
… add a release note
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.
Description
The completion and code-action menus consume
MoveUp,MoveDown,EnterandEscapedirectly. An application therefore cannot rebind the menu keys (sayctrl-n/ctrl-p) without also changing caret movement and editing in every input, and cannot say "only while a menu is open".This adds four dedicated actions and a key context for them:
OverlayMenuNext,OverlayMenuPrevious,OverlayMenuAccept,OverlayMenuDismiss.menu_opento its key context while a menu is open. Default bindings inInput && menu_open:up,down,enter,shift-enter,escape. They are registered last because GPUI breaks ties between equally deep contexts by registration order; with no menu open nothing changes for caret or editing keys.overlay_menu_actionhandler is registered for every input kind and hands the action to the open menu, bubbling when unclaimed. It replaces the single-linemenu_up/menu_downhandlers.CompletionMenuandCodeActionMenuaccept the new actions in addition to the old ones, so existing custom bindings keep working.Tabis deliberately not bound: it indents in editors and moves focus in inputs. Applications can add it.An application rebinds with the ordinary keymap:
Public API
gpui_base::input::{OverlayMenuNext, OverlayMenuPrevious, OverlayMenuAccept, OverlayMenuDismiss}(re-exported bygpui_component::input) — unit actions the open completion or code-action menu handles: select next / previous, accept the selected item, dismiss.menu_open, added to an input's key context while a completion or code-action menu is open; default bindings are inInput && menu_open.Breaking Changes
None. The menus keep handling
MoveUp,MoveDown,EnterandEscape. The default keys behave as before, now through the new actions while a menu is open.How to Test
menu_keys_follow_the_keymap_and_can_be_rebounddrives the real keymap on anInputState: Escape dismisses, Enter accepts, and an addedctrl-ybinding toOverlayMenuAcceptinInput && menu_openaccepts only while the menu is open. The editor completion and code-action tests pass unchanged (1333 base, 667 component).Checklist
cargo runfor story tests related to the changes.