vim-ctrlspace / vim-ctrlspace

Vim Space Controller
1.75k stars 73 forks source link

Move selection bar multiple lines at once #314

Closed swoh816 closed 6 months ago

swoh816 commented 7 months ago

In normal vim mode, run a command multiple times by pressing before running the command. For example, you can do +up to move cursor up for the of times. Such functionality is missing inside CtrlSpace window.

Describe the solution you'd like I guess this issue can be automatically fixed if Telescope gets incorporated into CtrlSpace as discussed in this issue. However, for the people who want to keep using the current CtrlSpace window setting, I think it'd still be useful to have the functionality to run a command multiple times (by pressing before running the command) inside CtrlSpace window.

Describe alternatives you've considered Given that Telescope gets integrated with CtrlSpace without changing any mapping of Telescope, this issue can be automatically fixed if Telescope is incorporated into CtrlSpace as discussed in this issue.

Additional context I doubt if implementing this functionality can cause any error because there's no mapping for any number in every window (bookmark, workspace, tab, buffer) in CtrlSpace.

Version(s) (please complete the following information):

Konfekt commented 7 months ago

This is a bit of work in

" autoload/ctrlspace/keys/common.vim (line 7)
function! ctrlspace#keys#common#Init() abort

where one would have to add maps such as

call s:map("ExpectInput1",                   "1")
call s:map("ExpectInput2",                   "2")
call s:map("ExpectInput3",                   "3")
call s:map("ExpectInput4",                   "4")
call s:map("ExpectInput5",                   "5")
call s:map("ExpectInput6",                   "6")
call s:map("ExpectInput7",                   "7")
call s:map("ExpectInput8",                   "8")
call s:map("ExpectInput9",                   "9")

that call input() and

" autoload/ctrlspace/window.vim (line 218)
function! ctrlspace#window#MoveSelectionBar(where) abort

if j or k is provided. Pull requests most welcome.

swoh816 commented 7 months ago

I followed your advice and made one using input() function. Please see https://github.com/vim-ctrlspace/vim-ctrlspace/pull/315 and see if it reflects the code you have in mind.

I want to note that, with input() function, you must press enter after a prompt (such as "Press key: "). It makes me press enter after I press k or j to go up or down, which is cumbersome if you're used to vim-like navigation where you don't press enter following j or k (also, you don't need to see prompt.).

I found another function called getchar that takes only one character value. (See Stackoverflow.) Using getchar, you don't need to press enter after pressing a key, and also you don't see a prompt before pressing the key, both of which make the navigation more vim-like. I prototyped CountPrefix2 with getchar in https://github.com/vim-ctrlspace/vim-ctrlspace/pull/316, please review it and leave comments. After we finalize that function, I'll use CountPrefix2 to make CountPrefix1 to CountPrefix9.

This is the first time I code in Vimscript, so my design of vimscript is probably not optimal. For example, I hope I can make a more generalized function for all CountPrefix1-CountPrefix9. Making functions for each CountPrefix1-CountPrefix9 seems very untidy, unless there's no other way. (It should be possible only if there's a Vimscript's built-in function that returns the mapping that triggered the function, in which case you get the number key that just triggered the function, and repeat whatever command is followed by for as many times as the number key.)

Please review and leave any comments to improve the vimscript code.

Konfekt commented 7 months ago

I want to note that, with input() function, you must press enter after a prompt (such as "Press key: "). It makes me press enter after I press k or j to go up or down, which is cumbersome if you're used to vim-like navigation where you don't press enter following j or k (also, you don't need to see prompt.). I found another function called getchar that takes only one character value. (See Stackoverflow.) Using getchar, you don't need to press enter after pressing a key, and also you don't see a prompt before pressing the key, both of which make the navigation more vim-like.

Yes, you are completely right, getchar() is the right function.

Konfekt commented 7 months ago

Thank you for making the first steps. It now at least takes a single digit and seems to work fine. That's quite something. Next step would be for completeness to allow for more digits, but no hurry.

swoh816 commented 7 months ago

Thanks @Konfekt for your close guidance. You generalized my code and now it works for all digits! I guess there's no more stuff to be done with regard to count prefix? If there's any more idea about developing it further, I'd appreciate if you could share your thoughts.

Also, just for my knowledge at this point, do you know any vimscript function that returns the mapping that just triggered the function? Something like the following:

function DummyFunction()
  let mapping = ReturnTriggerMapping()
  echo "Mapping: " mapping
endfunction

nmap p :call DummyFunction()

Then if you press p in normal mode, it echos Mapping: p. I wanted to know if vimscript has any functions that do the job, then I can generalize the countprefix to any functions (although it's probably unnecessary to do so because I think it's mainly j/k that you'd usually use with count prefix).

Konfekt commented 7 months ago

There's no built-in function, but maybe we can map 1 ... 9 to

function! CaptureMappingChars()
    " This variable will hold the typed characters
    let g:trigger_chars = ''

    " Capture the last typed character using getchar()
    let l:char = nr2char(getchar())

    " Append the character to the global variable
    let g:trigger_chars .= l:char

    " Do something with the captured characters here
    " ...

endfunction

nnoremap <expr> 2 CaptureMappingChars()

Stop once a non-digit is read in. Get the count with str2nr(g:trigger_chars[:-2]).

Konfekt commented 6 months ago

Implemented in https://github.com/vim-ctrlspace/vim-ctrlspace/commit/c43997bc331903a68d3e70d4eeb33fc4bd2aa451 (though by simply looping over the input)