From fd5bde1a3a862550f0ab77903ce9dcc15ab3754b Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Sun, 3 Feb 2019 17:30:55 +0100 Subject: [PATCH] allow to show the statusline on top This is an experimental feature that allows to display the statusline in the tabline. It might still be a bit rough, but seems to work so far. Remaining problem: - Mode changes are not immediately detected, only after moving the cursor fixes #1388 closes #1867 --- CHANGELOG.md | 3 ++ autoload/airline.vim | 4 +-- autoload/airline/extensions/branch.vim | 3 +- autoload/airline/extensions/default.vim | 2 +- autoload/airline/extensions/hunks.vim | 6 ++-- autoload/airline/extensions/nrrwrgn.vim | 2 +- autoload/airline/extensions/po.vim | 6 ++-- autoload/airline/extensions/tabline.vim | 20 ++++++++++++- .../airline/extensions/tabline/autoshow.vim | 4 +-- .../wordcount/formatters/default.vim | 2 +- autoload/airline/init.vim | 2 +- autoload/airline/parts.vim | 9 ++++-- autoload/airline/util.vim | 23 ++++++++++----- doc/airline.txt | 13 +++++++-- plugin/airline.vim | 28 ++++++++++++++++--- 15 files changed, 94 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 254519da..770d5f97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This is the Changelog for the vim-airline project. - New features - Extensions: - [Defx](https://github.com/Shougo/defx.nvim) support + - Improvements + - The statusline can be configured to be shown on top (in the tabline) + Set the `g:airline_statusline_ontop` to enable this experimental feature. ## [0.10] - 2018-12-15 - New features diff --git a/autoload/airline.vim b/autoload/airline.vim index eacdc7c1..43e07563 100644 --- a/autoload/airline.vim +++ b/autoload/airline.vim @@ -180,7 +180,8 @@ function! s:invoke_funcrefs(context, funcrefs) if err == 1 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.')') + let option = get(g:, 'airline_statusline_ontop', 0) ? '&tabline' : '&statusline' + call setwinvar(a:context.winnr, option, '%!airline#statusline('.a:context.winnr.')') endif endfunction @@ -190,7 +191,6 @@ function! airline#statusline(winnr) if has_key(s:contexts, a:winnr) return '%{airline#check_mode('.a:winnr.')}'.s:contexts[a:winnr].line endif - " in rare circumstances this happens...see #276 return '' endfunction diff --git a/autoload/airline/extensions/branch.vim b/autoload/airline/extensions/branch.vim index fcf4d3a7..fadfc31c 100644 --- a/autoload/airline/extensions/branch.vim +++ b/autoload/airline/extensions/branch.vim @@ -88,7 +88,8 @@ function! s:update_git_branch() let s:vcs_config['git'].branch = exists("*FugitiveHead") ? \ FugitiveHead(s:sha1size) : fugitive#head(s:sha1size) - if s:vcs_config['git'].branch is# 'master' && winwidth(0) < 81 + if s:vcs_config['git'].branch is# 'master' && + \ airline#util#winwidth() < 81 " Shorten default a bit let s:vcs_config['git'].branch='mas' endif diff --git a/autoload/airline/extensions/default.vim b/autoload/airline/extensions/default.vim index f9ca3d4d..db8f11a9 100644 --- a/autoload/airline/extensions/default.vim +++ b/autoload/airline/extensions/default.vim @@ -19,7 +19,7 @@ let s:layout = get(g:, 'airline#extensions#default#layout', [ function! s:get_section(winnr, key, ...) if has_key(s:section_truncate_width, a:key) - if winwidth(a:winnr) < s:section_truncate_width[a:key] + if airline#util#winwidth(a:winnr) < s:section_truncate_width[a:key] return '' endif endif diff --git a/autoload/airline/extensions/hunks.vim b/autoload/airline/extensions/hunks.vim index aba84ccf..c04c49e4 100644 --- a/autoload/airline/extensions/hunks.vim +++ b/autoload/airline/extensions/hunks.vim @@ -66,7 +66,7 @@ function! airline#extensions#hunks#get_hunks() " Cache values, so that it isn't called too often if exists("b:airline_hunks") && \ get(b:, 'airline_changenr', 0) == b:changedtick && - \ winwidth(0) == get(s:, 'airline_winwidth', 0) && + \ airline#util#winwidth() == get(s:, 'airline_winwidth', 0) && \ get(b:, 'source_func', '') isnot# 's:get_hunks_signify' && \ get(b:, 'source_func', '') isnot# 's:get_hunks_gitgutter' && \ get(b:, 'source_func', '') isnot# 's:get_hunks_empty' && @@ -77,14 +77,14 @@ function! airline#extensions#hunks#get_hunks() let string = '' if !empty(hunks) for i in [0, 1, 2] - if (s:non_zero_only == 0 && winwidth(0) > 100) || hunks[i] > 0 + if (s:non_zero_only == 0 && airline#util#winwidth() > 100) || hunks[i] > 0 let string .= printf('%s%s ', s:hunk_symbols[i], hunks[i]) endif endfor endif let b:airline_hunks = string let b:airline_changenr = b:changedtick - let s:airline_winwidth = winwidth(0) + let s:airline_winwidth = airline#util#winwidth() return string endfunction diff --git a/autoload/airline/extensions/nrrwrgn.vim b/autoload/airline/extensions/nrrwrgn.vim index e97c8a57..dfc20ead 100644 --- a/autoload/airline/extensions/nrrwrgn.vim +++ b/autoload/airline/extensions/nrrwrgn.vim @@ -19,7 +19,7 @@ function! airline#extensions#nrrwrgn#apply(...) let dict=nrrwrgn#NrrwRgnStatus() let vmode = { 'v': 'Char ', 'V': 'Line ', '': 'Block '} let mode = dict.visual ? vmode[dict.visual] : vmode['V'] - let winwidth = winwidth(0) + let winwidth = airline#util#winwidth() if winwidth < 80 let mode = mode[0] endif diff --git a/autoload/airline/extensions/po.vim b/autoload/airline/extensions/po.vim index 3ec29421..e377b1ae 100644 --- a/autoload/airline/extensions/po.vim +++ b/autoload/airline/extensions/po.vim @@ -13,7 +13,7 @@ function! airline#extensions#po#shorten() let b:airline_po_stats = b:airline_po_stats[0:(w:displayed_po_limit - 2)].(&encoding==?'utf-8' ? '…' : '.'). ']' endif endif - if strlen(get(b:, 'airline_po_stats', '')) >= 30 && winwidth(0) < 150 + if strlen(get(b:, 'airline_po_stats', '')) >= 30 && airline#util#winwidth() < 150 let fuzzy = '' let untranslated = '' let messages = '' @@ -35,8 +35,8 @@ endfunction function! airline#extensions#po#on_winenter() " only reset cache, if the window size changed - if get(b:, 'airline_winwidth', 0) != winwidth(0) - let b:airline_winwidth = winwidth(0) + if get(b:, 'airline_winwidth', 0) != airline#util#winwidth() + let b:airline_winwidth = airline#util#winwidth() " needs re-formatting unlet! b:airline_po_stats endif diff --git a/autoload/airline/extensions/tabline.vim b/autoload/airline/extensions/tabline.vim index 10e235ec..1b88e9cb 100644 --- a/autoload/airline/extensions/tabline.vim +++ b/autoload/airline/extensions/tabline.vim @@ -33,6 +33,11 @@ function! s:toggle_off() endfunction function! s:toggle_on() + if get(g:, 'airline_statusline_ontop', 0) + call airline#extensions#tabline#enable() + let &tabline='%!airline#statusline('.winnr().')' + return + endif call airline#extensions#tabline#autoshow#on() call airline#extensions#tabline#tabs#on() call airline#extensions#tabline#buffers#on() @@ -58,12 +63,25 @@ function! s:update_tabline() return endif call airline#util#doautocmd('BufMRUChange') + call airline#extensions#tabline#redraw() +endfunction + +function! airline#extensions#tabline#redraw() " sometimes, the tabline is not correctly updated see #1580 " so force redraw here if exists(":redrawtabline") == 2 redrawtabline else - let &tabline = &tabline + " Have to set a property equal to itself to get airline to re-eval. + " Setting `let &tabline=&tabline` destroys the cursor position so we + " need something less invasive. + let &ro = &ro + endif +endfunction + +function! airline#extensions#tabline#enable() + if &lines > 3 + set showtabline=2 endif endfunction diff --git a/autoload/airline/extensions/tabline/autoshow.vim b/autoload/airline/extensions/tabline/autoshow.vim index ac1413fa..ae6c66b9 100644 --- a/autoload/airline/extensions/tabline/autoshow.vim +++ b/autoload/airline/extensions/tabline/autoshow.vim @@ -24,9 +24,7 @@ function! airline#extensions#tabline#autoshow#on() augroup airline_tabline_autoshow autocmd! if s:buf_min_count <= 0 && s:tab_min_count <= 1 - if &lines > 3 - set showtabline=2 - endif + call airline#extensions#tabline#enable() else if s:show_buffers == 1 autocmd BufEnter * call show_tabline(s:buf_min_count, len(airline#extensions#tabline#buflist#list())) diff --git a/autoload/airline/extensions/wordcount/formatters/default.vim b/autoload/airline/extensions/wordcount/formatters/default.vim index 56829214..21cb3047 100644 --- a/autoload/airline/extensions/wordcount/formatters/default.vim +++ b/autoload/airline/extensions/wordcount/formatters/default.vim @@ -24,7 +24,7 @@ else endif function! airline#extensions#wordcount#formatters#default#to_string(wordcount) - if winwidth(0) >= 80 + if airline#util#winwidth() >= 80 if a:wordcount > 999 " Format number according to locale, e.g. German: 1.245 or English: 1,245 let wordcount = substitute(a:wordcount, '\d\@<=\(\(\d\{3\}\)\+\)$', s:decimal_group.'&', 'g') diff --git a/autoload/airline/init.vim b/autoload/airline/init.vim index 18a59dae..5f616370 100644 --- a/autoload/airline/init.vim +++ b/autoload/airline/init.vim @@ -194,7 +194,7 @@ function! airline#init#sections() let g:airline_section_y = airline#section#create_right(['ffenc']) endif if !exists('g:airline_section_z') - if winwidth(0) > 80 + if airline#util#winwidth() > 80 let g:airline_section_z = airline#section#create(['windowswap', 'obsession', '%3p%%'.spc, 'linenr', 'maxlinenr', spc.':%3v']) else let g:airline_section_z = airline#section#create(['%3p%%'.spc, 'linenr', ':%3v']) diff --git a/autoload/airline/parts.vim b/autoload/airline/parts.vim index b6625c6f..6574e37d 100644 --- a/autoload/airline/parts.vim +++ b/autoload/airline/parts.vim @@ -67,9 +67,10 @@ endfunction function! airline#parts#spell() let spelllang = g:airline_detect_spelllang ? printf(" [%s]", toupper(substitute(&spelllang, ',', '/', 'g'))) : '' if g:airline_detect_spell && &spell - if winwidth(0) >= 90 + let winwidth = airline#util#winwidth() + if winwidth >= 90 return g:airline_symbols.spell . spelllang - elseif winwidth(0) >= 70 + elseif winwidth >= 70 return g:airline_symbols.spell else return split(g:airline_symbols.spell, '\zs')[0] @@ -99,7 +100,9 @@ function! airline#parts#readonly() endfunction function! airline#parts#filetype() - return winwidth(0) < 90 && strlen(&filetype) > 3 ? matchstr(&filetype, '...'). (&encoding is? 'utf-8' ? '…' : '>') : &filetype + return (airline#util#winwidth() < 90 && strlen(&filetype) > 3) + \ ? matchstr(&filetype, '...'). (&encoding is? 'utf-8' ? '…' : '>') + \ : &filetype endfunction function! airline#parts#ffenc() diff --git a/autoload/airline/util.vim b/autoload/airline/util.vim index 65e123ce..0b2aef36 100644 --- a/autoload/airline/util.vim +++ b/autoload/airline/util.vim @@ -1,17 +1,26 @@ " MIT License. Copyright (c) 2013-2018 Bailey Ling et al. " vim: et ts=2 sts=2 sw=2 -" TODO: Try to cache winwidth(0) function -" e.g. store winwidth per window and access that, only update it, if the size -" actually changed. scriptencoding utf-8 call airline#init#bootstrap() let s:spc = g:airline_symbols.space let s:nomodeline = (v:version > 703 || (v:version == 703 && has("patch438"))) ? '' : '' +" TODO: Try to cache winwidth(0) function +" e.g. store winwidth per window and access that, only update it, if the size +" actually changed. +function! airline#util#winwidth(...) + let nr = get(a:000, 0, 0) + if get(g:, 'airline_statusline_ontop', 0) + return &columns + else + return winwidth(nr) + endif +endfunction + function! airline#util#shorten(text, winwidth, minwidth, ...) - if winwidth(0) < a:winwidth && len(split(a:text, '\zs')) > a:minwidth + if airline#util#winwidth() < a:winwidth && len(split(a:text, '\zs')) > a:minwidth if get(a:000, 0, 0) " shorten from tail return '…'.matchstr(a:text, '.\{'.a:minwidth.'}$') @@ -25,14 +34,14 @@ function! airline#util#shorten(text, winwidth, minwidth, ...) endfunction function! airline#util#wrap(text, minwidth) - if a:minwidth > 0 && winwidth(0) < a:minwidth + if a:minwidth > 0 && airline#util#winwidth() < a:minwidth return '' endif return a:text endfunction function! airline#util#append(text, minwidth) - if a:minwidth > 0 && winwidth(0) < a:minwidth + if a:minwidth > 0 && airline#util#winwidth() < a:minwidth return '' endif let prefix = s:spc == "\ua0" ? s:spc : s:spc.s:spc @@ -46,7 +55,7 @@ function! airline#util#warning(msg) endfunction function! airline#util#prepend(text, minwidth) - if a:minwidth > 0 && winwidth(0) < a:minwidth + if a:minwidth > 0 && airline#util#winwidth() < a:minwidth return '' endif return empty(a:text) ? '' : a:text.s:spc.g:airline_right_alt_sep.s:spc diff --git a/doc/airline.txt b/doc/airline.txt index bd247e83..a4e81918 100644 --- a/doc/airline.txt +++ b/doc/airline.txt @@ -228,10 +228,19 @@ values): < * configure the fileformat output By default, it will display something like 'utf-8[unix]', however, you can - skip displaying it, if the output matches a configured string. To do so, - set > + skip displaying it, if the output matches a configured string. To do so, set > let g:airline#parts#ffenc#skip_expected_string='utf-8[unix]' < +* Display the statusline in the tabline (first top line): > + let g:airline_statusline_ontop = 1 +< + Setting this option, allows to use the statusline option to be used by + a custom function or another plugin, since airline won't change it. + + Note: This setting is experimental and works on a best effort approach. + Updating the statusline might not always happen as fast as needed, but that + is a limitation, that comes from Vim. airline tries to force an update if + needed, but it might not always work as expected. ============================================================================== COMMANDS *airline-commands* diff --git a/plugin/airline.vim b/plugin/airline.vim index c91ff206..491a853f 100644 --- a/plugin/airline.vim +++ b/plugin/airline.vim @@ -57,6 +57,19 @@ function! s:on_window_changed() call airline#update_statusline() endfunction +function! s:on_cursor_moved() + if winnr() != s:active_winnr + call on_window_changed() + endif + call update_tabline() +endfunction + +function! s:update_tabline() + if get(g:, 'airline_statusline_ontop', 0) + call airline#extensions#tabline#redraw() + endif +endfunction + function! s:on_colorscheme_changed() call s:init() unlet! g:airline#highlighter#normal_fg_hi @@ -84,11 +97,15 @@ function! s:airline_toggle() if exists("s:stl") let &stl = s:stl endif + if exists("s:tal") + let [&tal, &showtabline] = s:tal + endif call airline#highlighter#reset_hlcache() call airline#util#doautocmd('AirlineToggledOff') else let s:stl = &statusline + let s:tal = [&tabline, &showtabline] augroup airline autocmd! @@ -113,10 +130,7 @@ function! s:airline_toggle() autocmd CompleteDone * call on_window_changed() endif " non-trivial number of external plugins use eventignore=all, so we need to account for that - autocmd CursorMoved * - \ if winnr() != s:active_winnr - \ | call on_window_changed() - \ | endif + autocmd CursorMoved * call on_cursor_moved() autocmd VimResized * unlet! w:airline_lastmode | :call airline_refresh() if exists('*timer_start') && exists('*funcref') @@ -137,6 +151,11 @@ function! s:airline_toggle() autocmd BufWritePost */autoload/airline/themes/*.vim \ exec 'source '.split(globpath(&rtp, 'autoload/airline/themes/'.g:airline_theme.'.vim', 1), "\n")[0] \ | call airline#load_theme() + + if get(g:, 'airline_statusline_ontop', 0) + " Force update of tabline more often + autocmd InsertEnter,InsertLeave,CursorMovedI * :call update_tabline() + endif augroup END if &laststatus < 2 @@ -174,6 +193,7 @@ function! s:airline_refresh() call airline#highlighter#reset_hlcache() call airline#load_theme() call airline#update_statusline() + call s:update_tabline() endfunction function! s:FocusGainedHandler(timer)