2

Im very new to vim scripting. I have the following script in my .vimrc:

  • If there is no user input aka I press <CR> => go to recent buffer
  • If input is 'd' => delete all buffers except for the current one
  • Else go to inputted buffer.
"Fast buffer switch
function Warp()
  ls
  call inputsave()
  let bufname = input('warp: ')
  call inputrestore()
  if bufname == ""
    b#
  elseif bufname == "d"
    %bd|e#|bd#
  else
    exe "b " . bufname
  endif
endfunction
nnoremap <silent> <C-f> :call Warp()<CR>

The :bcommand works so that I dont have to write the full filepath but only a substring of the file name. For example I can navigate to bar/foo/helloworld.js with :b hello. However, sometimes file names can overlap which causes :b to error out. An intuitive solution to this is to use tab-completion to select the correct file when using :b on the command line. However, I dont know how this could be integrated into my function or even if it is possible. Somethings I noticed:

  • nnoremap <C-f> :b allows me to use tab-completion
  • getchar() == 13 allows me to detect <CR>
  • Maybe something with feedkeys but I dont know if that works with cmdline. Some further ideas I have but dont think is possible in simple vim scripting is catching the error so that the user can revise or use tab-completion the file name inputted clashes.

Thank you in advance. Any advice is greatly appreciated.

4
  • 2
    I think you want to read :h :command-complete: The idea would be to create a new command (:h user-commands) Warp which will have -complete=buffer and which will call your Warp() function. This way you can use :Warp hel<tab> and you will get the same completion as for :b hel<tab>
    – statox
    May 26 at 12:51
  • @statox Thank you so much. With your advice, I was able to get :Warp working: Imgur. The problem is :ls no longer works. When I map using |, :Warp is not invoked as shown in the picture.
    – prizel
    May 26 at 14:13
  • I fixed it! Ended up not needing <bar>. @statox many thanks!
    – prizel
    May 26 at 14:37
  • 1
    I didn't have time to answer but it's great you figured it out by yourself. Welcome to our site and congrats on your first question and answer :)
    – statox
    May 26 at 15:20
2

A simple fix is to use the third argument of input, which is a {completion} type (list at :help :command-completion):

…
const bufname = input('warp: ', '', 'buffer')
…

(I used const instead of let, too.)

1
  • Wow I really like this solution. Thanks for sharing!
    – prizel
    May 26 at 16:08
1

I ended up writing this little script:

" --Warp: fast buffer switch
function Warp(...)
  let bufname = a:1
  if bufname == ""
    b#
  else
    if bufname == "d"
      echo("d")
      %bd|e#|bd#
    else
      exe "b " . bufname
    endif
  endif
endfunction
command! -nargs=? -complete=buffer Warp :call Warp(<q-args>)
nnoremap <C-f> :buffers<CR>:Warp 

The UI isnt as nice as the first iteration because the command :buffers stays in the view and :Warp doesnt feel like im filling into input box like warp: but the tab-completion works perfectly. Many thanks to @statox for helping me out. Any advice for extending my script will be greatly appreciated.

2
  • 1
    Some nits: bufname == "" could be written empty(bufname); I prefer to spell out commands (so buffer #, %bdelete, edit #, bdelete#, etc.); execute automatically adds a single space between arguments, so execute 'buffer' bufname is enough; elseif is valid, so you can save yourself some nesting
    – D. Ben Knoble
    May 26 at 16:33
  • @D.BenKnoble Thank you very much for taking the time, Ill make these changes.
    – prizel
    May 26 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.