[英]Show mode in statusline in Vim
我在Vim中开发了一个不错的可自定义状态行,但是在显示我正在其中使用的当前模式时确实遇到了麻烦。
我使用字典来指示要在状态行的左侧和右侧显示哪些选项:
" Display Options {{{
let s:statusline_options = {
\ 'active': {
\ 'left': [ 'readonly', 'mode' , 'git' ],
\ 'right': [ 'time', 'project' ],
\ },
\ 'components': {
\ 'readonly': 'Statusline_readonly()',
\ 'mode': 'Statusline_mode()',
\ 'git': 'Statusline_git()',
\ 'time': "strftime(%a\ %d\ %b\ %H:%M)",
\ 'project': 'Statusline_project()'
\ },
\ 'seperators': {
\ 'readonly': ' %s',
\ 'mode': '%s >',
\ 'git': ' %s',
\ 'time': ' < ',
\ 'project': '[%s] '
\ },
\ 'components_to_color': {
\ 'mode': 1,
\ 'project': 1
\ },
\ 'theme_colors': {
\ 'default': [ '#abb2bf', '#61afef', '#98c379' ],
\ 'onedark': [ '#abb2bf', '#61afef', '#98c379' ],
\ 'materialbox': [ '#1d272b', '#fb8c00', '#43a047']
\ },
\ 'mode_map': {
\ 'n': 'NORMAL', 'i': 'INSERT', 'R': 'REPLACE', 'v': 'VISUAL', 'V': 'VISUAL', "\<C-v>": 'V-BLOCK',
\ 'c': 'COMMAND', 's': 'SELECT', 'S': 'S-LINE', "\<C-s>": 'S-BLOCK', 't': 'TERMINAL'
\ },
\ }
" }}}
然后,通过引入颜色组和分隔符并调用用户在上面的词典中指定为Components的函数,来组合状态线的创建:
" Statusline Functions {{{
function! StatuslineComponents(side) abort
let output = ''
" Fetch the components in the statusline dictionary
for v in Fetch('active', a:side)
let method = split(Fetch('components', v), '(')
let component_color = ''
" Check if the item should be specifically coloured
if len(method) > 1 && method[1] != ')'
let output .= StatuslineColor(v) . StatuslineFormat(v, method[0], method[1])
else
let output .= StatuslineColor(v) . StatuslineFormat(v, method[0])
endif
endfor
return output
endfunction
function! StatuslineColor(component)
for v in keys(s:statusline_options.components_to_color)
if v == a:component
return '%#Component_' . v . '#'
endif
endfor
return '%#ComponentDefault#'
endfunction
function! StatuslineFormat(...)
let output = ''
let seperator = Fetch('seperators', a:1)
if a:0 > 2
for param in split(a:3, ',')
let value = call(a:2, [ param ], {})
endfor
else
let value = call(a:2, [], {})
endif
" Remove any last )'s from the value
let value = substitute(value, ')\+$', '', '')
if seperator =~ '%s'
let output = printf(seperator, value)
else
let output = value . seperator
endif
return output
endfunction
function! ChangeStatuslineColor() abort
let s:mode_colors = []
try
for mode_color in Fetch('theme_colors', g:colors_name)
let s:mode_colors += [mode_color]
endfor
catch
try
for mode_color in Fetch('theme_colors', 'default')
let s:mode_colors += [mode_color]
endfor
catch
let s:mode_colors = ['#e06c75'] + ['#e06c75'] + ['#e06c75']
endtry
endtry
if (mode() ==# 'i')
exec printf('hi ComponentDefault guifg=%s', s:mode_colors[1])
elseif (mode() =~# '\v(v|V)')
exec printf('hi ComponentDefault guifg=%s', s:mode_colors[2])
else
exec printf('hi ComponentDefault guifg=%s', s:mode_colors[0])
endif
for component in keys(s:statusline_options.components_to_color)
if (mode() ==# 'i')
exec printf('hi Component_%s guifg=%s', component, s:mode_colors[1])
elseif (mode() =~# '\v(v|V)')
exec printf('hi Component_%s guifg=%s', component, s:mode_colors[2])
else
exec printf('hi Component_%s guifg=%s', component, s:mode_colors[0])
endif
endfor
return ''
endfunction
" Fetch a value from the Statusline options
function! Fetch(key, value) abort
return get(s:statusline_options[a:key], a:value, '')
endfunction
" }}}
我的自定义函数以及关键的Statusline_mode()函数将包含在状态栏中,如下所示:
" Component Functions {{{
" Show the mode in the statuslin
function! Statusline_mode() abort
return get(s:statusline_options.mode_map, mode(), '')
endfunction
function! Statusline_project() abort
return GetCurrentSite(g:code_dir)
endfunction
function! Statusline_git() abort
let git = fugitive#head()
if git != ''
return ' '.fugitive#head()
else
return ''
endif
endfunction
function! Statusline_readonly() abort
if &readonly || !&modifiable
return ' '
else
return ''
endif
endfunction
" }}}
然后通过以下命令组设置状态行:
" Set The Statusline {{{
augroup statusline
hi StatusLine guibg=NONE gui=NONE
autocmd!
autocmd WinEnter,BufWinEnter,FileType,ColorScheme,SessionLoadPost
\ * let &l:statusline = StatuslineComponents('left') . '%=' . StatuslineComponents('right') |
\ call ChangeStatuslineColor()
augroup end
" }}}
我已经尝试过使用InsertEnter
命令组,但似乎无法解决问题。
让我们从更简单的情况开始:
let &l:statusline = mode() . ' ' . StatuslineComponents('left') . '%=' . StatuslineComponents('right')
定义'statusline'
时,它将调用一次mode()
; 它永远不会更新 ,并且值停留在n
。
要解决此问题,每当状态栏更新时,您都需要使用%{...}
项目来评估表达式:
let &l:statusline = '%{mode()} ' . StatuslineComponents('left') . '%=' . StatuslineComponents('right')
现在回到您的完整案例。 这是同样的问题:
autocmd WinEnter,BufWinEnter,FileType,ColorScheme,SessionLoadPost
\ * let &l:statusline = StatuslineComponents('left') . '%=' . StatuslineComponents('right') |
\ call ChangeStatuslineColor()
尽管您更新了某些:autocmd
事件,但是在模式更改时不会触发任何事件,因此您始终会看到相同的模式。 无论如何,正如:help mode()
告诉您的那样,只能从提到的状态行表达式中获取正确的值。
作为解决此问题的第一步,我将完全删除:autocmd
并将所有内容放入状态行表达式中:
let &statusline = "%{StatuslineComponents('left')}%=%{StatuslineComponents('right')}"
如果遇到性能问题,我可以将慢速元素(而不是mode()
调用!)提取到窗口局部变量中,从statusline表达式中引用它们,并使用:autocmd
更新它们。
autocmd WinEnter,BufWinEnter,FileType,ColorScheme,SessionLoadPost * let w:left = StatuslineComponents('left')
let &statusline = "%{w:left}%=%{StatuslineComponents('right')}"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.