Skip to content

Commit d7b76a1

Browse files
committed
init
0 parents  commit d7b76a1

6 files changed

Lines changed: 354 additions & 0 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# taberian.vim
2+
3+
Clickable tabs per VIM window.
4+
5+
[![screenshot](/taberian.png)](https://user-images.githubusercontent.com/717109/131985507-4877c889-a2ef-4d41-90f9-b770b8912e65.mp4)

autoload/taberian.vim

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
function! s:create_tab(bufnr)
2+
let tab = #{
3+
\ bufnr: -1,
4+
\ }
5+
let tab.bufnr = a:bufnr
6+
return tab
7+
endfunction
8+
9+
function! s:clamp(value, min, max)
10+
if a:value < a:min
11+
return a:min
12+
elseif a:value > a:max
13+
return a:max
14+
else
15+
return a:value
16+
endif
17+
endfunction
18+
19+
function! s:winbar_width(tabs)
20+
return strdisplaywidth(join(a:tabs, ' ')) + 4 " + left\right padding
21+
endfunction
22+
23+
function! s:underscored(str)
24+
return a:str->str2list()->map({_, val -> list2str([val, 818])})->join('')
25+
endfunction
26+
27+
" tab indexing is zero based
28+
function! s:init_once()
29+
if !exists('w:taberian')
30+
let w:taberian = #{
31+
\ tabs: [],
32+
\ curr_nr: -1,
33+
\ prev_nr: -1,
34+
\ }
35+
endif
36+
endfunction
37+
call s:init_once()
38+
39+
function! taberian#update_current_window()
40+
call s:init_once()
41+
if len(w:taberian.tabs) < 2 || w:taberian.curr_nr == -1
42+
return
43+
endif
44+
let w:taberian.tabs[w:taberian.curr_nr].bufnr = bufnr('%')
45+
46+
call taberian#render_current_window()
47+
endfunction
48+
49+
function! taberian#create_tab()
50+
if len(w:taberian.tabs) < 2
51+
let w:taberian.curr_nr = 0
52+
let w:taberian.tabs = [s:create_tab(bufnr('%'))]
53+
endif
54+
55+
let w:taberian.curr_nr += 1
56+
call insert(w:taberian.tabs, s:create_tab(bufnr('%')), w:taberian.curr_nr)
57+
58+
doautocmd User TaberianChanged
59+
endfunction
60+
61+
function! taberian#goto_tab_nr(nr)
62+
if a:nr == -1 || a:nr >= len(w:taberian.tabs) || w:taberian.curr_nr == a:nr
63+
return
64+
endif
65+
66+
let w:taberian.prev_nr = w:taberian.curr_nr
67+
let w:taberian.curr_nr = a:nr
68+
execute 'silent buffer ' . w:taberian.tabs[w:taberian.curr_nr].bufnr
69+
70+
doautocmd User TaberianChanged
71+
endfunction
72+
73+
function! taberian#goto_tab_offset(offset)
74+
let nr = s:clamp(w:taberian.curr_nr + a:offset, 0, len(w:taberian.tabs) - 1)
75+
call taberian#goto_tab_nr(nr)
76+
endfunction
77+
78+
function! taberian#goto_previous_tab()
79+
call taberian#goto_tab_nr(w:taberian.prev_nr)
80+
endfunction
81+
82+
function! taberian#move_current_tab_offset(offset)
83+
let nr = w:taberian.curr_nr + a:offset
84+
if nr < 0 || nr >= len(w:taberian.tabs)
85+
return
86+
endif
87+
let tab = w:taberian.tabs[w:taberian.curr_nr]->deepcopy()
88+
call remove(w:taberian.tabs, w:taberian.curr_nr)
89+
call insert(w:taberian.tabs, tab, nr)
90+
if w:taberian.prev_nr == nr
91+
let w:taberian.prev_nr = w:taberian.curr_nr
92+
endif
93+
let w:taberian.curr_nr = nr
94+
doautocmd User TaberianChanged
95+
endfunction
96+
97+
function! taberian#close_current_tab()
98+
if len(w:taberian.tabs) < 2 || w:taberian.curr_nr == -1
99+
return
100+
endif
101+
102+
let old_curr = w:taberian.curr_nr
103+
104+
if w:taberian.curr_nr > 0
105+
call taberian#goto_tab_offset(-1)
106+
else
107+
call taberian#goto_tab_offset(+1)
108+
endif
109+
110+
call remove(w:taberian.tabs, old_curr)
111+
if len(w:taberian.tabs) < 2
112+
let w:taberian.tabs = []
113+
let w:taberian.curr_nr = -1
114+
endif
115+
doautocmd User TaberianChanged
116+
endfunction
117+
118+
function! taberian#render_current_window()
119+
function! s:tab_prototyperim(str, max, remainder)
120+
let max = a:max
121+
let elipsis = ''
122+
let len = strdisplaywidth(a:str)
123+
if len > max
124+
if a:remainder.value > 0
125+
let max += 1
126+
let a:remainder.value -= 1
127+
endif
128+
elseif len < max
129+
let a:remainder.value += max - len
130+
endif
131+
if len > max
132+
let elipsis = ''
133+
let max -= 1
134+
endif
135+
return strcharpart(a:str, 0, max) . elipsis
136+
endfunction
137+
138+
call s:init_once()
139+
aunmenu WinBar
140+
let tabs = gettabwinvar(tabpagenr(), winnr(), 'taberian').tabs->deepcopy()
141+
let ts_count = len(tabs)
142+
if ts_count < 2 " render only if more than 1 tab
143+
return
144+
endif
145+
146+
" convert bufnr to tab name:
147+
call map(tabs, {key, tab -> printf('%d %s ᴮ%d', key + 1, fnamemodify(bufname(tab.bufnr), ':t'), tab.bufnr)})
148+
149+
" make sure there is enough room:
150+
let win_width = winwidth(0)
151+
if win_width < 2 " there is a maximized window
152+
" create empty WinBar:
153+
execute 'amenu WinBar.\ \ '
154+
return
155+
endif
156+
let min_win_width = tabs->len() * (7 + 2 + 4) + 4 " 7: tab nr (2) + space + tab name (3 chars + '…')
157+
if win_width < min_win_width
158+
execute 'vertical resize ' . min_win_width
159+
endif
160+
161+
if s:winbar_width(tabs) > win_width
162+
" drop bufnr
163+
call map(tabs, {_, tab_name -> substitute(tab_name, '\(.*\) ᴮ.*', '\1', '')})
164+
endif
165+
166+
let max_bonus = 10
167+
while s:winbar_width(tabs) > win_width
168+
" trim the end
169+
let max_len = win_width / ts_count
170+
let remainder = #{value: win_width - max_len * ts_count}
171+
call map(tabs, {_, tab_name -> s:tab_prototyperim(tab_name, max_len - 4 + max_bonus, remainder)}) " - padding
172+
let max_bonus -= 1
173+
endwhile
174+
175+
" mark current tab:
176+
let tabs[w:taberian.curr_nr] = s:underscored(tabs[w:taberian.curr_nr])
177+
" escape whitespace and dots (including Unicode underscored):
178+
call map(tabs, {_, tab_name -> substitute(tab_name, '[ ̲.̲]', '\\&', 'g')})
179+
180+
let nr = 0
181+
for tab in tabs
182+
execute 'amenu <silent> WinBar.' . tab . ' <Cmd>call taberian#goto_tab_nr(' . nr . ')<CR>'
183+
let nr += 1
184+
endfor
185+
endfunction
186+
187+
function! taberian#render_all_windows()
188+
let winids = gettabinfo(tabpagenr())[0].windows
189+
for winid in winids
190+
call win_execute(winid, 'call taberian#update_current_window()')
191+
endfor
192+
endfunction

