'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.

vim


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 keys 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