'vim - What's the best way to set statusline color to change, based on mode
I've tried to improve my vim experience trying to have the vim statusline color to change everytime the mode changes.
I've triend this: (found here)
"Automatically change the statusline color depending on mode
function! ChangeStatuslineColor()
if (mode() =~# '\v(n|no)')
exe 'hi! StatusLine ctermfg=008'
elseif (mode() =~# '\v(v|V)' || g:currentmode[mode()] ==# 'V·Block' || get(g:currentmode, mode(), '') ==# 't')
exe 'hi! StatusLine ctermfg=005'
elseif (mode() ==# 'i')
exe 'hi! StatusLine ctermfg=004'
else
exe 'hi! StatusLine ctermfg=006'
endif
return ''
endfunction
...and include:
set statusline+=%{ChangeStatuslineColor()}
But there's an issue, if you switch to insert mode and then press Esc to come back to normal mode, it doesn't change back the color. It'll change back the color only when you manually enter a different mode.
Solution 1:[1]
Sorry for necroposting, but I think I found a way better solution for this task. Set up desired colors like this
hi NormalColor guifg=Black guibg=Green ctermbg=46 ctermfg=0
hi InsertColor guifg=Black guibg=Cyan ctermbg=51 ctermfg=0
hi ReplaceColor guifg=Black guibg=maroon1 ctermbg=165 ctermfg=0
hi VisualColor guifg=Black guibg=Orange ctermbg=202 ctermfg=0
Now add to statusline
set statusline+=%#NormalColor#%{(mode()=='n')?'\ \ NORMAL\ ':''}
set statusline+=%#InsertColor#%{(mode()=='i')?'\ \ INSERT\ ':''}
set statusline+=%#ReplaceColor#%{(mode()=='R')?'\ \ REPLACE\ ':''}
set statusline+=%#VisualColor#%{(mode()=='v')?'\ \ VISUAL\ ':''}
It works perfect, doesn't need any workarounds for visual mode and doesn't require additional cursor movements to trigger color change.
Solution 2:[2]
I found that the below approach was the best for me. It gives me colors for all different modes, not just insert, replace, visual and normal.
function! GitBranch()
return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")
endfunction
function! StatuslineGit()
let l:branchname = GitBranch()
return strlen(l:branchname) > 0?' '.l:branchname.' ':''
endfunction
let g:currentmode={
\ 'n' : 'n',
\ 'v' : 'v',
\ 'V' : 'vl',
\ '' : 'vb',
\ 'i' : 'i',
\ 'R' : 'r',
\ 'Rv' : 'rv',
\ 'c' : 'c',
\ 't' : 'f',
\}
hi NormalColor ctermbg=black ctermfg=white
hi InsertColor ctermbg=darkgreen ctermfg=black
hi ReplaceColor ctermbg=darkred ctermfg=black
hi VisualColor ctermbg=darkblue ctermfg=black
set laststatus=2
set statusline=
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='n')?'\ \ normal\ ':''}
set statusline+=%#InsertColor#%{(g:currentmode[mode()]=='i')?'\ \ insert\ ':''}
set statusline+=%#ReplaceColor#%{(g:currentmode[mode()]=='r')?'\ \ replace\ ':''}
set statusline+=%#ReplaceColor#%{(g:currentmode[mode()]=='rv')?'\ \ v-replace\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='v')?'\ \ visual\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='vl')?'\ \ v-line\ ':''}
set statusline+=%#VisualColor#%{(g:currentmode[mode()]=='vb')?'\ \ v-block\ ':''}
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='c')?'\ \ command\ ':''}
set statusline+=%#NormalColor#%{(g:currentmode[mode()]=='f')?'\ \ finder\ ':''}
set statusline+=%#PmenuSel#
set statusline+=%{StatuslineGit()}
set statusline+=%#Statusline#
set statusline+=\ %f
set statusline+=%m
set statusline+=%=
set statusline+=%#StatusLineNc#
set statusline+=\ %y
set statusline+=\ %{&fileencoding?&fileencoding:&encoding}
set statusline+=\ %p%%
set statusline+=\ %l:%c
Solution 3:[3]
May be you should try this vim plugin vim-airline. It can automatically change statusline color as mode changing based on which colortheme you set.
Solution 4:[4]
I like to have two vim configs, one which uses plugins and another which only has a vimrc. To do this without plugin like airline i normally use this snippet from: http://vim.wikia.com/wiki/Change_statusline_color_to_show_insert_or_normal_mode
function! InsertStatuslineColor(mode)
if a:mode == 'i'
hi statusline guibg=magenta
elseif a:mode == 'r'
hi statusline guibg=blue
else
hi statusline guibg=red
endif
endfunction
au InsertEnter * call InsertStatuslineColor(v:insertmode)
au InsertChange * call InsertStatuslineColor(v:insertmode)
au InsertLeave * hi statusline guibg=green
" default the statusline to
green when entering Vim hi statusline guibg=green
As stated on the wiki:
The following small piece changes the color of the statusline when you enter insert mode, and when you leave insert mode. There are no mapping keys or new commands to remember, it works totally automatically.
Of course if you don't like the colors chosen you can just alter these bits:
guibg=magenta
Solution 5:[5]
I know that this question was asked long time ago and you probably got what you'd want but anyway I will post my solution which in my opinion is good enough to share it here.
hi StatusLine ctermfg=253 ctermbg=233 cterm=bold
hi StatusLineNormal ctermfg=251 ctermbg=26 cterm=bold
hi StatusLineInsert ctermfg=251 ctermbg=22 cterm=bold
hi StatusLineReplace ctermfg=251 ctermbg=88 cterm=bold
hi StatusLineVisual ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineVisualL ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineVisualB ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineCommand ctermfg=251 ctermbg=26 cterm=bold
hi StatusLineSelect ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineSelectL ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineSelectB ctermfg=251 ctermbg=130 cterm=bold
hi StatusLineTerminal ctermfg=251 ctermbg=22 cterm=bold
let s:statusline_modes_dict = {
\ 'n' : {
\ 'text' : 'NORMAL',
\ 'color_group' : 'StatusLineNormal'
\ },
\ 'i' : {
\ 'text' : 'INSERT',
\ 'color_group' : 'StatusLineInsert'
\ },
\ 'R' : {
\ 'text' : 'REPLACE',
\ 'color_group' : 'StatusLineReplace'
\ },
\ 'v' : {
\ 'text' : 'VISUAL',
\ 'color_group' : 'StatusLineVisual'
\ },
\ 'V' : {
\ 'text' : 'V-LINE',
\ 'color_group' : 'StatusLineVisualL'
\ },
\ "\<C-v>" : {
\ 'text' : 'V-BLOCK',
\ 'color_group' : 'StatusLineVisualB'
\ },
\ 'c' : {
\ 'text' : 'COMMAND',
\ 'color_group' : 'StatusLineCommand'
\ },
\ 's' : {
\ 'text' : 'SELECT',
\ 'color_group' : 'StatusLineSelect'
\ },
\ 'S' : {
\ 'text' : 'S-LINE',
\ 'color_group' : 'StatusLineSelectL'
\ },
\ "\<C-s>" : {
\ 'text' : 'S-BLOCK',
\ 'color_group' : 'StatusLineSelectB'
\ },
\ 't' : {
\ 'text' : 'TERMINAL',
\ 'color_group' : 'StatusLineTerminal'
\ },
\ }
function Get_current_mode_text ()
let md = mode()
if (has_key (s:statusline_modes_dict, md))
return s:statusline_modes_dict[md]['text']
endif
return md
endfunction
function Get_current_mode_color_group ()
let md = mode()
if (has_key (s:statusline_modes_dict, md))
return "%#" . s:statusline_modes_dict[md]['color_group'] . "#"
endif
return "%#StatusLine#"
endfunction
" left
set statusline=
set statusline+=%{%Get_current_mode_color_group()%}\
set statusline+=%{Get_current_mode_text()}\
set statusline+=%#Statusline#\
Here statusline_modes_dict
stores key
s that are exactly what mode()
returns and it has text
to be shown in the status line and highlight group (color_group
) that of course has to be added to colorscheme, or somewhere else.
Maybe there is possibility to merge Get_current_mode_text()
and Get_current_mode_color_group()
into a single function to reduce operations but I have failed to make it work in a statusline.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | wasd |
Solution 2 | |
Solution 3 | Lucien |
Solution 4 | axwr |
Solution 5 | Artur Pyszczuk |