doc/taberian.txt

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
*taberian.txt* Clickable tabs per window
2+
3+
Author: Sergey Vlasov <sergey@vlasov.me>
4+
Licence: Vim licence, see |license|
5+
Site: https://github.com/noscript/taberian.vim
6+
Version: 0.1
7+
8+
================================================================================
9+
CONTENTS *taberian-contents*
10+
11+
Intro...................................................|taberian-intro|
12+
Mappings.............................................|taberian-mappings|
13+
Commands.............................................|taberian-commands|
14+
Variables...........................................|taberian-variables|
15+
16+
================================================================================
17+
INTRO *taberian-intro*
18+
19+
Taberian applies the concept of tabs to VIM windows. Each VIM window (split)
20+
may contain a number of buffers, so user can switch between them, rearrange,
21+
close etc.
22+
23+
Taberian works out of the box and does not require any configuration. If there
24+
are no tabs created then Taberian will not display anything. To start create a
25+
new tab via CTRL-W t (see |taberian-new-tab|).
26+
27+
================================================================================
28+
MAPPINGS *taberian-mappings*
29+
30+
It is possible to switch between tabs using mouse clicks or via these default
31+
mappings:
32+
*taberian-new-tab*
33+
<C-W>t Create a new tab by cloning the current tab and place it
34+
on the right from the current tab.
35+
36+
*taberian-close-tab*
37+
<C-W>x Close the current tab and switch to the tab on the left,
38+
if any, otherwise switch to the tab on the right.
39+
40+
*taberian-goto-left-tab*
41+
<C-W>m Go to tab on the left side of the current tab.
42+
43+
*taberian-goto-right-tab*
44+
<C-W>, Go to tab on the right side of the current tab.
45+
46+
*taberian-move-tab-left*
47+
<C-W>. Move current tab one position to the left.
48+
49+
*taberian-move-tab-right*
50+
<C-W>/ Move current tab one position to the right.
51+
52+
<A-1> Go to tab 1.
53+
<A-2> Go to tab 2.
54+
<A-3> Go to tab 3.
55+
<A-4> Go to tab 4.
56+
<A-5> Go to tab 5.
57+
<A-6> Go to tab 6.
58+
<A-7> Go to tab 7.
59+
<A-8> Go to tab 8.
60+
<A-9> Go to tab 9.
61+
62+
*taberian-goto-previous-tab*
63+
<C-Tab> or <A-0> Go to previous tab, useful to switch between two recent
64+
tabs.
65+
66+
If you wish to not use the default mappings, disable them by defining
67+
|g:taberian_no_default_mappings| variable. You can define your own mapping
68+
using this example:
69+
70+
>
71+
map <silent> <C-W>t <Cmd>TaberianNewTab<CR>
72+
map <silent> <C-W>x <Cmd>TaberianCloseCurrentTab<CR>
73+
map <silent> <C-W>m <Cmd>TaberianGotoLeftTab<CR>
74+
map <silent> <C-W>, <Cmd>TaberianGotoRightTab<CR>
75+
map <silent> <C-W>. <Cmd>TaberianMoveCurrentTabLeft<CR>
76+
map <silent> <C-W>/ <Cmd>TaberianMoveCurrentTabRight<CR>
77+
map <silent> <A-1> <Cmd>TaberianGoToTabNr 0<CR>
78+
map <silent> <A-2> <Cmd>TaberianGoToTabNr 1<CR>
79+
map <silent> <A-3> <Cmd>TaberianGoToTabNr 2<CR>
80+
map <silent> <A-4> <Cmd>TaberianGoToTabNr 3<CR>
81+
map <silent> <A-5> <Cmd>TaberianGoToTabNr 4<CR>
82+
map <silent> <A-6> <Cmd>TaberianGoToTabNr 5<CR>
83+
map <silent> <A-7> <Cmd>TaberianGoToTabNr 6<CR>
84+
map <silent> <A-8> <Cmd>TaberianGoToTabNr 7<CR>
85+
map <silent> <A-9> <Cmd>TaberianGoToTabNr 8<CR>
86+
map <silent> <C-Tab> <Cmd>TaberianGoToPreviousTab<CR>
87+
map <silent> <A-0> <Cmd>TaberianGoToPreviousTab<CR>
88+
>
89+
90+
================================================================================
91+
COMMANDS *taberian-commands*
92+
93+
:TaberianNewTab See |taberian-new-tab|.
94+
95+
:TaberianCloseCurrentTab See |taberian-close-tab|.
96+
97+
:TaberianGotoLeftTab See |taberian-goto-left-tab|.
98+
99+
:TaberianGotoRightTab See |taberian-goto-right-tab|.
100+
101+
:TaberianMoveCurrentTabLeft See |taberian-move-tab-left|.
102+
103+
:TaberianMoveCurrentTabRight See |taberian-move-tab-right|.
104+
105+
:TaberianGoToTabNr N Go to tab with index N. Taberian tab indices
106+
are zero-based, use 0 to go to the first tab.
107+
108+
:TaberianGoToPreviousTab See |taberian-goto-previous-tab|.
109+
110+
================================================================================
111+
VARIABLES *taberian-variables*
112+
113+
*g:taberian_no_default_mappings* Define this variable to prevent the
114+
default mappings from being created.
115+
Example:
116+
>
117+
let g:taberian_no_default_mappings = v:true
118+
<

