I usually use {num}Ctrl-6 to switch buffers in Neovim, where {num} is the number of buffer (see this post). Since Neovim has builtin gt mapping to switch between tabpages, I thought it might be a good idea to use gb as buffer switching shortcut avoid strech when pressing Ctrl-6.

Here is what I have got:

Click to show the code.
nnoremap <silent> gb :<C-U>call <SID>GoToBuffer(v:count, 'forward')<CR>
nnoremap <silent> gB :<C-U>call <SID>GoToBuffer(v:count, 'backward')<CR>

function! s:GoToBuffer(count, direction) abort
  if a:count == 0
    if a:direction ==# 'forward'
    elseif a:direction ==# 'backward'
      echoerr 'Bad argument ' a:direction
  " Check the validity of buffer number.
  if index(s:GetBufNums(), a:count) == -1
    echohl WarningMsg | echomsg 'Invalid bufnr: ' a:count | echohl None

  if a:direction ==# 'forward'
    silent execute('buffer' . a:count)

function! s:GetBufNums() abort
  let l:buf_infos = getbufinfo({'buflisted':1})
  let l:buf_nums = map(l:buf_infos, "v:val['bufnr']")
  return l:buf_nums

You can use gb and gB without count to switch forward and backward in the buffer list. When provided with a count, gb can also switch the buffer with that number. For example, if we have buffer with number 6, press 6gb in normal mode will switch to that buffer.

Issues I have met

Using count in mappings

If we use a count before the mapping, and then execute some command, vim will insert a range for this command automatically1. To prevent this, we use Ctrl-U to delete the range inserted by Vim.


s:MyFunc or <SID>MyFunc

Another issue is that we need to use call <SID>GoToBuffer instead of call s:GoToBuffer. The s: notation only works if we are in the same script that defines this function. When we execute the mapping, we are usually in other files. If we use s: notation, we get the following error:

> E81: Using <SID> not in a script context

See also Neovim help file on this topic (h <SID>).


  1. To verify, press a number, and then press : to enter command line mode. ↩︎