feat(menu): let a menu close at the end of the word it was opened for - #1209
Open
shreeve wants to merge 1 commit into
Open
feat(menu): let a menu close at the end of the word it was opened for#1209shreeve wants to merge 1 commit into
shreeve wants to merge 1 commit into
Conversation
shreeve
force-pushed
the
menu-closes-at-word-boundary
branch
3 times, most recently
from
September 9, 2026 12:53
a0c4213 to
fc1d31a
Compare
A menu opened over a word refilters against everything typed after it, so
it stays active for the rest of the line and keeps its claim on `Enter`.
The user finishes the statement, presses `Enter`, and the menu answers
instead of the line: the highlighted suggestion lands at the cursor, or,
once the filter has emptied, nothing happens at all.
`with_word_chars` bounds a menu's life to the word instead, the way fish
and zsh dismiss their pagers as a word ends. What counts as a word is
grammar-specific: alphanumerics always extend one, and the setting lists
the punctuation that also does. `Some("_.")` suits SQL identifiers,
`Some("_-./")` paths.
It belongs to the menu rather than the engine because a menu filtering on
whole command lines has no word to end. Left unset, as a history menu
would leave it, a menu behaves exactly as it always has.
The close runs ahead of the rest of the edit handling, so a completer is
never asked to refilter a word the user has already left, and an
abbreviation expanding on the same space cannot carry the menu past it.
Only typed characters end a word; text that arrives whole does not.
shreeve
force-pushed
the
menu-closes-at-word-boundary
branch
from
September 12, 2026 02:27
fc1d31a to
1134947
Compare
| return; | ||
| }; | ||
| let word_ended = commands.iter().any(|command| { | ||
| matches!(command, EditCommand::InsertChar(c) if menu.settings().word_ends_at(*c)) |
Collaborator
There was a problem hiding this comment.
InsertNewline does not end the word: only InsertChar is checked here.
The default Alt+Enter and Shift+Enter bindings emit EditCommand::InsertNewline, so a menu opened over th stays active after it and still holds Enter on the next line. In a multi-line statement that is #1176 again.
InsertChar(' ') and InsertChar('\n') both close it.
Count InsertNewline as ending the word.
| /// Only characters typed into the line end a word; text inserted whole, | ||
| /// such as a bracketed paste, does not. | ||
| #[must_use] | ||
| fn with_word_chars(mut self, word_chars: Option<String>) -> Self { |
Collaborator
There was a problem hiding this comment.
The sibling builders take the bare value: with_input_mode(mode: InputMode), with_output_mode(mode: OutputMode).
Take impl Into<String> and store Some, here and in MenuSettings::with_word_chars at line 305.
Collaborator
|
Plus a rebase. Then we are set i think. |
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.
Summary
Closes #1176.
A menu opened over a word refilters against everything typed after it, so it stays
active for the rest of the line and keeps its claim on
Enter. The user finishes thestatement, presses
Enter, and the menu answers instead of the line: the highlightedsuggestion lands at the cursor, or, once the filter has emptied, nothing happens at all.
#1175 fixed the empty half. The other half it structurally cannot reach, because a
grammar-driven completer is never empty: type
show tab, Tab to open themenu, then
les;and Enter. After the;a SQL completer offersnext-statement keywords, so the menu still has values, so
Enterstill goes to themenu — and appends
tableto a finished statement. That is the report behind #1176.MenuBuilder::with_word_charsbounds a menu's life to the word it was opened for, theway fish and zsh dismiss their pagers as a word ends.
Why it is a menu setting, and why the caller picks the characters
Not every menu is filtering on a word. A history menu filters on whole command lines,
where a space is ordinary input and ending on it would break multi-word search — so
the setting lives on the menu, and the one that has no word to end simply never sets
it.
examples/demo.rspairs exactly those two menus; there is a test for it.What ends a word is grammar-specific too.
/ends a SQL identifier and sits in themiddle of a path;
DefaultCompletersplits on spaces alone. So the caller says: analphanumeric character always extends a word, and the setting lists the punctuation
that also does.
Noneis the default, and is today's behavior exactly.Where the close runs
Ahead of the rest of the
Edithandling, which matters twice:has already left, only for the answer to be thrown away with the menu
is looked at again, so a close placed after it would be skipped on the exact
keystroke the feature is about
Notes
as one
Editwith severalInsertChars, and the word can end anywhere in it.Without
use_bracketed_pastea terminal cannot tell the engine a paste from fasttyping, and the word ends either way — the doc comment says so.
with_persistent_menusstill wins.Enteraway before the key ispressed, Don't let a menu with no suggestions swallow Enter #1175 guards the key once a menu is open. Either is useful without the other.
Tests
;and)end the word, a letter,_and.do notInsertStringis unaffectedEdit, which is how the rest of a statementarrives when typed at speed
show tables;runs with no stray word appended
cargo fmt --checkandcargo clippy --all-targets --all-features -- -D warningsareclean; the suite passes with default and with all features.