在 Vim 中突出显示 if-else-endif 结构

在 Vim 中突出显示 if-else-endif 结构

有没有办法根据 if-else-endif 结构在整个程序层次结构中的“级别”按需突出显示 Vim 中的 if-else-endif 结构?例如,我想要类似

if <<< highlight in red
   foo
else <<<< red
   if <<< blue
      baz
      bar
   endif <<< blue
endif <<< red

我主要编辑 FORTRAN 代码,但我猜这个功能会非常通用,只要语法高亮适用于给定的语言...

答案1

我编写了自己的 Vim 插件来实现这一点(至少对于 FORTRAN 来说,这是我的用例):https://github.com/fpnick/flowhighlight 请随意尝试和/或根据您的需要进行扩展。

流程突出显示.vim

" File: flowhighlight.vim
" Author: Fabian P. Nick <[email protected]>
" Version: 0.1
" Description: 
"   Highlights if-else-endif structures in different colors based on
"   their 'level' in the program flow. 
"   As of October 2015 only works with Fortran.
"   VERY EARLY DEVELOPMENT VERSION!
" Uasge:
"   Use the 'FlowHighlight' command to highlight control structures.
"   Use 'FlowHighlightClear' to disable highlights.
" Configuration:
"   To define custom colors set the following variables
"     g:lcolor_bg - Background color for line highlighting
"     g:lcolor_fg - Foreground color for line highlighting
"     g:pcolor_bg - Background color for pattern highlighting
"     g:pcolor_fg - Foreground color for pattern highlighting
" Limitation:
"   Only works with a very limited FORTRAN syntax
" Acknowledgement:
"   Thanks to Amit Sethi, Dan Sharp, Michael Geddes and Benji Fisher
"   for their wonderful pieces of code.
"   Also thanks to Jarrod Taylor for his Vim Plugin framework.

python import sys
python import vim
python sys.path.append(vim.eval('expand("<sfile>:h")'))

" Main function to highlight control structures.
function! FlowHighlight()

" Python script adding 'tags' to control stuctures that are used to
" highlight the structures later.
" Also writes maximal 'depth' of control structures to the last line
" of the file.
python << endOfPython
from flowhighlight import find_flow
old_buffer = vim.current.buffer
vim.current.buffer[:] = find_flow(vim.current.buffer[:])
endOfPython

:normal mT

" Get maximum 'depth' of structures in this file
:normal G
let g:fhl_max_level = eval(getline("."))
:normal dd

" For each level, highlight the control structures
let i = 0
while i <= g:fhl_max_level
   :normal gg
   let curr_line = line(".")
   let last_line = -1
   while curr_line > last_line
      let last_line = curr_line
      let match_pat = 'flowhighlightlevel'.string(i)
      execute 'normal /' . match_pat . '
'
      let curr_line = line(".")
      let match_pat = '.*\%'.line(".").'l.*'
      exec 'syn match '. s:lcolor_grp . i  . ' "' . match_pat . '" containedin=ALL'
   endw
   let match_pat = '!flowhighlightlevel'.string(i)
   execute 'normal :%s/' . match_pat . '//g
'
   let i = i+1
endw

:normal 'T
endfunction

" Clear highlights.
function! FlowHighlight_clear()
   let i = 0
   while i <= g:fhl_max_level
      exec 'syn clear ' . s:lcolor_grp . i
      let i = i+1
   endw
endfunction

" --------------------------------
"  Expose our commands to the user
" --------------------------------
command! FlowHighlight call FlowHighlight()
command! FlowHighlightClear call FlowHighlight_clear()

" #############################################################################
" The code after this line is from highlight.vim
" (http://www.vim.org/scripts/script.php?script_id=1599) by Amit Sethi.


" Define colors for Line highlight
if !exists('g:lcolor_bg')
   let g:lcolor_bg = "purple,seagreen,violet,lightred,lightgreen,lightblue,darkmagenta,slateblue"
endif
if !exists('g:lcolor_fg')
   let g:lcolor_fg = "white,white,black,black,black,black,white,white"
