Resaltado automático de texto de líneas idénticas

13

Vi a un hábil vim ninja hacer esto hace un tiempo, pero no tengo idea de dónde comenzar.

A) ¿Hay alguna manera de configurar el color de fondo de vims para que las líneas consecutivas con contenido idéntico se resalten.

B) Si alguien sabe cómo hacer eso, un buen ajuste sería si el resaltado ocurriera en líneas consecutivas, pero solo considere la primera palabra (no la línea completa).

Se utiliza un segundo ajuste si el resaltado se puede configurar para diferentes colores en función del número de líneas coincidentes (o las palabras que dependen de AB están activas). Por lo tanto, solo tenemos dos líneas consecutivas que coinciden con verde, 3-5 líneas consecutivas, luego naranja, 6+ y luego rojo.

Martin York
fuente
Publicación

Respuestas:

10

Los siguientes matchconjuntos parecen funcionar para (A):

:syn match Low /\v(.+)\n(\1\n)/
:syn match Medium /\v(.+)\n(\1\n){2,4}/
:syn match Critical /\v(.+)\n(\1\n){5,}/
:hi Critical  ctermfg=red
:hi Medium  ctermfg=yellow
:hi Low  ctermfg=green

Parece que el orden es crucial aquí. Si las coincidencias Lowo Mediumvienen después Critical, quedan subsumidas por los requisitos más flexibles de estas, y de manera similar para Lowwrt Medium.

El resaltado no aparece inmediatamente después de agregar, digamos, una tercera o sexta línea de duplicación, pero una vez que se mueve un poco después de agregarlas. No estoy seguro de qué lo desencadena, exactamente.

Para B, imagino que podrías reemplazar la expresión regular con:

/\v(\S+).*\n(\1.*\n)/

En general, reemplace todo (.*)con (\S+).*y \1con \1.*, o lo que sea que sea una palabra para usted.

muru
fuente
Le di a esta respuesta la marca porque para mí es cómo hacer el resaltado que necesitaba (como lo expresa la pregunta). @Matts expresión regular agradable pero no responde la pregunta real que hice (cambiando el resaltado).
Martin York
8

Como punto de partida, aquí hay un patrón de búsqueda que coincide con líneas duplicadas (ignorando los cambios en los espacios en blanco iniciales):

              \zs                marks start of the pattern. Everything before here will not be highlighted
 ^                               start of the line
  \s*                            leading whitespace
       .\+                       match 1 or more non-newline characters
     \(   \)                     and use parens to capture this in match group 1

            \n                   match the newline character
                 \(        \)\+  1 or more
                      \1         copies of what was in the match group 1
                   \s*  \n       with leading whitespace followed by a newline
/^\s*\(.\+\)\n\zs\(\s*\1\n\)\+   the full regex

:help pattern proporcionará más información sobre cómo hacer expresiones regulares como esta

:help syntax le mostrará cómo tomar esta expresión regular y convertirla en algo resaltado para usted

Aprender a escribir scripts de sintaxis puede ser difícil, por lo que una buena solución a corto plazo es hacer esto 'sobre la marcha' asegurándose de que 'incsearch'esté configurado para que las búsquedas estén resaltadas y mapear una clave para hacer la búsqueda anterior, es decirnnoremap <F5> /^\s*\(.\+\)\n\zs\(\s*\1\n\)\+<CR>

Matt Boehm
fuente
¿Hay alguna forma automatizada de distribuir la expresión regular de esa manera? Proporciona una representación tan clara.
muru
1
Lo he estado haciendo a mano. La forma más fácil y rápida en vim sería hacer algo como yy10pen la línea con la expresión regular completa y luego seleccionar las partes que desea eliminar y presionar r<space>. Tal vez agregue un comando para 'reemplazar todo excepto la selección en esta línea con espacios' para acelerar un poco las cosas.
Matt Boehm
¡Guauu! ¡Eso es bastante esfuerzo!
muru
1
Hice una función vim (realmente fea) para hacer esto un poco más rápido: gist.github.com/mattboehm/da63a48eedf6f14375aa . Seleccione una línea, presione y ,rluego una las líneas juntas <space>en modo normal / visual.
Matt Boehm