feat(menu): let a menu close at the end of the word it was opened for - #1209
Conversation
fc1d31a to
1134947
Compare
| return; | ||
| }; | ||
| let word_ended = commands.iter().any(|command| { | ||
| matches!(command, EditCommand::InsertChar(c) if menu.settings().word_ends_at(*c)) |
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.
There was a problem hiding this comment.
Good catch. InsertNewline now ends the word too, in the same match as InsertChar, and there's a test for it: a menu opened over th is closed by Edit(vec![InsertNewline]).
| /// 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 { |
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.
There was a problem hiding this comment.
Done. Both MenuBuilder::with_word_chars and MenuSettings::with_word_chars take impl Into<String> and store Some, matching with_input_mode and the others. The four call sites and the docs are updated.
|
Plus a rebase. Then we are set i think. |
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. `"_."` suits SQL identifiers, `"_-./"`
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. A
newline ends it whether it comes as `InsertChar('\n')` or as
`InsertNewline`, the command the default `Alt+Enter` and `Shift+Enter`
bindings emit, so a menu cannot outlive the first line of a multi-line
statement and hold `Enter` on the next.
1134947 to
ad4a916
Compare
|
Rebased onto current main and both points addressed. CI is green. |
|
Awesome! Thanks Martin |
|
@shreeve Sure thing. |
## Description Bumps reedline to `db34d84`, seven commits past the previous pin `c9e7035`: - nushell/reedline#1214 `feat(engine)!: switch between edit modes with one SwitchMode event` - nushell/reedline#1226 `fix(engine): Up and Down report whether they moved anything` - nushell/reedline#1225 `refactor(editor): give paste-after the same shape as paste-before` - nushell/reedline#1223 `chore(deps): drop fd-lock, itertools, thiserror and unicase` - nushell/reedline#1209 `feat(menu): let a menu close at the end of the word it was opened for` - nushell/reedline#1206 `fix(painter): trust the measured cursor row over a short terminal size` - nushell/reedline#1222 `fix(ci): change typos to v1` #1214 replaces `ViChangeMode` and `HelixChangeMode` with one `SwitchMode` event and gives vi visual mode its own keybinding table and cursor slot. Both old names still parse and mean the same, so existing configs keep working. ## User-facing changes (Release notes) - Added the `SwitchMode` keybinding event, `{ send: SwitchMode, mode: vi_normal }`, taking the same mode names `mode` takes on a keybinding. A switch into the mode already active reports itself inapplicable, so an `until` list falls through to its next event where it used to stop; `ViChangeMode` and `HelixChangeMode` share that. - Added `vi_visual` as a keybinding mode and `$env.config.cursor_shape.vi_visual`, which follows `vi_normal` while left on `inherit`. Bindings for `vi_normal` no longer apply in visual mode.
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.