Est-il possible d'utiliser deux arrière-plans de couleurs différentes dans un seul tampon vim?

20

Je cherche une solution possible pour appliquer deux couleurs d'arrière-plan différentes à l'intérieur d'un seul tampon vim en fonction du contexte comme dans cet exemple de texte sublime .

Un cas d'utilisation de cela est de colorer les extraits de code à l'intérieur des fichiers de balisage différemment afin qu'ils se démarquent davantage.

Cependant, je n'ai jamais vu d'exemple avec une telle configuration.

Est-ce que cela est possible dans vim?

Karolis Koncevičius
la source
2
aimerait vraiment connaître la réponse à cela, je dirais que ce sera possible avec la syntaxe mettant en évidence ce message sur SO peut être pertinent stackoverflow.com/questions/7033310/…
Nick J Adams

Réponses:

9

Parce que j'étais curieux de savoir comment cela fonctionnerait, j'ai piraté quelque chose ensemble ce genre de travaux.

entrez la description de l'image ici

Comme mentionné dans les commentaires sur la réponse précédente, la seule façon de le faire est de remplir les régions avec des espaces; c'est exactement ce que nous faisons; avant d'écrire, nous supprimons ces espaces, vous ne devriez donc pas déranger qui que ce soit d'autre.

Notez que cet exemple est très spécifique pour le type de fichier Markdown!

Effets secondaires :

  • La copie de texte copiera également de nombreux espaces
  • Utiliser $et Endne fonctionne plus comme prévu (il va à la colonne 80), et des clés telles que jet kse comportent également différemment.
  • L'arrière-plan ne s'affiche pas lorsque 'list'est activé
  • Les lignes complètement vides ne fonctionnent pas, vous devez ajouter manuellement une tabulation ou 4 espaces
  • ... Peut-être plus?

Tout d'abord, vous devez l'ajouter à votre ~/.vim/after/syntax/markdown.vim:

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

Vous pouvez bien sûr ajuster les couleurs à votre guise ;-)

Ensuite, ajoutez ceci à votre 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()                            

Je ne vais pas expliquer le code ligne par ligne, les commentaires devraient clarifier l'essentiel général ;-)

Martin Tournoij
la source
Merci pour cette réponse. Je l'ai acceptée au lieu de la réponse initiale donnée par @Rich car elle semblait plus complète. Je vais l'essayer mais je ne sais pas si je vais l'utiliser à cause de tous les effets secondaires donc pas de promesse ici :) Merci beaucoup pour tout l'effort!
Karolis Koncevičius
1
@ KarolisKoncevičius Merci. Je l'ai également ajouté à mon vimrc. Cela semble sympa :-) Faites-moi savoir si vous rencontrez des problèmes.
Martin Tournoij
Hahaha. Eh bien, je pense que cela peut être considéré comme hacky, mais ce n'est pas aussi horrible que je m'y attendais. Bon travail. Bien sûr, maintenant que vous êtes allé aussi loin, ne vous sentez-vous pas obligé de résoudre les problèmes avec j, k, $, etc. en les remappant et en supprimant l'espace blanc avant de tirer? ;)
Rich
2
@ Rich Ouais, c'est un hack. Cela m'a fait plaisir à faire ;-) La correction de certaines touches (d'une manière ou d'une autre) m'a également traversé l'esprit, mais j'ai déjà passé pas mal de temps là-dessus, et je veux d'abord voir si cela fonctionne vraiment, et si je même comme ça, avant d'y consacrer encore plus de temps :-)
Martin Tournoij
2
@Carpetsmoker Eh bien, la dernière fois que j'ai vaguement laissé entendre que quelque chose pourrait être possible, vous êtes parti et vous l'avez fait, donc j'ai hâte de voir votre solution multilingue robuste dans quelques semaines.
Rich
13

Il est certainement possible d'utiliser une couleur d'arrière-plan différente pour les éléments mis en évidence par la syntaxe. Définissez simplement les couleurs guibget ctermbgdans votre hilightcommande. Le premier définit la couleur d'arrière-plan pour GUI Vim, et le second pour le terminal Vim.

Cependant, cela présente l'importante limitation du fait qu'il ne peut définir que les couleurs d'arrière-plan des caractères qui existent réellement dans le fichier.

Le résultat est que la couleur d'arrière-plan ne peut pas s'étendre au-delà de la fin du texte sur une ligne jusqu'au bord de la fenêtre, de sorte que la coloration des blocs de code illustrés dans votre exemple n'est pas possible:

Un exemple de la coloration de fond possible dans Vim

Vous pouvez également modifier la couleur d'arrière-plan de lignes entières à l'aide de la fonction Signer. (Voir linehldans :help sign.txt)

Un exemple de coloration de l'arrière-plan avec des signes

Cependant, notez que:

  1. Pour ce faire, il faut écrire du code pour placer des signes sur chaque ligne qui doit être colorée et les garder à jour lorsque le contenu du fichier change,

  2. Par défaut, lorsque vous placez un signe, la colonne du signe sera affichée à gauche de la fenêtre. Il est possible de modifier la coloration de la colonne de signe avec le SignColumngroupe de surbrillance, et dans les versions plus récentes de Vim, il peut être entièrement supprimé. (Voir :help 'signcolumn'.)

Par exemple, pour adapter la solution de Carpetsmoker à l'utilisation du mécanisme de signe (plus robuste), vous pouvez procéder comme suit:

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

Cela simplifie quelque peu le code et comporte moins de mises en garde que la version de Carpetsmoker.

Le plugin DynamicSigns de @ChristianBrabandt facilite l'utilisation de la fonction Sign à cette fin: il décrit comment l'utiliser pour le faire dans cette réponse .

Riches
la source
1
+1 pour une réponse. Cependant (et corrigez-moi si je me trompe) mais guibgne fonctionne que pour gvim, n'est-ce pas?
Karolis Koncevičius
1
@Karolis Oui. Pour le terminal Vim, vous devez utiliser ctermbg, comme indiqué.
Rich
1
Si vous utilisez des plis, vous obtenez ce que vous voulez: les plis ont une couleur bg différente, cependant, cela est accompli en remplissant l'arrière-plan avec des caractères d'espace qui ont un jeu de couleurs bg différent ... Cela provoque des effets secondaires: copie / paste ne fonctionnera plus correctement (car il copiera également beaucoup de caractères d'espace, c'est aussi comment vous pouvez le vérifier par vous-même).
Martin Tournoij
@Rich, merci pour la réponse. Bien que ce ne soit pas une solution parfaite (en termes de mise en évidence des blocs), il répond pleinement à la question démontrant que cela est possible. Réponse acceptée.
Karolis Koncevičius
3
Il faudrait que quelqu'un soit vraiment fou pour écrire un script comme ça.
joeytwiddle