¿Cómo buscar un patrón en ciertas regiones de sintaxis?

10

Estoy usando vim para editar documentos de látex. A menudo, querré cambiar el nombre de una variable a otra cosa. Sin embargo, es un poco molesto tener que sortear coincidencias irrelevantes cuando busco el nombre de la variable. Me gustaría buscar solo en "zonas matemáticas" como se define en el archivo de sintaxis tex. ¿Hay alguna manera fácil de limitar una búsqueda a una región de sintaxis específica?

Rob F.
fuente
1
Creo que la respuesta es no: no hay una manera fácil de limitar una búsqueda a una región de sintaxis específica.
Karl Yngve Lervåg
2
Este mapeo se utiliza synIDattr()para obtener grupos de sintaxis para el carácter debajo del cursor. Puede escribir una función que realice la búsqueda (o lo haga normal n) y luego use synIDattr()para decidir si permanecer en esta ubicación o continuar la búsqueda hacia adelante.
joeytwiddle
@joeytwiddle Vi tu comentario justo ahora después de publicar una respuesta con dicha función. ¿Es como lo que tenías en mente?
jjaderberg
@jjaderberg Sí, lo es. ¡Gran trabajo!
joeytwiddle
Solo para completar (me pareció una buena respuesta): stackoverflow.com/a/2696143/5000478
VanLaser

Respuestas:

4

Aquí hay una función que puedes probar. Solo lo probé un poco, pero parece funcionar bien.

function! JJSyntaxSearch(pattern, syntaxitem)
  while search(a:pattern, 'W') > 0
    for id in synstack(line("."),col("."))
      if synIDattr(id,"name") =~? a:syntaxitem
        return line(".")
      endif
    endfor
  endwhile
  return 0
endfunc

command! -nargs=* JJSyntaxSearch call JJSyntaxSearch(<f-args>)

La función llama a la función de búsqueda de Vim en un bucle hasta que encuentra una coincidencia 'ordinaria' que también es una coincidencia 'calificada' con un elemento de sintaxis particular, o hasta que llega al final del búfer.

Se necesitan dos argumentos. El primero es el patrón de búsqueda y se pasa sin cambios a la search()función de Vim . Vea :help search()cómo funciona esa función. El segundo argumento es el nombre del elemento de sintaxis en el que desea filtrar estas coincidencias. Esto también puede ser un patrón y se compara como una expresión regular que no distingue entre mayúsculas y minúsculas.

Para encontrar el patrón 'alfa' en zonas matemáticas puedes hacer

:JJSyntaxSearch alpha texMathZone.

Al .final es el átomo de patrón para cualquier carácter individual, vea :help /.. Esto es porque hay muchos elementos de sintaxis de zona matemática llamados texMathZoneA, texMathZoneBetc.

La search()función mueve el cursor a la siguiente coincidencia 'ordinaria'. Luego, nuestra función obtiene todas las ID de elementos de sintaxis para esa nueva posición del cursor con synstack(). Al recorrerlos, recupera el nombre de cada elemento a su vez y lo prueba contra el syntaxitemargumento. Ver :help synstack()y :help synIDattr(). Si hay una coincidencia 'calificada', devuelve el número de línea. Si llega al final del búfer sin encontrar ninguna coincidencia 'calificada', regresa 0. El objetivo de la función es llevar el cursor a la siguiente coincidencia 'calificada' para que pueda realizar alguna operación allí, pero es útil devolver "número de línea o 0" para indicar si es significativo volver a llamar a la función, por instancia si desea llamar a la función repetidamente desde otra función o una macro.

Elegí usar la Wbandera para el search()porque evita 'envolver' el final del búfer. De lo contrario, la función podría atascarse ya que sigue encontrando las mismas coincidencias "normales" pero no coincidencias "calificadas".

jjaderberg
fuente
¡Gracias por tu ayuda! Todavía no he probado esta función, pero parece lo que quería.
Rob F.
1

En caso de que sus "zonas matemáticas" estén calificadas por algún patrón sintáctico, digamos, la cadena "matemáticas", entonces al menos podría usar secuencias de patrones para encontrar una línea con el patrón correspondiente, como en:

