Vi mode: hack in support for df and friends

Commit 38e633d49b (fish_vi_key_bindings: add support for count,
2025-12-16) introduced an operator mode which kind of makes a lot of
sense for today's fish.  If we end up needing more flexibility and
tighter integration, we might want to move some of this into core.

Unfortunately the change is at odds with our cursed forward-jump
implementation.  The forward-jump special input function works by
magically reading the next key from stdin, which causes problems when
we are executing a script:

	commandline -f begin-selection
	commandline -f forward-jump
	commandline -f end-selection

here end-selection will be executed immediately
and forward-jump fails to wait for a keystroke.

We should get rid of forward-jump implementation.

For now, replace only the broken thing with a dedicated bind mode
for each of f/F/t/T.

Fixes #12417
This commit is contained in:
Johannes Altmanninger
2026-02-06 13:17:36 +11:00
parent 6f895935a9
commit d25965afba
10 changed files with 138 additions and 38 deletions

View File

@@ -18,7 +18,7 @@ function fish_default_mode_prompt --description "Display vi prompt mode"
case visual
set_color --bold magenta
echo '[V]'
case operator
case operator f F t T
set_color --bold cyan
echo '[N]'
end

View File

@@ -53,7 +53,7 @@ function fish_vi_yank_selection
end
function fish_vi_exec_motion
argparse linewise -- $argv
argparse --stop-nonopt linewise -- $argv
or return
set -l motion $argv
@@ -83,7 +83,7 @@ function fish_vi_exec_motion
else
set -l use_selection true
set -l swap_case_hack
switch $motion
switch $motion[1]
case forward-word-vi forward-bigword-vi
if test $__fish_vi_operator = swap-case
set swap_case_hack (string replace -r -- '^forward-((?:big)?word)-vi$' '$1' $motion)
@@ -93,50 +93,62 @@ function fish_vi_exec_motion
set motion (string replace -- forward kill $motion)
end
end
switch $motion[1]
case commandline
case '*'
set motion commandline -f $motion
end
if $use_selection
commandline -f begin-selection
else
commandline -f begin-undo-group
end
set -l ok true
switch $__fish_vi_operator
case delete
for i in (seq $total)
commandline -f $motion
$motion || { set ok false; break }
end
if $use_selection
if $ok && $use_selection
commandline -f kill-selection
end
case change
for i in (seq $total)
commandline -f $motion
$motion || { set ok false; break }
end
if $use_selection
commandline -f kill-selection
if $ok
if $use_selection
commandline -f kill-selection
end
set fish_bind_mode insert
end
set fish_bind_mode insert
case yank
for i in (seq $total)
commandline -f $motion
$motion || { set ok false; break }
end
if $use_selection
fish_vi_yank_selection
else
commandline -f yank
if $ok
if $use_selection
fish_vi_yank_selection
else
commandline -f yank
end
end
case swap-case
for i in (seq $total)
commandline -f $motion
$motion || { set ok false; break }
end
if set -q swap_case_hack[1]
set -l word $swap_case_hack
commandline -f \
backward-$word \
forward-$word-end \
togglecase-selection \
backward-$word \
forward-$word-vi
else
commandline -f togglecase-selection
if $ok
if set -q swap_case_hack[1]
set -l word $swap_case_hack
commandline -f \
backward-$word \
forward-$word-end \
togglecase-selection \
backward-$word \
forward-$word-vi
else
commandline -f togglecase-selection
end
end
end
if $use_selection
@@ -400,10 +412,16 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
bind --preset -M operator \^ 'fish_vi_exec_motion beginning-of-line'
bind --preset -M operator \$ 'fish_vi_exec_motion end-of-line'
bind --preset -M operator f 'fish_vi_exec_motion forward-jump'
bind --preset -M operator F 'fish_vi_exec_motion backward-jump'
bind --preset -M operator t 'fish_vi_exec_motion forward-jump-till'
bind --preset -M operator T 'fish_vi_exec_motion backward-jump-till'
bind --preset -M operator f --sets-mode f ''
bind --preset -M operator F --sets-mode F ''
bind --preset -M operator t --sets-mode t ''
bind --preset -M operator T --sets-mode T ''
bind --preset -M f '' get-key 'fish_vi_exec_motion commandline --forward-jump=$fish_key' 'set -eg fish_key'
bind --preset -M F '' get-key 'fish_vi_exec_motion commandline --backward-jump=$fish_key' 'set -eg fish_key'
bind --preset -M t '' get-key 'fish_vi_exec_motion commandline --forward-jump-till=$fish_key' 'set -eg fish_key'
bind --preset -M T '' get-key 'fish_vi_exec_motion commandline --backward-jump-till=$fish_key' 'set -eg fish_key'
bind --preset -M operator ';' 'fish_vi_exec_motion repeat-jump'
bind --preset -M operator , 'fish_vi_exec_motion repeat-jump-reverse'

View File

@@ -86,7 +86,7 @@ function fish_prompt
switch $fish_bind_mode
case default
set mode (set_color --bold red)N
case operator
case operator f F t T
set mode (set_color --bold cyan)N
case insert
set mode (set_color --bold green)I