2

I am using a convenient macro to list my buffers: map <leader>bb :buffers<cr>

I am trying to come up with a way to then switch to the buffer of interest with <leader>b<number> but I haven't found how to catch a number in this map. I assume there should be some kind of delay involved in case I have a 2-digit number (highly unlikely), however, even single-digit number would suffice.

3

I am using a convenient macro

Just FYI, one can also do :ls<CR> to achieve the same result. So that one does not look like "a life saver" to me.

a way to then switch to the buffer of interest

Again, that does not look so useful, as one can always do :b[Number]<CR> without any hassle. But let's figure out how we can create a "parameterized" mapping for this particular example.

First of all, normal mode commands in Vim can have a count, but it must be supplied before a command, not after it. So we aim to support [Number]<leader>b and not vice versa. The counter then will be available in a special variable v:count (or v:count1). Also, a user can press just <leader>b without any count supplied. And we must do something reasonable in this case, so let it be a "next buffer" command.

Next, we should make a command out of an expression (strings and numbers) and execute it. There are several ways to do so, but I think that :h map-<expr> is the best suit for this case.

So the mapping can be:

nnoremap <silent><expr><leader>b printf(":\<C-U>%s\n", v:count ? 'buffer' . v:count : 'bnext')

Now, N<leader>b works as :buffer N, and <leader>b works as :bnext.

  • Thanks for the answer! Could you please elaborate on the mapping you came up with? Specifically on the printf part. – arbulgazar Dec 9 '19 at 16:36
  • 1
    I know about both :ls<CR> and :b[number]<cr>, I just don't like typing ":" - it's not convenient for me. :) Not trying to promote any life-saving shortcut here, just a personal preference. – arbulgazar Dec 9 '19 at 16:38
  • 2
    @arbulgazar Here printf() is used merely to simplify string concatenation: the mapping produces a string which gets re-scanned because of <expr>. A possible alternative is to use :execute. BTW. to ease typing of : you can use nnoremap ; : – Matt Dec 9 '19 at 17:03
0

For single-digit buffers, you can actually hardcode 9 mappings, one for each digit:

nnoremap <Leader>b1 :buffer 1<CR>
nnoremap <Leader>b2 :buffer 2<CR>
nnoremap <Leader>b3 :buffer 3<CR>
nnoremap <Leader>b4 :buffer 4<CR>
nnoremap <Leader>b5 :buffer 5<CR>
nnoremap <Leader>b6 :buffer 6<CR>
nnoremap <Leader>b7 :buffer 7<CR>
nnoremap <Leader>b8 :buffer 8<CR>
nnoremap <Leader>b9 :buffer 9<CR>

If you don't like the repetition, you could use a :for loop to produce these lines:

for i in range(1, 9)
    execute 'nnoremap <Leader>b'.i.
        \ ' :buffer '.i.'<CR>'
endfor

For the double-digit case, it can be tricky to do with a mapping. You can potentially use getchar() to keep getting more characters and check whether they're valid digits. But you need a way to terminate the sequence, possibly by checking when you get a <CR> from getchar(), but that means the user will have to press an extra key to finish the sequence. (Though you could handle keys other than <CR> or digits by terminating the sequence and feeding them back with feedkeys().)

Since an extra key is likely needed, you might consider using input() instead, in which case you can even allow completion on buffer names!

function! SwitchBuffer()
    " Start by listing existing buffers
    buffers
    let n = input('Switch to: ', '', 'buffer')
    execute 'buffer' n
endfunction

nnoremap <Leader>bs :call SwitchBuffer()<CR>

You could use such a mapping in addition to the single-digit mappings, for cases where you want to use buffer names or two-digit buffer numbers. Also, listing them first as part of the command might be useful as well.

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.