:/math//your pattern/

(Nota: ¡los dos patrones pueden estar en líneas diferentes!)

Es posible que esto no restrinja sus coincidencias a las zonas, para eso necesitaría identificar el final de la zona, pero solo mostrará esas coincidencias después de un patrón inicial / matemáticas /. Puede repetir la búsqueda de la próxima aparición utilizando el historial en modo ex ( : up-arrow enter).


Nota: ISTR que en versiones anteriores de vim / vi también pude usar ese método directamente como un comando de búsqueda (a diferencia de un comando ex-mode) /math//your pattern/con la ventaja de escribir y usar menos los comandos ny N, pero no puedo confirmar eso para mi versión vim actual.

Janis
fuente
1

Si está buscando la cadena foodentro de $...$o $$...$$, esto debería funcionar:

\$.*\zsfoo

Esto ancla la coincidencia a un $personaje pero solo selecciona la cadena foo.

No es realmente una solución fácil, pero uno podría usar un :global+ :substitutepara encontrar "zonas matemáticas" y buscar dentro de ellas:

:global /\v\\begin\{%(align|alignat|displaymath)\}/ +1,/\\end/-1 s/foo/&/gc

Fingiendo que :substitutees un comando de búsqueda, puede ir a la siguiente aparición con ny salir con q. Si confirma una sustitución por error, no debería haber ningún problema.

Tendrás que configurar la lista dentro %(... )con los nombres de los entornos matemáticos que utilizas (la lista completa es un poco pesada:) align|alignat|displaymath|eqnarray|equation|flalign|gather|math|multline|subequations|xalignat|xxalignat. Tenga en cuenta que estoy usando un \vpatrón muy mágico ( ) aquí.

Explicación:

:globalejecutar un comando Ex ( :s) en cada línea, donde los partidos de patrones ( :help :global)
/\vcomienzan un patrón muy mágica ( :h /, :h pattern, :h magic)
\\begin\{coincida con un literal \begin{
%(align|alignat|displaymath)coincide con ninguna de estas palabras ( :h /\%(, :h /bar)
\}/coincida con un literal }y poner fin al patrón.

+1,/\\end/-1un rango que consiste en la siguiente línea (contando desde la encontrada por :global) hasta la línea anterior a la encontrada por el patrón de búsqueda /\\end. Dentro de ese rango,

s/foo/&/gcbuscar y reemplazar cada aparición del literal fooconsigo mismo, después de la confirmación ( :h :substitute)

Peter Lewerin
fuente
Este es sin duda un comienzo, pero hago uso frecuente de los entornos de ecuación, alineación y IEEEeqnarray, y no quiero excluirlos de mi búsqueda.
Rob F.
@RobF .: es bastante posible hacer coincidir dentro de una variedad de entornos, pero no será fácil a menos que uno lo escriba. Sin embargo, si usa constantemente \mathitalrededor de nombres de variables, encontrarlos es mucho más fácil.
Peter Lewerin
0

Si está buscando la cadena 'mañana' dentro del archivo /morning, enterpresione ny avance para avanzar

Arvind Gangwar
fuente
1
La pregunta decía que I would like to search only in "math zones"su método busca todo el archivo, no delimita una zona de investigación.
statox
0

No hay más opción que escribir una función dedicada para esto. Escribí una función que busca la cadena que desea y solo se detiene si:

  1. se queda sin fósforos
  2. hay una coincidencia que está dentro del entorno matemático (se detendrá en la partida)

Simplemente llámalo con la cadena que deseas buscar.

function! Finmath(nextstr)
    while 1
        if search(a:nextstr)==0
            break
        endif
        if searchpairpos('\(', '','\)','n')!=[0,0]
            break
        endif
        if searchpairpos('\[', '','\]','n')!=[0,0]
            break
        endif
        let a = getcurpos() 
        if count(strpart(getline('.'),0,a[2]),'$')%2==1
            break
        endif 
    endwhile 
endfunction

Tengo la intención de escribir una función similar para GrammerousCheck que solo se detiene en errores de gramática fuera de las matemáticas.

eyal karni
fuente