繁体   English   中英

在Vim的状态栏中显示模式

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM