Quand je cherche avec
/\vSEARCHTERM
Vim commence la recherche de la position du curseur vers le bas, et elle se retournera vers le haut. Cependant, quand chercher & remplacer en utilisant
:%s/\vBEFORE/AFTER/gc
Vim commence en haut du fichier.
Existe-t-il un moyen de faire en sorte que Vim recherche et remplace à partir de la position du curseur ET s’enroulant vers le haut une fois qu’il atteint la fin?
Il n’est pas difficile d’obtenir 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, cette 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 allant de la première ligne du fichier à la ligne où la marque de contexte précédente a été définie, moins un. Étant donné que la première commande :substitute
Stocke la position du curseur avant de commencer les remplacements, la ligne adressée par ''
Est la ligne actuelle avant l'exécution de la commande de substitution.
Notez que la deuxième commande (après le symbole |
) Ne nécessite aucune modification lorsque le motif ou les drapeaux de la première sont modifiés.
Vous utilisez déjà une plage, %
, qui est un raccourci pour 1,$
signifie le fichier entier. Pour aller de la ligne courante à la fin, utilisez .,$
. La période correspond à la ligne en cours et $
signifie la dernière ligne. Donc, la commande serait:
:.,$s/\vBEFORE/AFTER/gc
Mais le .
ou la ligne en cours peut être considérée comme pouvant ê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 afin que vous puissiez faire
:.,$s/\vBEFORE/AFTER/gc
Pour 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 gamme :help range
à peu près toutes les commandes fonctionnent avec une plage.
J'ai finalement trouvé une solution au fait que quitter la recherche revient au début du fichier sans écrire une fonction énorme ...
Vous ne croiriez pas combien de temps il m'a fallu pour arriver à ça. Ajoutez simplement une invite si vous souhaitez envelopper: si l'utilisateur appuie à nouveau sur q
, ne le retourne pas. 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
En fait, je mappe cela sur un raccourci clavier. Ainsi, par exemple, si vous souhaitez rechercher et remplacer tous les mots situés sous le curseur, à partir de la position actuelle, par q*
:
exe 'nno q* :,$s/\<<c-r>=expand("<cword>")<cr>\>//gce\|echo "Continue at beginning of file? (y/q)"\|if getchar()==121\|1,''''-&&\|en'.repeat('<left>',77)
Je suis en retard à la fête, mais je me suis trop souvent appuyé sur les réponses tardives de stackoverflow pour ne pas le faire. J'ai rassemblé des astuces sur reddit et stackoverflow, et la meilleure option consiste à utiliser le motif \%>...c
Dans la recherche, qui ne correspond qu'après le curseur.
Cela dit, cela perturbe également le schéma de la prochaine étape de remplacement et il est difficile à taper. Pour contrer ces effets, une fonction personnalisée doit filtrer le motif de recherche par la suite, en le réinitialisant. Voir ci-dessous.
Je me suis opposé à un mappage qui remplace l'occurrence suivante et passe à l'énoncé suivant, et non plus (c'était mon objectif de toute façon). Je suis sûr que, sur cette base, une substitution globale peut être élaborée. Gardez à l'esprit lorsque vous travaillez sur une solution visant quelque chose comme :%s/.../.../g
, Que le modèle ci-dessous filtre les correspondances dans tous lignes laissées à la position du curseur - mais est nettoyé après la substitution unique termine, donc il perd cet effet directement après, saute au match suivant et peut ainsi parcourir tous les matchs un par un.
fun! g:CleanColFromPattern(prevPattern) return substitute(a:prevPattern, '\V\^\\%>\[0-9]\+c', '', '') endf nmap <F3>n m`:s/\%><C-r>=col(".")-1<CR>c<C-.r>=g:CleanColFromPattern(getreg("/"))<CR>/~/&<CR>:call setreg("/", g:CleanColFromPattern(getreg("/")))<CR>``n
Voici quelque chose de très grossier qui résout le problème de boucler 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 <Leader>e :Substitute/\v<<C-R>=expand('<cword>')<CR>>//<Left>
" And that command calls a script-local function.
command! -nargs=1 Substitute call s:Substitute(<q-args>)
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 <Esc> (^[) here with <C-v><Esc>:
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 quelques hacks pour vérifier si nous devrions nous en tenir au sommet: