Fix Vi mode glitch when replacing at last character

Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.

Fix this.

This surfaces a tricky problem: when we use something like

	bind '' self-insert some-command

When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.

Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".

The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.

Fixes #11484

(cherry picked from commit 107e4d11de)
This commit is contained in:
Johannes Altmanninger
2025-05-12 22:50:30 +02:00
parent b8cfd6d12b
commit d4b4d44f14
3 changed files with 12 additions and 5 deletions

View File

@@ -261,10 +261,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
# Lowercase r, enters replace_one mode
#
bind -s --preset -m replace_one r repaint-mode
bind -s --preset -M replace_one -m default '' delete-char self-insert backward-char repaint-mode
bind -s --preset -M replace_one -m default enter 'commandline -f delete-char; commandline -i \n; commandline -f backward-char; commandline -f repaint-mode'
bind -s --preset -M replace_one -m default ctrl-j 'commandline -f delete-char; commandline -i \n; commandline -f backward-char; commandline -f repaint-mode'
bind -s --preset -M replace_one -m default ctrl-m 'commandline -f delete-char; commandline -i \n; commandline -f backward-char; commandline -f repaint-mode'
bind -s --preset -M replace_one -m default '' 'set -g fish_cursor_end_mode exclusive' delete-char self-insert backward-char repaint-mode 'set -g fish_cursor_end_mode inclusive'
bind -s --preset -M replace_one -m default enter 'set -g fish_cursor_end_mode exclusive' 'commandline -f delete-char; commandline -i \n; commandline -f backward-char' repaint-mode 'set -g fish_cursor_end_mode inclusive'
bind -s --preset -M replace_one -m default ctrl-j 'set -g fish_cursor_end_mode exclusive' 'commandline -f delete-char; commandline -i \n; commandline -f backward-char' repaint-mode 'set -g fish_cursor_end_mode inclusive'
bind -s --preset -M replace_one -m default ctrl-m 'set -g fish_cursor_end_mode exclusive' 'commandline -f delete-char; commandline -i \n; commandline -f backward-char' repaint-mode 'set -g fish_cursor_end_mode inclusive'
bind -s --preset -M replace_one -m default escape cancel repaint-mode
bind -s --preset -M replace_one -m default ctrl-\[ cancel repaint-mode

View File

@@ -841,7 +841,7 @@ fn read_characters_no_readline(&mut self) -> CharEvent {
let evt_to_return: CharEvent;
loop {
let evt = self.readch();
if evt.is_readline_or_command() {
if evt.is_readline_or_command() || evt.is_check_exit() {
saved_events.push(evt);
} else {
evt_to_return = evt;

View File

@@ -12,3 +12,10 @@ isolated-tmux send-keys v b y p i 3
tmux-sleep
isolated-tmux capture-pane -p
# CHECK: [I] prompt 0> echo 1241234
isolated-tmux send-keys Escape
tmux-sleep # disambiguate escape from alt
isolated-tmux send-keys e r 5
tmux-sleep
isolated-tmux capture-pane -p
# CHECK: [N] prompt 0> echo 1241235