Comment rechercher un motif dans certaines régions de syntaxe?

10

J'utilise vim pour éditer des documents en latex. Souvent, je veux changer le nom d'une variable en autre chose. Cependant, c'est un peu ennuyeux de devoir parcourir des correspondances non pertinentes lorsque je recherche le nom de la variable. Je voudrais rechercher uniquement dans les "zones mathématiques" telles que définies dans le fichier de syntaxe tex. Existe-t-il un moyen simple de limiter une recherche à une région de syntaxe spécifique?

Rob F.
la source
1
Je pense que la réponse est non: il n'y a pas de moyen facile de limiter une recherche à une région de syntaxe spécifique.
Karl Yngve Lervåg
2
Cette cartographie utilise synIDattr()pour obtenir des groupes de syntaxe pour le caractère sous le curseur. Vous pouvez écrire une fonction qui effectue (ou effectue normal n) la recherche , puis utilise synIDattr()pour décider de rester à cet emplacement ou de poursuivre la recherche.
joeytwiddle
@joeytwiddle J'ai vu votre commentaire juste après avoir posté une réponse avec une telle fonction. C'est comme ça que tu avais en tête?
jjaderberg
@jjaderberg Oui, c'est ça. Bon travail!
joeytwiddle
Juste pour être complet (je l'ai trouvé une bonne réponse): stackoverflow.com/a/2696143/5000478
VanLaser

Réponses:

4

Voici une fonction que vous pourriez essayer. Je l'ai seulement testé un peu, mais cela semble fonctionner correctement.

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 fonction appelle la fonction de recherche de Vim dans une boucle jusqu'à ce qu'elle trouve une correspondance «ordinaire» qui est également une correspondance «qualifiée» à un élément de syntaxe particulier, ou jusqu'à ce qu'elle atteigne la fin du tampon.

Il faut deux arguments. Le premier est le modèle de recherche et il est transmis tel quel à la search()fonction de Vim . Voir :help search()comment cette fonction fonctionne. Le deuxième argument est le nom de l'élément de syntaxe sur lequel vous souhaitez filtrer ces correspondances. Cela peut également être un modèle et est comparé comme une expression régulière insensible à la casse.

Pour trouver le motif «alpha» dans les zones mathématiques, vous pouvez le faire

:JJSyntaxSearch alpha texMathZone.

À .la fin est l'atome de modèle pour n'importe quel caractère unique, voir :help /.. En effet, de nombreux éléments de syntaxe de zone mathématique sont appelés texMathZoneA, texMathZoneBetc.

La search()fonction déplace le curseur sur la prochaine correspondance «ordinaire». Ensuite, notre fonction obtient tous les ID d'élément de syntaxe pour cette nouvelle position de curseur avec synstack(). En les parcourant, il récupère tour à tour le nom de chaque élément et le teste par rapport à l' syntaxitemargument. Voir :help synstack()et :help synIDattr(). S'il existe une correspondance «qualifiée», elle renvoie le numéro de ligne. S'il atteint la fin du tampon sans trouver de correspondance «qualifiée», il revient 0. Le but de la fonction est de placer le curseur sur la prochaine correspondance «qualifiée» afin que vous puissiez y effectuer certaines opérations, mais il est utile de renvoyer «numéro de ligne ou 0» pour indiquer s'il est utile d'appeler à nouveau la fonction, par exemple par exemple si vous souhaitez appeler la fonction à plusieurs reprises à partir d'une autre fonction ou d'une macro.

J'ai choisi d'utiliser l' Windicateur pour le search()car il empêche de «contourner» la fin du tampon. Sinon, la fonction peut rester bloquée car elle continue de trouver les mêmes correspondances «ordinaires» mais aucune correspondance «qualifiée».

jjaderberg
la source
Merci de votre aide! Je n'ai pas encore essayé cette fonction, mais elle ressemble à ce que je voulais.
Rob F.
1

Dans le cas où vos "zones mathématiques" sont qualifiées par un motif syntaxique, par exemple, la chaîne "math", vous pouvez au moins utiliser des séquences de motifs pour trouver une ligne avec le motif correspondant, comme dans:

:/math//your pattern/

(Remarque: les deux modèles peuvent être sur des lignes différentes!)

Cela peut ne pas restreindre vos correspondances aux zones - pour cela, vous devez identifier la fin de la zone -, mais il n'affichera que les correspondances après un modèle / math / initial. Vous pouvez répéter la recherche de l'occurrence suivante en utilisant l'historique ex-mode ( : up-arrow enter).


Remarque: ISTR que dans les versions antérieures de vim / vi, j'ai également pu utiliser cette méthode directement comme commande de recherche (par opposition à une commande ex-mode) /math//your pattern/avec l'avantage de moins taper et utiliser les commandes net N, mais je ne peux pas confirmer que pour ma version actuelle de vim.

Janis
la source
1

Si vous recherchez la chaîne à l' foointérieur de $...$ou $$...$$, cela devrait fonctionner:

\$.*\zsfoo

Cela ancre la correspondance à un $caractère mais ne sélectionne que la chaîne foo.

Ce n'est pas vraiment une solution facile, mais on pourrait utiliser un :global+ :substitutepour trouver des "zones mathématiques" et chercher à l'intérieur:

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

En faisant semblant qu'il :substitutes'agit d'une commande de recherche, vous pouvez passer à l'occurrence suivante avec net quitter avec q. Si vous confirmez une substitution par erreur, il ne devrait pas y avoir de problème.

Vous devrez définir la liste à l'intérieur %(... )aux noms des environnements mathématiques que vous utilisez (la liste complète est un peu lourde:) align|alignat|displaymath|eqnarray|equation|flalign|gather|math|multline|subequations|xalignat|xxalignat. Notez que j'utilise \vici un motif très magique ( ).

Explication:

:globalexécuter une commande Ex ( :s) sur chaque ligne où les matchs de motif ( :help :global)
/\vcommencent un modèle très magique ( :h /, :h pattern, :h magic) désigner
\\begin\{un caractère \begin{
%(align|alignat|displaymath)correspond à l' un de ces mots ( :h /\%(, :h /bar) désigner
\}/un caractère }et à la fin du modèle.

+1,/\\end/-1une plage composée de la ligne suivante (à partir de celle trouvée par :global) jusqu'à la ligne précédant celle trouvée par le modèle de recherche /\\end. Dans cette plage,

s/foo/&/gcrechercher et remplacer chaque occurrence du littéral foopar lui-même, après confirmation ( :h :substitute)

Peter Lewerin
la source
C'est certainement un début, mais j'utilise fréquemment les environnements d'équation, d'alignement et IEEEeqnarray, et je ne veux pas les exclure de ma recherche.
Rob F.
@RobF .: il est tout à fait possible de faire correspondre à l'intérieur d'une gamme d'environnements, mais cela ne sera pas facile à moins que l'on ne le scripte. Si, cependant, vous utilisez systématiquement \mathitautour des noms de variables, il est beaucoup plus facile de les trouver.
Peter Lewerin
0

Si vous recherchez la chaîne 'matin' dans le fichier, /morningpuis enterappuyez sur npour avancer

Arvind Gangwar
la source
1
La question indique que I would like to search only in "math zones"votre méthode recherche le fichier entier sans délimiter une zone de recherche.
statox
0

Il n'y a pas d'autre option que d'écrire une fonction dédiée pour cela. J'ai écrit une fonction qui recherche la chaîne que vous voulez et ne s'arrête que si:

  1. il manque de matchs
  2. il y a une correspondance qui se trouve dans l'environnement mathématique (elle s'arrêtera lors de la correspondance)

Vous l'appelez simplement avec la chaîne que vous souhaitez rechercher.

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

J'ai l'intention d'écrire une fonction similaire pour GrammerousCheck qui ne s'arrête qu'aux erreurs de grammaire en dehors des mathématiques.

eyal karni
la source