在Vim的状态行中显示模式

在Vim的状态行中显示模式,vim,Vim,我在Vim中开发了一个很好的可定制状态行,但是我在显示当前模式时遇到了实际问题 我使用字典指示通过状态行的左侧和右侧显示哪些选项: " Display Options {{{ let s:statusline_options = { \ 'active': { \ 'left': [ 'readonly', 'mode' , 'git' ], \ 'right': [ 'time', 'project'

我在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'
            \   },
            \ }
" }}}
要包含在Statusline中的自定义函数以及键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'
时,会调用
模式()
一次它从不更新,并且该值固定在
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()
告诉您的,正确的值只能从提到的statusline表达式中获得

作为解决此问题的第一步,我将完全删除
:autocmd
,并将所有内容放入状态行表达式中:

let &statusline = "%{StatuslineComponents('left')}%=%{StatuslineComponents('right')}"
如果遇到性能问题,我会将慢速元素(但不是
模式()
调用!)提取到窗口局部变量中,从状态行表达式中引用它们,并使用
:autocmd
更新它们

autocmd WinEnter,BufWinEnter,FileType,ColorScheme,SessionLoadPost * let w:left = StatuslineComponents('left')
let &statusline = "%{w:left}%=%{StatuslineComponents('right')}"

让我们从您更简约的案例开始:

let &l:statusline = mode() . ' ' . StatuslineComponents('left') . '%=' . StatuslineComponents('right')
当定义
'statusline'
时,会调用
模式()
一次它从不更新,并且该值固定在
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()
告诉您的,正确的值只能从提到的statusline表达式中获得

作为解决此问题的第一步,我将完全删除
:autocmd
,并将所有内容放入状态行表达式中:

let &statusline = "%{StatuslineComponents('left')}%=%{StatuslineComponents('right')}"
如果遇到性能问题,我会将慢速元素(但不是
模式()
调用!)提取到窗口局部变量中,从状态行表达式中引用它们,并使用
:autocmd
更新它们

autocmd WinEnter,BufWinEnter,FileType,ColorScheme,SessionLoadPost * let w:left = StatuslineComponents('left')
let &statusline = "%{w:left}%=%{StatuslineComponents('right')}"

真是一堵文字墙!如果我尝试这个
let&l:statusline=mode()。StatuslineComponents('left')。%='。StatuslineComponents(“右”)
没有区别。它似乎没有接收到模式转换,真是一堵文字墙!如果我尝试这个
let&l:statusline=mode()。StatuslineComponents('left')。%='。StatuslineComponents(“右”)
没有区别。它似乎没有接受模式转换,这是一个真正全面的答案!了解更新状态行和不更新状态行之间的区别。在您的答案提出的最后一种形式中,情况会很好地更新,但是由
StatuslineColor()
定义的突出显示组显示为字符串,例如
\%Component\u Default
,而不是被解析。这可以通过欺骗来解决吗?
%{…}
表达式本身不会进一步解析其他符号(即,它是非递归的);您不能通过其中的
%#…#
添加突出显示。如果无法将突出显示内容移到
%{…}
之外(例如,当您想根据某些条件更改突出显示时),则必须使用
:set statusline=%!MyStatusLine
;该表达式可以返回其他符号/是递归的。Cp.
:帮助“stl”
:当选项以“%!”开头时,它将被用作一个表达式—一个真正全面的答案!了解更新状态行和不更新状态行之间的区别。在您的答案提出的最后一种形式中,情况会很好地更新,但是由
StatuslineColor()
定义的突出显示组显示为字符串,例如
\%Component\u Default
,而不是被解析。这可以通过欺骗来解决吗?
%{…}
表达式本身不会进一步解析其他符号(即,它是非递归的);您不能通过其中的
%#…#
添加突出显示。如果无法将突出显示内容移到
%{…}
之外(例如,当您想根据某些条件更改突出显示时),则必须使用
:set statusline=%!MyStatusLine
;该表达式可以返回其他符号/是递归的。Cp.
:帮助“stl”
:当选项以“%!”开头时,它将用作表达式