Update 2026-01-25 09:38 OpenBSD/amd64-t14

This commit is contained in:
c0dev0id
2026-01-25 09:38:17 +01:00
parent 0769d7a789
commit 186dfa8096
1240 changed files with 189747 additions and 315946 deletions

View File

@@ -0,0 +1,5 @@
/plugin/buftabline.vim export-subst
/.gitignore export-ignore
/.gitattributes export-ignore
/README.md export-ignore
/LICENSE export-ignore

View File

@@ -0,0 +1 @@
/doc/tags

View File

@@ -1,21 +1,21 @@
The MIT License (MIT)
Copyright (C) 2013 Bailey Ling
Copyright (c) 2015 Aristotle Pagaltzis
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:
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 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.
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.

View File

@@ -1,38 +1,150 @@
# vim-bufferline
<h1 align="center">Buftabline</h1>
Super simple vim plugin to show the list of buffers in the command bar.
<div align="center">
A well-integrated, low-configuration buffer list that lives in the tabline<br>
<img src="https://raw.githubusercontent.com/ap/vim-buftabline/fe615be277cfba1ecadc52d61fa173d034817d67/screenshot.png" width="787">
</div>
# screenshots
#### in the statusline
Buffer basics
-------------
![img](img/bufferline-status.png)
If you dont know anything about buffers, the minimum you have to know is that
a buffer in Vim essentially means a file, and if you set `hidden`, Vim can keep
files open without necessarily displaying them on screen. You can then use the
`:bnext` and `:bprev` commands to change which buffer is being displayed in the
current window, and `:ls` to look at the list of buffers.
#### or the command bar
If this is all news to you, you should probably add this to your configuration:
![img](img/bufferline-command.png)
set hidden
nnoremap <C-N> :bnext<CR>
nnoremap <C-P> :bprev<CR>
# configuration
For the full story, read [`:help windows.txt`][windows].
`:help bufferline`
# installation
Why this and not Vim tabs?
--------------------------
* [pathogen](https://github.com/tpope/vim-pathogen)
* `git clone https://github.com/bling/vim-bufferline ~/.vim/bundle/vim-bufferline`
* [neobundle](https://github.com/Shougo/neobundle.vim)
* `NeoBundle 'bling/vim-bufferline'`
* [vundle](https://github.com/gmarik/vundle)
* `Plugin 'bling/vim-bufferline'`
* [vam](https://github.com/MarcWeber/vim-addon-manager)
* `call vam#ActivateAddons([ 'vim-bufferline' ])`
* [vim-plug](https://github.com/junegunn/vim-plug)
* `Plug 'bling/vim-bufferline'`
Vim tabs are not very useful except in very particular circumstances.
To understand why this is, you have to understand that the display in Vim
has 3 layers of indirection:
# credits
1. Buffers correspond to files.
This was inspired by the [buftabs](http://www.vim.org/scripts/script.php?script_id=1664) script.
Not necessarily to files on disk, but in potentiality; i.e. a buffer becomes
the content of a file when you do `:w`
# license
2. Windows correspond to rectangular areas on the screen, each associated with
some buffer.
MIT License. Copyright (c) 2013 Bailey Ling.
Any window can be associated with any buffer, and any buffer with any
window. You can change which buffer is shown in a window at any time, and
you can split and resize windows to create any on-screen arrangement you
want. So you could have 3 windows showing the same buffer, e.g. to work on
several areas of a file at once.
Note that while windows are always associated with a buffer - i.e. an area
of the screen always shows some file , a buffer need not be associated with
any window i.e. a file may be loaded without being shown on screen.
3. Tabs correspond to entire screens, i.e. to an arrangement of windows.
In other windowing environments this concept is often called a viewport,
or a virtual desktop. Each window belongs to one particular tab. But note
that a buffer can be shown in any window (or no window at all), so any file
can appear any number of times in any number of tabs. Tabs and files do not
have anything to do with each other.
Now it is possible to open just one full-screen window in each tab, and in each
window edit a different buffer, in effect associating tabs with files. But this
only works if you stay away from any other window or buffer management, i.e. if
you never create splits and never touch the buffer list. Even then there are
parts of Vim (such as the help function and the netrw Explorer) that expect to
be working with windows, not tabs, and so can easily inadvertently shatter the
illusion.
So if you consider what Vim tabs actually are, i.e. viewports, and you use Vim
in a typical way, there are only very limited circumstances in which you will
ever need such functionality, if at all.
What the typical user wants when they think of tabs is simply the ability to
open multiple files and then flip between them, which in Vim means they want
buffers not tabs.
Buftabline vs. X
----------------
As of Nov 15, 2014, here is how Buftabline compares with some other plugins
of which I am aware that they offer related functionality, roughly in order
of their age.
* [MiniBufExpl](http://www.vim.org/scripts/script.php?script_id=159)
Obviously no rundown can be complete without the veteran of buffer list
plugins, Mini Buffer Explorer. There are two major differences:
1. Buftabline uses the tabline while MiniBufExpl renders to a special buffer
in a split. The tabline is newer than MiniBufExpl, and unlike a buffer, it
is guaranteed to stick to the top of the screen within Vim, unaffected by
any splits.
2. Because Buftabline uses the tabline, it cannot offer any functionality
relating to the management of buffers: all it does is show you the list.
OTOH, this also makes Buftabline very lightweight from a user perspective:
Vim has plenty of facilities for managing buffers and with Buftabline you
will be using those same as without it. Buftabline need not aspire to be
your sole interface to Vims buffers.
* [buftabs](http://www.vim.org/scripts/script.php?script_id=1664)
Buftabs is what you get when you try to implement Buftabline on a Vim that
does not yet have the `tabline`. It can only render your tabs near or at the
bottom of the Vim screen, and you have the choice between trading in your
`statusline` for the list, or having it flicker “behind” the command line. If
MiniBufExpl is too heavy for you, buftabs is the best you can do in absence
of the `tabline`.
I used this for a long time.
* [bufferline](https://github.com/bling/vim-bufferline)
Essentially a newer rendition of buftabs.
* [Airline](http://www.vim.org/scripts/script.php?script_id=4661)
If you already use Airline, you do not need Buftabline: the functionality
comes built in see `:help airline-tabline`.
If you do not already use Airline, you may not want to: it is far heavier
than Buftabline, to the point of dragging down performance. C.f.
[Pretty statuslines vs cursor speed][badperf]
* [BufLine](http://www.vim.org/scripts/script.php?script_id=4940)
This is very similar in scope and strategy to Buftabline, but not nearly as
simple. The code is more than 5 times as long. There are lots of options and
mappings so despite its limited scope compared to something like MiniBufExpl
or Airline, it feels like a Big Plugin one that requires a large up-front
commitment. And subjective though this is, I will call its default colors
ugly (while the ones in Buftabline depend entirely on your colorscheme), nor
does it make any attempt to harmonise with the user colorscheme.
* [WinTabs](https://github.com/zefei/vim-wintabs)
This is another Big Plugin, though much, much better. It supports Vim tabs
in addition to buffers, and tries to implement a functionality that is not
native to Vim tabs: scoping buffers to certain tabs. This means it also
needs to hook into sessions in order to support them, which it does. All in
all, if you want to use Vim tabs (i.e. viewports), this is probably the best
plugin for you Buftabline will be too simplistic for your preferences.
<!-- vim: et fenc=utf8
-->
[windows]: http://vimdoc.sourceforge.net/htmldoc/windows.html
[badperf]: https://www.reddit.com/r/vim/comments/2lw1fd/pretty_statuslines_vs_cursor_speed/

View File

@@ -1,130 +0,0 @@
" keep track of vimrc setting
let s:updatetime = &updatetime
" keep track of scrollinf window start
let s:window_start = 0
function! s:generate_names()
let names = []
let i = 1
let last_buffer = bufnr('$')
let current_buffer = bufnr('%')
while i <= last_buffer
if bufexists(i) && buflisted(i)
let modified = ' '
if getbufvar(i, '&mod')
let modified = g:bufferline_modified
endif
let fname = fnamemodify(bufname(i), g:bufferline_fname_mod)
if g:bufferline_pathshorten != 0
let fname = pathshorten(fname)
endif
let fname = substitute(fname, "%", "%%", "g")
let skip = 0
for ex in g:bufferline_excludes
if match(fname, ex) > -1
let skip = 1
break
endif
endfor
if !skip
let name = ''
if g:bufferline_show_bufnr != 0 && g:bufferline_status_info.count >= g:bufferline_show_bufnr
let name = i . ':'
endif
let name .= fname . modified
if current_buffer == i
let name = g:bufferline_active_buffer_left . name . g:bufferline_active_buffer_right
let g:bufferline_status_info.current = name
else
let name = g:bufferline_separator . name . g:bufferline_separator
endif
call add(names, [i, name])
endif
endif
let i += 1
endwhile
if len(names) > 1
if g:bufferline_rotate == 1
call bufferline#algos#fixed_position#modify(names)
endif
endif
return names
endfunction
function! bufferline#get_echo_string()
" check for special cases like help files
let current = bufnr('%')
if !bufexists(current) || !buflisted(current)
return bufname('%')
endif
let names = s:generate_names()
let line = ''
for val in names
let line .= val[1]
endfor
let index = match(line, '\V'.g:bufferline_status_info.current)
let g:bufferline_status_info.count = len(names)
let g:bufferline_status_info.before = strpart(line, 0, index)
let g:bufferline_status_info.after = strpart(line, index + len(g:bufferline_status_info.current))
return line
endfunction
function! s:echo()
if &filetype ==# 'unite'
return
endif
let line = bufferline#get_echo_string()
" 12 is magical and is the threshold for when it doesn't wrap text anymore
let width = &columns - 12
if g:bufferline_rotate == 2
let current_buffer_start = stridx(line, g:bufferline_active_buffer_left)
let current_buffer_end = stridx(line, g:bufferline_active_buffer_right)
if current_buffer_start < s:window_start
let s:window_start = current_buffer_start
endif
if current_buffer_end > (s:window_start + width)
let s:window_start = current_buffer_end - width + 1
endif
let line = strpart(line, s:window_start, width)
else
let line = strpart(line, 0, width)
endif
echo line
if &updatetime != s:updatetime
let &updatetime = s:updatetime
endif
endfunction
function! s:cursorhold_callback()
call s:echo()
autocmd! bufferline CursorHold
endfunction
function! s:refresh(updatetime)
let &updatetime = a:updatetime
autocmd bufferline CursorHold * call s:cursorhold_callback()
endfunction
function! bufferline#init_echo()
augroup bufferline
au!
" events which output a message which should be immediately overwritten
autocmd BufWinEnter,WinEnter,InsertLeave,VimResized * call s:refresh(1)
augroup END
autocmd CursorHold * call s:echo()
endfunction

View File

@@ -1,9 +0,0 @@
" pins the active buffer to a specific index in the list
function! bufferline#algos#fixed_position#modify(names)
let current = bufnr('%')
while a:names[g:bufferline_fixed_index][0] != current
let first = remove(a:names, 0)
call add(a:names, first)
endwhile
endfunction

View File

@@ -1,119 +0,0 @@
*bufferline.txt* Simple plugin for generating buffer list names
==============================================================================
INTRODUCTION *bufferline*
vim-bufferline is a simple plugin that helps you keep track of all your open
buffers. It also integrates nicely with vim-airline.
==============================================================================
CONFIGURATION *bufferline-configuration*
There are a couple configuration values available (shown with their default
values):
* denotes whether bufferline should automatically echo to the command bar
>
let g:bufferline_echo = 1
<
* the separator used on the left side of a buffer
>
let g:bufferline_active_buffer_left = '['
<
* the separator used on the right side of a buffer
>
let g:bufferline_active_buffer_right = ']'
<
* the symbol to denote that a buffer is modified
>
let g:bufferline_modified = '+'
<
* denotes whether buffer numbers should be displayed
>
let g:bufferline_show_bufnr = 1
<
* denotes whether the bufferline should have rotation applied
>
" default, no rotate, no scrolling
let g:bufferline_rotate = 0
" scrolling with fixed current buffer position
let g:bufferline_rotate = 1
" scrolling without fixed current buffer position
let g:bufferline_rotate = 2
<
* only valid when `g:bufferline_rotate` is set to 1:
>
let g:bufferline_fixed_index = 0 "always first
let g:bufferline_fixed_index = 1 "always second (default)
let g:bufferline_fixed_index = -1 "always last
<
* denotes how to display the filename of a buffer (see |filename-modifiers|
for more details)
>
let g:bufferline_fname_mod = ':t'
<
* denotes the highlight group for inactive buffers when used in the
|statusline|
>
let g:bufferline_inactive_highlight = 'StatusLineNC'
<
* denotes the highlight group for the active buffer when used in the
|statusline|
>
let g:bufferline_active_highlight = 'StatusLine'
<
* denotes whether the active highlight should be used when there is only one
buffer.
>
let g:bufferline_solo_highlight = 0
<
* denotes any exclude patterns.
>
let g:bufferline_excludes = [] "see source for defaults
<
* denotes whether paths in buffer names should be |pathshorten()|-ed.
>
let g:bufferline_pathshorten = 0
<
==============================================================================
STATUSLINE INTEGRATION *bufferline-statusline*
>
let g:bufferline_echo = 0
autocmd VimEnter *
\ let &statusline='%{bufferline#refresh_status()}'
\ .bufferline#get_status_string()
<
The function refresh_status() returns an empty string and only exists to
populate some global variables. Since it is inside an %{} block, the
variables will get updated whenever the statusline needs to be drawn.
get_status_string() creates a string which references these variables.
==============================================================================
CONTRIBUTIONS *bufferline-contributions*
Contributions and pull requests are welcome.
==============================================================================
LICENSE *bufferline-license*
MIT License. Copyright © 2013 Bailey Ling.
vim:tw=78:ts=8:ft=help:norl:

View File

@@ -0,0 +1,143 @@
*buftabline.txt* Use the tabline to render buffer tabs
BUFTABLINE by Aristotle Pagaltzis
==============================================================================
0. Contents *buftabline*
1. Intro ....................................... |buftabline-intro|
2. Configuration settings ...................... |buftabline-config|
3. Mappings .................................... |buftabline-mappings|
4. Tab coloring and colorscheme support ........ |buftabline-colors|
5. Source ...................................... |buftabline-source|
==============================================================================
1. Intro *buftabline-intro*
This plugin takes over the 'tabline' and renders the buffer list in it instead
of a tab list. It is designed with the ideal that it should Just Work: drop it
into your setup and you're done. There is only minimal configurable behavior.
==============================================================================
2. Configuration settings *buftabline-config*
Changes to any of the plugin's configuration settings at runtime will not take
effect immediately unless you force an update: >
:call buftabline#update(0)
<
*g:buftabline_show* number (default 2)
The value of this option specifies when the line with buffer labels will
be displayed:
0: never
1: only if there are at least two buffers
2: always
This is analogous to the 'showtabline' setting, only for the |buftabline|.
*g:buftabline_numbers* number (default 0)
The value of this option specifies how to number the buffer labels:
0: no numbering
1: buffer number
2: ordinal number
The buffer number corresponds to Vim's internal buffer number as shown by
the |:ls| command, whereas the ordinal number is a simple sequential count
from left to right.
*g:buftabline_indicators* boolean (default off)
When on, the buffer's state is indicated in the buffer label. Currently
the only state indicated is whether the buffer is 'modified'.
*g:buftabline_separators* boolean (default off)
When on, a vertical line is drawn inbetween tabs. (This is not strictly
correct. The effect is actually achieved by replacing the space on the
left side of each tab with U+23B8 LEFT VERTICAL BOX LINE. Therefore the
separator will be highlighted the same way as the tab to its left.)
*g:buftabline_plug_max* number (default 10)
The number of |buftabline-mappings| that will be created by the plugin.
You can request more of them or turn off the functionality entirely by
setting this to 0. Note it only has an effect before loading the plugin,
not if you change it later.
==============================================================================
3. Mappings *buftabline-mappings*
To switch buffers by their ordinal number (|g:buftabline_numbers| = 2) you can
map keys to the |<Plug>| mappings provided by this plugin: >
nmap <leader>1 <Plug>BufTabLine.Go(1)
nmap <leader>2 <Plug>BufTabLine.Go(2)
nmap <leader>3 <Plug>BufTabLine.Go(3)
nmap <leader>4 <Plug>BufTabLine.Go(4)
nmap <leader>5 <Plug>BufTabLine.Go(5)
nmap <leader>6 <Plug>BufTabLine.Go(6)
nmap <leader>7 <Plug>BufTabLine.Go(7)
nmap <leader>8 <Plug>BufTabLine.Go(8)
nmap <leader>9 <Plug>BufTabLine.Go(9)
nmap <leader>0 <Plug>BufTabLine.Go(10)
<
There is also a |<Plug>| mapping which always switches to the last buffer: >
nmap <leader>0 <Plug>BufTabLine.Go(-1)
<
On Mac OS, you probably want to use a |<D-| mapping instead, which will emulate
the standard Cmd+1, Cmd+2, etc. keybindings for this feature: >
nmap <D-1> <Plug>BufTabLine.Go(1)
nmap <D-2> <Plug>BufTabLine.Go(2)
nmap <D-3> <Plug>BufTabLine.Go(3)
nmap <D-4> <Plug>BufTabLine.Go(4)
nmap <D-5> <Plug>BufTabLine.Go(5)
nmap <D-6> <Plug>BufTabLine.Go(6)
nmap <D-7> <Plug>BufTabLine.Go(7)
nmap <D-8> <Plug>BufTabLine.Go(8)
nmap <D-9> <Plug>BufTabLine.Go(9)
nmap <D-0> <Plug>BufTabLine.Go(10)
" or to go to the last buffer:
nmap <D-0> <Plug>BufTabLine.Go(-1)
<
You can ask for more (or fewer) than the default 10 <Plug> mappings using the
|g:buftabline_plug_max| setting.
==============================================================================
4. Tab coloring and colorscheme support *buftabline-colors*
This plugin uses several custom highlight groups to render the buffer tabs.
The custom groups are linked to several other built-in Vim highlight groups
that should provide a sensible default which automatically harmonizes with
your |colorscheme|.
However, if you dislike your colorscheme's chosen tabline colours, you can
override the default links in your |vimrc| -- c.f. |:hi-link|.
Or if you are a colorscheme designer (|44.1|), you can add support to your
colorscheme for this plugin specifically.
The highlight groups and their default links are as follows:
Custom group Default link Meaning
*BufTabLineCurrent* |TabLineSel| Buffer shown in current window
*BufTabLineActive* |PmenuSel| Buffer shown in other window
*BufTabLineHidden* |TabLine| Buffer not currently visible
*BufTabLineFill* |TabLineFill| Empty area
*BufTabLineModifiedCurrent* |BufTabLineCurrent| (Same as linked but 'modified')
*BufTabLineModifiedActive* |BufTabLineActive| (Same as linked but 'modified')
*BufTabLineModifiedHidden* |BufTabLineHidden| (Same as linked but 'modified')
==============================================================================
5. Source *buftabline-source*
https://github.com/ap/vim-buftabline
vim:tw=78:et:ft=help:norl:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,61 +0,0 @@
if exists('g:loaded_bufferline')
finish
endif
let g:loaded_bufferline = 1
function! s:check_defined(variable, default)
if !exists(a:variable)
let {a:variable} = a:default
endif
endfunction
call s:check_defined('g:bufferline_active_buffer_left', '[')
call s:check_defined('g:bufferline_active_buffer_right', ']')
call s:check_defined('g:bufferline_separator', ' ')
call s:check_defined('g:bufferline_modified', '+')
call s:check_defined('g:bufferline_echo', 1)
call s:check_defined('g:bufferline_show_bufnr', 1)
call s:check_defined('g:bufferline_fname_mod', ':t')
call s:check_defined('g:bufferline_inactive_highlight', 'StatusLineNC')
call s:check_defined('g:bufferline_active_highlight', 'StatusLine')
call s:check_defined('g:bufferline_rotate', 0)
call s:check_defined('g:bufferline_fixed_index', 1)
call s:check_defined('g:bufferline_solo_highlight', 0)
call s:check_defined('g:bufferline_excludes', ['\[vimfiler\]'])
call s:check_defined('g:bufferline_pathshorten', 0)
function! bufferline#generate_string()
return "bufferline#generate_string() is obsolete! Please consult README."
endfunction
let g:bufferline_status_info = {
\ 'count': 0,
\ 'before': '',
\ 'current': '',
\ 'after': '',
\ }
function! bufferline#refresh_status()
if g:bufferline_solo_highlight
if g:bufferline_status_info.count == 1
exec printf('highlight! link %s %s', g:bufferline_active_highlight, g:bufferline_inactive_highlight)
else
exec printf('highlight! link %s NONE', g:bufferline_active_highlight)
endif
endif
call bufferline#get_echo_string()
return ''
endfunction
function! bufferline#get_status_string()
return
\ '%#'.g:bufferline_inactive_highlight.'#'
\.'%{g:bufferline_status_info.before}'
\.'%#'.g:bufferline_active_highlight.'#'
\.' %{g:bufferline_status_info.current} '
\.'%#'.g:bufferline_inactive_highlight.'#'
\.'%{g:bufferline_status_info.after}'
endfunction
if g:bufferline_echo
call bufferline#init_echo()
endif

View File

@@ -0,0 +1,219 @@
" Vim global plugin for rendering the buffer list in the tabline
" Licence: The MIT License (MIT)
" Commit: $Format:%H$
" {{{ Copyright (c) 2015 Aristotle Pagaltzis <pagaltzis@gmx.de>
"
" 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
hi default link BufTabLineCurrent TabLineSel
hi default link BufTabLineActive PmenuSel
hi default link BufTabLineHidden TabLine
hi default link BufTabLineFill TabLineFill
hi default link BufTabLineModifiedCurrent BufTabLineCurrent
hi default link BufTabLineModifiedActive BufTabLineActive
hi default link BufTabLineModifiedHidden BufTabLineHidden
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)
let g:buftabline_plug_max = get(g:, 'buftabline_plug_max', 10)
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
function! s:switch_buffer(bufnum, clicks, button, mod)
execute 'buffer' a:bufnum
endfunction
function s:SID()
return matchstr(expand('<sfile>'), '<SNR>\d\+_')
endfunction
let s:dirsep = fnamemodify(getcwd(),':p')[-1:]
let s:centerbuf = winbufnr(0)
let s:tablineat = has('tablineat')
let s:sid = s:SID() | delfunction s:SID
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)
" pick up data on all the buffers
let tabs = []
let path_tabs = []
let tabs_per_tail = {}
let currentbuf = winbufnr(0)
let screen_num = 0
for bufnum in bufnums
let screen_num = show_num ? bufnum : show_ord ? screen_num + 1 : ''
let tab = { 'num': bufnum, 'pre': '' }
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 = tab.path[tab.sep + 1:]
let pre = screen_num
if getbufvar(bufnum, '&mod')
let tab.hilite = 'Modified' . tab.hilite
if show_mod | let pre = '+' . pre | endif
endif
if strlen(pre) | let tab.pre = pre . ' ' | endif
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 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
let lpad_width = strwidth(lpad)
for tab in tabs
let tab.width = lpad_width + strwidth(tab.pre) + strwidth(tab.label) + 1
let tab.label = lpad . tab.pre . substitute(strtrans(tab.label), '%', '%%', 'g') . ' '
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
\ = lft.width < lft.half ? [ [ rgt, &columns - lft.width ] ]
\ : rgt.width < rgt.half ? [ [ lft, &columns - rgt.width ] ]
\ : [ [ lft, lft.half ], [ rgt, rgt.half ] ]
for [side, budget] in oversized
let delta = side.width - budget
" 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 s:tablineat
\ ? join(map(tabs,'"%#BufTabLine".v:val.hilite."#" . "%".v:val.num."@'.s:sid.'switch_buffer@" . strtrans(v:val.label)'),'') . '%#BufTabLineFill#' . swallowclicks
\ : swallowclicks . join(map(tabs,'"%#BufTabLine".v:val.hilite."#" . strtrans(v:val.label)'),'') . '%#BufTabLineFill#'
endfunction
function! buftabline#update(zombie)
set tabline=
" silent! is used here because neovim lacks guioptions and v0.11.0 broke backcompat
" by making setting it an E519 unsupported error instead of the previous no-op
" N.B. :set processes options in order and will abort on error even under silent!
if tabpagenr('$') > 1 | silent! set showtabline=2 guioptions+=e | return | endif
silent! set guioptions-=e
if 0 == g:buftabline_show
set showtabline=1
return
elseif 1 == g:buftabline_show
" account for BufDelete triggering before buffer is actually deleted
let bufnums = filter(buftabline#user_buffers(), 'v:val != a:zombie')
let &g:showtabline = 1 + ( len(bufnums) > 1 )
elseif 2 == g:buftabline_show
set showtabline=2
endif
set tabline=%!buftabline#render()
endfunction
augroup BufTabLine
autocmd!
autocmd VimEnter * call buftabline#update(0)
autocmd TabEnter * call buftabline#update(0)
autocmd BufAdd * call buftabline#update(0)
autocmd FileType qf call buftabline#update(0)
autocmd BufDelete * call buftabline#update(str2nr(expand('<abuf>')))
augroup END
for s:n in range(1, g:buftabline_plug_max) + ( g:buftabline_plug_max > 0 ? [-1] : [] )
let s:b = s:n == -1 ? -1 : s:n - 1
execute printf("noremap <silent> <Plug>BufTabLine.Go(%d) :<C-U>exe 'b'.get(buftabline#user_buffers(),%d,'')<cr>", s:n, s:b)
endfor
unlet! s:n s:b
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