junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
64.25k stars 2.38k forks source link

Vi-mode for input field navigation and editing. Maybe by introducing readline support? #3853

Closed sebastiancarlos closed 3 months ago

sebastiancarlos commented 3 months ago

Checklist

Output of fzf --version

0.53.0 (brew)

OS

Shell

Problem / Steps to reproduce

Hi!

First off, thanks for fzf. It's been an essential tool in my workflow, and I really appreciate all the work that has gone into it.

I was wondering if there could be an option to enable vi-mode for the input field in the fzf finder. The idea is to allow vim-style commands for navigating and editing text within the input line, similar to how readline can be configured for vi-mode.

For example, being able to use commands like b and w to move between words, I and A for inserting at the start and end of the line, cw for changing words, D to delete to the end of the line, and so on. This would really enhance the efficiency for those of us who are accustomed to vim keybindings.

I know there was a similar issue opened here: #1505, but I believe my suggestion is a bit different. That issue seemed to focus more on using vim commands for selecting elements within the list, which was addressed by using Ctrl-j/k. However, my request is specifically about enhancing the input field itself with vi-style text-editing commands.

Of course, this should be an optional feature, and users should be able to configure whether they prefer the default "emacs" style or vi-mode, much like how readline offers the choice. Again, just like readline, an option to display an optionally customizable "mode indicator" could be helpful too.

And indeed, could this feature be somewhat easily implemented by adding readline support or some of their equivalents, as done in several interactive programs such as sqlite and gdb?

I'd love to hear your thoughts on this, as the concept of vi-mode for terminal inputs is underappreciated. Yet, those who do use them are very successful both in our professional as well as in our romantic lives (vim fingers, if you know what I mean) Thanks again for the amazing tool!

junegunn commented 3 months ago

Thanks for suggestion.

I don't see myself implementing it, as I think mode switching is overkill for fzf where you don't spend a lot of time editing your query. I think this holds true for most of the other users, they wouldn't spend more than a few seconds inside fzf 90% of the time; open fzf, type in a few characters, and you get the best match at your hand, press enter. So I don't think it's worth the effort, but if anyone's interested in implementing it, I can review the patch though there's no guarantee that it'll finally land on fzf.

FWIW, I've been using Vim for many years by now, and I can safely say that I know one or two things about it, but I don't use vi-mode on command-line because I feel Emacs-style bindings work better for input prompts. I wasn't familiar with all the bindings, but after properly learning them, I realized I was severely underutilizing them, and they can be more efficient than vi-mode in quick editing mode.

And fzf implements all of these.

Even if we incorporate some readline library, implementing it properly won't be trivial, because fzf allows full customization of the keys via --bind and it's going to be a lot of work to reconcile the two systems.

thjbdvlt commented 1 month ago

hello! i've made a mini python script that generates bindings for a pseudo vi-mode from a config file (because i have no alt key, and dislike ctrl because of an idiosyncratic keyboard). it's a really quick-and-dirty solution but well i can't do better and impact on performance is not terrible in my experience (it produces a veeeery long binding). i really like using fzf like this (escape, then j/k to go down/up, c for delete, i/a/I/A for insert mode, and so on). it's here on github: thjbdvlt/fzf-vi-mode

here is how the config file could look:

[mode]
escape = esc
insert_before = i
insert_after = a 
insert_end_line = A
insert_beginning_line = I

[normal]
j = down
k = up
s = jump
p = toggle-preview
h = backward-char
l = forward-char
e = forward-word
b = backward-word
d = clear-query
y = execute(echo {} | xsel -b)
E = preview-half-page-down
U = preview-half-page-up
c = cancel
x = forward-char+backward-delete-char
X = backward-delete-char

[insert]
® = backward-kill-word
change = top
backward-eof = abort

and here is the bindings for this config file:

--bind=j:down,k:up,s:jump,p:toggle-preview \
--bind=h:backward-char,l:forward-char,e:forward-word,b:backward-word \
--bind=d:clear-query \
--bind='y:execute(echo {} | xsel -b)' \
--bind=E:preview-half-page-down,U:preview-half-page-up \
--bind=c:cancel,x:forward-char+backward-delete-char \
--bind=X:backward-delete-char \
--bind=start:enable-search+unbind(e,j,s,p,h,l,é,b,d,y,E,U,c,x,X,i,a,A,I)  \
--bind=i:enable-search+unbind(j,k,s,p,h,l,e,b,d,y,E,U,c,x,X,i,a,A,I) \
--bind=a:enable-search+unbind(j,k,s,p,h,l,e,b,d,y,E,U,c,x,X,i,a,A,I)+forward-char \
--bind=A:enable-search+unbind(j,k,s,p,h,l,e,b,d,y,E,U,c,x,X,i,a,A,I)+end-of-line \
--bind=I:enable-search+unbind(j,k,s,p,h,l,e,b,d,y,E,U,c,x,X,i,a,A,I)+beginning-of-line \
--bind=esc:disable-search+rebind(j,k,s,p,h,l,e,b,d,y,E,U,c,x,X,i,a,A,I) \
--bind=®:backward-kill-word,change:top,backward-eof:abort