endif
if !exists('g:lcolor_bg_cterm')
   let g:lcolor_bg_cterm = "Blue,Green,Cyan,Red,Yellow,Magenta,Brown,LightGray"
endif
if !exists('g:lcolor_fg_cterm')
   let g:lcolor_fg_cterm = "White,White,White,White,White,White,Black,Black"
endif
" HighlightInitFH: Initialize the highlight groups for line highlight
" Based on 'MultipleSearchInit' function developed by Dan Sharp in 
" MultipleSearch2.vim at http://www.vim.org/scripts/script.php?script_id=1183 
function! s:HighlightInitFH()
   let s:lcolor_grp = "FlowHiColor"
   let s:lcolor_n = 0

   let s:lcolor_max = s:Min(s:ItemCount(g:lcolor_bg . ','), s:ItemCount(g:lcolor_fg . ','))

   let ci = 0
   while ci < s:lcolor_max
      let bgColor = s:Strntok(g:lcolor_bg, ',', ci + 1)
      let fgColor = s:Strntok(g:lcolor_fg, ',', ci + 1)
      let bgColor_cterm = s:Strntok(g:lcolor_bg_cterm, ',', ci + 1)
      let fgColor_cterm = s:Strntok(g:lcolor_fg_cterm, ',', ci + 1)

      exec 'hi ' . s:lcolor_grp . ci .
         \ ' guifg =' . fgColor . ' guibg=' . bgColor
         \ ' ctermfg =' . fgColor_cterm . ' ctermbg=' . bgColor_cterm

      let ci = ci + 1
   endw
endfunction
" Min: Returns the minimum of the given parameters.
" Developed by Dan Sharp in MultipleSearch2.vim at
" http://www.vim.org/scripts/script.php?script_id=1183 
function! s:Min(...)
    let min = a:1
    let index = 2
    while index <= a:0
        execute "if min > a:" . index . " | let min = a:" . index . " | endif"
        let index = index + 1
    endwhile
    return min
endfunction
" Strntok: Utility function to implement C-like strntok() by Michael Geddes
" and Benji Fisher at http://groups.yahoo.com/group/vimdev/message/26788
function! s:Strntok( s, tok, n)
    return matchstr( a:s.a:tok[0], '\v(\zs([^'.a:tok.']*)\ze['.a:tok.']){'.a:n.'}')
endfunction
" ItemCount: Returns the number of items in the given string.
" Developed by Dan Sharp in MultipleSearch2.vim at
" http://www.vim.org/scripts/script.php?script_id=1183 
function! s:ItemCount(string)
    let itemCount = 0
    let newstring = a:string
    let pos = stridx(newstring, ',')
    while pos > -1
        let itemCount = itemCount + 1
        let newstring = strpart(newstring, pos + 1)
        let pos = stridx(newstring, ',')
    endwhile
    return itemCount
endfunction
" #############################################################################

call s:HighlightInitFH()

流程突出显示.py

import re 
def find_flow(buffer_contents):
    """ Uses regex to find ifs and corresponding elses and endifs
    Marks them with a tag that can be used by vi later.
    """
    level = 0
    max_level = 0
    for i in range(len(buffer_contents)):

        string = buffer_contents[i]
        if ( re.match('[ ]*if.*then.*',string,re.IGNORECASE) ):
            buffer_contents[i] = string + '!flowhighlightlevel' + str(level)
            level = level+1
            if max_level < level:
                max_level = level

        if ( re.match('[ ]*else',string,re.IGNORECASE) ):
            buffer_contents[i] = string + '!flowhighlightlevel' + str(level-1)

        if ( re.match('[ ]*else if .* then',string,re.IGNORECASE) ):
            buffer_contents[i] = string + '!flowhighlightlevel' + str(level-1)

        if ( re.match('[ ]*endif',string,re.IGNORECASE) ):
            level = level-1
            buffer_contents[i] = string + '!flowhighlightlevel' + str(level)

    buffer_contents.append(str(max_level-1))
    return buffer_contents

相关内容