diff --git a/README.md b/README.md index d053cf93..2ea032e5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# vim-airline +# vim-airline [![Build Status](https://travis-ci.org/bling/vim-airline.png)](https://travis-ci.org/bling/vim-airline) Lean & mean statusline for vim that's light as air. @@ -13,7 +13,7 @@ Lean & mean statusline for vim that's light as air. * Extensive suite of themes for popular colorschemes including [solarized][23] (dark and light), [tomorrow][24] (all variants), [base16][32] (all variants), [molokai][25], [jellybeans][26] and others; have a look at the [screenshots][14] in the wiki. * Supports 7.2 as the minimum Vim version. * Stable release cycle; bleeding edge changes happen on the `dev` branch, and after they have gone through a [full regression test][33] will eventually be merged in the stable master branch. Releases typically occur every 2 weeks. -* Unit tests: [![Build Status](https://travis-ci.org/bling/vim-airline.png)](https://travis-ci.org/bling/vim-airline) +* Unit testing suite. ## Straightforward customization @@ -27,17 +27,13 @@ Sections are automatically hidden when the window size shrinks. ![image](https://f.cloud.github.com/assets/306502/1060831/05c08aac-11bc-11e3-8470-a506a3037f45.png) -## Fine-tuned configuration +## Smarter tab line -Every section is composed of parts, and you can reorder and reconfigure them at will. +Automatically displays all buffers when there's only one tab open. This is disabled by default; add the following to your vimrc to enable the extension: -![image](https://f.cloud.github.com/assets/306502/1064458/9a5632a8-1332-11e3-82e1-8208d8285455.png) + let g:airline#extensions#tabline#enabled = 1 -## Extensible pipeline - -Completely transform the statusline to your liking. Build out the statusline as you see fit by extracting colors from the current colorscheme's highlight groups. - -![allyourbase](https://f.cloud.github.com/assets/306502/1022714/e150034a-0da7-11e3-94a5-ca9d58a297e8.png) +![tabline](https://f.cloud.github.com/assets/306502/1072623/44c292a0-1495-11e3-9ce6-dcada3f1c536.gif) ## Seamless integration @@ -66,11 +62,25 @@ vim-airline integrates with a variety of plugins out of the box. These extensio ## Extras -vim-airline also supplies some supplementary stand-alone extensions. +vim-airline also supplies some supplementary stand-alone extensions. In addition to the tabline extension mentioned earlier, there is also: #### whitespace ![image](https://f.cloud.github.com/assets/306502/962401/2a75385e-04ef-11e3-935c-e3b9f0e954cc.png) +## Configurable and extensible + +#### Fine-tuned configuration + +Every section is composed of parts, and you can reorder and reconfigure them at will. + +![image](https://f.cloud.github.com/assets/306502/1073278/f291dd4c-14a3-11e3-8a83-268e2753f97d.png) + +#### Extensible pipeline + +Completely transform the statusline to your liking. Build out the statusline as you see fit by extracting colors from the current colorscheme's highlight groups. + +![allyourbase](https://f.cloud.github.com/assets/306502/1022714/e150034a-0da7-11e3-94a5-ca9d58a297e8.png) + # Rationale There's already [powerline][2], why yet another statusline? diff --git a/autoload/airline.vim b/autoload/airline.vim index 202920ad..4d1eb785 100644 --- a/autoload/airline.vim +++ b/autoload/airline.vim @@ -43,7 +43,6 @@ function! airline#switch_theme(name) let w:airline_lastmode = '' call airline#update_statusline() call airline#load_theme() - call airline#check_mode() endfunction function! airline#switch_matching_theme() @@ -82,6 +81,7 @@ function! airline#update_statusline() call s:invoke_funcrefs(context, g:airline_statusline_funcrefs) endfunction +let s:contexts = {} let s:core_funcrefs = [ \ function('airline#extensions#apply'), \ function('airline#extensions#default#apply') ] @@ -89,11 +89,13 @@ function! s:invoke_funcrefs(context, funcrefs) let builder = airline#builder#new(a:context) let err = airline#util#exec_funcrefs(a:funcrefs + s:core_funcrefs, builder, a:context) if err == 1 - call setwinvar(a:context.winnr, '&statusline', builder.build()) + let a:context.line = builder.build() + let s:contexts[a:context.winnr] = a:context + call setwinvar(a:context.winnr, '&statusline', '%!airline#statusline('.a:context.winnr.')') endif endfunction -function! airline#check_mode() +function! airline#statusline(winnr) if get(w:, 'airline_active', 1) let l:m = mode() if l:m ==# "i" @@ -123,6 +125,7 @@ function! airline#check_mode() call airline#highlighter#highlight(l:mode) let w:airline_lastmode = mode_string endif - return '' + + return s:contexts[a:winnr].line endfunction diff --git a/autoload/airline/builder.vim b/autoload/airline/builder.vim index e4430fe4..2d38ba12 100644 --- a/autoload/airline/builder.vim +++ b/autoload/airline/builder.vim @@ -39,7 +39,7 @@ function! airline#builder#new(context) let builder._context = a:context let builder._side = 1 let builder._curgroup = '' - let builder._line = '%{airline#check_mode()}' + let builder._line = '' return builder endfunction diff --git a/autoload/airline/extensions.vim b/autoload/airline/extensions.vim index e9c72f62..54a05a40 100644 --- a/autoload/airline/extensions.vim +++ b/autoload/airline/extensions.vim @@ -2,6 +2,8 @@ " vim: et ts=2 sts=2 sw=2 let s:ext = {} +let s:ext._theme_funcrefs = [] + function! s:ext.add_statusline_func(name) dict call airline#add_statusline_func(a:name) endfunction @@ -11,8 +13,11 @@ endfunction function! s:ext.add_inactive_statusline_func(name) dict call airline#add_inactive_statusline_func(a:name) endfunction +function! s:ext.add_theme_func(name) dict + call add(self._theme_funcrefs, function(a:name)) +endfunction -let s:script_path = resolve(expand(':p:h')) +let s:script_path = tolower(resolve(expand(':p:h'))) let s:filetype_overrides = { \ 'netrw': [ 'netrw', '%f' ], @@ -109,9 +114,7 @@ function! s:is_excluded_window() endfunction function! airline#extensions#load_theme() - if get(g:, 'loaded_ctrlp', 0) - call airline#extensions#ctrlp#load_theme() - endif + call airline#util#exec_funcrefs(s:ext._theme_funcrefs, g:airline#themes#{g:airline_theme}#palette) endfunction function! s:sync_active_winnr() @@ -178,20 +181,25 @@ function! airline#extensions#load() call airline#extensions#virtualenv#init(s:ext) endif - if (get(g:, 'airline#extensions#whitespace#enabled', 1) && get(g:, 'airline_detect_whitespace', 1)) - call airline#extensions#whitespace#init(s:ext) - endif if (get(g:, 'airline#extensions#syntastic#enabled', 1) && get(g:, 'airline_enable_syntastic', 1)) \ && exists(':SyntasticCheck') call airline#extensions#syntastic#init(s:ext) endif + if (get(g:, 'airline#extensions#whitespace#enabled', 1) && get(g:, 'airline_detect_whitespace', 1)) + call airline#extensions#whitespace#init(s:ext) + endif + + if get(g:, 'airline#extensions#tabline#enabled', 0) + call airline#extensions#tabline#init(s:ext) + endif + " load all other extensions not part of the default distribution for file in split(globpath(&rtp, "autoload/airline/extensions/*.vim"), "\n") " we have to check both resolved and unresolved paths, since it's possible " that they might not get resolved properly (see #187) - if stridx(resolve(fnamemodify(file, ':p')), s:script_path) < 0 - \ && stridx(fnamemodify(file, ':p'), s:script_path) < 0 + if stridx(tolower(resolve(fnamemodify(file, ':p'))), s:script_path) < 0 + \ && stridx(tolower(fnamemodify(file, ':p')), s:script_path) < 0 let name = fnamemodify(file, ':t:r') if !get(g:, 'airline#extensions#'.name.'#enabled', 1) continue diff --git a/autoload/airline/extensions/ctrlp.vim b/autoload/airline/extensions/ctrlp.vim index ec882f19..d3a696b0 100644 --- a/autoload/airline/extensions/ctrlp.vim +++ b/autoload/airline/extensions/ctrlp.vim @@ -14,15 +14,15 @@ function! airline#extensions#ctrlp#generate_color_map(dark, light, white) \ } endfunction -function! airline#extensions#ctrlp#load_theme() - if exists('g:airline#themes#{g:airline_theme}#palette.ctrlp') - let theme = g:airline#themes#{g:airline_theme}#palette.ctrlp +function! airline#extensions#ctrlp#load_theme(palette) + if exists('a:palette.ctrlp') + let theme = a:palette.ctrlp else - let s:color_template = has_key(g:airline#themes#{g:airline_theme}#palette, s:color_template) ? s:color_template : 'insert' + let s:color_template = has_key(a:palette, s:color_template) ? s:color_template : 'insert' let theme = airline#extensions#ctrlp#generate_color_map( - \ g:airline#themes#{g:airline_theme}#palette[s:color_template]['airline_c'], - \ g:airline#themes#{g:airline_theme}#palette[s:color_template]['airline_b'], - \ g:airline#themes#{g:airline_theme}#palette[s:color_template]['airline_a']) + \ a:palette[s:color_template]['airline_c'], + \ a:palette[s:color_template]['airline_b'], + \ a:palette[s:color_template]['airline_a']) endif for key in keys(theme) call airline#highlighter#exec(key, theme[key]) @@ -60,5 +60,6 @@ function! airline#extensions#ctrlp#init(ext) \ 'prog': 'airline#extensions#ctrlp#ctrlp_airline_status', \ } call a:ext.add_statusline_func('airline#extensions#ctrlp#apply') + call a:ext.add_theme_func('airline#extensions#ctrlp#load_theme') endfunction diff --git a/autoload/airline/extensions/default.vim b/autoload/airline/extensions/default.vim index 4ae686ce..5cbfcbaf 100644 --- a/autoload/airline/extensions/default.vim +++ b/autoload/airline/extensions/default.vim @@ -48,7 +48,7 @@ function! airline#extensions#default#apply(builder, context) if airline#util#getwinvar(winnr, 'airline_render_left', active || (!active && !g:airline_inactive_collapse)) call build_sections(a:builder, a:context, s:layout[0]) else - call a:builder.add_section('airline_a', '%f%m ') + call a:builder.add_section('airline_b', ' %f%m ') call a:builder.add_section('airline_c', '') endif diff --git a/autoload/airline/extensions/tabline.vim b/autoload/airline/extensions/tabline.vim new file mode 100644 index 00000000..fd10f820 --- /dev/null +++ b/autoload/airline/extensions/tabline.vim @@ -0,0 +1,85 @@ +" MIT License. Copyright (c) 2013 Bailey Ling. +" vim: et ts=2 sts=2 sw=2 + +let s:fmod = get(g:, 'airline#extensions#tabline#fnamemod', ':p:.') +let s:excludes = get(g:, 'airline#extensions#tabline#excludes', []) + +function! airline#extensions#tabline#init(ext) + set showtabline=2 + set tabline=%!airline#extensions#tabline#get() + + call a:ext.add_theme_func('airline#extensions#tabline#load_theme') +endfunction + +function! airline#extensions#tabline#load_theme(palette) + call airline#highlighter#exec('airline_tab', a:palette.normal.airline_b) + call airline#highlighter#exec('airline_tabsel', a:palette.normal.airline_a) + call airline#highlighter#exec('airline_tabtype', a:palette.visual.airline_a) + call airline#highlighter#exec('airline_tabfill', a:palette.normal.airline_c) + call airline#highlighter#exec('airline_tabmod', a:palette.insert.airline_a) +endfunction + +function! airline#extensions#tabline#get() + if tabpagenr('$') == 1 + return s:get_buffers() + else + return s:get_tabs() + endif +endfunction + +function! airline#extensions#tabline#title(n) + let buflist = tabpagebuflist(a:n) + let winnr = tabpagewinnr(a:n) + return airline#extensions#tabline#get_buffer_name(buflist[winnr - 1]) +endfunction + +function! airline#extensions#tabline#get_buffer_name(nr) + let name = bufname(a:nr) + if empty(name) + return '[No Name]' + endif + return fnamemodify(name, s:fmod) +endfunction + +function! s:get_buffers() + let b = airline#builder#new({'active': 1}) + let cur = bufnr('%') + for nr in range(1, bufnr('$')) + if buflisted(nr) && bufexists(nr) + for ex in s:excludes + if match(bufname(nr), ex) + continue + endif + endfor + if cur == nr + if g:airline_detect_modified && getbufvar(nr, '&modified') + let group = 'airline_tabmod' + else + let group = 'airline_tabsel' + endif + else + let group = 'airline_tab' + endif + call b.add_section(group, '%( %{airline#extensions#tabline#get_buffer_name('.nr.')} %)') + endif + endfor + call b.add_section('airline_tabfill', '') + call b.split() + call b.add_section('airline_tabtype', ' buffers ') + return b.build() +endfunction + +function! s:get_tabs() + let b = airline#builder#new({'active': 1}) + for i in range(1, tabpagenr('$')) + let group = i == tabpagenr() ? 'airline_tabsel' : 'airline_tab' + call b.add_section(group, ' %{len(tabpagebuflist(tabpagenr()))}%( %'.i.'T %{airline#extensions#tabline#title('.i.')} %)') + endfor + call b.add_raw('%T') + call b.add_section('airline_tabfill', '') + call b.split() + call b.add_section('airline_tab', ' %999XX ') + call b.add_section('airline_tabtype', ' tabs ') + return b.build() +endfunction + diff --git a/autoload/airline/highlighter.vim b/autoload/airline/highlighter.vim index f424f35a..b811dfa7 100644 --- a/autoload/airline/highlighter.vim +++ b/autoload/airline/highlighter.vim @@ -13,6 +13,44 @@ function! s:gui2cui(rgb, fallback) return rgb[0]+rgb[1]+rgb[2] endfunction +function! s:get_syn(group, what) + " need to pass in mode, known to break on 7.3.547 + let mode = has('gui_running') ? 'gui' : 'cterm' + let color = synIDattr(synIDtrans(hlID(a:group)), a:what, mode) + if empty(color) || color == -1 + let color = synIDattr(synIDtrans(hlID('Normal')), a:what, mode) + endif + if empty(color) || color == -1 + if has('gui_running') + let color = a:what ==# 'fg' ? '#000000' : '#FFFFFF' + else + let color = a:what ==# 'fg' ? 0 : 1 + endif + endif + return color +endfunction + +function! s:get_array(fg, bg, opts) + let fg = a:fg + let bg = a:bg + return has('gui_running') + \ ? [ fg, bg, '', '', join(a:opts, ',') ] + \ : [ '', '', fg, bg, join(a:opts, ',') ] +endfunction + +function! airline#highlighter#get_highlight(group, ...) + let fg = s:get_syn(a:group, 'fg') + let bg = s:get_syn(a:group, 'bg') + let reverse = synIDattr(synIDtrans(hlID(a:group)), 'reverse', has('gui_running') ? 'gui' : 'term') + return reverse ? s:get_array(bg, fg, a:000) : s:get_array(fg, bg, a:000) +endfunction + +function! airline#highlighter#get_highlight2(fg, bg, ...) + let fg = s:get_syn(a:fg[0], a:fg[1]) + let bg = s:get_syn(a:bg[0], a:bg[1]) + return s:get_array(fg, bg, a:000) +endfunction + function! airline#highlighter#exec(group, colors) let colors = a:colors if s:is_win32term @@ -50,6 +88,7 @@ endfunction function! airline#highlighter#add_separator(from, to, inverse) let s:separators[a:from.a:to] = [a:from, a:to, a:inverse] + call exec_separator({}, a:from, a:to, a:inverse, '') endfunction function! airline#highlighter#highlight(modes) diff --git a/autoload/airline/themes.vim b/autoload/airline/themes.vim index 0d9158dd..770b476a 100644 --- a/autoload/airline/themes.vim +++ b/autoload/airline/themes.vim @@ -15,42 +15,12 @@ function! airline#themes#generate_color_map(section1, section2, section3, file) \ } endfunction -function! s:get_syn(group, what) - " need to pass in mode, known to break on 7.3.547 - let mode = has('gui_running') ? 'gui' : 'cterm' - let color = synIDattr(synIDtrans(hlID(a:group)), a:what, mode) - if empty(color) || color == -1 - let color = synIDattr(synIDtrans(hlID('Normal')), a:what, mode) - endif - if empty(color) || color == -1 - if has('gui_running') - let color = a:what ==# 'fg' ? '#000000' : '#FFFFFF' - else - let color = a:what ==# 'fg' ? 0 : 1 - endif - endif - return color -endfunction - -function! s:get_array(fg, bg, opts) - let fg = a:fg - let bg = a:bg - return has('gui_running') - \ ? [ fg, bg, '', '', join(a:opts, ',') ] - \ : [ '', '', fg, bg, join(a:opts, ',') ] -endfunction - function! airline#themes#get_highlight(group, ...) - let fg = s:get_syn(a:group, 'fg') - let bg = s:get_syn(a:group, 'bg') - let reverse = synIDattr(synIDtrans(hlID(a:group)), 'reverse', has('gui_running') ? 'gui' : 'term') - return reverse ? s:get_array(bg, fg, a:000) : s:get_array(fg, bg, a:000) + return call('airline#highlighter#get_highlight', [a:group] + a:000) endfunction function! airline#themes#get_highlight2(fg, bg, ...) - let fg = s:get_syn(a:fg[0], a:fg[1]) - let bg = s:get_syn(a:bg[0], a:bg[1]) - return s:get_array(fg, bg, a:000) + return call('airline#highlighter#get_highlight2', [a:fg, a:bg] + a:000) endfunction function! airline#themes#patch(palette) diff --git a/doc/airline.txt b/doc/airline.txt index 1e7a7f4e..259f9e01 100644 --- a/doc/airline.txt +++ b/doc/airline.txt @@ -250,7 +250,7 @@ csv.vim vim-gitgutter vim-signify -* enable/disable showing a summary of changed hunks under source control. +* enable/disable showing a summary of changed hunks under source control. > let g:airline#extensions#hunks#enabled = 1 < * enable/disable showing only non-zero hunks. > @@ -259,6 +259,22 @@ vim-signify * set hunk count symbols. > let g:airline#extensions#hunks#hunk_symbols = ['+', '~', '-'] < +------------------------------------- *airline-ctrlp* +ctrlp + +* configure which mode colors should ctrlp window use (takes effect + only if the active airline theme doesn't define ctrlp colors) > + let g:airline#extensions#ctrlp#color_template = 'insert' (default) + let g:airline#extensions#ctrlp#color_template = 'normal' + let g:airline#extensions#ctrlp#color_template = 'visual' + let g:airline#extensions#ctrlp#color_template = 'replace' +< +------------------------------------- *airline-virtualenv* +virtualenv + +* enable/disable virtualenv integration > + let g:airline#extensions#virtualenv#enabled = 1 +< ------------------------------------- *airline-whitespace* * enable/disable detection of whitespace errors. > let g:airline#extensions#whitespace#enabled = 1 @@ -276,21 +292,17 @@ vim-signify let g:airline#extensions#whitespace#trailing_format = 'trailing[%s]' let g:airline#extensions#whitespace#mixed_indent_format = 'mixed-indent[%s]' < -------------------------------------- *airline-ctrlp* -ctrlp - -* configure which mode colors should ctrlp window use (takes effect - only if the active airline theme doesn't define ctrlp colors) > - let g:airline#extensions#ctrlp#color_template = 'insert' (default) - let g:airline#extensions#ctrlp#color_template = 'normal' - let g:airline#extensions#ctrlp#color_template = 'visual' - let g:airline#extensions#ctrlp#color_template = 'replace' +------------------------------------- *airline-tabline* +* enable/disable enhanced tabline. > + let g:airline#extensions#tabline#enabled = 0 < -------------------------------------- *airline-virtualenv* -virtualenv - -* enable/disable virtualenv integration > - let g:airline#extensions#virtualenv#enabled = 1 +* configure the formatting of filenames (see |filename-modifiers|). > + let g:airline#extensions#tabline#fnamemod = ':p:.' +< +* configure filename match rules to exclude from the tabline. > + let g:airline#extensions#tabline#excludes = [] +< +Note: You will likely want to set |showtabline| to 2. ============================================================================== ADVANCED CUSTOMIZATION *airline-advanced-customization* diff --git a/t/airline.vim b/t/airline.vim index 8cb0054a..b523d439 100644 --- a/t/airline.vim +++ b/t/airline.vim @@ -1,3 +1,4 @@ +let g:airline_theme = 'dark' call airline#init#bootstrap() call airline#init#sections() source plugin/airline.vim @@ -28,7 +29,7 @@ describe 'airline' call airline#add_statusline_func('MyFuncref') let &statusline = '' call airline#update_statusline() - Expect &statusline =~ 'hello world' + Expect airline#statusline(1) =~ 'hello world' end it 'should not change the statusline with -1' @@ -42,13 +43,13 @@ describe 'airline' call airline#add_statusline_func('MyAppend1') call airline#add_statusline_func('MyAppend2') call airline#update_statusline() - Expect &statusline =~ 'helloworld' + Expect airline#statusline(1) =~ 'helloworld' end it 'should allow users to redefine sections' let g:airline_section_a = airline#section#create(['mode', 'mode']) call airline#update_statusline() - Expect &statusline =~ '%{airline#util#wrap(airline#parts#mode(),0)}%{airline#util#wrap(airline#parts#mode(),0)}' + Expect airline#statusline(1) =~ '%{airline#util#wrap(airline#parts#mode(),0)}%{airline#util#wrap(airline#parts#mode(),0)}' end it 'should remove funcrefs properly' @@ -60,8 +61,8 @@ describe 'airline' it 'should overwrite the statusline with active and inactive splits' wincmd s - Expect getwinvar(1, '&statusline') !~ 'inactive' - Expect getwinvar(2, '&statusline') =~ 'inactive' + Expect airline#statusline(1) !~ 'inactive' + Expect airline#statusline(2) =~ 'inactive' wincmd c end diff --git a/t/builder.vim b/t/builder.vim index b96d8deb..0c12d329 100644 --- a/t/builder.vim +++ b/t/builder.vim @@ -5,9 +5,9 @@ describe 'active builder' let s:builder = airline#builder#new({'active': 1}) end - it 'should have a call to check mode' + it 'should start with an empty statusline' let stl = s:builder.build() - Expect stl =~ '%{airline#check_mode()}' + Expect stl == '' end it 'should transition colors from one to the next' diff --git a/t/extensions_default.vim b/t/extensions_default.vim index d9d719e6..71cc3c16 100644 --- a/t/extensions_default.vim +++ b/t/extensions_default.vim @@ -23,8 +23,8 @@ describe 'default' it 'should only render warning section in active splits' wincmd s - Expect getwinvar(1, '&statusline') =~ 'whitespace' - Expect getwinvar(2, '&statusline') !~ 'whitespace' + Expect airline#statusline(1) =~ 'whitespace' + Expect airline#statusline(2) !~ 'whitespace' wincmd c end end diff --git a/t/highligher.vim b/t/highligher.vim new file mode 100644 index 00000000..658e8167 --- /dev/null +++ b/t/highligher.vim @@ -0,0 +1,10 @@ +describe 'highlighter' + it 'should create separator highlight groups' + hi Foo1 ctermfg=1 ctermbg=2 + hi Foo2 ctermfg=3 ctermbg=4 + call airline#highlighter#add_separator('Foo1', 'Foo2', 0) + let hl = airline#highlighter#get_highlight('Foo1_to_Foo2') + Expect hl == [ '', '', '4', '2', '' ] + end +end + diff --git a/t/themes.vim b/t/themes.vim index d37c8fa3..cc814abc 100644 --- a/t/themes.vim +++ b/t/themes.vim @@ -25,5 +25,13 @@ describe 'themes' Expect colors[2] == '222' Expect colors[3] == '103' end + + it 'should pass args through correctly' + let hl = airline#themes#get_highlight('Foo', 'bold', 'italic') + Expect hl == ['', '', 0, 1, 'bold,italic'] + + let hl = airline#themes#get_highlight2(['Foo','bg'], ['Foo','fg'], 'italic', 'bold') + Expect hl == ['', '', 1, 0, 'italic,bold'] + end end