在单个vim缓冲区中可以使用两种不同的颜色背景吗?


20

我正在寻找一种可能的解决方案,具体取决于上下文,例如在此高级文本示例中,在单个vim缓冲区中应用两种不同的背景颜色。

一种用例是对标记文件中的代码片段进行不同的颜色编码,使它们更加突出。

但是,我从未见过这样的设置示例。

vim完全有可能吗?


2
真的想知道这个问题的答案,我会建议,这将是可能的语法高亮SO这篇文章可能是相关stackoverflow.com/questions/7033310/...
尼克·亚当斯Ĵ

Answers:


9

因为我很好奇它的工作原理,所以我一起研究了一些东西。

在此处输入图片说明

如对先前答案的评论中所述,唯一的方法是用空格填充区域。这正是我们所做的;在写之前,我们会删除这些空格,因此您不应该为此而烦扰其他人。

请注意,此示例是针对markdown文件类型的!

副作用

  • 复制文字也会复制很多空格
  • 使用$End不再按预期方式工作(它去80列),和钥匙等 j,并k也表现得不同。
  • 'list'启用后不显示背景
  • 完全空白行不起作用,您需要手动添加制表符或4个空格
  • ...也许更多?

首先,您需要将此添加到您的~/.vim/after/syntax/markdown.vim

syn clear markdownCodeBlock                                                 
syn region markdownCodeBlock start="    \|\t" end="$"                       
hi def markdownCodeBlock ctermbg=230 guibg=lightyellow                      

当然,您可以根据自己的喜好调整颜色;-)

然后,将其添加到您的vimrc中:

fun! MarkdownBlocks()                                                       
    fun! s:fill(line)                                                       
        " Remove all trailing whitespace                                    
        let l:line = substitute(a:line, " *$", "", "")                      

        " Add trailing whitespace up to 'textwidth' length                  
        return l:line . repeat(' ', (&tw > 0 ? &tw : 80) - strdisplaywidth(l:line))
    endfun                                                                  

    " Get all lines in a list                                               
    let l:lines = getline(1, line('$'))                                     

    " Map s:fill() to the lines that are a code block                       
    call map(l:lines, 'v:val[0] == "\t" || v:val[:3] == "    " ? s:fill(v:val) : v:val')

    " Reset the buffer to the lines                                         
    call setline(1, l:lines)                                                
endfun                                                                      

" Remove all the trailing spaces                                            
fun! MarkdownBlocksClean()                                                  
    let l:save_cursor = getpos(".")                                         
    silent %s/^\(    \|\t\)\(.\{-}\)\( *\)$/\1\2/e                          
    call setpos('.', l:save_cursor)                                         
endfun                                                                      
au BufWritePre *.markdown call MarkdownBlocksClean()                        

" Set spaces on loading the file, leaving insert mode, and after writing it 
au FileType markdown call MarkdownBlocks()                                  
au InsertLeave *.markdown call MarkdownBlocks()                             
au BufWritePost *.markdown call MarkdownBlocks()                            

我不会逐行解释代码,这些注释应该使代码的基本要义清楚;-)


感谢您的回答。我接受了它,而不是@Rich给出的最初答案,因为它似乎更完整。我会尝试一下,但由于所有副作用我不确定我是否会使用它,所以在这里不做承诺:)大谢谢您所做的一切!
KarolisKoncevičius15年

1
@KarolisKoncevičius谢谢。我也将其添加到我的vimrc中。看起来不错:-)如果您遇到问题,请告诉我。
马丁·图尔诺伊

哈哈哈 好吧,我认为这算是骇人听闻的,但是还不如我预期的那么可怕。不错的工作。当然,既然您已经走了这么远,您是否不感到被迫通过重新映射来解决j,k,$等问题,并在拉动之前删除了空白?;)
Rich

2
@Rich是的,这是一个hack。这使它变得很有趣;-)修复一些键(以某种方式)也使我心烦,但是我已经花了很多时间在此上,并想首先看看它是否真的起作用,以及是否我甚至喜欢它,然后再花更多的时间:-)
Martin Tournoij 2015年

2
@Carpetsmoker好吧,我上次模糊地暗示您可能离开并成功了,所以我希望在接下来的几周内看到您强大的多语言解决方案。
丰富

13

对于语法突出显示的元素,当然可以使用其他背景色。只需在命令中定义guibgctermbg颜色即可hilight。前者为GUI Vim设置背景颜色,后者为终端Vim设置背景颜色。

但是,这有一个重要的限制,即它只能为文件中实际存在的字符设置背景色。

这样做的结果是,背景色不能延伸超过一行文本的末端到窗口的边缘,因此示例中显示的代码无法着色:

Vim中可能的背景着色示例

您还可以使用“签名”功能更改整个行的背景颜色。(参见linehl:help sign.txt

用标志为背景着色的示例

但是,请注意:

  1. 为此,需要编写代码在需要涂色的每一行上放置标志,并随着文件内容的更改而使这些标志保持更新,

  2. 默认情况下,放置标志时,标志列将显示在窗口的左侧。可以使用SignColumn高亮组更改符号列的颜色,在Vim的最新版本中,可以将其完全删除。(请参阅:help 'signcolumn'。)

例如,要使Carpetsmoker的解决方案使用(更健壮的)标志机制,您可以执行以下操作:

" Define a highlight group and a sign that uses it
highlight default markdownCodeBlock ctermbg=230 guibg=lightyellow
sign define codeblock linehl=markdownCodeBlock

" Use signs to highlight code blocks
function! MarkdownBlocks()
    function! s:applySign(idx, val)
        if a:val[0] == "\t" || a:val[:3] == "    "
            let l = a:idx + 1
            execute "sign place " . l . " line=" . l . " name=codeblock file=" . expand("%:p")
        endif
    endfunction

    " Remove old signs
    execute "sign unplace * file=" . expand("%:p")

    " Get all lines in a list
    let l:lines = getline(1, line('$'))
    " Add new signs
    call map(l:lines, function('s:applySign'))
endfunction

" Set signs on loading the file, leaving insert mode, and after writing it
au FileType markdown call MarkdownBlocks()
au InsertLeave *.markdown call MarkdownBlocks()
au BufWritePost *.markdown call MarkdownBlocks()

与Carpetsmoker的版本相比,这在某种程度上简化了代码,并减少了警告。

@ChristianBrabandtDynamicSigns插件使为此目的使用Sign功能更加容易:他在此答案中描述了如何使用Sign功能。


1
+1为答案。但是(如果我错了,请纠正我)但guibg仅适用于gvim,对吗?
KarolisKoncevičius15年

1
@Karolis是的。对于终端Vim,您需要使用ctermbg,如前所述。
丰富

1
如果使用折叠,则可以得到想要的结果:折叠具有不同的bg颜色,但是,这是通过在背景中填充具有不同bg颜色设置的空格字符来实现的。这会产生一些副作用:复制/ paste无法正常工作(因为它还会复制很多空格字符,这也是您自己验证的方式)。
马丁·图尔诺伊

@Rich,谢谢您的回答。尽管这不是一个完美的解决方案(以高亮显示块),但它完全回答了表明这是可能的问题。答案已接受。
KarolisKoncevičius15年

3
编写这样的脚本必须要非常疯狂。
joeytwiddle
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.