¿Es posible usar dos fondos de color diferentes en un solo búfer vim?

20

Estoy buscando una posible solución para aplicar dos colores de fondo diferentes dentro de un solo búfer vim dependiendo del contexto como en este ejemplo de texto sublime .

Un caso de uso de eso es colorear fragmentos de código dentro de archivos de marcado de manera diferente para que se destaquen más.

Sin embargo, nunca he visto un ejemplo con una configuración como esa.

¿Es esto posible en vim?

Karolis Koncevičius
fuente
2
realmente me gustaría saber la respuesta a esto, sugeriría que será posible con la sintaxis resaltando que esta publicación en SO puede ser relevante stackoverflow.com/questions/7033310/…
Nick J Adams

Respuestas:

9

Como tenía curiosidad por saber qué tan bien funcionaría, he pirateado algo que funciona.

ingrese la descripción de la imagen aquí

Como se mencionó en los comentarios sobre la respuesta anterior, la única forma de hacerlo es llenar regiones con espacios; que es exactamente lo que hacemos; antes de escribir, eliminamos estos espacios, por lo que no debería molestar a nadie más con él.

¡Tenga en cuenta que este ejemplo es muy específico para el tipo de archivo markdown!

Efectos secundarios :

  • Copiar texto también copiará muchos espacios
  • Usando $y Endya no funciona como se esperaba (va a la columna 80), y las teclas como jy ktambién se comportan de manera diferente.
  • El fondo no se muestra cuando 'list'está habilitado
  • Las líneas completamente en blanco no funcionan, debe agregar manualmente una pestaña o 4 espacios
  • ... ¿Quizás más?

Primero, necesita agregar esto a su ~/.vim/after/syntax/markdown.vim:

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

Puede ajustar los colores a su gusto, por supuesto ;-)

Luego, agregue esto a su 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()                            

No voy a explicar el código línea por línea, los comentarios deberían dejar en claro la esencia general del mismo ;-)

Martin Tournoij
fuente
Gracias por esta respuesta Lo acepté en lugar de la respuesta inicial dada por @Rich porque parecía más completa. Lo probaré, pero no estoy seguro de si lo usaré debido a todos los efectos secundarios, así que no lo prometo aquí :) ¡Muchas gracias por todo el esfuerzo!
Karolis Koncevičius
1
@ KarolisKoncevičius Gracias. Lo agregué a mi vimrc también. Parece agradable :-) Avísame si tienes problemas.
Martin Tournoij
Jajaja. Bueno, creo que esto califica como hacky, pero no es tan horrible como esperaba. Buen trabajo. Por supuesto, ahora que has llegado tan lejos, ¿no te sientes obligado a solucionar los problemas con j, k, $, etc. reasignándolos y eliminar el espacio en blanco antes de tirar? ;)
Rico
2
@ Rich Sí, es un truco. Eso hizo que fuera divertido hacerlo ;-) La fijación de algunas de las teclas (de alguna manera) también se me pasó por la cabeza, pero ya pasé bastante tiempo en esto, y quiero ver primero si realmente funciona, y si incluso me gusta, antes de pasar aún más tiempo en él :-)
Martin Tournoij
2
@Carpetsmoker Bueno, la última vez que insinué vagamente que algo podría ser posible, te fuiste y lo lograste, así que espero ver tu robusta solución multilingüe en otras dos semanas.
Rico
13

Ciertamente es posible usar un color de fondo diferente para los elementos resaltados de sintaxis. Simplemente defina los colores guibgy ctermbgen su hilightcomando. El primero establece el color de fondo para la GUI Vim, y el segundo para el terminal Vim.

Sin embargo, esto tiene la importante limitación de que solo puede establecer los colores de fondo para los caracteres que realmente existen en el archivo.

El resultado de esto es que el color de fondo no puede extenderse más allá del final del texto en una línea hasta el borde de la ventana, por lo que no es posible colorear los bloques de código que se muestran en su ejemplo:

Un ejemplo del color de fondo posible en Vim

También puede cambiar el color de fondo de líneas enteras utilizando la función Firmar. (Ver linehlen :help sign.txt)

Un ejemplo de colorear el fondo con signos

Sin embargo, tenga en cuenta que:

  1. Para hacerlo, es necesario escribir código para colocar letreros en cada línea que deba colorearse y mantenerlos actualizados a medida que cambia el contenido del archivo,

  2. Por defecto, al colocar una señal, la columna de la señal se mostrará a la izquierda de la ventana. Es posible cambiar el color de la columna de signos con el SignColumngrupo resaltado, y en las versiones más recientes de Vim se puede eliminar por completo. (Ver :help 'signcolumn')

Por ejemplo, para adaptar la solución de Carpetsmoker para usar el mecanismo de signos (más robusto), puede hacer lo siguiente:

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

Esto simplifica un poco el código y tiene menos advertencias que la versión de Carpetsmoker.

@ChristianBrabandt 's DynamicSigns plug-in hace utilizando la función de sesión para este fin más fácil: él describe cómo utilizarlo para hacerlo en esta respuesta .

Rico
fuente
1
+1 por una respuesta. Sin embargo (y corrígeme si estoy equivocado) pero guibgsolo funciona para gvim, ¿es eso correcto?
Karolis Koncevičius
1
@ Karolis Sí. Para el terminal Vim, debe usar ctermbg, como se indica.
Rico
1
Si usa pliegues, obtiene lo que desea: los pliegues tienen un color bg diferente, sin embargo, esto se logra al llenar el fondo con caracteres de espacio que tienen un conjunto de colores bg diferente ... Esto causa algunos efectos secundarios: copiar / paste ya no funcionará correctamente (ya que también copiará muchos caracteres de espacio, así es como puede verificar esto por sí mismo).
Martin Tournoij
@ Rich, gracias por la respuesta. Si bien no es una solución perfecta (en términos de resaltar bloques), responde completamente la pregunta que demuestra que esto es posible. Respuesta aceptada
Karolis Koncevičius
3
Alguien tendría que estar realmente loco para escribir un guión como ese.
joeytwiddle