web-dev-qa-db-fra.com

Changer les noms de variables dans Vim

J'essaie de lire beaucoup de code C/Perl via Vim qui contient de nombreux noms de variables à lettre unique.

Ce serait bien d'avoir une commande qui pourrait m'aider à changer le nom d'une variable en quelque chose de plus significatif pendant que je suis en train de lire le code afin de pouvoir lire le reste plus rapidement.

Y a-t-il un commandement à Vim qui pourrait me permettre de le faire rapidement?

Je ne pense pas que les regex fonctionneraient parce que:

  1. le même nom d'une seule lettre peut avoir des objectifs différents dans différents blocs de portée

  2. la même combinaison de lettres pourrait faire partie d'un autre nom var plus grand, ou dans une chaîne ou un commentaire ... ne voudrait pas les modifier

Des solutions connues?

87
Aditya Mukherji

Voici comment renommer une variable définie dans la portée actuelle {}.

Déplacez votre curseur sur l'utilisation variable. Appuyez sur Gd. Ce qui signifie - déplacer le curseur sur la définition. Maintenant, appuyez sur [{ - cela vous amènera à la portée de commencer. Appuyez sur V - pour activer la sélection de la ligne visuelle. Presse % - passera à l'opposé } sélectionnera donc toute la portée. Presse :s/ - début de la commande de substitution. <C-R>/ - insérera un modèle qui correspond au nom de la variable (ce nom que vous utilisiez avant d'appuyer sur Gd). /newname/gc<CR> - lancera la recherche et la remplacera par une confirmation à chaque correspondance.

Vous devez maintenant enregistrer une macro ou mieux encore - mapper une clé.

Voici les mappages finaux:

" For local replace
nnoremap gr Gd[{V%::s/<C-R>///gc<left><left><left>

" For global replace
nnoremap gR Gd:%s/<C-R>///gc<left><left><left>

Mettez ceci à votre .vimrc ou simplement exécuter. Après cela, appuyer sur gr sur la variable locale vous amènera à :s commande où vous devez simplement entrer new_variable_name et appuyez sur Enter.

182
Mykola Golubyev

AFAIK, il n'y a pas de support de refactoring réel dans VIM. Lorsque je fais un changement de nom avec l'intention d'un refactor, je prends généralement les précautions suivantes:

  1. Limitez la portée de la modification de mes marques d'utilisation.
  2. Lorsque vous entrez l'expression régulière, mettez le nom entre parenthèses avec\<et>. Cela le fera correspondre à un mot entier, ce qui réduit les types de renommages incorrects qui se produiront.
  3. Ne faites pas de remplacement multiligne pour réduire les risques de mauvais remplacement
  4. Regardez attentivement le code diff s'il ne s'agit que d'un petit changement.

Mon changement de fin ressemble à ceci

:'a,'bs/\<foo\>/bar

J'aimerais avoir tort de ne pas avoir d'outil de refactoring pour VIM mais je ne l'ai pas vu.

9
JaredPar

Mettez ceci dans votre .vimrc

" Function to rename the variable under the cursor
function! Rnvar()
  let Word_to_replace = expand("<cword>")
  let replacement = input("new name: ")
  execute '%s/\(\W\)' . Word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction

Appelez-le avec :call Rnvar()

expand("<cword>") place le mot sous le curseur. La chaîne de recherche utilise % Pour la portée du fichier, et les modèles \(\W\) recherchent des caractères non Word à la limite du mot à remplacer et les enregistrent dans des variables \1 et \2 pour être réinsérés dans le motif de remplacement.

8
Mike

Je sais que c'est une vieille question, et la manière de @ mykola-golubyev est évidemment IS la meilleure réponse pour le cas particulier de la question OP (qui, je suppose, passe par du code obscurci où vous êtes susceptible de avoir plusieurs blocs avec les mêmes noms var); mais avec le nom de la question comme ça, beaucoup de gens venant ici de recherches Google recherchent probablement des moyens moins spécifiques à la situation pour renommer des variables dans VIM - et ceux-ci peuvent être plus concis

Je suis surpris que personne n'ait suggéré de cette façon:

*:s// [~ # ~] nouveau nom [~ # ~]/gc

* Est identique à gn - il recherche la prochaine occurrence du mot sous le curseur ET il devient le dernier modèle recherché, donc lorsque vous omettez le modèle de recherche dans la commande de remplacement, VIM suppose que c'est le modèle à rechercher.

Pour de petites quantités de copies var, encore plus rapide:

*cw [~ # ~] nouveau nom [~ # ~]<esc> puis répétez n. pour d'autres occurrences

Rechercher l'occurrence, cw est la commande pour changer Word, n passe à l'occurrence suivante pour la dernière recherche et . Répète la dernière commande ( qui est changez Word en NEWNAME)

(Les crédits pour moi sachant tout cela vont à @ doomedbunnies sur Reddit )

Une autre astuce intéressante est la suivante: ( crédits à @ nobe4 )

*cgn [~ # ~] nouveau nom [~ # ~]<esc> puis répétez . pour d'autres occurrences

cgn est "changer le résultat de (trouver l'occurrence suivante)". Maintenant que c'est la dernière commande, vous n'avez plus besoin de n pour passer à l'occurrence suivante, donc moins de coups à nouveau et, plus important encore, pas besoin d'alterner n et .. Mais, évidemment, celui-ci a l'inconvénient de ne pas pouvoir ignorer un événement.

Voici quelques avantages:

  • pas de mappage, pas de .vimrc (ou init.vim), vous pouvez donc l'utiliser dans n'importe quelle copie VIM que vous rencontrez (par exemple, une tâche rapide sur un VPS ou la machine de votre ami lors de la configuration de VIM à votre guise) irait à l'encontre de l'objectif de "rapide")
  • utiliser * ou gn pour la sélection de Word est très rapide - une seule touche (enfin, disons 1,5)
  • l'utilisation de * ou gn garantit que vous n'obtiendrez aucune correspondance dans les autres mots, tout comme :%s/<C-R>//gc. Beats tapant le :%s/\<OLDNAME\>/NEWNAME/gc À la main: J'ai personnellement tendance à oublier d'utiliser les choses \< Pour limiter les correspondances aux mots entiers uniquement.
  • L'absence de portée n'entraînera que quelques coups supplémentaires de n pour ignorer les correspondances indésirables - probablement encore moins que les coups supplémentaires nécessaires pour limiter la portée. Dans des circonstances normales, vos variables sont très probablement quelque peu localisées dans un certain bloc de code de toute façon.
7
Ivan Bartsov

Vous pouvez utiliser le modificateur "c" dans la recherche globale et remplacer qui vous demanderait une confirmation pour chaque remplacement. Cela prendrait plus de temps, mais cela pourrait fonctionner pour un fichier de code non gigantesque:

%s/\$var/\$foo/gc

Le c signifie confirmer.

2
Adnan

S'il s'agit de plusieurs fichiers, vous pouvez envisager de jeter un œil à sed. Utilisez find pour récupérer vos fichiers et xargs plus sed pour un remplacement. Supposons que vous souhaitiez remplacer a par a_better_name dans tous les fichiers correspondant à * .c, vous pouvez le faire

trouver . -nom "* .c" | xargs sed -i -e 's/a/a_better_name/g'

Gardez à l'esprit que cela remplacera TOUTES les occurrences d'un, donc vous voudrez peut-être une expression régulière plus robuste.

0
Drew Olson

En c, vous pourrez peut-être faire des progrès en utilisant cscope. Il essaie de comprendre la syntaxe, donc aurait une chance de savoir quand la lettre était une variable.

0
Kim Reece