plugin/taberian.vim

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
if exists("g:taberian_loaded")
2+
finish
3+
endif
4+
const g:taberian_loaded = v:true
5+
6+
augroup Taberian
7+
autocmd!
8+
autocmd WinEnter,BufEnter,VimResized,SessionLoadPost * call taberian#render_all_windows()
9+
autocmd User TaberianChanged call taberian#render_current_window()
10+
augroup END
11+
12+
command! -nargs=0 TaberianNewTab :call taberian#create_tab()
13+
command! -nargs=0 TaberianCloseCurrentTab :call taberian#close_current_tab()
14+
command! -nargs=0 TaberianGotoLeftTab :call taberian#goto_tab_offset(-1)
15+
command! -nargs=0 TaberianGotoRightTab :call taberian#goto_tab_offset(+1)
16+
command! -nargs=0 TaberianMoveCurrentTabLeft :call taberian#move_current_tab_offset(-1)
17+
command! -nargs=0 TaberianMoveCurrentTabRight :call taberian#move_current_tab_offset(+1)
18+
command! -nargs=1 TaberianGoToTabNr :call taberian#goto_tab_nr(<q-args>)
19+
command! -nargs=0 TaberianGoToPreviousTab :call taberian#goto_previous_tab()
20+
21+
if !exists('g:taberian_no_default_mappings') || !g:taberian_no_default_mappings
22+
map <silent> <C-W>t <Cmd>TaberianNewTab<CR>
23+
map <silent> <C-W>x <Cmd>TaberianCloseCurrentTab<CR>
24+
map <silent> <C-W>m <Cmd>TaberianGotoLeftTab<CR>
25+
map <silent> <C-W>, <Cmd>TaberianGotoRightTab<CR>
26+
map <silent> <C-W>. <Cmd>TaberianMoveCurrentTabLeft<CR>
27+
map <silent> <C-W>/ <Cmd>TaberianMoveCurrentTabRight<CR>
28+
map <silent> <A-1> <Cmd>TaberianGoToTabNr 0<CR>
29+
map <silent> <A-2> <Cmd>TaberianGoToTabNr 1<CR>
30+
map <silent> <A-3> <Cmd>TaberianGoToTabNr 2<CR>
31+
map <silent> <A-4> <Cmd>TaberianGoToTabNr 3<CR>
32+
map <silent> <A-5> <Cmd>TaberianGoToTabNr 4<CR>
33+
map <silent> <A-6> <Cmd>TaberianGoToTabNr 5<CR>
34+
map <silent> <A-7> <Cmd>TaberianGoToTabNr 6<CR>
35+
map <silent> <A-8> <Cmd>TaberianGoToTabNr 7<CR>
36+
map <silent> <A-9> <Cmd>TaberianGoToTabNr 8<CR>
37+
map <silent> <C-Tab> <Cmd>TaberianGoToPreviousTab<CR>
38+
map <silent> <A-0> <Cmd>TaberianGoToPreviousTab<CR>
39+
endif

taberian.mp4

150 KB
Binary file not shown.

taberian.png

63.3 KB
Loading

0 commit comments

Comments
 (0)