É possível usar dois fundos de cores diferentes em um único buffer vim?

20

Estou procurando uma solução possível para aplicar duas cores de plano de fundo diferentes dentro de um único buffer vim, dependendo do contexto, como neste exemplo de texto sublime .

Um caso de uso disso é trechos de código de cores dentro dos arquivos de marcação de maneira diferente, para que eles se destaquem mais.

No entanto, eu nunca vi um exemplo com uma configuração como essa.

Isso é possível no vim?

Karolis Koncevičius
fonte
2
realmente gostaria de saber a resposta para isso, eu sugeriria que será possível com destaque de sintaxe deste post no SO pode ser relevante stackoverflow.com/questions/7033310/...
Nick J Adams

Respostas:

9

Porque eu estava curioso para saber como isso funcionaria, eu hackeei algo que funciona.

insira a descrição da imagem aqui

Como mencionado nos comentários da resposta anterior, a única maneira de fazer isso é preencher as regiões com espaços; que é exatamente o que fazemos; antes de escrever, removemos esses espaços, para que você não incomode mais ninguém.

Observe que este exemplo é muito específico para o tipo de arquivo de remarcação!

Efeitos colaterais :

  • A cópia de texto também copiará muitos espaços
  • Usar $e Endnão funciona mais como o esperado (vai para a coluna 80) e chaves como je ktambém se comportam de maneira diferente.
  • O fundo não é exibido quando 'list'está ativado
  • Linhas completamente em branco não funcionam, você precisa adicionar manualmente uma guia ou 4 espaços
  • ... talvez mais?

Primeiro, você precisa adicionar isso ao seu ~/.vim/after/syntax/markdown.vim:

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

Você pode ajustar as cores ao seu gosto, é claro ;-)

Em seguida, adicione isso ao seu 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()                            

Não vou explicar o código linha por linha, os comentários devem deixar clara a essência geral ;-)

Martin Tournoij
fonte
Obrigado por esta resposta. Aceitei-o em vez da resposta inicial dada por @Rich, porque parecia mais completa. Vou experimentá-lo, mas não tenho certeza se vou usá-lo por causa de todos os efeitos colaterais, então não prometo aqui :) Muito obrigado por todo o esforço!
Karolis Koncevičius
11
@ KarolisKoncevičius Obrigado. Eu o adicionei ao meu vimrc também. Parece bom :-) Deixe-me saber se você encontrar problemas.
Martin Tournoij 25/02
Hahaha Bem, acho que isso se qualifica como hacky, mas não é tão horrível quanto eu esperava. Bom trabalho. Claro, agora que você chegou até aqui, não se sente compelido a corrigir os problemas com j, k, $ etc. etc. remapeando-os e removendo o espaço em branco antes de puxar? ;)
Rich
2
@ Rich Sim, é um hack. Foi divertido fazer isso ;-) Consertar algumas das chaves (de alguma forma) também passou pela minha cabeça, mas eu já gastei bastante tempo nisso e quero primeiro ver se realmente funciona e se eu até mesmo como ele, antes de gastar ainda mais tempo com isso :-)
Martin Tournoij
2
@Carpetsmoker Bem, na última vez em que insinuei vagamente que algo seria possível, você foi embora, e estou ansioso para ver sua solução robusta em vários idiomas em mais algumas semanas.
Rich
13

Certamente é possível usar uma cor de fundo diferente para elementos destacados pela sintaxe. Apenas defina as cores guibge ctermbgem seu hilightcomando. O primeiro define a cor de fundo do GUI Vim e o segundo do terminal Vim.

No entanto, essa limitação é importante: ele só pode definir as cores de plano de fundo para os caracteres que realmente existem no arquivo.

O resultado disso é que a cor do plano de fundo não pode se estender além do final do texto em uma linha até a borda da janela; portanto, a coloração dos blocos de código mostrados no seu exemplo não é possível:

Um exemplo da coloração de fundo possível no Vim

Você também pode alterar a cor de fundo de linhas inteiras usando o recurso Assinar. (Ver linehlem :help sign.txt)

Um exemplo de colorir o fundo com sinais

No entanto, observe que:

  1. Para fazer isso, é necessário escrever código para colocar sinais em cada linha que precisa ser colorida e mantê-los atualizados à medida que o conteúdo do arquivo for alterado,

  2. Por padrão, ao colocar um sinal, a coluna do sinal será exibida à esquerda da janela. É possível alterar a coloração da coluna de sinal com o SignColumngrupo de destaque e nas versões mais recentes do Vim ele pode ser removido completamente. (Veja :help 'signcolumn'.)

Por exemplo, para adaptar a solução Carpetsmoker para usar o mecanismo de sinalização (mais robusto), você pode fazer o seguinte:

" 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()

Isso simplifica um pouco o código e possui menos advertências do que a versão do Carpetsmoker.

O plugin DynamicSigns de @ChristianBrabandt facilita o uso do recurso Assinar para esse fim: ele descreve como usá-lo nesta resposta .

Rico
fonte
11
+1 para uma resposta. No entanto (e me corrija se eu estiver errado), mas guibgsó funciona para o gvim, está certo?
Karolis Koncevičius
11
@Karolis Sim. Para o terminal Vim, você precisa usar ctermbg, conforme indicado.
Rich
11
Se você usa dobras, consegue o que deseja: As dobras têm uma cor BG diferente, no entanto, isso é feito preenchendo o plano de fundo com caracteres de espaço com uma cor BG diferente ... Isso causa alguns efeitos colaterais: copiar / paste não funcionará mais (como também copiará muitos caracteres de espaço, também é assim que você pode verificar isso por si mesmo).
Martin Tournoij
@ Rich, obrigado pela resposta. Embora não seja uma solução perfeita (em termos de blocos de destaque), ela responde totalmente à pergunta demonstrando que isso é possível. Resposta Aceita.
Karolis Koncevičius
3
Alguém teria que ser realmente louco para escrever um roteiro como esse.
Joeytwiddle 26/02