3

I am using multiple files within the same tab and when I switch buffers using :bn I reach the terminal, at which point I have to issue the command again to move. Here is the catch, I am using keymaps to do buffer switching instead of typing the entire command.

is there a way to skip the terminal buffer and move on with this keymap.

The possible solution I can think as of now is using a separate tab for the terminal while keeping the present one for code. this is not a huge deal, just keeping my laziness alive.

Any and all ideas are appreciated.

3
  • 1
    I don't think your suggested workaround will work. Having the terminal buffer open in a tab won't prevent :bn from opening it in another tab.
    – Rich
    Jul 10, 2018 at 9:27
  • Have you thought about jumping to the exact buffer instead of cycling? You can use :b partial<tab> to go directly where you want to go. Related question: How can I prevent some buffers from being reachable using bnext, bprev? Jul 11, 2018 at 14:23
  • from what I know, tabs are the group of windows and windows display buffers, I was not aware that buffers can move across tabs. If that is is the case then I might have to rethink my approach. as of now, I am using the full command, will try the answers provided too.
    – ArunMKumar
    Jul 13, 2018 at 4:12

3 Answers 3

5

This should work too:

augroup termIgnore
    autocmd!
    autocmd TerminalOpen * set nobuflisted
augroup END
3
  • You actually posted yours 9s before mine!
    – Rich
    Jul 10, 2018 at 9:14
  • Stack exchange magic ^^ Jul 10, 2018 at 9:15
  • Haha! Anyhow, good solution. +1
    – Rich
    Jul 10, 2018 at 9:24
3

This should do the job:

function! BnSkipTerm()
  let start_buffer = bufnr('%')
  bn
  while &buftype ==# 'terminal' && bufnr('%') != start_buffer
    bn
  endwhile
endfunction

nnoremap <leader>bn :call BnSkipTerm()<CR>

It just keeps invoking :bn until it's not in a terminal window, by checking the 'buftype' setting.

2
  • 2
    What happens if a terminal is the last buffer? Does this abort if the bn fails, or might it get stuck in the loop?
    – D. Ben Knoble
    Jul 10, 2018 at 13:03
  • 1
    ahem. Fixed. :)
    – Rich
    Jul 10, 2018 at 13:49
1

Based on @Rich's answer, this is an extended version which ignores all special buffers (like the quickfix window), also takes a count to skip buffers and preserves the alternate buffer:

function! s:bswitch_normal(count, direction)
    " This function switches to the previous or next normal buffer excluding
    " all special buffers like quickfix or terminals
    " Modified version of https://vi.stackexchange.com/a/16710/37509
    let l:count = a:count
    let l:cmd = (a:direction ==# 'previous') ? 'bprevious' : 'bnext'
    let l:start_buffer = bufnr('%')
    while 1
        execute 'keepalt ' . l:cmd
        if &buftype == ''
            let l:count -= 1
            if l:count <= 0
                break
            endif
        endif
        " Prevent infinite loops if no buffer is a normal buffer
        if bufnr('%') == l:start_buffer && l:count == a:count
            break
        endif
    endwhile
    if bufnr('%') != l:start_buffer
        " Jump back to the start buffer once to set the alternate buffer
        execute 'buffer ' . l:start_buffer
        buffer #
    endif
endfunction

" Taken from `:help SID`
function! s:SID()
    return matchstr(expand('<SID>'), '<SNR>\zs\d\+\ze_')
endfunction

nnoremap <silent> <leader>bp :<C-u>execute 'call <SNR>' . <SID>SID() . '_bswitch_normal(' . v:count1 . ', "previous")'<CR>
nnoremap <silent> <leader>bn :<C-u>execute 'call <SNR>' . <SID>SID() . '_bswitch_normal(' . v:count1 . ', "next")'<CR>

The function s:bswitch_normal can be further improved by avoiding buffer switching (which can be slow on large files):

function! s:bswitch_normal(count, direction)
    " This function switches to the previous or next normal buffer excluding
    " all special buffers like quickfix or terminals
    let l:normal_buffers = filter(
                \ range(1, bufnr('$')),
                \ 'buflisted(v:val) && getbufvar(v:val, "&buftype") == ""'
                \ )
    if a:direction ==# 'previous'
        call reverse(l:normal_buffers)
    endif
    let l:next_buffer_index = 0
    " while
    "   `l:next_buffer_index` is not out of range and
    "   direction is 'next'      =>  buffer number <= active buffer number and
    "   direction is 'previous'  =>  buffer number >= active buffer number
    " `a => b` is expressed with `!a || b`
    while l:next_buffer_index < len(l:normal_buffers) &&
                \ (a:direction ==# 'previous' || l:normal_buffers[l:next_buffer_index] <= bufnr('%')) &&
                \ (a:direction !=# 'previous' || l:normal_buffers[l:next_buffer_index] >= bufnr('%'))
        let l:next_buffer_index += 1
    endwhile
    let l:next_buffer_index = (l:next_buffer_index + a:count - 1) % len(l:normal_buffers)
    execute 'buffer ' . l:normal_buffers[l:next_buffer_index]
endfunction
2
  • 1
    Welcome to Vi and Vim!
    – D. Ben Knoble
    Mar 18 at 21:03
  • Didn't see this answer when you posted it. Great stuff! +1
    – Rich
    Jul 12 at 9:54

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.