7cb5c24151
Adding an option to prevent windows from being closed when a buffer in
the tabline is middle clicked and the clicked buffer is currently open
in a window.
When this option is enabled, instead of closing the window a new buffer
will be opened in all of the windows editing the clicked buffer instead.
This is my first pull request AND my first experience with vimscript, so
my apologies if this is a bit sloppy 😄
249 lines
8.1 KiB
VimL
249 lines
8.1 KiB
VimL
" MIT License. Copyright (c) 2013-2016 Bailey Ling.
|
|
" vim: et ts=2 sts=2 sw=2
|
|
|
|
scriptencoding utf-8
|
|
|
|
let s:buffer_idx_mode = get(g:, 'airline#extensions#tabline#buffer_idx_mode', 0)
|
|
let s:show_tab_type = get(g:, 'airline#extensions#tabline#show_tab_type', 1)
|
|
let s:buffers_label = get(g:, 'airline#extensions#tabline#buffers_label', 'buffers')
|
|
let s:spc = g:airline_symbols.space
|
|
|
|
let s:current_bufnr = -1
|
|
let s:current_modified = 0
|
|
let s:current_tabline = ''
|
|
let s:current_visible_buffers = []
|
|
|
|
let s:number_map = {
|
|
\ '0': '⁰',
|
|
\ '1': '¹',
|
|
\ '2': '²',
|
|
\ '3': '³',
|
|
\ '4': '⁴',
|
|
\ '5': '⁵',
|
|
\ '6': '⁶',
|
|
\ '7': '⁷',
|
|
\ '8': '⁸',
|
|
\ '9': '⁹'
|
|
\ }
|
|
let s:number_map = &encoding == 'utf-8'
|
|
\ ? get(g:, 'airline#extensions#tabline#buffer_idx_format', s:number_map)
|
|
\ : {}
|
|
|
|
function! airline#extensions#tabline#buffers#off()
|
|
augroup airline_tabline_buffers
|
|
autocmd!
|
|
augroup END
|
|
endfunction
|
|
|
|
function! airline#extensions#tabline#buffers#on()
|
|
augroup airline_tabline_buffers
|
|
autocmd!
|
|
autocmd BufDelete * call airline#extensions#tabline#buffers#invalidate()
|
|
autocmd User BufMRUChange call airline#extensions#tabline#buflist#invalidate()
|
|
autocmd User BufMRUChange call airline#extensions#tabline#buffers#invalidate()
|
|
augroup END
|
|
endfunction
|
|
|
|
function! airline#extensions#tabline#buffers#invalidate()
|
|
let s:current_bufnr = -1
|
|
endfunction
|
|
|
|
function! airline#extensions#tabline#buffers#get()
|
|
call <sid>map_keys()
|
|
let cur = bufnr('%')
|
|
if cur == s:current_bufnr
|
|
if !g:airline_detect_modified || getbufvar(cur, '&modified') == s:current_modified
|
|
return s:current_tabline
|
|
endif
|
|
endif
|
|
|
|
let l:index = 1
|
|
let b = airline#extensions#tabline#new_builder()
|
|
let tab_bufs = tabpagebuflist(tabpagenr())
|
|
for nr in s:get_visible_buffers()
|
|
if nr < 0
|
|
call b.add_raw('%#airline_tabhid#...')
|
|
continue
|
|
endif
|
|
|
|
let group = airline#extensions#tabline#group_of_bufnr(tab_bufs, nr)
|
|
|
|
if nr == cur
|
|
let s:current_modified = (group == 'airline_tabmod') ? 1 : 0
|
|
endif
|
|
|
|
" Neovim feature: Have clickable buffers
|
|
if has("tablineat")
|
|
call b.add_raw('%'.nr.'@airline#extensions#tabline#buffers#clickbuf@')
|
|
endif
|
|
if s:buffer_idx_mode
|
|
if len(s:number_map) > 0
|
|
call b.add_section(group, s:spc . get(s:number_map, l:index, '') . '%(%{airline#extensions#tabline#get_buffer_name('.nr.')}%)' . s:spc)
|
|
else
|
|
call b.add_section(group, '['.l:index.s:spc.'%(%{airline#extensions#tabline#get_buffer_name('.nr.')}%)'.']')
|
|
endif
|
|
let l:index = l:index + 1
|
|
else
|
|
call b.add_section(group, s:spc.'%(%{airline#extensions#tabline#get_buffer_name('.nr.')}%)'.s:spc)
|
|
endif
|
|
if has("tablineat")
|
|
call b.add_raw('%X')
|
|
endif
|
|
endfor
|
|
|
|
call b.add_section('airline_tabfill', '')
|
|
call b.split()
|
|
call b.add_section('airline_tabfill', '')
|
|
if s:show_tab_type
|
|
call b.add_section_spaced('airline_tabtype', s:buffers_label)
|
|
endif
|
|
|
|
let s:current_bufnr = cur
|
|
let s:current_tabline = b.build()
|
|
return s:current_tabline
|
|
endfunction
|
|
|
|
function! s:get_visible_buffers()
|
|
let buffers = airline#extensions#tabline#buflist#list()
|
|
let cur = bufnr('%')
|
|
|
|
let total_width = 0
|
|
let max_width = 0
|
|
|
|
for nr in buffers
|
|
let width = len(airline#extensions#tabline#get_buffer_name(nr)) + 4
|
|
let total_width += width
|
|
let max_width = max([max_width, width])
|
|
endfor
|
|
|
|
" only show current and surrounding buffers if there are too many buffers
|
|
let position = index(buffers, cur)
|
|
let vimwidth = &columns
|
|
if total_width > vimwidth && position > -1
|
|
let buf_count = len(buffers)
|
|
|
|
" determine how many buffers to show based on the longest buffer width,
|
|
" use one on the right side and put the rest on the left
|
|
let buf_max = vimwidth / max_width
|
|
let buf_right = 1
|
|
let buf_left = max([0, buf_max - buf_right])
|
|
|
|
let start = max([0, position - buf_left])
|
|
let end = min([buf_count, position + buf_right])
|
|
|
|
" fill up available space on the right
|
|
if position < buf_left
|
|
let end += (buf_left - position)
|
|
endif
|
|
|
|
" fill up available space on the left
|
|
if end > buf_count - 1 - buf_right
|
|
let start -= max([0, buf_right - (buf_count - 1 - position)])
|
|
endif
|
|
|
|
let buffers = eval('buffers[' . start . ':' . end . ']')
|
|
|
|
if start > 0
|
|
call insert(buffers, -1, 0)
|
|
endif
|
|
|
|
if end < buf_count - 1
|
|
call add(buffers, -1)
|
|
endif
|
|
endif
|
|
|
|
let s:current_visible_buffers = buffers
|
|
return buffers
|
|
endfunction
|
|
|
|
function! s:select_tab(buf_index)
|
|
" no-op when called in the NERDTree buffer
|
|
if exists('t:NERDTreeBufName') && bufname('%') == t:NERDTreeBufName
|
|
return
|
|
endif
|
|
|
|
let idx = a:buf_index
|
|
if s:current_visible_buffers[0] == -1
|
|
let idx = idx + 1
|
|
endif
|
|
|
|
let buf = get(s:current_visible_buffers, idx, 0)
|
|
if buf != 0
|
|
exec 'b!' . buf
|
|
endif
|
|
endfunction
|
|
|
|
function! s:jump_to_tab(offset)
|
|
let l = s:current_visible_buffers
|
|
let i = index(l, bufnr('%'))
|
|
if i > -1
|
|
exec 'b!' . l[float2nr(fmod(i + a:offset, len(l)))]
|
|
endif
|
|
endfunction
|
|
|
|
function! s:map_keys()
|
|
if s:buffer_idx_mode
|
|
noremap <silent> <Plug>AirlineSelectTab1 :call <SID>select_tab(0)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab2 :call <SID>select_tab(1)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab3 :call <SID>select_tab(2)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab4 :call <SID>select_tab(3)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab5 :call <SID>select_tab(4)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab6 :call <SID>select_tab(5)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab7 :call <SID>select_tab(6)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab8 :call <SID>select_tab(7)<CR>
|
|
noremap <silent> <Plug>AirlineSelectTab9 :call <SID>select_tab(8)<CR>
|
|
noremap <silent> <Plug>AirlineSelectPrevTab :<C-u>call <SID>jump_to_tab(-v:count1)<CR>
|
|
noremap <silent> <Plug>AirlineSelectNextTab :<C-u>call <SID>jump_to_tab(v:count1)<CR>
|
|
endif
|
|
endfunction
|
|
|
|
function! airline#extensions#tabline#buffers#clickbuf(minwid, clicks, button, modifiers) abort
|
|
" Clickable buffers
|
|
" works only in recent NeoVim with has('tablineat')
|
|
|
|
" single mouse button click without modifiers pressed
|
|
if a:clicks == 1 && a:modifiers !~# '[^ ]'
|
|
if a:button is# 'l'
|
|
" left button - switch to buffer
|
|
silent execute 'buffer' a:minwid
|
|
elseif a:button is# 'm'
|
|
" middle button - delete buffer
|
|
|
|
if get(g:, 'airline#extensions#tabline#middle_click_preserves_windows', 0) == 0
|
|
" just simply delete the clicked buffer. This will cause windows
|
|
" associated with the clicked buffer to be closed.
|
|
silent execute 'bdelete' a:minwid
|
|
else
|
|
" find windows displaying the clicked buffer and open an new
|
|
" buffer in them.
|
|
let current_window = bufwinnr("%")
|
|
let window_number = bufwinnr(a:minwid)
|
|
let last_window_visited = -1
|
|
|
|
" Set to 1 if the clicked buffer was open in any windows.
|
|
let buffer_in_window = 0
|
|
|
|
" Find the next window with the clicked buffer open. If bufwinnr()
|
|
" returns the same window number, this is because we clicked a new
|
|
" buffer, and then tried editing a new buffer. Vim won't create a
|
|
" new empty buffer for the same window, so we get the same window
|
|
" number from bufwinnr(). In this case we just give up and don't
|
|
" delete the buffer.
|
|
" This could be made cleaner if we could check if the clicked buffer
|
|
" is a new buffer, but I don't know if there is a way to do that.
|
|
while window_number != -1 && window_number != last_window_visited
|
|
let buffer_in_window = 1
|
|
silent execute window_number . 'wincmd w'
|
|
silent execute 'enew'
|
|
let last_window_visited = window_number
|
|
let window_number = bufwinnr(a:minwid)
|
|
endwhile
|
|
silent execute current_window . 'wincmd w'
|
|
if window_number != last_window_visited || buffer_in_window == 0
|
|
silent execute 'bdelete' a:minwid
|
|
endif
|
|
endif
|
|
endif
|
|
endif
|
|
endfunction
|