patch 9.2.0083: Cannot have a mutli-line statusline

Problem:  Cannot have a mutli-line statusline.
Solution: Add support for multi-line statusline
          (Hirohito Higashi).

closes: #19123

Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi
2026-03-01 16:57:08 +00:00
committed by Christian Brabandt
parent f8ec661ff5
commit a4186316ba
38 changed files with 891 additions and 335 deletions
+36 -5
View File
@@ -1,4 +1,4 @@
*options.txt* For Vim version 9.2. Last change: 2026 Feb 25
*options.txt* For Vim version 9.2. Last change: 2026 Mar 01
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -8519,6 +8519,9 @@ A jump table for the options with a short description can be found at |Q_op|.
applied to StatusLineNC for the statusline of non-current
windows.
The number N must be between 1 and 9. See |hl-User1..9|
*stl-%@*
@ - Insert a line break (for the |tabpanel| or when the status line
'statuslineopt' has a "maxheight" value greater than 1).
When displaying a flag, Vim removes the leading comma, if any, when
that flag comes right after plaintext. This will make a nice display
@@ -8576,6 +8579,34 @@ A jump table for the options with a short description can be found at |Q_op|.
:function VarExists(var, val)
: if exists(a:var) | return a:val | else | return '' | endif
:endfunction
<
*'statuslineopt'* *'stlo'*
'statuslineopt' 'stlo' string (default "")
global
{not available when compiled without the |+statusline|
feature}
Optional settings for |status-line|. It can consist of the following
items. All are optional. Items must be separated by a comma.
maxheight:{n} Set the maximum status line height to {n}.
{n} must be 1 or greater.
If not present, 1 is used.
Check whether {n} is applicable to all windows
on all tab pages, and if not, set it to the
closest possible value.
The option value is updated to the actual
applied value. For example, setting
maxheight:999 may result in a smaller value
depending on the available space.
When {n} is set to 2 or more, you can use "@"
in 'statusline' to display information on
multiple lines in the status line.
See |stl-%@|.
Examples: >
:set stlo=
:set stlo=maxheight:2
:set stlo+=maxheight:3
<
*'suffixes'* *'su'*
'suffixes' 'su' string (default ".bak,~,.o,.h,.info,.swp,.obj")
@@ -8762,11 +8793,11 @@ A jump table for the options with a short description can be found at |Q_op|.
You can use |g:actual_curtabpage| within a function assigned to
tabpanel. |g:actual_curtabpage| represents current tab's label number.
The option value can contain "\n" to force line breaks: >
You can use "%@" or "\n" to insert a new line: >
set tabpanel=%!TabPanel()
function! TabPanel() abort
return printf("(%2d)\n %%f", g:actual_curtabpage)
return "(" .. g:actual_curtabpage .. ")%@ %f"
endfunction
<
The result is:
@@ -8780,8 +8811,8 @@ A jump table for the options with a short description can be found at |Q_op|.
| |
| |
<
Note: using "\n" is considered experimental and may change in the
future; a %-atom may be used instead.
Note: using "\n" is considered experimental and deprecated, prefer
the |stl-%@| atom instead.
*'tabpanelopt'* *'tplo'*
'tabpanelopt' 'tplo' string (default "")
+2 -1
View File
@@ -1,4 +1,4 @@
*quickref.txt* For Vim version 9.2. Last change: 2026 Feb 14
*quickref.txt* For Vim version 9.2. Last change: 2026 Mar 01
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -939,6 +939,7 @@ Short explanation of each option: *option-list*
'splitright' 'spr' new window is put right of the current one
'startofline' 'sol' commands move cursor to first non-blank in line
'statusline' 'stl' custom format for the status line
'statuslineopt' 'stlo' additional options for the |status-line|
'suffixes' 'su' suffixes that are ignored with multiple match
'suffixesadd' 'sua' suffixes added when searching for a file
'swapfile' 'swf' whether to use a swapfile for a buffer
+3
View File
@@ -1034,7 +1034,9 @@ $quote eval.txt /*$quote*
'stal' options.txt /*'stal'*
'startofline' options.txt /*'startofline'*
'statusline' options.txt /*'statusline'*
'statuslineopt' options.txt /*'statuslineopt'*
'stl' options.txt /*'stl'*
'stlo' options.txt /*'stlo'*
'stmp' options.txt /*'stmp'*
'stpl' options.txt /*'stpl'*
'sts' options.txt /*'sts'*
@@ -10527,6 +10529,7 @@ static-tag tagsrch.txt /*static-tag*
status-line windows.txt /*status-line*
statusmsg-variable eval.txt /*statusmsg-variable*
stl-%! options.txt /*stl-%!*
stl-%@ options.txt /*stl-%@*
stl-%{ options.txt /*stl-%{*
str2blob() builtin.txt /*str2blob()*
str2float() builtin.txt /*str2float()*
+7 -1
View File
@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.2. Last change: 2026 Feb 25
*version9.txt* For Vim version 9.2. Last change: 2026 Mar 01
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52593,6 +52593,7 @@ Other ~
- The new |xdg.vim| script for full XDG compatibility is included.
- |ConPTY| support is considered stable as of Windows 11.
- Support for "dap" channel mode for the |debug-adapter-protocol|.
- |status-line| can use several lines, see 'statuslineopt'.
*changed-9.3*
Changed~
@@ -52607,6 +52608,11 @@ Autocommands: ~
|SessionLoadPre| before loading a |Session| file
Options: ~
'statuslineopt' Extra options for the 'statusline', e.g. use the
"maxheight" suboption to use several lines.
==============================================================================
PATCHES *patches-9.3* *bug-fixes-9.3*
*patches-after-9.2*
+2 -1
View File
@@ -1,4 +1,4 @@
*windows.txt* For Vim version 9.2. Last change: 2026 Feb 24
*windows.txt* For Vim version 9.2. Last change: 2026 Mar 01
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -125,6 +125,7 @@ when the last window also has a status line:
You can change the contents of the status line with the 'statusline' option.
This option can be local to the window, so that you can have a different
status line in each window.
You can change the height of the status line with the 'statuslineopt' option.
Normally, inversion is used to display the status line. This can be changed
with the 's' character in the 'highlight' option. For example, "sb" sets it
+4 -2
View File
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
" Last Change: 2025 Nov 27
" Last Change: 2026 Mar 01
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" If there already is an option window, jump to that one.
@@ -490,8 +490,10 @@ call append("$", " \tset ls=" . &ls)
if has("statusline")
call <SID>AddOption("statusline", gettext("alternate format to be used for a status line"))
call <SID>OptionG("stl", &stl)
call append("$", "\t" .. s:local_to_window)
call <SID>AddOption("statuslineopt", gettext("optional settings for the status line"))
call <SID>OptionG("stlo", &stlo)
endif
call append("$", "\t" .. s:local_to_window)
call <SID>AddOption("equalalways", gettext("make all windows the same size when adding/removing windows"))
call <SID>BinOptionG("ea", &ea)
call <SID>AddOption("eadirection", gettext("in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\""))
+9 -9
View File
@@ -2,7 +2,7 @@
" Language: Vim script
" Maintainer: Hirohito Higashi <h.east.727 ATMARK gmail.com>
" Doug Kearns <dougkearns@gmail.com>
" Last Change: 2026 Feb 20
" Last Change: 2026 Mar 01
" Former Maintainer: Charles E. Campbell
" DO NOT CHANGE DIRECTLY.
@@ -70,9 +70,9 @@ syn keyword vimOption contained efm errorformat ek esckeys ei eventignore eiw ev
syn keyword vimOption contained hi history hk hkmap hkp hkmapp hls hlsearch icon iconstring ic ignorecase imaf imactivatefunc imak imactivatekey imc imcmdline imd imdisable imi iminsert ims imsearch imsf imstatusfunc imst imstyle inc include inex includeexpr is incsearch inde indentexpr indk indentkeys inf infercase im insertmode isf isfname isi isident isk iskeyword isp isprint js joinspaces jop jumpoptions key kmp keymap km keymodel kpc keyprotocol kp keywordprg lmap langmap lm langmenu lnr langnoremap lrm langremap ls laststatus lz lazyredraw lhi lhistory lbr linebreak lines lsp linespace lisp lop lispoptions lw lispwords list lcs listchars lpl loadplugins luadll magic mef makeef menc makeencoding mp makeprg mps matchpairs mat matchtime mco maxcombine mfd maxfuncdepth skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained mmd maxmapdepth mm maxmem mmp maxmempattern mmt maxmemtot msc maxsearchcount mis menuitems mopt messagesopt msm mkspellmem ml modeline mle modelineexpr mls modelines ma modifiable mod modified more mouse mousef mousefocus mh mousehide mousem mousemodel mousemev mousemoveevent mouses mouseshape mouset mousetime mzq mzquantum mzschemedll mzschemegcdll nf nrformats nu number nuw numberwidth ofu omnifunc odev opendevice opfunc operatorfunc ost osctimeoutlen pp packpath para paragraphs paste pt pastetoggle pex patchexpr pm patchmode pa path perldll pi preserveindent pvh previewheight pvp previewpopup pvw previewwindow pdev printdevice penc printencoding pexpr printexpr pfn printfont pheader printheader pmbcs printmbcharset pmbfn printmbfont skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained popt printoptions prompt pb pumborder ph pumheight pmw pummaxwidth pw pumwidth pythondll pythonhome pythonthreedll pythonthreehome pyx pyxversion qftf quickfixtextfunc qe quoteescape ro readonly rdt redrawtime re regexpengine rnu relativenumber remap rop renderoptions report rs restorescreen ri revins rl rightleft rlc rightleftcmd rubydll ru ruler ruf rulerformat rtp runtimepath scr scroll scb scrollbind scf scrollfocus sj scrolljump so scrolloff sbo scrollopt sect sections secure sel selection slm selectmode ssop sessionoptions sh shell shcf shellcmdflag sp shellpipe shq shellquote srr shellredir ssl shellslash stmp shelltemp st shelltype sxe shellxescape sxq shellxquote sr shiftround sw shiftwidth shm shortmess sn shortname sbr showbreak skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding tgc termguicolors twk termwinkey twsl termwinscroll skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys wcr wincolor wi window wfb winfixbuf wfh winfixheight skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline stlo statuslineopt su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding tgc termguicolors twk termwinkey skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained twsl termwinscroll tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys wcr wincolor wi window wfb winfixbuf skipwhite nextgroup=vimSetEqual,vimSetMod
syn keyword vimOption contained wfh winfixheight wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes skipwhite nextgroup=vimSetEqual,vimSetMod
" vimOptions: These are the turn-off setting variants {{{2
" GEN_SYN_VIM: vimOption turn-off, START_STR='syn keyword vimOption contained', END_STR=''
@@ -109,9 +109,9 @@ syn keyword vimOptionVarName contained efm errorformat ek esckeys ei eventignore
syn keyword vimOptionVarName contained hi history hk hkmap hkp hkmapp hls hlsearch icon iconstring ic ignorecase imaf imactivatefunc imak imactivatekey imc imcmdline imd imdisable imi iminsert ims imsearch imsf imstatusfunc imst imstyle inc include inex includeexpr is incsearch inde indentexpr indk indentkeys inf infercase im insertmode isf isfname isi isident isk iskeyword isp isprint js joinspaces jop jumpoptions key kmp keymap km keymodel kpc keyprotocol kp keywordprg lmap langmap lm langmenu lnr langnoremap lrm langremap ls laststatus lz lazyredraw lhi lhistory lbr linebreak lines lsp linespace lisp lop lispoptions lw lispwords list lcs listchars lpl loadplugins luadll magic mef makeef menc makeencoding mp makeprg mps matchpairs mat matchtime mco maxcombine
syn keyword vimOptionVarName contained mfd maxfuncdepth mmd maxmapdepth mm maxmem mmp maxmempattern mmt maxmemtot msc maxsearchcount mis menuitems mopt messagesopt msm mkspellmem ml modeline mle modelineexpr mls modelines ma modifiable mod modified more mouse mousef mousefocus mh mousehide mousem mousemodel mousemev mousemoveevent mouses mouseshape mouset mousetime mzq mzquantum mzschemedll mzschemegcdll nf nrformats nu number nuw numberwidth ofu omnifunc odev opendevice opfunc operatorfunc ost osctimeoutlen pp packpath para paragraphs paste pt pastetoggle pex patchexpr pm patchmode pa path perldll pi preserveindent pvh previewheight pvp previewpopup pvw previewwindow pdev printdevice penc printencoding pexpr printexpr pfn printfont pheader printheader pmbcs printmbcharset
syn keyword vimOptionVarName contained pmbfn printmbfont popt printoptions prompt pb pumborder ph pumheight pmw pummaxwidth pw pumwidth pythondll pythonhome pythonthreedll pythonthreehome pyx pyxversion qftf quickfixtextfunc qe quoteescape ro readonly rdt redrawtime re regexpengine rnu relativenumber remap rop renderoptions report rs restorescreen ri revins rl rightleft rlc rightleftcmd rubydll ru ruler ruf rulerformat rtp runtimepath scr scroll scb scrollbind scf scrollfocus sj scrolljump so scrolloff sbo scrollopt sect sections secure sel selection slm selectmode ssop sessionoptions sh shell shcf shellcmdflag sp shellpipe shq shellquote srr shellredir ssl shellslash stmp shelltemp st shelltype sxe shellxescape sxq shellxquote sr shiftround sw shiftwidth shm shortmess
syn keyword vimOptionVarName contained sn shortname sbr showbreak sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding tgc termguicolors
syn keyword vimOptionVarName contained twk termwinkey twsl termwinscroll tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys wcr wincolor
syn keyword vimOptionVarName contained wi window wfb winfixbuf wfh winfixheight wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes
syn keyword vimOptionVarName contained sn shortname sbr showbreak sc showcmd sloc showcmdloc sft showfulltag sm showmatch smd showmode stal showtabline stpl showtabpanel ss sidescroll siso sidescrolloff scl signcolumn scs smartcase si smartindent sta smarttab sms smoothscroll sts softtabstop spell spc spellcapcheck spf spellfile spl spelllang spo spelloptions sps spellsuggest sb splitbelow spk splitkeep spr splitright sol startofline stl statusline stlo statuslineopt su suffixes sua suffixesadd swf swapfile sws swapsync swb switchbuf smc synmaxcol syn syntax tcl tabclose tal tabline tpm tabpagemax tpl tabpanel tplo tabpanelopt ts tabstop tbs tagbsearch tc tagcase tfu tagfunc tl taglength tr tagrelative tag tags tgst tagstack tcldll term tbidi termbidi tenc termencoding
syn keyword vimOptionVarName contained tgc termguicolors twk termwinkey twsl termwinscroll tws termwinsize twt termwintype terse ta textauto tx textmode tw textwidth tsr thesaurus tsrfu thesaurusfunc top tildeop to timeout tm timeoutlen title titlelen titleold titlestring tb toolbar tbis toolbariconsize ttimeout ttm ttimeoutlen tbi ttybuiltin tf ttyfast ttym ttymouse tsl ttyscroll tty ttytype udir undodir udf undofile ul undolevels ur undoreload uc updatecount ut updatetime vsts varsofttabstop vts vartabstop vbs verbose vfile verbosefile vdir viewdir vop viewoptions vi viminfo vif viminfofile ve virtualedit vb visualbell warn wiv weirdinvert ww whichwrap wc wildchar wcm wildcharm wig wildignore wic wildignorecase wmnu wildmenu wim wildmode wop wildoptions wak winaltkeys
syn keyword vimOptionVarName contained wcr wincolor wi window wfb winfixbuf wfh winfixheight wfw winfixwidth wh winheight wmh winminheight wmw winminwidth winptydll wiw winwidth wse wlseat wst wlsteal wtm wltimeoutlen wrap wm wrapmargin ws wrapscan write wa writeany wb writebackup wd writedelay xtermcodes
" GEN_SYN_VIM: vimOption term output code variable, START_STR='syn keyword vimOptionVarName contained', END_STR=''
syn keyword vimOptionVarName contained t_AB t_AF t_AU t_AL t_al t_bc t_BE t_BD t_cd t_ce t_Ce t_CF t_cl t_cm t_Co t_CS t_Cs t_cs t_CV t_da t_db t_DL t_dl t_ds t_Ds t_EC t_EI t_fs t_fd t_fe t_GP t_IE t_IS t_ke t_ks t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RF t_RB t_RC t_RI t_Ri t_RK t_RS t_RT t_RV t_Sb t_SC t_se t_Sf t_SH t_SI t_Si t_so t_SR t_sr t_ST t_Te t_te t_TE t_ti t_TI t_Ts t_ts t_u7 t_ue t_us t_Us t_ut t_vb t_ve t_vi t_VS t_vs t_WP t_WS t_XM t_xn t_xs t_ZH t_ZR t_8f t_8b t_8u t_xo
syn keyword vimOptionVarName contained t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ku
@@ -134,8 +134,8 @@ syn keyword vimErrSetting contained invakm invaltkeymap invanti invantialias inv
syn case ignore
" GEN_SYN_VIM: vimAutoEvent, START_STR='syn keyword vimAutoEvent contained', END_STR='skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern'
syn keyword vimAutoEvent contained BufAdd BufCreate BufDelete BufEnter BufFilePost BufFilePre BufHidden BufLeave BufNew BufNewFile BufRead BufReadCmd BufReadPost BufReadPre BufUnload BufWinEnter BufWinLeave BufWipeout BufWrite BufWriteCmd BufWritePost BufWritePre CmdlineChanged CmdlineEnter CmdlineLeave CmdlineLeavePre CmdUndefined CmdwinEnter CmdwinLeave ColorScheme ColorSchemePre CompleteChanged CompleteDone CompleteDonePre CursorHold CursorHoldI CursorMoved CursorMovedC CursorMovedI DiffUpdated DirChanged DirChangedPre EncodingChanged ExitPre FileAppendCmd FileAppendPost FileAppendPre FileChangedRO FileChangedShell FileChangedShellPost FileEncoding FileReadCmd FileReadPost FileReadPre FileType FileWriteCmd FileWritePost FileWritePre FilterReadPost FilterReadPre skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern
syn keyword vimAutoEvent contained FilterWritePost FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave InsertLeavePre KeyInputPre MenuPopup ModeChanged OptionSet QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SafeState SafeStateAgain SessionLoadPost SessionWritePost ShellCmdPost ShellFilterPost SigUSR1 SourceCmd SourcePost SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabClosed TabClosedPre TabEnter TabLeave TabNew TermChanged TerminalOpen TerminalWinOpen TermResponse TermResponseAll TextChanged TextChangedI TextChangedP TextChangedT TextYankPost VimEnter VimLeave VimLeavePre VimResized VimResume VimSuspend WinClosed WinEnter WinLeave WinNew WinNewPre WinResized skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern
syn keyword vimAutoEvent contained WinScrolled skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern
syn keyword vimAutoEvent contained FilterWritePost FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave InsertLeavePre KeyInputPre MenuPopup ModeChanged OptionSet QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SafeState SafeStateAgain SessionLoadPost SessionLoadPre SessionWritePost ShellCmdPost ShellFilterPost SigUSR1 SourceCmd SourcePost SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabClosed TabClosedPre TabEnter TabLeave TabNew TermChanged TerminalOpen TerminalWinOpen TermResponse TermResponseAll TextChanged TextChangedI TextChangedP TextChangedT TextYankPost VimEnter VimLeave VimLeavePre VimResized VimResume VimSuspend WinClosed WinEnter WinLeave WinNew WinNewPre skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern
syn keyword vimAutoEvent contained WinResized WinScrolled skipwhite nextgroup=vimAutoEventSep,@vimAutocmdPattern
syn keyword vimAutoEvent contained User skipwhite nextgroup=vimUserAutoEvent
syn match vimUserAutoEvent contained "\<\h\w*\>" skipwhite nextgroup=vimUserAutoEventSep,vimAutocmdMod,vimAutocmdBlock
+168 -3
View File
@@ -45,6 +45,12 @@ static int buf_same_ino(buf_T *buf, stat_T *stp);
static int otherfile_buf(buf_T *buf, char_u *ffname);
#endif
static int value_changed(char_u *str, char_u **last);
#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE)
static int build_stl_str_hl_local(stl_mode_T mode, win_T *wp,
char_u *out, size_t outlen, char_u **fmt_arg,
char_u *opt_name, int opt_scope, int fillchar, int maxwidth,
stl_hlrec_T **hltab, stl_hlrec_T **tabtab, int *lbreaks);
#endif
static int append_arg_number(win_T *wp, char_u *buf, size_t buflen, int add_file);
static void free_buffer(buf_T *);
static void free_buffer_stuff(buf_T *buf, int free_options);
@@ -4366,6 +4372,94 @@ build_stl_str_hl(
int maxwidth,
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
stl_hlrec_T **tabtab) // return: tab page nrs (can be NULL)
{
return build_stl_str_hl_local(STL_MODE_SINGLE, wp, out, outlen, &fmt,
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, NULL);
}
int
build_stl_str_hl_mline(
win_T *wp,
char_u *out, // buffer to write into != NameBuff
size_t outlen, // length of out[]
char_u **fmt, // (in/out)
char_u *opt_name, // option name corresponding to "fmt"
int opt_scope, // scope for "opt_name"
int fillchar,
int maxwidth,
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
stl_hlrec_T **tabtab) // return: tab page nrs (can be NULL)
{
return build_stl_str_hl_local(STL_MODE_MULTI, wp, out, outlen, fmt,
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, NULL);
}
# ifdef ENABLE_STL_MODE_MULTI_NL
int
build_stl_str_hl_mline_nl(
win_T *wp,
char_u *out, // buffer to write into != NameBuff
size_t outlen, // length of out[]
char_u **fmt, // (in/out)
char_u *opt_name, // option name corresponding to "fmt"
int opt_scope, // scope for "opt_name"
int fillchar,
int maxwidth,
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
stl_hlrec_T **tabtab) // return: tab page nrs (can be NULL)
{
return build_stl_str_hl_local(STL_MODE_MULTI_NL, wp, out, outlen, fmt,
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, NULL);
}
# endif
int
get_stl_rendered_height(
win_T *wp,
char_u *fmt,
char_u *opt_name, // option name corresponding to "fmt"
int opt_scope) // scope for "opt_name"
{
int rendered_height = 0;
char_u buf[MAXPATHL] = {0};
(void)build_stl_str_hl_local(STL_MODE_GET_RENDERED_HEIGHT,
wp, buf, sizeof(buf), &fmt,
opt_name, opt_scope, 0, 0, NULL, NULL, &rendered_height);
return rendered_height;
}
/*
* mode:
* STL_MODE_SINGLE:
* - Does not accept line breaks ("%@")
* STL_MODE_MULTI:
* - Accept line breaks
* - Update fmt_arg to the start of the next line or last NUL position
* STL_MODE_GET_RENDERED_HEIGHT:
* - Just get stl rendered height
* - Update rendered_height (if not NULL)
*
* NOTE:
* Line break counting is performed here because `%{% ... %}` items
* are re-evaluated on redraw and may change the final rendered text.
* Therefore, layout decisions must be based on the fully evaluated statusline
* string, not on pre-evaluation parsing.
*/
static int
build_stl_str_hl_local(
stl_mode_T mode,
win_T *wp,
char_u *out, // buffer to write into != NameBuff
size_t outlen, // length of out[]
char_u **fmt_arg,
char_u *opt_name, // option name corresponding to "fmt"
int opt_scope, // scope for "opt_name"
int fillchar,
int maxwidth,
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
stl_hlrec_T **tabtab, // return: tab page nrs (can be NULL)
int *rendered_height) // return: stl rendered height (can be NULL)
{
linenr_T lnum;
colnr_T len;
@@ -4400,6 +4494,7 @@ build_stl_str_hl(
char_u opt;
# define TMPLEN 70
char_u buf_tmp[TMPLEN];
char_u *fmt = *fmt_arg;
char_u *usefmt = fmt;
stl_hlrec_T *sp;
int save_redraw_not_allowed = redraw_not_allowed;
@@ -4408,6 +4503,7 @@ build_stl_str_hl(
// matter?
// int called_emsg_before = called_emsg;
int did_emsg_before = did_emsg;
int rheight = 1; // stl rendered height
// When inside update_screen() we do not want redrawing a statusline,
// ruler, title, etc. to trigger another redraw, it may cause an endless
@@ -4534,7 +4630,23 @@ build_stl_str_hl(
* Handle up to the next '%' or the end.
*/
while (*s != NUL && *s != '%' && p + 1 < out + outlen)
# ifdef ENABLE_STL_MODE_MULTI_NL
{
if (*s == '\n' || *s == '\r')
{
if (mode == STL_MODE_MULTI_NL)
{
s++;
goto find_linebreak;
}
else if (mode == STL_MODE_GET_RENDERED_HEIGHT)
rheight++;
}
# endif
*p++ = *s++;
# ifdef ENABLE_STL_MODE_MULTI_NL
}
# endif
if (*s == NUL || p + 1 >= out + outlen)
break;
@@ -4544,6 +4656,21 @@ build_stl_str_hl(
s++;
if (*s == NUL) // ignore trailing %
break;
if (*s == STL_LINEBREAK)
{
if (mode == STL_MODE_MULTI
# ifdef ENABLE_STL_MODE_MULTI_NL
|| mode == STL_MODE_MULTI_NL
# endif
)
{
s++;
break;
}
else if (mode == STL_MODE_GET_RENDERED_HEIGHT)
rheight++;
}
if (*s == '%')
{
if (p + 1 >= out + outlen)
@@ -5201,14 +5328,52 @@ build_stl_str_hl(
vim_free(str);
curitem++;
}
# ifdef ENABLE_STL_MODE_MULTI_NL
find_linebreak:
# endif
*p = NUL;
outputlen = (size_t)(p - out);
itemcnt = curitem;
# ifdef FEAT_EVAL
if (usefmt != fmt)
vim_free(usefmt);
if (mode == STL_MODE_MULTI
# ifdef ENABLE_STL_MODE_MULTI_NL
|| mode == STL_MODE_MULTI_NL
# endif
)
{
// In multi-line mode, ownership of the format buffer is transferred
// back to the caller via *fmt_arg.
// When "%!" evaluation occurred (usefmt != fmt), "usefmt" is the newly
// allocated eval result and "fmt" is the caller's original buffer
// which is no longer needed. "s" points into "usefmt", so we free
// "fmt" and shift the remaining format string within "usefmt" for the
// caller's next iteration.
# ifdef FEAT_EVAL
if (usefmt != fmt)
vim_free(fmt);
# endif
size_t fmt_remain_len = strlen((char *)s);
mch_memmove(usefmt, s, fmt_remain_len);
usefmt[fmt_remain_len] = NUL;
*fmt_arg = usefmt;
}
else
{
// In single-line mode, the caller retains ownership of its buffer.
// Free the eval result if "%!" was used.
# ifdef FEAT_EVAL
if (usefmt != fmt)
vim_free(usefmt);
# endif
}
if (mode == STL_MODE_GET_RENDERED_HEIGHT)
{
if (rendered_height != NULL)
*rendered_height = rheight;
return 0;
}
width = vim_strsize(out);
if (maxwidth > 0 && width > maxwidth)
+5 -4
View File
@@ -457,6 +457,7 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
int row;
int fillchar;
int attr;
int i;
static int busy = FALSE;
// It's possible to get here recursively when 'statusline' (indirectly)
@@ -535,8 +536,6 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
}
else if (has_mbyte)
{
int i;
// Count total number of display cells.
plen = mb_string2cells(p, -1);
@@ -560,7 +559,8 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
}
screen_puts(p, row, wp->w_wincol, attr);
screen_fill(row, row + 1, plen + wp->w_wincol,
for (i = 0; i < wp->w_status_height; i++)
screen_fill(row + i, row + i + 1, plen + wp->w_wincol,
this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
if ((NameBufflen = get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)) > 0
&& (this_ru_col - plen) > (NameBufflen + 1))
@@ -590,7 +590,8 @@ win_redr_status(win_T *wp, int ignore_pum UNUSED)
fillchar = fillchar_status(&attr, wp);
else
fillchar = fillchar_vsep(&attr, wp);
screen_putchar(fillchar, row, W_ENDCOL(wp), attr);
for (i = 0; i < wp->w_status_height; i++)
screen_putchar(fillchar, row + i, W_ENDCOL(wp), attr);
}
busy = FALSE;
}
+3 -2
View File
@@ -309,8 +309,9 @@
#endif
/*
* +statusline 'statusline', 'rulerformat' and special format of
* 'titlestring' and 'iconstring' options.
* +statusline 'statusline', 'statuslineopt', 'rulerformat' and
* special format of 'titlestring' and 'iconstring'
* options.
*/
#ifdef FEAT_NORMAL
# define FEAT_STL_OPT
+5 -3
View File
@@ -4979,13 +4979,15 @@ xy2win(int x, int y, mouse_find_T popup)
else
update_mouseshape(SHAPE_IDX_MORE);
}
else if (row > wp->w_height) // below status line
else if (row >= wp->w_height + wp->w_status_height) // below status line
update_mouseshape(SHAPE_IDX_CLINE);
else if (!(State & MODE_CMDLINE) && wp->w_vsep_width > 0 && col == wp->w_width
&& (row != wp->w_height || !stl_connected(wp)) && msg_scrolled == 0)
&& (!(row >= wp->w_height && row < wp->w_height
+ wp->w_status_height) || !stl_connected(wp)) && msg_scrolled == 0)
update_mouseshape(SHAPE_IDX_VSEP);
else if (!(State & MODE_CMDLINE) && wp->w_status_height > 0
&& row == wp->w_height && msg_scrolled == 0)
&& row >= wp->w_height && row < wp->w_height + wp->w_status_height
&& msg_scrolled == 0)
update_mouseshape(SHAPE_IDX_STATUS);
else
update_mouseshape(-2);
+3 -1
View File
@@ -363,9 +363,10 @@ typedef enum {
#define STL_TRUNCMARK '<' // truncation mark if line is too long
#define STL_USER_HL '*' // highlight from (User)1..9 or 0
#define STL_HIGHLIGHT '#' // highlight name
#define STL_LINEBREAK '@' // insert a line break
#define STL_TABPAGENR 'T' // tab page label nr
#define STL_TABCLOSENR 'X' // tab page close nr
#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaNS{#")
#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaNS{#@")
// flags used for parsed 'wildmode'
#define WIM_FULL 0x01
@@ -942,6 +943,7 @@ EXTERN int p_ssl; // 'shellslash'
#endif
#ifdef FEAT_STL_OPT
EXTERN char_u *p_stl; // 'statusline'
EXTERN char_u *p_stlo; // 'statuslineopt'
#endif
EXTERN int p_sr; // 'shiftround'
EXTERN long p_sw; // 'shiftwidth'
+8
View File
@@ -2516,6 +2516,14 @@ static struct vimoption options[] =
(char_u *)&p_stl, PV_STL, did_set_statusline, NULL,
#else
(char_u *)NULL, PV_NONE, NULL, NULL,
#endif
{(char_u *)"", (char_u *)0L} SCTX_INIT},
{"statuslineopt" ,"stlo", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE
|P_ONECOMMA|P_COLON|P_NODUP,
#ifdef FEAT_STL_OPT
(char_u *)&p_stlo, PV_NONE, did_set_statuslineopt, expand_set_statuslineopt,
#else
(char_u *)NULL, PV_NONE, NULL, NULL,
#endif
{(char_u *)"", (char_u *)0L} SCTX_INIT},
{"suffixes", "su", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+52 -1
View File
@@ -96,6 +96,9 @@ static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
"sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
NULL};
#endif
#if defined(FEAT_STL_OPT)
static char *(p_stlo_values[]) = {"maxheight:", NULL};
#endif
// Keep in sync with SWB_ flags in option.h
static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL};
static char *(p_spk_values[]) = {"cursor", "screen", "topline", NULL};
@@ -664,6 +667,11 @@ check_stl_option(char_u *s)
if (!*s)
break;
s++;
if (*s == STL_LINEBREAK)
{
s++;
continue;
}
if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE)
{
s++;
@@ -4187,7 +4195,50 @@ expand_set_splitkeep(optexpand_T *args, int *numMatches, char_u ***matches)
char *
did_set_statusline(optset_T *args)
{
return parse_statustabline_rulerformat(args, FALSE);
char *ret = parse_statustabline_rulerformat(args, FALSE);
if (ret != NULL)
return ret;
frame_change_statusline_height();
return NULL;
}
/*
* The 'statuslineopt' option is changed.
*/
char *
did_set_statuslineopt(optset_T *args)
{
char_u **varp = (char_u **)args->os_varp;
if (statuslineopt_changed(*varp) == FAIL)
return e_invalid_argument;
frame_change_statusline_height();
if (*varp != empty_option)
{
// Update the maxheight value to the actual value set.
// Note: Must be changed if p_stlo_values are changed.
free_string_option(*varp);
vim_snprintf((char *)IObuff, IOSIZE, "maxheight:%d",
statusline_height(NULL));
*varp = vim_strsave(IObuff);
}
return NULL;
}
int
expand_set_statuslineopt(optexpand_T *args, int *numMatches, char_u ***matches)
{
return expand_set_opt_string(
args,
p_stlo_values,
ARRAY_LENGTH(p_stlo_values) - 1,
numMatches,
matches);
}
#endif
+3
View File
@@ -50,6 +50,9 @@ void maketitle(void);
void resettitle(void);
void free_titles(void);
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab);
int build_stl_str_hl_mline(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab);
int build_stl_str_hl_mline_nl(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab);
int get_stl_rendered_height(win_T *wp, char_u *fmt, char_u *opt_name, int opt_scope);
int get_rel_pos(win_T *wp, char_u *buf, int buflen);
char_u *fix_fname(char_u *fname);
void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname);
+2
View File
@@ -167,6 +167,8 @@ int expand_set_spellsuggest(optexpand_T *args, int *numMatches, char_u ***matche
char *did_set_splitkeep(optset_T *args);
int expand_set_splitkeep(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_statusline(optset_T *args);
char *did_set_statuslineopt(optset_T *args);
int expand_set_statuslineopt(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_swapsync(optset_T *args);
int expand_set_swapsync(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_switchbuf(optset_T *args);
+3
View File
@@ -90,6 +90,9 @@ void win_new_width(win_T *wp, int width);
void win_comp_scroll(win_T *wp);
void command_height(void);
void last_status(int morewin);
void frame_change_statusline_height(void);
int statuslineopt_changed(char_u *stlopt);
int statusline_height(win_T *wp);
int tabline_height(void);
int last_stl_height(int morewin);
int min_rows(void);
+69 -52
View File
@@ -1188,6 +1188,7 @@ win_redr_custom(
int width;
int n;
int len;
int stlh_cnt;
int fillchar;
char_u buf[MAXPATHL];
char_u *stl;
@@ -1278,64 +1279,80 @@ win_redr_custom(
ewp = wp == NULL ? curwin : wp;
p_crb_save = ewp->w_p_crb;
ewp->w_p_crb = FALSE;
stlh_cnt = draw_ruler || stl == p_tal ? 1 : wp->w_status_height;
// Make a copy, because the statusline may include a function call that
// might change the option value and free the memory.
stl = vim_strsave(stl);
width = build_stl_str_hl(ewp, buf, sizeof(buf),
(stl == NULL) ? (char_u *)"" : stl, opt_name, opt_scope,
fillchar, maxwidth, &hltab, &tabtab);
vim_free(stl);
char_u *stl_tmp = (stl == NULL) ? (char_u *)"" : stl;
int col_save = col;
for (int i = 0; i < stlh_cnt; i++)
{
col = col_save;
buf[0] = NUL;
width = build_stl_str_hl_mline(ewp, buf, sizeof(buf),
&stl_tmp,
opt_name, opt_scope,
fillchar, maxwidth, &hltab, &tabtab);
// Make all characters printable.
p = transstr(buf);
if (p != NULL)
{
len = vim_snprintf((char *)buf, sizeof(buf), "%s", p);
vim_free(p);
}
else
len = (int)STRLEN(buf);
// fill up with "fillchar"
while (width < maxwidth && len < (int)sizeof(buf) - 1)
{
len += (*mb_char2bytes)(fillchar, buf + len);
++width;
}
buf[len] = NUL;
/*
* Draw each snippet with the specified highlighting.
*/
curattr = attr;
p = buf;
for (n = 0; hltab[n].start != NULL; n++)
{
len = (int)(hltab[n].start - p);
screen_puts_len(p, len, row + i, col, curattr);
col += vim_strnsize(p, len);
p = hltab[n].start;
if (hltab[n].userhl == 0)
curattr = attr;
else if (hltab[n].userhl < 0)
curattr = syn_id2attr(-hltab[n].userhl);
# ifdef FEAT_TERMINAL
else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
&& wp->w_status_height != 0)
curattr = highlight_stltermnc[hltab[n].userhl - 1];
else if (wp != NULL && bt_terminal(wp->w_buffer)
&& wp->w_status_height != 0)
curattr = highlight_stlterm[hltab[n].userhl - 1];
# endif
else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
curattr = highlight_stlnc[hltab[n].userhl - 1];
else
curattr = highlight_user[hltab[n].userhl - 1];
}
screen_puts(p, row + i, col, curattr);
}
ewp->w_p_crb = p_crb_save;
// Make all characters printable.
p = transstr(buf);
if (p != NULL)
{
len = vim_snprintf((char *)buf, sizeof(buf), "%s", p);
vim_free(p);
}
else
len = (int)STRLEN(buf);
// fill up with "fillchar"
while (width < maxwidth && len < (int)sizeof(buf) - 1)
{
len += (*mb_char2bytes)(fillchar, buf + len);
++width;
}
buf[len] = NUL;
/*
* Draw each snippet with the specified highlighting.
*/
curattr = attr;
p = buf;
for (n = 0; hltab[n].start != NULL; n++)
{
len = (int)(hltab[n].start - p);
screen_puts_len(p, len, row, col, curattr);
col += vim_strnsize(p, len);
p = hltab[n].start;
if (hltab[n].userhl == 0)
curattr = attr;
else if (hltab[n].userhl < 0)
curattr = syn_id2attr(-hltab[n].userhl);
# ifdef FEAT_TERMINAL
else if (wp != NULL && wp != curwin && bt_terminal(wp->w_buffer)
&& wp->w_status_height != 0)
curattr = highlight_stltermnc[hltab[n].userhl - 1];
else if (wp != NULL && bt_terminal(wp->w_buffer)
&& wp->w_status_height != 0)
curattr = highlight_stlterm[hltab[n].userhl - 1];
# endif
else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
curattr = highlight_stlnc[hltab[n].userhl - 1];
else
curattr = highlight_user[hltab[n].userhl - 1];
}
screen_puts(p, row, col, curattr);
// Note: In the loop, build_stl_str_hl_mline() may replace stl_tmp with
// a newly allocated buffer (when "%!" evaluation occurs), freeing the
// original "stl" internally. After the loop, stl_tmp must be freed
// instead of stl, as it holds the current buffer ownership.
if (stl != NULL)
vim_free(stl_tmp);
if (wp == NULL)
{
+5 -2
View File
@@ -4050,8 +4050,11 @@ struct window_S
// status/command/winbar line(s)
int w_prev_winrow; // previous winrow used for 'splitkeep'
int w_prev_height; // previous height used for 'splitkeep'
int w_status_height; // number of status lines (0 or 1)
int w_status_height; // number of status lines.
// If 'statuslineopt' was changed, this
// member will be the previous value until
// call function
// frame_change_statusline_height().
int w_wincol; // Leftmost column of window in screen.
int w_width; // Width of window, excluding separation.
int w_vsep_width; // Number of separator columns (0 or 1).
+76 -166
View File
@@ -245,7 +245,7 @@ screen_puts_len_for_tabpanel(
int attr,
tabpanel_T *pargs)
{
int j, k;
int j;
int chlen;
int chcells;
char_u buf[IOSIZE];
@@ -257,7 +257,30 @@ screen_puts_len_for_tabpanel(
&& pargs->maxrow <= *pargs->prow - pargs->offsetrow)
break;
if (p[j] == '\n' || p[j] == '\r')
if (has_mbyte)
chlen = (*mb_ptr2len)(p + j);
else
chlen = 1;
for (int k = 0; k < chlen; k++)
buf[k] = p[j + k];
buf[chlen] = NUL;
j += chlen;
// Make all characters printable.
temp = transstr(buf);
if (temp != NULL)
{
vim_strncpy(buf, temp, sizeof(buf) - 1);
vim_free(temp);
}
if (has_mbyte)
chcells = (*mb_ptr2cells)(buf);
else
chcells = 1;
if (pargs->col_end < (*pargs->pcol) + chcells)
{
// fill the tailing area of current row.
if (*pargs->prow - pargs->offsetrow >= 0
@@ -266,62 +289,23 @@ screen_puts_len_for_tabpanel(
*pargs->prow - pargs->offsetrow,
*pargs->prow - pargs->offsetrow + 1,
*pargs->pcol, pargs->col_end, attr);
(*pargs->prow)++;
*pargs->pcol = pargs->col_start;
j++;
*pargs->pcol = pargs->col_end;
if (pargs->col_end < chcells)
break;
}
else
if (*pargs->pcol + chcells <= pargs->col_end)
{
if (has_mbyte)
chlen = (*mb_ptr2len)(p + j);
else
chlen = (int)STRLEN(p + j);
for (k = 0; k < chlen; k++)
buf[k] = p[j + k];
buf[chlen] = NUL;
j += chlen;
// Make all characters printable.
temp = transstr(buf);
if (temp != NULL)
{
vim_strncpy(buf, temp, sizeof(buf) - 1);
vim_free(temp);
}
if (has_mbyte)
chcells = (*mb_ptr2cells)(buf);
else
chcells = 1;
if (pargs->col_end < (*pargs->pcol) + chcells)
{
// fill the tailing area of current row.
if (*pargs->prow - pargs->offsetrow >= 0
&& *pargs->prow - pargs->offsetrow < pargs->maxrow)
screen_fill_tailing_area(tplmode,
*pargs->prow - pargs->offsetrow,
*pargs->prow - pargs->offsetrow + 1,
*pargs->pcol, pargs->col_end, attr);
*pargs->pcol = pargs->col_end;
if (pargs->col_end < chcells)
break;
}
if (*pargs->pcol + chcells <= pargs->col_end)
{
int off = (tpl_align == ALIGN_RIGHT)
? topframe->fr_width
: 0;
if (TPLMODE_REDRAW == tplmode
&& (*pargs->prow - pargs->offsetrow >= 0
&& *pargs->prow - pargs->offsetrow < pargs->maxrow))
screen_puts(buf, *pargs->prow - pargs->offsetrow,
*pargs->pcol + off, attr);
*pargs->pcol += chcells;
}
int off = (tpl_align == ALIGN_RIGHT)
? topframe->fr_width
: 0;
if (tplmode == TPLMODE_REDRAW
&& (*pargs->prow - pargs->offsetrow >= 0
&& *pargs->prow - pargs->offsetrow < pargs->maxrow))
screen_puts(buf, *pargs->prow - pargs->offsetrow,
*pargs->pcol + off, attr);
*pargs->pcol += chcells;
}
}
}
@@ -382,35 +366,20 @@ draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
}
/*
* default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
* Draw tabpanel content with highlight handling.
* Processes hltab entries and fills tailing area.
*/
static void
draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
draw_tabpanel_with_highlight(
int tplmode,
char_u *buf,
stl_hlrec_T *hltab,
tabpanel_T *pargs)
{
char_u *p;
int p_crb_save;
char_u buf[IOSIZE];
stl_hlrec_T *hltab;
stl_hlrec_T *tabtab;
int curattr;
int n;
// Temporarily reset 'cursorbind', we don't want a side effect from moving
// the cursor away and back.
p_crb_save = pargs->cwp->w_p_crb;
pargs->cwp->w_p_crb = FALSE;
// Make a copy, because the statusline may include a function call that
// might change the option value and free the memory.
p = vim_strsave(pargs->user_defined);
build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
p, opt_name, opt_scope,
TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
vim_free(p);
pargs->cwp->w_p_crb = p_crb_save;
curattr = pargs->attr;
p = buf;
for (n = 0; hltab[n].start != NULL; n++)
@@ -448,54 +417,6 @@ draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
*pargs->pcol = pargs->col_end;
}
static char_u *
starts_with_percent_and_bang(tabpanel_T *pargs)
{
int len = 0;
char_u *usefmt = p_tpl;
int did_emsg_before = did_emsg;
if (usefmt == NULL)
return NULL;
len = (int)STRLEN(usefmt);
if (len == 0)
return NULL;
#ifdef FEAT_EVAL
// if "fmt" was set insecurely it needs to be evaluated in the sandbox
int use_sandbox = was_set_insecurely(curwin, opt_name, opt_scope);
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
if (len > 1 && usefmt[0] == '%' && usefmt[1] == '!')
{
typval_T tv;
char_u *p = NULL;
tv.v_type = VAR_NUMBER;
tv.vval.v_number = pargs->cwp->w_id;
set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
if (p != NULL)
usefmt = p;
do_unlet((char_u *)"g:tabpanel_winid", TRUE);
if (did_emsg > did_emsg_before)
{
usefmt = NULL;
set_string_option_direct(opt_name, -1, (char_u *)"",
OPT_FREE | opt_scope, SID_ERROR);
}
}
#endif
return usefmt;
}
/*
* do something by tplmode for drawing tabpanel.
*/
@@ -545,6 +466,7 @@ do_by_tplmode(
if (tplmode == TPLMODE_GET_CURTAB_ROW)
{
*pcurtab_row = row;
do_unlet((char_u *)"g:actual_curtabpage", TRUE);
break;
}
}
@@ -562,54 +484,41 @@ do_by_tplmode(
args.wp = tp->tp_firstwin;
}
char_u *usefmt = starts_with_percent_and_bang(&args);
if (usefmt != NULL)
char_u *usefmt = vim_strsave(p_tpl);
if (usefmt != NULL && *usefmt != NUL)
{
char_u buf[IOSIZE];
char_u *p = usefmt;
size_t i = 0;
while (p[i] != NUL)
while (*usefmt != NUL)
{
while (p[i] == '\n' || p[i] == '\r')
{
// fill the tailing area of current row.
if (row - args.offsetrow >= 0
&& row - args.offsetrow < args.maxrow)
screen_fill_tailing_area(tplmode,
row - args.offsetrow,
row - args.offsetrow + 1,
col, args.col_end, args.attr);
row++;
col = col_start;
p++;
}
char_u buf[IOSIZE];
stl_hlrec_T *hltab;
stl_hlrec_T *tabtab;
while (p[i] != '\n' && p[i] != '\r' && p[i] != NUL)
{
if (i + 1 >= sizeof(buf))
break;
buf[i] = p[i];
i++;
}
buf[i] = NUL;
if (args.maxrow <= row - args.offsetrow)
break;
buf[0] = NUL;
#ifdef ENABLE_STL_MODE_MULTI_NL
(void)build_stl_str_hl_mline_nl
#else
(void)build_stl_str_hl_mline
#endif
(args.cwp, buf, sizeof(buf),
&usefmt, opt_name, opt_scope, TPL_FILLCHAR,
args.col_end - args.col_start, &hltab, &tabtab);
args.user_defined = buf;
args.prow = &row;
args.pcol = &col;
draw_tabpanel_userdefined(tplmode, &args);
// p_tpl could have been freed in build_stl_str_hl()
if (p_tpl == NULL || *p_tpl == NUL)
{
usefmt = NULL;
break;
}
p += i;
i = 0;
draw_tabpanel_with_highlight(tplmode, buf, hltab, &args);
// Move to next line for %@
if (*usefmt != NUL)
{
row++;
col = col_start;
}
}
if (usefmt != p_tpl)
VIM_CLEAR(usefmt);
}
else
{
@@ -619,6 +528,7 @@ do_by_tplmode(
draw_tabpanel_default(tplmode, &args);
}
vim_free(usefmt);
do_unlet((char_u *)"g:actual_curtabpage", TRUE);
tp = tp->tp_next;
+2
View File
@@ -312,6 +312,7 @@ NEW_TESTS = \
test_startup_utf8 \
test_stat \
test_statusline \
test_statuslineopt \
test_substitute \
test_suspend \
test_swap \
@@ -578,6 +579,7 @@ NEW_TESTS_RES = \
test_startup.res \
test_stat.res \
test_statusline.res \
test_statuslineopt.res \
test_substitute.res \
test_suspend.res \
test_swap.res \
@@ -0,0 +1,6 @@
> +0&#ffffff0@74
|~+0#4040ff13&| @73
|L+3#0000000&|1|A|0|1| @29|L+0&#ffff4012|1|A|0|2| +3&#ffffff0@29|L+0&&|1|A|0|3
|L|2|B|0|1| +3&&@29|L|2|B|0|2| @29|L+0&#ffff4012|2|B|0|3
|L|3|C|0|1| +3&#ffffff0@29|L+0&&|3|C|0|2| +3&&@29|L|3|C|0|3
| +0&&@74
@@ -0,0 +1,6 @@
> +0&#ffffff0@74
|~+0#4040ff13&| @73
|L+3#0000000&|1|A|0|1| @29|L+0&#ffff4012|1|A|0|2| +3&#ffffff0@29|L+0#ffffff16#ff404010|1|A|0|3
|L|2|B|0|1| +3#0000000#ffffff0@29|L|2|B|0|2| @29|L+0&#ffff4012|2|B|0|3
|L|3|C|0|1| +3&#ffffff0@29|L+0#ffffff16#ff404010|3|C|0|2| +3#0000000#ffffff0@29|L|3|C|0|3
| +0&&@74
@@ -7,4 +7,4 @@
|t+2#0000000&|o|p| @6|~+0#4040ff13&| @33
|$+2#0000000&| |[|c@2|]| @1|$|~+0#4040ff13&| @33
|b+2#0000000&|o|t@1|o|m| @3|~+0#4040ff13&| @33
| +1#0000000&@9|"+0&&|c@2|"| |[|N|e|w|]| @23
| +1#0000000&@9| +0&&@34
+151
View File
@@ -0,0 +1,151 @@
" Test 'statuslineopt' with 'statusline'
"
source util/screendump.vim
def SetUp()
set laststatus=2
set ch=1
enddef
def TearDown()
set laststatus&
set statusline&
set statuslineopt&
set ch&
:only
enddef
def s:Assert_match_statusline(winid: number, stlh: number, expect: list<string>): void
if has('gui_running')
redraw!
sleep 1m
endif
var wi = getwininfo(winid)[0]
var winh = wi.winrow + wi.height
var lines = [winh, winh + wi.status_height - 1]
var actual = mapnew(g:ScreenLines(lines, &columns), (_, v) =>
v[wi.wincol - 1 : wi.wincol - 1 + wi.width - 1])
assert_equal(stlh, wi.status_height)
for i in range(len(expect))
assert_match(expect[i], actual[i], $'[{i}]')
endfor
enddef
def Test_statuslineopt()
set statuslineopt=maxheight:2
&statusline = "AAA"
var wid = win_getid()
var stlh = 2
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^ *'])
&statusline = "AAA%@BBB"
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *'])
&statusline = "AAA%@BBB%@CCC"
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *'])
set statuslineopt=maxheight:3
stlh = 3
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^CCC *'])
&statusline = "AAA%@BBB"
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^ *'])
# Best effort
&statusline = "AAA%@BBB%@CCC"
set statuslineopt=maxheight:999
stlh = &lines - &ch - 1
s:Assert_match_statusline(wid, stlh, ['^AAA *', '^BBB *', '^CCC *', '^ *'])
# Single line
set statuslineopt=maxheight:1
stlh = 1
s:Assert_match_statusline(wid, stlh, ['^AAA *'])
enddef
def Test_statuslineopt_multi_win()
&statusline = "AAA%@BBB%@BB3"
var wid1 = win_getid()
new ccc
&l:statusline = "CCC%@DDD%@DD3"
var wid2 = win_getid()
set statuslineopt=maxheight:2
var stlh = 2
s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])
vnew eee
&l:statusline = "EEE%@FFF%@FF3"
var wid3 = win_getid()
s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])
s:Assert_match_statusline(wid3, stlh, ['^EEE *', '^FFF *'])
quit
new eee
wid3 = win_getid()
s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *'])
s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *'])
s:Assert_match_statusline(wid3, stlh, ['^EEE *', '^FFF *'])
# Best effort
set statuslineopt=maxheight:999
stlh = (&lines - &ch - 3) / 3
s:Assert_match_statusline(wid1, stlh, ['^AAA *', '^BBB *', '^BB3 *', '^ *'])
s:Assert_match_statusline(wid2, stlh, ['^CCC *', '^DDD *', '^DD3 *', '^ *'])
s:Assert_match_statusline(wid3, stlh, ['^EEE *', '^FFF *', '^FF3 *', '^ *'])
# Single line
set statuslineopt=maxheight:1
stlh = 1
s:Assert_match_statusline(wid1, stlh, ['^AAA *'])
s:Assert_match_statusline(wid2, stlh, ['^CCC *'])
s:Assert_match_statusline(wid3, stlh, ['^EEE *'])
enddef
let g:StloStatusVar = ''
def g:StloStatusLine(): string
return g:StloStatusVar
enddef
def Test_statuslineopt_expr()
new bbb.txt
g:StloStatusVar = 'A001%@A002%@%t'
set statuslineopt=maxheight:3
&statusline = "%!StloStatusLine()"
var wid = win_getid()
var stlh = 3
s:Assert_match_statusline(wid, stlh, ['^A001 *', '^A002 *', '^bbb\.txt *'])
&statusline = "%{%StloStatusLine()%}"
s:Assert_match_statusline(wid, stlh, ['^A001 *', '^A002 *', '^bbb\.txt *'])
g:StloStatusVar = 'B00001%@B002'
s:Assert_match_statusline(wid, stlh, ['^B00001 *', '^B002 *', '^ *'])
enddef
func Test_multistatusline_highlight()
CheckScreendump
let lines =<< trim END
func MyStatusLine()
return 'L1A01%=%#Search#L1A02%*%=%2*L1A03%*%@'
\ .. '%2*L2B01%*%=L2B02%=%#Search#L2B03%*%@'
\ .. '%#Search#L3C01%*%=%2*L3C02%*%=L3C03%@'
endfunc
set laststatus=2
set statuslineopt=maxheight:3
set statusline=%!MyStatusLine()
END
call writefile(lines, 'XTest_multistatusline_highlight', 'D')
let buf = g:RunVimInTerminal('-S XTest_multistatusline_highlight', {'rows': 6})
call term_sendkeys(buf, "\<C-L>")
call VerifyScreenDump(buf, 'Test_multistatusline_highlight_01', {})
call term_sendkeys(buf, ":hi link User2 Error\<CR>\<C-L>")
call VerifyScreenDump(buf, 'Test_multistatusline_highlight_02', {})
call term_sendkeys(buf, ":hi link User2 NONE\<CR>\<C-L>")
call VerifyScreenDump(buf, 'Test_multistatusline_highlight_01', {})
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+59 -46
View File
@@ -98,7 +98,7 @@ func Call_cmd_funcs()
let g:results = [getcmdpos(), getcmdscreenpos(), getcmdline()]
endfunc
function Test_tabpanel_cmdline()
function Test_tabpanel_cmdline_pos()
let save_showtabline = &showtabline
let g:results = []
cnoremap <expr> <F2> Call_cmd_funcs()
@@ -133,6 +133,29 @@ function Test_tabpanel_cmdline()
let &showtabline = save_showtabline
endfunc
function Test_tabpanel_cmdline_compl()
CheckScreendump
let lines =<< trim END
set showtabpanel=2
set tabpanelopt=columns:10
set showtabline=0
tabnew
END
call writefile(lines, 'XTest_tabpanel_cmdline_compl', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_cmdline_compl', {'rows': 10, 'cols': 45})
call term_sendkeys(buf, ":ab\<Tab>")
call VerifyScreenDump(buf, 'Test_tabpanel_cmdline_compl_0', {})
call term_sendkeys(buf, "\<Esc>")
call term_sendkeys(buf, ":set wildoptions=pum\<CR>")
call term_sendkeys(buf, ":ab\<Tab>")
call VerifyScreenDump(buf, 'Test_tabpanel_cmdline_compl_1', {})
call StopVimInTerminal(buf)
endfunc
function Test_tabpanel_mouse()
let save_showtabline = &showtabline
let save_mouse = &mouse
@@ -233,7 +256,7 @@ function Test_tabpanel_drawing()
function MyTabPanel()
let n = g:actual_curtabpage
let hi = n == tabpagenr() ? 'TabLineSel' : 'TabLine'
let label = printf("\n%%#%sTabNumber#%d:%%#%s#", hi, n, hi)
let label = printf("%%@%%#%sTabNumber#%d:%%#%s#", hi, n, hi)
let label ..= '%1*%f%*'
return label
endfunction
@@ -342,12 +365,16 @@ function Test_tabpanel_drawing_fill_tailing()
let &tabpanel = "abc"
redraw!
" Check whether "abc" is cleared
let &tabpanel = "\nTOP\n%f\nBOTTOM"
let &tabpanel = "%@TOP%@%f%@BOTTOM"
END
call writefile(lines, 'XTest_tabpanel_fill_tailing', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_fill_tailing', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_drawing_fill_tailing_0', {})
" TODO: If line breaks within 'tabpanel' using "\n" are no longer supported,
" delete the following two lines:
call term_sendkeys(buf, ':let &tabpanel = "\nTOP\n%f\nBOTTOM"' .. "\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_drawing_fill_tailing_0', {})
call StopVimInTerminal(buf)
@@ -464,30 +491,7 @@ function Test_tabpanel_visual()
call StopVimInTerminal(buf)
endfunc
function Test_tabpanel_commandline()
CheckScreendump
let lines =<< trim END
set showtabpanel=2
set tabpanelopt=columns:10
set showtabline=0
tabnew
END
call writefile(lines, 'XTest_tabpanel_commandline', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_commandline', {'rows': 10, 'cols': 45})
call term_sendkeys(buf, ":ab\<Tab>")
call VerifyScreenDump(buf, 'Test_tabpanel_commandline_0', {})
call term_sendkeys(buf, "\<Esc>")
call term_sendkeys(buf, ":set wildoptions=pum\<CR>")
call term_sendkeys(buf, ":ab\<Tab>")
call VerifyScreenDump(buf, 'Test_tabpanel_commandline_1', {})
call StopVimInTerminal(buf)
endfunc
function Test_tabpanel_tabline_and_tabpanel()
function Test_tabpanel_with_tabline()
CheckScreendump
let lines =<< trim END
@@ -501,10 +505,10 @@ function Test_tabpanel_tabline_and_tabpanel()
tabnew
e ccc.txt
END
call writefile(lines, 'XTest_tabpanel_tabline_and_tabpanel', 'D')
call writefile(lines, 'XTest_tabpanel_with_tabline', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_tabline_and_tabpanel', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_tabline_and_tabpanel_0', {})
let buf = RunVimInTerminal('-S XTest_tabpanel_with_tabline', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_with_tabline_0', {})
call StopVimInTerminal(buf)
endfunc
@@ -582,7 +586,7 @@ endfunc
""" call StopVimInTerminal(buf)
"""endfunc
function Test_tabpanel_eval_tabpanel_statusline_tabline()
function Test_tabpanel_eval()
CheckScreendump
let lines =<< trim END
@@ -602,17 +606,17 @@ function Test_tabpanel_eval_tabpanel_statusline_tabline()
tabnew
e ccc
END
call writefile(lines, 'XTest_tabpanel_eval_tabpanel_statusline_tabline', 'D')
call writefile(lines, 'XTest_tabpanel_eval', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_eval_tabpanel_statusline_tabline', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_statusline_tabline_0', {})
let buf = RunVimInTerminal('-S XTest_tabpanel_eval', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_eval_0', {})
call term_sendkeys(buf, ":set tabpanelopt+=align:right\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_statusline_tabline_1', {})
call VerifyScreenDump(buf, 'Test_tabpanel_eval_1', {})
call StopVimInTerminal(buf)
endfunc
function Test_tabpanel_noeval_tabpanel_statusline_tabline()
function Test_tabpanel_noeval()
CheckScreendump
let lines =<< trim END
@@ -629,22 +633,23 @@ function Test_tabpanel_noeval_tabpanel_statusline_tabline()
tabnew
e ccc
END
call writefile(lines, 'XTest_tabpanel_noeval_tabpanel_statusline_tabline', 'D')
call writefile(lines, 'XTest_tabpanel_noeval', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_noeval_tabpanel_statusline_tabline', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_noeval_tabpanel_statusline_tabline_0', {})
let buf = RunVimInTerminal('-S XTest_tabpanel_noeval', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_noeval_0', {})
call term_sendkeys(buf, ":set tabpanelopt+=align:right\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_noeval_tabpanel_statusline_tabline_1', {})
call VerifyScreenDump(buf, 'Test_tabpanel_noeval_1', {})
call StopVimInTerminal(buf)
endfunc
function Test_tabpanel_eval_tabpanel_with_linebreaks()
function Test_tabpanel_eval_with_linebreaks()
CheckScreendump
let lines =<< trim END
let g:ExprRetVal = "top%@$%=[%f]%=$%@bottom"
function Expr()
return "top\n$%=[%f]%=$\nbottom"
return g:ExprRetVal
endfunction
set showtabpanel=2
set tabpanel=%!Expr()
@@ -656,12 +661,20 @@ function Test_tabpanel_eval_tabpanel_with_linebreaks()
tabnew
e ccc
END
call writefile(lines, 'XTest_tabpanel_eval_tabpanel_with_linebreaks', 'D')
call writefile(lines, 'XTest_tabpanel_eval_with_linebreaks', 'D')
let buf = RunVimInTerminal('-S XTest_tabpanel_eval_tabpanel_with_linebreaks', {'rows': 10, 'cols': 45})
call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_with_linebreaks_0', {})
let buf = RunVimInTerminal('-S XTest_tabpanel_eval_with_linebreaks', {'rows': 10, 'cols': 45})
call term_sendkeys(buf, "\<C-L>") " Clear cmdline area
call VerifyScreenDump(buf, 'Test_tabpanel_eval_with_linebreaks_0', {})
call term_sendkeys(buf, ":set tabpanelopt+=align:right\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_with_linebreaks_1', {})
call VerifyScreenDump(buf, 'Test_tabpanel_eval_with_linebreaks_1', {})
" TODO: If line breaks within 'tabpanel' using "\n" are no longer supported,
" delete the following five lines:
call term_sendkeys(buf, ':let g:ExprRetVal = "top\n$%=[%f]%=$\nbottom"' .. "\<CR>")
call term_sendkeys(buf, ":set tabpanelopt=columns:10\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_eval_with_linebreaks_0', {})
call term_sendkeys(buf, ":set tabpanelopt+=align:right\<CR>")
call VerifyScreenDump(buf, 'Test_tabpanel_eval_with_linebreaks_1', {})
call StopVimInTerminal(buf)
endfunc
+1
View File
@@ -312,6 +312,7 @@ let test_values = {
\ ['xxx', '-1', 'timeout:', 'best,double', 'double,fast']],
\ 'splitkeep': [['', 'cursor', 'screen', 'topline'], ['xxx']],
\ 'statusline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
\ 'statuslineopt': [['', 'maxheight:1'], ['xxx', 'maxheight', 'fixedheight:3']],
\ 'swapsync': [['', 'sync', 'fsync'], ['xxx']],
\ 'switchbuf': [['', 'useopen', 'usetab', 'split', 'vsplit', 'newtab',
\ 'uselast', 'split,newtab'],
+2
View File
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
83,
/**/
82,
/**/
+15 -1
View File
@@ -1692,7 +1692,8 @@ typedef UINT32_TYPEDEF UINT32_T;
#define MIN_COLUMNS 12 // minimal columns for screen
#define MIN_LINES 2 // minimal lines for screen
#define MIN_CMDHEIGHT 1 // minimal height for command line
#define STATUS_HEIGHT 1 // height of a status line under a window
#define STATUS_HEIGHT 1 // default height of a status line under a
// window
#ifdef FEAT_MENU // height of a status line under a window
# define WINBAR_HEIGHT(wp) (wp)->w_winbar_height
# define VISIBLE_HEIGHT(wp) ((wp)->w_height + (wp)->w_winbar_height)
@@ -2451,6 +2452,19 @@ typedef enum {
ESTACK_SCRIPT,
} estack_arg_T;
// For temporarily backward compatibility, to be removed soon.
#define ENABLE_STL_MODE_MULTI_NL
// Argument for build_stl_str_hl_local().
typedef enum {
STL_MODE_SINGLE, // Does not accept line breaks "%@"
STL_MODE_MULTI, // Accept line breaks "%@"
STL_MODE_GET_RENDERED_HEIGHT, // Just get stl rendered height
#ifdef ENABLE_STL_MODE_MULTI_NL
STL_MODE_MULTI_NL, // Accept line breaks "%@" and "\n"
#endif
} stl_mode_T;
// Return value of match_keyprotocol()
typedef enum {
KEYPROTOCOL_NONE,
+183 -34
View File
@@ -53,6 +53,10 @@ static void win_goto_ver(int up, long count);
static void win_goto_hor(int left, long count);
static void frame_add_height(frame_T *frp, int n);
static void last_status_rec(frame_T *fr, int statusline);
#if defined(FEAT_STL_OPT)
static void frame_change_statusline_height_rec(frame_T *frp,
bool actual_change);
#endif
static void frame_flatten(frame_T *frp);
static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr);
@@ -94,6 +98,11 @@ static int close_disallowed = 0;
// to avoid that winframe_remove() is called recursively
static int frame_locked = 0;
#if defined(FEAT_STL_OPT)
static int stlo_mh = STATUS_HEIGHT;
static int stlh_effort;
#endif
/*
* Disallow changing the window layout (split window, close window, move
* window). Resizing is still allowed.
@@ -1035,7 +1044,7 @@ win_split_ins(
emsg(_(e_not_enough_room));
goto theend;
}
need_status = STATUS_HEIGHT;
need_status = statusline_height(oldwin);
}
#ifdef FEAT_GUI
@@ -1140,7 +1149,7 @@ win_split_ins(
*/
// Current window requires at least 1 space.
wmh1 = (p_wmh == 0 ? 1 : p_wmh) + WINBAR_HEIGHT(curwin);
needed = wmh1 + STATUS_HEIGHT;
needed = wmh1 + statusline_height(oldwin);
if (flags & WSP_ROOM)
needed += p_wh - wmh1;
if (flags & (WSP_BOT | WSP_TOP))
@@ -1179,18 +1188,23 @@ win_split_ins(
oldwin_height = oldwin->w_height;
if (need_status)
{
oldwin->w_status_height = STATUS_HEIGHT;
oldwin_height -= STATUS_HEIGHT;
oldwin->w_status_height = statusline_height(oldwin);
oldwin_height -= oldwin->w_status_height;
}
if (new_size == 0)
new_size = oldwin_height / 2;
if (new_size > available - minheight - STATUS_HEIGHT)
new_size = available - minheight - STATUS_HEIGHT;
{
if (lastwin == firstwin && p_ls == 0)
new_size = (oldwin_height - statusline_height(oldwin) + 1) / 2;
else
new_size = (oldwin_height - oldwin->w_status_height + 1) / 2;
}
if (new_size > available - minheight - statusline_height(oldwin))
new_size = available - minheight - statusline_height(oldwin);
if (new_size < wmh1)
new_size = wmh1;
// if it doesn't fit in the current window, need win_equal()
if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
if (oldwin_height - new_size - statusline_height(oldwin) < p_wmh)
do_equal = TRUE;
// We don't like to take lines for the new window from a
@@ -1203,11 +1217,11 @@ win_split_ins(
set_fraction(oldwin);
did_set_fraction = TRUE;
win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
oldwin);
win_setheight_win(oldwin->w_height + new_size
+ statusline_height(oldwin), oldwin);
oldwin_height = oldwin->w_height;
if (need_status)
oldwin_height -= STATUS_HEIGHT;
oldwin_height -= statusline_height(oldwin);
}
// Only make all windows the same height if one of them (except oldwin)
@@ -1221,7 +1235,7 @@ win_split_ins(
if (frp->fr_win != oldwin && frp->fr_win != NULL
&& (frp->fr_win->w_height > new_size
|| frp->fr_win->w_height > oldwin_height - new_size
- STATUS_HEIGHT))
- statusline_height(oldwin)))
{
do_equal = TRUE;
break;
@@ -1346,16 +1360,16 @@ win_split_ins(
if (need_status)
{
win_new_height(oldwin, oldwin->w_height - 1);
win_new_height(oldwin, oldwin->w_height - need_status);
oldwin->w_status_height = need_status;
}
if (flags & (WSP_TOP | WSP_BOT))
{
// set height and row of new window to full height
wp->w_winrow = tabline_height();
win_new_height(wp, curfrp->fr_height - (p_ls > 0)
- WINBAR_HEIGHT(wp));
wp->w_status_height = (p_ls > 0);
win_new_height(wp, curfrp->fr_height
- statusline_height(curfrp->fr_win) - WINBAR_HEIGHT(wp));
wp->w_status_height = statusline_height(curfrp->fr_win);
}
else
{
@@ -1424,27 +1438,28 @@ win_split_ins(
+ WINBAR_HEIGHT(wp);
if (!((flags & WSP_BOT) && p_ls == 0))
new_fr_height -= STATUS_HEIGHT;
new_fr_height -= statusline_height(curfrp->fr_win);
if (flags & WSP_BOT)
frame_add_statusline(curfrp);
frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE,
FALSE);
}
else
win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
win_new_height(oldwin, oldwin_height - (new_size
+ statusline_height(wp)));
if (before) // new window above current one
{
wp->w_winrow = oldwin->w_winrow;
wp->w_status_height = STATUS_HEIGHT;
oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
wp->w_status_height = statusline_height(wp);
oldwin->w_winrow += wp->w_height + statusline_height(wp);
}
else // new window below current one
{
wp->w_winrow = oldwin->w_winrow + VISIBLE_HEIGHT(oldwin)
+ STATUS_HEIGHT;
+ statusline_height(oldwin);
wp->w_status_height = old_status_height;
if (!(flags & WSP_BOT))
oldwin->w_status_height = STATUS_HEIGHT;
oldwin->w_status_height = statusline_height(oldwin);
}
frame_fix_height(wp);
frame_fix_height(oldwin);
@@ -1742,7 +1757,7 @@ make_windows(
{
// Each window needs at least 'winminheight' lines and a status line.
maxcount = (VISIBLE_HEIGHT(curwin) + curwin->w_status_height
- (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
- (p_wh - p_wmh)) / (p_wmh + statusline_height(curwin));
}
if (maxcount < 2)
@@ -1773,8 +1788,8 @@ make_windows(
else
{
if (win_split(curwin->w_height - (curwin->w_height - todo
* STATUS_HEIGHT) / (todo + 1)
- STATUS_HEIGHT, WSP_ABOVE) == FAIL)
* statusline_height(curwin)) / (todo + 1)
- statusline_height(curwin), WSP_ABOVE) == FAIL)
break;
}
@@ -2104,6 +2119,9 @@ win_equal(
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
topframe, dir, firstwin->w_wincol, tabline_height(),
topframe->fr_width, topframe->fr_height);
#if defined(FEAT_STL_OPT)
frame_change_statusline_height();
#endif
if (!is_aucmd_win(next_curwin))
win_fix_scroll(TRUE);
}
@@ -2301,10 +2319,11 @@ win_equal_rec(
n = frame_minheight(topfr, NOWIN);
// add one for the bottom window if it doesn't have a statusline
if (row + height == cmdline_row && p_ls == 0)
extra_sep = 1;
extra_sep = statusline_height(NULL);
else
extra_sep = 0;
totwincount = (n + extra_sep) / (p_wmh + 1);
totwincount = (n + extra_sep) / (p_wmh
+ statusline_height(NULL));
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2343,7 +2362,8 @@ win_equal_rec(
else
// These windows don't use up room.
totwincount -= (n + (fr->fr_next == NULL
? extra_sep : 0)) / (p_wmh + 1);
? extra_sep : 0))
/ (p_wmh + statusline_height(NULL));
room -= new_size - n;
if (room < 0)
{
@@ -2394,7 +2414,7 @@ win_equal_rec(
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
/ (p_wmh + 1);
/ (p_wmh + statusline_height(NULL));
m = frame_minheight(fr, next_curwin);
if (has_next_curwin)
hnc = frame_has_win(fr, next_curwin);
@@ -4121,7 +4141,7 @@ frame_add_statusline(frame_T *frp)
if (frp->fr_layout == FR_LEAF)
{
wp = frp->fr_win;
wp->w_status_height = STATUS_HEIGHT;
wp->w_status_height = statusline_height(wp);
}
else if (frp->fr_layout == FR_ROW)
{
@@ -6377,6 +6397,9 @@ win_comp_pos(void)
int col = TPL_LCOL();
frame_comp_pos(topframe, &row, &col);
#if defined(FEAT_STL_OPT)
frame_change_statusline_height();
#endif
}
/*
@@ -6445,6 +6468,9 @@ win_ensure_size(void)
win_setheight(int height)
{
win_setheight_win(height, curwin);
#if defined(FEAT_STL_OPT)
frame_change_statusline_height();
#endif
}
/*
@@ -7522,6 +7548,9 @@ last_status(
{
// Don't make a difference between horizontal or vertical split.
last_status_rec(topframe, last_stl_height(morewin) > 0);
#if defined(FEAT_STL_OPT)
frame_change_statusline_height();
#endif
}
static void
@@ -7536,7 +7565,7 @@ last_status_rec(frame_T *fr, int statusline)
if (wp->w_status_height != 0 && !statusline)
{
// remove status line
win_new_height(wp, wp->w_height + 1);
win_new_height(wp, wp->w_height + wp->w_status_height);
wp->w_status_height = 0;
comp_col();
}
@@ -7558,15 +7587,16 @@ last_status_rec(frame_T *fr, int statusline)
else
fp = fp->fr_parent;
}
wp->w_status_height = 1;
wp->w_status_height = statusline_height(wp);
if (fp != fr)
{
frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE, FALSE);
frame_new_height(fp, fp->fr_height - wp->w_status_height,
FALSE, FALSE, FALSE);
frame_fix_height(wp);
win_comp_pos();
}
else
win_new_height(wp, wp->w_height - 1);
win_new_height(wp, wp->w_height - wp->w_status_height);
comp_col();
redraw_all_later(UPD_SOME_VALID);
}
@@ -7589,6 +7619,125 @@ last_status_rec(frame_T *fr, int statusline)
}
}
#if defined(FEAT_STL_OPT)
/*
* Set a status line height to windows at the bottom of "frp".
* Note: Does not check if there is room!
*/
void
frame_change_statusline_height(void)
{
tabpage_T *tp;
stlh_effort = stlo_mh;
FOR_ALL_TABPAGES(tp)
frame_change_statusline_height_rec(tp->tp_topframe, false);
stlo_mh = stlh_effort;
FOR_ALL_TABPAGES(tp)
frame_change_statusline_height_rec(tp->tp_topframe, true);
comp_col();
redraw_all_later(UPD_SOME_VALID);
}
static void
frame_change_statusline_height_rec(frame_T *frp, bool actual_change)
{
if (frp->fr_layout == FR_LEAF)
{
win_T *wp = frp->fr_win;
if (wp->w_height > 0 && wp->w_status_height > 0)
{
if (actual_change)
{
wp->w_status_height = stlo_mh;
if (wp->w_status_height > frp->fr_height - wp->w_winbar_height
- p_wmh)
{
wp->w_status_height = frp->fr_height - wp->w_winbar_height
- p_wmh;
}
win_new_height(wp, frp->fr_height - wp->w_status_height
- wp->w_winbar_height);
}
else
{
if (frp->fr_height - wp->w_winbar_height - p_wmh < stlh_effort)
stlh_effort = frp->fr_height - wp->w_winbar_height - p_wmh;
}
}
}
else if (frp->fr_layout == FR_ROW)
{
// Handle all the frames in the row.
for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
frame_change_statusline_height_rec(frp, actual_change);
}
else // frp->fr_layout == FR_COL
{
// Handle all the frames in the column.
for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
frame_change_statusline_height_rec(frp, actual_change);
}
}
/*
* Check "stlopt" as 'statuslineopt' and update the members of "wp".
* This is called when 'statuslineopt' is changed.
* Returns FAIL for failure, OK otherwise.
*/
int
statuslineopt_changed(
char_u *stlopt
)
{
char_u *p;
int l_stlo_mh = 1;
p = stlopt;
while (*p != NUL)
{
// Note: Keep this in sync with p_stlo_values
if (STRNCMP(p, "maxheight:", 10) == 0 && VIM_ISDIGIT(p[10]))
{
p += 10;
l_stlo_mh = getdigits(&p);
if (l_stlo_mh < 1)
return FAIL;
}
if (*p != ',' && *p != NUL)
return FAIL;
if (*p == ',')
++p;
}
stlo_mh = l_stlo_mh;
return OK;
}
#endif
/*
* Return the number of lines used by the status line.
* "wp" is not used currently because 'statuslineopt' is a global option.
* NULL is passed when called from layout calculations (e.g. 'laststatus')
* where no specific window context is available.
*/
int
statusline_height(win_T *wp UNUSED)
{
return
#if defined(FEAT_STL_OPT)
stlo_mh
#else
STATUS_HEIGHT
#endif
;
}
/*
* Return the number of lines used by the tab page line.
*/