buffers.vim 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. " MIT License. Copyright (c) 2013-2021 Bailey Ling et al.
  2. " vim: et ts=2 sts=2 sw=2
  3. scriptencoding utf-8
  4. let s:spc = g:airline_symbols.space
  5. let s:current_bufnr = -1
  6. let s:current_modified = 0
  7. let s:current_tabline = ''
  8. let s:current_visible_buffers = []
  9. let s:number_map = {
  10. \ '0': '⁰',
  11. \ '1': '¹',
  12. \ '2': '²',
  13. \ '3': '³',
  14. \ '4': '⁴',
  15. \ '5': '⁵',
  16. \ '6': '⁶',
  17. \ '7': '⁷',
  18. \ '8': '⁸',
  19. \ '9': '⁹'
  20. \ }
  21. let s:number_map = &encoding == 'utf-8'
  22. \ ? get(g:, 'airline#extensions#tabline#buffer_idx_format', s:number_map)
  23. \ : {}
  24. function! airline#extensions#tabline#buffers#off()
  25. augroup airline_tabline_buffers
  26. autocmd!
  27. augroup END
  28. endfunction
  29. function! airline#extensions#tabline#buffers#on()
  30. let terminal_event = has("nvim") ? 'TermOpen' : 'TerminalOpen'
  31. augroup airline_tabline_buffers
  32. autocmd!
  33. autocmd BufDelete * call airline#extensions#tabline#buflist#clean()
  34. if exists("##".terminal_event)
  35. exe 'autocmd '. terminal_event. ' * call airline#extensions#tabline#buflist#clean()'
  36. endif
  37. autocmd User BufMRUChange call airline#extensions#tabline#buflist#clean()
  38. augroup END
  39. endfunction
  40. function! airline#extensions#tabline#buffers#invalidate()
  41. let s:current_bufnr = -1
  42. endfunction
  43. function! airline#extensions#tabline#buffers#get()
  44. try
  45. call <sid>map_keys()
  46. catch
  47. " no-op
  48. endtry
  49. let cur = bufnr('%')
  50. if cur == s:current_bufnr && &columns == s:column_width
  51. if !g:airline_detect_modified || getbufvar(cur, '&modified') == s:current_modified
  52. return s:current_tabline
  53. endif
  54. endif
  55. let b = airline#extensions#tabline#new_builder()
  56. let tab_bufs = tabpagebuflist(tabpagenr())
  57. let show_buf_label_first = 0
  58. if get(g:, 'airline#extensions#tabline#buf_label_first', 0)
  59. let show_buf_label_first = 1
  60. endif
  61. if show_buf_label_first
  62. call airline#extensions#tabline#add_label(b, 'buffers', 0)
  63. endif
  64. let b.tab_bufs = tabpagebuflist(tabpagenr())
  65. let b.overflow_group = 'airline_tabhid'
  66. let b.buffers = airline#extensions#tabline#buflist#list()
  67. if get(g:, 'airline#extensions#tabline#current_first', 0)
  68. if index(b.buffers, cur) > -1
  69. call remove(b.buffers, index(b.buffers, cur))
  70. endif
  71. let b.buffers = [cur] + b.buffers
  72. endif
  73. function! b.get_group(i) dict
  74. let bufnum = get(self.buffers, a:i, -1)
  75. if bufnum == -1
  76. return ''
  77. endif
  78. let group = airline#extensions#tabline#group_of_bufnr(self.tab_bufs, bufnum)
  79. if bufnum == bufnr('%')
  80. let s:current_modified = (group == 'airline_tabmod') ? 1 : 0
  81. endif
  82. return group
  83. endfunction
  84. if has("tablineat")
  85. function! b.get_pretitle(i) dict
  86. let bufnum = get(self.buffers, a:i, -1)
  87. return '%'.bufnum.'@airline#extensions#tabline#buffers#clickbuf@'
  88. endfunction
  89. function! b.get_posttitle(i) dict
  90. return '%X'
  91. endfunction
  92. endif
  93. function! b.get_title(i) dict
  94. let bufnum = get(self.buffers, a:i, -1)
  95. let group = self.get_group(a:i)
  96. let pgroup = self.get_group(a:i - 1)
  97. " always add a space when powerline_fonts are used
  98. " or for the very first item
  99. if get(g:, 'airline_powerline_fonts', 0) || a:i == 0
  100. let space = s:spc
  101. else
  102. let space= (pgroup == group ? s:spc : '')
  103. endif
  104. if get(g:, 'airline#extensions#tabline#buffer_idx_mode', 0)
  105. if len(s:number_map) > 0
  106. return space. s:get_number(a:i) . '%(%{airline#extensions#tabline#get_buffer_name('.bufnum.')}%)' . s:spc
  107. else
  108. return '['.(a:i+1).s:spc.'%(%{airline#extensions#tabline#get_buffer_name('.bufnum.')}%)'.']'
  109. endif
  110. else
  111. return space.'%(%{airline#extensions#tabline#get_buffer_name('.bufnum.')}%)'.s:spc
  112. endif
  113. endfunction
  114. let current_buffer = max([index(b.buffers, cur), 0])
  115. let last_buffer = len(b.buffers) - 1
  116. call b.insert_titles(current_buffer, 0, last_buffer)
  117. call b.add_section('airline_tabfill', '')
  118. call b.split()
  119. call b.add_section('airline_tabfill', '')
  120. if !show_buf_label_first
  121. call airline#extensions#tabline#add_label(b, 'buffers', 1)
  122. endif
  123. call airline#extensions#tabline#add_tab_label(b)
  124. let s:current_bufnr = cur
  125. let s:column_width = &columns
  126. let s:current_tabline = b.build()
  127. let s:current_visible_buffers = copy(b.buffers)
  128. " Do not remove from s:current_visible_buffers, this breaks s:select_tab()
  129. "if b._right_title <= last_buffer
  130. " call remove(s:current_visible_buffers, b._right_title, last_buffer)
  131. "endif
  132. "if b._left_title > 0
  133. " call remove(s:current_visible_buffers, 0, b._left_title)
  134. "endif
  135. return s:current_tabline
  136. endfunction
  137. function! s:get_number(index)
  138. if len(s:number_map) == 0
  139. return a:index
  140. endif
  141. let bidx_mode = get(g:, 'airline#extensions#tabline#buffer_idx_mode', 0)
  142. let number_format = bidx_mode > 1 ? '%02d' : '%d'
  143. let l:count = bidx_mode == 2 ? a:index+11 : a:index+1
  144. return join(map(split(printf(number_format, l:count), '\zs'),
  145. \ 'get(s:number_map, v:val, "")'), '')
  146. endfunction
  147. function! s:select_tab(buf_index)
  148. " no-op when called in 'keymap_ignored_filetypes'
  149. if count(get(g:, 'airline#extensions#tabline#keymap_ignored_filetypes',
  150. \ ['vimfiler', 'nerdtree']), &ft)
  151. return
  152. endif
  153. let idx = a:buf_index
  154. if s:current_visible_buffers[0] == -1
  155. let idx = idx + 1
  156. endif
  157. let buf = get(s:current_visible_buffers, idx, 0)
  158. if buf != 0
  159. exec 'b!' . buf
  160. endif
  161. endfunction
  162. function! s:jump_to_tab(offset)
  163. let l = airline#extensions#tabline#buflist#list()
  164. let i = index(l, bufnr('%'))
  165. if i > -1
  166. exec 'b!' . l[(i + a:offset) % len(l)]
  167. endif
  168. endfunction
  169. function! s:map_keys()
  170. let bidx_mode = get(g:, 'airline#extensions#tabline#buffer_idx_mode', 1)
  171. if bidx_mode > 0
  172. if bidx_mode == 1
  173. for i in range(1, 10)
  174. exe printf('noremap <silent> <Plug>AirlineSelectTab%d :call <SID>select_tab(%d)<CR>', i%10, i-1)
  175. endfor
  176. else
  177. let start_idx = bidx_mode == 2 ? 11 : 1
  178. for i in range(start_idx, 99)
  179. exe printf('noremap <silent> <Plug>AirlineSelectTab%02d :call <SID>select_tab(%d)<CR>', i, i-start_idx)
  180. endfor
  181. endif
  182. noremap <silent> <Plug>AirlineSelectPrevTab :<C-u>call <SID>jump_to_tab(-v:count1)<CR>
  183. noremap <silent> <Plug>AirlineSelectNextTab :<C-u>call <SID>jump_to_tab(v:count1)<CR>
  184. " Enable this for debugging
  185. " com! AirlineBufferList :echo map(copy(s:current_visible_buffers), {i,k -> k.": ".bufname(k)})
  186. endif
  187. endfunction
  188. function! airline#extensions#tabline#buffers#clickbuf(minwid, clicks, button, modifiers) abort
  189. " Clickable buffers
  190. " works only in recent NeoVim with has('tablineat')
  191. " single mouse button click without modifiers pressed
  192. if a:clicks == 1 && a:modifiers !~# '[^ ]'
  193. if a:button is# 'l'
  194. " left button - switch to buffer
  195. try
  196. silent execute 'buffer' a:minwid
  197. catch
  198. call airline#util#warning("Cannot switch buffer, current buffer is modified! See :h 'hidden'")
  199. endtry
  200. elseif a:button is# 'm'
  201. " middle button - delete buffer
  202. if get(g:, 'airline#extensions#tabline#middle_click_preserves_windows', 0) == 0 || winnr('$') == 1
  203. " just simply delete the clicked buffer. This will cause windows
  204. " associated with the clicked buffer to be closed.
  205. silent execute 'bdelete' a:minwid
  206. else
  207. " find windows displaying the clicked buffer and open an new
  208. " buffer in them.
  209. let current_window = bufwinnr("%")
  210. let window_number = bufwinnr(a:minwid)
  211. let last_window_visited = -1
  212. " Set to 1 if the clicked buffer was open in any windows.
  213. let buffer_in_window = 0
  214. " Find the next window with the clicked buffer open. If bufwinnr()
  215. " returns the same window number, this is because we clicked a new
  216. " buffer, and then tried editing a new buffer. Vim won't create a
  217. " new empty buffer for the same window, so we get the same window
  218. " number from bufwinnr(). In this case we just give up and don't
  219. " delete the buffer.
  220. " This could be made cleaner if we could check if the clicked buffer
  221. " is a new buffer, but I don't know if there is a way to do that.
  222. while window_number != -1 && window_number != last_window_visited
  223. let buffer_in_window = 1
  224. silent execute window_number . 'wincmd w'
  225. silent execute 'enew'
  226. let last_window_visited = window_number
  227. let window_number = bufwinnr(a:minwid)
  228. endwhile
  229. silent execute current_window . 'wincmd w'
  230. if window_number != last_window_visited || buffer_in_window == 0
  231. silent execute 'bdelete' a:minwid
  232. endif
  233. endif
  234. endif
  235. endif
  236. endfunction