I tried to write a small script to give the statusline distinguishable appearance on current and non-current window.
The local active and inactive statuslines are defined by the following code:
- Active
statusline:
function! SttLine_Active(usesimple)
setl statusline=
if (!a:usesimple)
setl statusline+=\%#StatusBlockColour#
setl statusline+=\ %{g:currentmode[mode()]}\ %0*
setl statusline+=\%#StatusLineColour#
setl statusline+=\ %p%%\(%L)\ ≡\ L%l\:%c\ \|%0*
setl statusline+=\%#StatusFileColour#
setl statusline+=\ [%{winnr()}]\ %f\ %m%=%0*
setl statusline+=\%#StatusBlockColour#
setl statusline+=\ ⌨\ %{&fileformat}:\ %y
setl statusline+=\ %{&fileencoding?&fileencoding:&encoding}\ %0*
else
setl statusline+=\%#StatusFileColour#
setl statusline+=\ %f\ %m\ %=%0*
endif
endfunction
- Inactive
statusline
function! SttLine_Inactive(usesimple)
setl statusline=
if (!a:usesimple)
setl statusline+=\%#StatusBlockGrey#
setl statusline+=\ %{g:currentmode[mode()]}\ %0*
setl statusline+=\%#StatusLineGrey#
setl statusline+=\ %p%%\(%L)\ ≡\ L%l\:%c\ \|%0*
setl statusline+=\%#StatusFileGrey#
setl statusline+=\ [%{winnr()}]\ %f\ %m%=%0*
setl statusline+=\%#StatusBlockGrey#
setl statusline+=\ ⌨\ %{&fileformat}:\ %y
setl statusline+=\ %{&fileencoding?&fileencoding:&encoding}\ %0*
else
setl statusline+=\%#StatusFileGrey#
setl statusline+=\ %f\ %m\ %=%0*
endif
endfunction
I then define some functions for different actions in vim, including VimEnter, WinNew, WinEnter and WinLeave as I want a different style for netrw window
- Function execute when vim start
function! SttLine_VimStart()
let usesimple = (&filetype=="netrw") || (&filetype=="help")
call SttLine_Active(usesimple)
endfunction
- Function that executes when a new window is opened:
function! SttLine_NewWin()
let nWin = bufnr("$")
let iwin = 0
let hasnetrw = 0
while (iwin < nWin)
if (getbufvar(iwin, "&filetype") == "netrw")
let hasnetrw = 1
endif
let iwin += 1
endwhile
if (hasnetrw>0)
vert res
vert res -25
endif
endfunction
- Function executes on enter a window
function! SttLine_Enter()
let usesimple = (&filetype=="netrw") || (&filetype=="help")
call SttLine_Active(usesimple)
endfunction
- Function executes on leaving a window
function! SttLine_Leave()
let usesimple = (&filetype=="netrw") || (&filetype=="help")
call SttLine_Inactive(usesimple)
endfunction
Finally the augroup for those functions above
augroupto call the correctstatusline:
augroup Auto_Change_SttLine
autocmd!
autocmd VimEnter * call SttLine_VimStart()
autocmd WinNew * call SttLine_NewWin()
autocmd WinEnter * call SttLine_Enter()
autocmd WinLeave * call SttLine_Leave()
augroup END
- To test the script:
- I open a file, let's call it file_01.txt from the terminal:
$ vim file01.txt - then in vim, I open another file, file_02.txt:
:new file_02.txt
- My problem
The first time, it worked as I expected. But for the next times I opened vim, it failed sometimes.
I realize that if I close file_02.txt before closing file_01.txt, the next time I start vim, my script fails.
In order to fix it, I need to close file_01.txt before closing file_02.txt.
- My question
What is causing this problem and how to make my script work regardless of the previous closing order?
Here is my youtube video demonstrating the steps I did to produce the error.
- Additional information
Below are the highlight I used for my statusline
hi StatusBlockColour cterm=bold ctermfg=235 ctermbg=190
hi StatusBlockGrey cterm=bold ctermfg=235 ctermbg=247
hi StatusLineColour cterm=bold ctermfg=190 ctermbg=240
hi StatusLineGrey cterm=bold ctermfg=245 ctermbg=240
hi StatusFileColour cterm=bold ctermfg=208 ctermbg=240
hi StatusFileGrey cterm=bold ctermfg=245 ctermbg=240
- Update 1
I just found some other issues in my
.vimrc. I used
au BufWinLeave * mkview
au BufWinEnter * silent loadview
to restore the last view. It accidentally enabled me to run SttLine_Enter() and the result is bad.
Recently I added to my augroup a new au for BufWinEnter, so it became:
- (Updated)
augroupto call thestatusline:
augroup Auto_Change_SttLine
autocmd!
autocmd VimEnter * call SttLine_VimStart()
autocmd WinNew * call SttLine_NewWin()
autocmd BufWinEnter * call SttLine_Enter()
autocmd WinEnter * call SttLine_Enter()
autocmd WinLeave * call SttLine_Leave()
augroup END
:help View, and also check:set viminfo?maybe. I'm just trying to think of things that could be automatically restoring state; normally, very few thing can affect vim between instances. See also How to debug my vimrc – D. Ben Knoble Feb 14 '22 at 19:20mkviewandloadview. Myautocmdfor setting up a sttline for newly opened window works because of those commands, but unfortunately they also cause the unexpected behaviour I post. I'll take a look to View and viminfo as you suggest to see if there is a work around to prevent the "negative" effect ofmkviewandloadview. I updated my post too. – Rekkhan Feb 15 '22 at 02:07