From 553aa40b34cd968ff03c2c276f0f5f3f3f47df54 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Mon, 2 Feb 2026 12:04:15 +1100 Subject: [PATCH] Fix crash in Vi's "dge" due to misplaced cursor kill-selection does not respect fish_cursor_end_mode; fix that. --- share/functions/fish_vi_key_bindings.fish | 21 ++++++++++++++------- src/reader/reader.rs | 3 +++ tests/pexpects/vi-key-bindings.py | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 tests/pexpects/vi-key-bindings.py diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index e22eec029..4e1530a5f 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -46,6 +46,12 @@ function __fish_vi_consume_count -a varname echo $effective_count end +function fish_vi_yank_selection + set -g fish_cursor_end_mode exclusive + commandline -f kill-selection -f yank + set -g fish_cursor_end_mode inclusive +end + function fish_vi_exec_motion argparse linewise -- $argv or return @@ -113,9 +119,10 @@ function fish_vi_exec_motion commandline -f $motion end if $use_selection - commandline -f kill-selection + fish_vi_yank_selection + else + commandline -f yank end - commandline -f yank case swap-case for i in (seq $total) commandline -f $motion @@ -457,10 +464,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset y,i,W kill-inner-bigword yank bind -s --preset y,a,w kill-a-word yank bind -s --preset y,a,W kill-a-bigword yank - bind -s --preset y,i,b jump-till-matching-bracket and jump-till-matching-bracket and begin-selection jump-till-matching-bracket kill-selection yank end-selection - bind -s --preset y,a,b jump-to-matching-bracket and jump-to-matching-bracket and begin-selection jump-to-matching-bracket kill-selection yank end-selection - bind -s --preset y,i backward-jump-till and repeat-jump-reverse and begin-selection repeat-jump kill-selection yank end-selection - bind -s --preset y,a backward-jump and repeat-jump-reverse and begin-selection repeat-jump kill-selection yank end-selection + bind -s --preset y,i,b jump-till-matching-bracket and jump-till-matching-bracket and begin-selection jump-till-matching-bracket fish_vi_yank_selection end-selection + bind -s --preset y,a,b jump-to-matching-bracket and jump-to-matching-bracket and begin-selection jump-to-matching-bracket fish_vi_yank_selection end-selection + bind -s --preset y,i backward-jump-till and repeat-jump-reverse and begin-selection repeat-jump fish_vi_yank_selection end-selection + bind -s --preset y,a backward-jump and repeat-jump-reverse and begin-selection repeat-jump fish_vi_yank_selection end-selection bind -s --preset % jump-to-matching-bracket bind -s --preset f forward-jump @@ -558,7 +565,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M visual -m default d kill-selection end-selection backward-char repaint-mode bind -s --preset -M visual -m default x kill-selection end-selection repaint-mode bind -s --preset -M visual -m default X kill-whole-line end-selection repaint-mode - bind -s --preset -M visual -m default y kill-selection yank end-selection repaint-mode + bind -s --preset -M visual -m default y fish_vi_yank_selection end-selection repaint-mode bind -s --preset -M visual -m default '",*,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode" bind -s --preset -M visual -m default '",+,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode" bind -s --preset -M visual -m default \~ togglecase-selection end-selection repaint-mode diff --git a/src/reader/reader.rs b/src/reader/reader.rs index a822ddd1b..d26e6ae5d 100644 --- a/src/reader/reader.rs +++ b/src/reader/reader.rs @@ -4155,6 +4155,9 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) { if let Some(selection) = self.get_selection() { self.kill(EditableLineTag::Commandline, selection, Kill::Append, newv); } + if self.is_at_end() { + self.update_buff_pos(self.active_edit_line_tag(), None); + } } rl::InsertLineOver => { let elt = loop { diff --git a/tests/pexpects/vi-key-bindings.py b/tests/pexpects/vi-key-bindings.py new file mode 100644 index 000000000..1e22a5e1e --- /dev/null +++ b/tests/pexpects/vi-key-bindings.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +from pexpect_helper import SpawnedProc + +sp = SpawnedProc() +send, sendline, sleep, expect_prompt, expect_re, expect_str = ( + sp.send, + sp.sendline, + sp.sleep, + sp.expect_prompt, + sp.expect_re, + sp.expect_str, +) +expect_prompt() + +sendline("fish_vi_key_bindings") +send("echo vim 1234 adsf") +send("\033") +sleep(1) +send(2 * "dge") +sendline("") +expect_re(r"\bvi\b") +expect_prompt()