Vim: recherche globale & remplacer, à partir de la position du curseur

Quand je recherche avec

/\vSEARCHTERM 

Vim lance la recherche de la position du curseur vers le bas, et le retourne au début. Cependant, lorsque vous recherchez et remplacez en utilisant

 :%s/\vBEFORE/AFTER/gc 

Vim commence en haut du fichier.

Existe-t-il un moyen de faire rechercher et remplacer Vim en partant de la position du curseur ET en remontant vers le haut une fois la fin atteinte?

Il n’est pas difficile de réaliser le comportement en utilisant une substitution en deux étapes:

 :,$s/BEFORE/AFTER/gc|1,''-&& 

Tout d’abord, une commande de substitution est exécutée pour chaque ligne à partir de la ligne actuelle jusqu’à la fin du fichier. Ensuite, la commande :substitute est répétée avec le même modèle de recherche, la même chaîne de remplacement et les mêmes indicateurs, à l’aide de la commande :& . Ce dernier effectue toutefois la substitution sur la plage de lignes de la première ligne du fichier à la ligne où la marque de contexte précédente a été définie, moins un. Comme la première commande :substitute stocke la position du curseur avant de commencer les remplacements réels, la ligne adressée par '' est la ligne qui était la ligne courante avant l’exécution de cette commande de substitution.

Notez que la deuxième commande (après le symbole | ) ne nécessite aucune modification lorsque le modèle ou les indicateurs du premier sont modifiés.

Vous utilisez déjà une plage, % , qui est une main courte pour 1,$ signifiant le fichier entier. Pour aller de la ligne courante à la fin que vous utilisez .,$ . La période signifie la ligne courante et $ la dernière ligne. Donc, la commande serait:

 :.,$s/\vBEFORE/AFTER/gc 

Mais le . ou on peut supposer que la ligne actuelle peut être supprimée:

 :,$s/\vBEFORE/AFTER/gc 

Pour plus d’aide voir

 :h range 

% est un raccourci pour 1,$
(Vim help => :help :% égal à 1, $ (le fichier entier).)

. est la position du curseur pour pouvoir faire

 :.,$s/\vBEFORE/AFTER/gc 

Remplacer depuis le début du document jusqu’au curseur

 :1,.s/\vBEFORE/AFTER/gc 

etc

Je vous suggère fortement de lire le manuel sur la plage :help range car à peu près toutes les commandes fonctionnent avec une plage.

J’ai finalement trouvé une solution au fait que quitter la recherche se termine au début du fichier sans écrire une fonction énorme …

Vous ne croiriez pas combien de temps cela m’a pris pour y arriver. Ajoutez simplement une invite pour envelopper: si l’utilisateur appuie à nouveau sur q , ne pas envelopper. Donc, fondamentalement, quittez la recherche en tapant sur qq au lieu de q ! (Et si vous voulez envelopper, tapez simplement y .)

 :,$s/BEFORE/AFTER/gce|echo 'Continue at beginning of file? (y/q)'|if getchar()!=113|1,''-&&|en 

Je l’ai en fait mappé sur un raccourci clavier. Donc, par exemple, si vous souhaitez rechercher et remplacer chaque mot sous le curseur, à partir de la position actuelle, avec q* :

 exe 'nno q* :,$s/\<=expand("")\>//gce\|echo "Continue at beginning of file? (y/q)"\|if getchar()==121\|1,''''-&&\|en'.repeat('',77) 

Voici quelque chose de très rude qui aborde les problèmes liés à la gestion de la recherche avec l’approche en deux étapes ( :,$s/BEFORE/AFTER/gc|1,''-&& ) ou avec un intermédiaire “Continuer au début du fichier?” approche:

 " Define a mapping that calls a command. nnoremap e :Substitute/\v<=expand('')>// " And that command calls a script-local function. command! -nargs=1 Substitute call s:Substitute() function! s:Substitute(patterns) if getregtype('s') != '' let l:register=getreg('s') endif normal! qs redir => l:replacements try execute ',$s' . a:patterns . 'gce#' catch /^Vim:Interrupt$/ return finally normal! q let l:transcript=getreg('s') if exists('l:register') call setreg('s', l:register) endif endtry redir END if len(l:replacements) > 0 " At least one instance of pattern was found. let l:last=strpart(l:transcript, len(l:transcript) - 1) " Note: type the literal  (^[) here with : if l:last ==# 'l' || l:last ==# 'q' || l:last ==# '^[' " User bailed. return endif endif " Loop around to top of file and continue. " Avoid unwanted "Backwards range given, OK to swap (y/n)?" messages. if line("''") > 1 1,''-&&" endif endfunction 

Cette fonction utilise un couple de hacks pour vérifier si nous devons boucler vers le haut:

  • Aucun emballage si l’utilisateur a appuyé sur “l”, “q” ou “Esc”, tout ce qui indique un désir d’abandonner.
  • Détectez cette dernière touche en enregistrant une macro dans le registre “s” et en inspectant le dernier caractère.
  • Évitez d’écraser une macro existante en sauvegardant / restaurant le registre “s”.
  • Si vous enregistrez déjà une macro lorsque vous utilisez la commande, tous les paris sont désactivés.
  • Essaie de faire la bonne chose avec les interruptions.
  • Évite les avertissements de “retour en arrière” avec une garde explicite.