web-dev-qa-db-fra.com

Vim: recherche globale et remplacement, à partir de la position du curseur

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?

108
basteln

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.

46
ib.

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
155
Peter Rincker

% 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.

46
mb14

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)
3
q335r49

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

1
simlei

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:

  • Pas d'habillage si l'utilisateur a appuyé sur "l", "q" ou "Echap", n'importe lequel indiquant 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 de celle-ci.
  • Évitez d’écraser une macro existante en sauvegardant/restaurant le registre "s".
  • Si vous enregistrez déjà une macro en utilisant la commande, tous les paris sont désactivés.
  • Essaie de faire la bonne chose avec les interruptions.
  • Evite les avertissements "à reculons" avec une protection explicite.
1
wincent