-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuftabline.vim
225 lines (204 loc) · 8.99 KB
/
buftabline.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
" Vim global plugin for rendering the buffer list in the tabline
" Licence: The MIT License (MIT)
" Commit: $Format:%H$
" {{{ Copyright (c) 2015 Aristotle Pagaltzis <[email protected]>
"
" Permission is hereby granted, free of charge, to any person obtaining a copy
" of this software and associated documentation files (the "Software"), to deal
" in the Software without restriction, including without limitation the rights
" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
" copies of the Software, and to permit persons to whom the Software is
" furnished to do so, subject to the following conditions:
"
" The above copyright notice and this permission notice shall be included in
" all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
" THE SOFTWARE.
" }}}
if v:version < 700
echoerr printf('Vim 7 is required for buftabline (this is only %d.%d)',v:version/100,v:version%100)
finish
endif
scriptencoding utf-8
augroup BufTabLine
autocmd!
hi default link BufTabLineCurrent TabLineSel
hi default link BufTabLineActive PmenuSel
hi default link BufTabLineHidden TabLine
hi default link BufTabLineFill TabLineFill
let g:buftabline_numbers = get(g:, 'buftabline_numbers', 0)
let g:buftabline_indicators = get(g:, 'buftabline_indicators', 0)
let g:buftabline_separators = get(g:, 'buftabline_separators', 0)
let g:buftabline_show = get(g:, 'buftabline_show', 2)
function! buftabline#user_buffers() " help buffers are always unlisted, but quickfix buffers are not
return filter(range(1,bufnr('$')),'buflisted(v:val) && "quickfix" !=? getbufvar(v:val, "&buftype")')
endfunction
let s:dirsep = fnamemodify(getcwd(),':p')[-1:]
let s:centerbuf = winbufnr(0)
function! buftabline#render()
let show_num = g:buftabline_numbers == 1
let show_ord = g:buftabline_numbers == 2
let show_mod = g:buftabline_indicators
let lpad = g:buftabline_separators ? nr2char(0x23B8) : ' '
let bufnums = buftabline#user_buffers()
let centerbuf = s:centerbuf " prevent tabline jumping around when non-user buffer current (e.g. help)
" start - custom numbers
let s:number_map = {
\ '0': '⁰',
\ '1': '¹',
\ '2': '²',
\ '3': '³',
\ '4': '⁴',
\ '5': '⁵',
\ '6': '⁶',
\ '7': '⁷',
\ '8': '⁸',
\ '9': '⁹'
\ }
" end - custom numbers
" pick up data on all the buffers
let tabs = []
let path_tabs = []
let tabs_per_tail = {}
let currentbuf = winbufnr(0)
let screen_num = 0
let l:index = 1
for bufnum in bufnums
"let screen_num = show_num ? bufnum : show_ord ? screen_num + 1 : ''
"let screen_num = show_num ? bufnum : show_ord ? get(s:number_map, screen_num + 1, '') : ''
let screen_num = show_num ? bufnum : show_ord ? get(s:number_map, l:index, '') : ''
let tab = { 'num': bufnum }
let tab.hilite = currentbuf == bufnum ? 'Current' : bufwinnr(bufnum) > 0 ? 'Active' : 'Hidden'
if currentbuf == bufnum | let [centerbuf, s:centerbuf] = [bufnum, bufnum] | endif
let bufpath = bufname(bufnum)
if strlen(bufpath)
let tab.path = fnamemodify(bufpath, ':p:~:.')
let tab.sep = strridx(tab.path, s:dirsep, strlen(tab.path) - 2) " keep trailing dirsep
let tab.label = WebDevIconsGetFileTypeSymbol(tab.path) . '' . tab.path[tab.sep + 1:] . ' ' . ( show_mod && getbufvar(bufnum, '&mod') ? '' : ' ' )
"let pre = ( show_mod && getbufvar(bufnum, '&mod') ? '+' : '' ) . screen_num
"let pre = screen_num . ( show_mod && getbufvar(bufnum, '&mod') ? '' : ' ' )
let pre = screen_num
let tab.pre = strlen(pre) ? pre . ' ' : ''
let tabs_per_tail[tab.label] = get(tabs_per_tail, tab.label, 0) + 1
let path_tabs += [tab]
elseif -1 < index(['nofile','acwrite'], getbufvar(bufnum, '&buftype')) " scratch buffer
let tab.label = ( show_mod ? '!' . screen_num : screen_num ? screen_num . ' !' : '!' )
else " unnamed file
let tab.label = ( show_mod && getbufvar(bufnum, '&mod') ? '+' : '' )
\ . ( screen_num ? screen_num : '*' )
endif
let l:index = l:index + 1
let tabs += [tab]
endfor
" disambiguate same-basename files by adding trailing path segments
while len(filter(tabs_per_tail, 'v:val > 1'))
let [ambiguous, tabs_per_tail] = [tabs_per_tail, {}]
for tab in path_tabs
if -1 < tab.sep && has_key(ambiguous, tab.label)
let tab.sep = strridx(tab.path, s:dirsep, tab.sep - 1)
let tab.label = tab.path[tab.sep + 1:]
endif
let tabs_per_tail[tab.label] = get(tabs_per_tail, tab.label, 0) + 1
endfor
endwhile
" now keep the current buffer center-screen as much as possible:
" 1. setup
let lft = { 'lasttab': 0, 'cut': '.', 'indicator': '<', 'width': 0, 'half': &columns / 2 }
let rgt = { 'lasttab': -1, 'cut': '.$', 'indicator': '>', 'width': 0, 'half': &columns - lft.half }
" 2. sum the string lengths for the left and right halves
let currentside = lft
for tab in tabs
let tab.label = lpad . get(tab, 'pre', '') . tab.label . ' '
let tab.width = strwidth(strtrans(tab.label))
if centerbuf == tab.num
let halfwidth = tab.width / 2
let lft.width += halfwidth
let rgt.width += tab.width - halfwidth
let currentside = rgt
continue
endif
let currentside.width += tab.width
endfor
if currentside is lft " centered buffer not seen?
" then blame any overflow on the right side, to protect the left
let [lft.width, rgt.width] = [0, lft.width]
endif
" 3. toss away tabs and pieces until all fits:
if ( lft.width + rgt.width ) > &columns
let [oversized, remainder]
\ = lft.width < lft.half ? [ [rgt], &columns - lft.width ]
\ : rgt.width < rgt.half ? [ [lft], &columns - rgt.width ]
\ : [ [lft, rgt], 0 ]
for side in oversized
let delta = side.width - ( remainder ? remainder : side.half )
" toss entire tabs to close the distance
while delta >= tabs[side.lasttab].width
let delta -= remove(tabs, side.lasttab).width
endwhile
" then snip at the last one to make it fit
let endtab = tabs[side.lasttab]
while delta > ( endtab.width - strwidth(strtrans(endtab.label)) )
let endtab.label = substitute(endtab.label, side.cut, '', '')
endwhile
let endtab.label = substitute(endtab.label, side.cut, side.indicator, '')
endfor
endif
if len(tabs) | let tabs[0].label = substitute(tabs[0].label, lpad, ' ', '') | endif
let swallowclicks = '%'.(1 + tabpagenr('$')).'X'
return swallowclicks . join(map(tabs,'printf("%%#BufTabLine%s#%s",v:val.hilite,strtrans(v:val.label))'),'') . '%#BufTabLineFill#'
endfunction
function! buftabline#update(deletion)
set tabline=
if tabpagenr('$') > 1 | set guioptions+=e showtabline=2 | return | endif
set guioptions-=e
if 0 == g:buftabline_show
set showtabline=1
return
elseif 1 == g:buftabline_show
let bufnums = buftabline#user_buffers()
let total = len(bufnums)
if a:deletion && -1 < index(bufnums, bufnr('%'))
" BufDelete triggers before buffer is deleted
" so if current buffer is a user buffer, it must be subtracted
let total -= 1
endif
let &g:showtabline = 1 + ( total > 1 )
elseif 2 == g:buftabline_show
set showtabline=2
endif
set tabline=%!buftabline#render()
endfunction
autocmd BufAdd * call buftabline#update(0)
autocmd BufDelete * call buftabline#update(1)
autocmd TabEnter * call buftabline#update(0)
autocmd VimEnter * call buftabline#update(0)
noremap <silent> <Plug>BufTabLine.Go(1) :exe 'b'.get(buftabline#user_buffers(),0,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(2) :exe 'b'.get(buftabline#user_buffers(),1,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(3) :exe 'b'.get(buftabline#user_buffers(),2,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(4) :exe 'b'.get(buftabline#user_buffers(),3,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(5) :exe 'b'.get(buftabline#user_buffers(),4,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(6) :exe 'b'.get(buftabline#user_buffers(),5,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(7) :exe 'b'.get(buftabline#user_buffers(),6,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(8) :exe 'b'.get(buftabline#user_buffers(),7,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(9) :exe 'b'.get(buftabline#user_buffers(),8,'')<cr>
noremap <silent> <Plug>BufTabLine.Go(10) :exe 'b'.get(buftabline#user_buffers(),9,'')<cr>
if v:version < 703
function s:transpile()
let [ savelist, &list ] = [ &list, 0 ]
redir => src
silent function buftabline#render
redir END
let &list = savelist
let src = substitute(src, '\n\zs[0-9 ]*', '', 'g')
let src = substitute(src, 'strwidth(strtrans(\([^)]\+\)))', 'strlen(substitute(\1, ''\p\|\(.\)'', ''x\1'', ''g''))', 'g')
return src
endfunction
exe "delfunction buftabline#render\n" . s:transpile()
delfunction s:transpile
endif