search - reemplazar - Vim: búsqueda y reemplazo global, comenzando desde la posición del cursor
vim buscar y reemplazar (5)
Cuando busco con
//vSEARCHTERM
Vim inicia la búsqueda desde la posición del cursor hacia abajo, y se ajustará a la parte superior. Sin embargo, al buscar y reemplazar usando
:%s//vBEFORE/AFTER/gc
Vim comienza en la parte superior del archivo.
¿Hay alguna manera de hacer que Vim busque y reemplace comenzando desde la posición del cursor Y envolviéndolo hasta la parte superior una vez que llega al final?
Aquí hay algo muy difícil que aborda las preocupaciones sobre el ajuste de la búsqueda con el enfoque de dos pasos ( :,$s/BEFORE/AFTER/gc|1,''''-&&
) o con un intermedio "¿Continuar al principio del archivo?" enfoque:
" 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
Esta función usa un par de cortes para verificar si debemos envolvernos en la parte superior:
- Sin envoltorio si el usuario presiona "l", "q" o "Esc", cualquiera de los cuales indica un deseo de abortar.
- Detecta la última pulsación de tecla registrando una macro en el registro "s" e inspeccionando el último carácter de la misma.
- Evite sobrescribir una macro existente guardando / restaurando el registro "s".
- Si ya está grabando una macro al usar el comando, todas las apuestas están desactivadas.
- Intenta hacer lo correcto con interrupciones.
- Evita las advertencias de "rango hacia atrás" con una guardia explícita.
FINALMENTE he encontrado una solución al hecho de que salir de la búsqueda se ajusta al principio del archivo sin escribir una función enorme ...
No creerías cuánto tiempo me llevó pensar en esto. Simplemente agregue un aviso si desea envolver: si el usuario presiona q
nuevamente, no lo ajuste. Así que, básicamente, ¡salga de la búsqueda tocando qq
lugar de q
! (Y si desea envolver, simplemente escriba y
)
:,$s/BEFORE/AFTER/gce|echo ''Continue at beginning of file? (y/q)''|if getchar()!=113|1,''''-&&|en
De hecho, tengo esto asignado a una tecla de acceso directo. Entonces, por ejemplo, si desea buscar y reemplazar cada palabra debajo del cursor, comenzando desde la posición actual, con 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)
No es difícil lograr el comportamiento utilizando una sustitución en dos pasos:
:,$s/BEFORE/AFTER/gc|1,''''-&&
Primero, se ejecuta un comando de sustitución para cada línea comenzando desde la actual hasta el final del archivo. Entonces, eso :substitute
comando :substitute
se repite con el mismo patrón de búsqueda, cadena de reemplazo y banderas, usando el comando :&
. Este último, sin embargo, realiza la sustitución en el rango de líneas desde la primera línea del archivo hasta la línea donde se ha establecido la marca de contexto anterior, menos uno. Dado que el primer comando :substitute
almacena la posición del cursor antes de comenzar los reemplazos reales, la línea dirigida por ''''
es la línea que era la actual antes de que se ejecutara el comando de sustitución.
Tenga en cuenta que el segundo comando (después del símbolo |
) no requiere ningún cambio cuando el patrón o las banderas del primero se modifican.
Ya está usando un rango, %
, que es mano corta para 1,$
significa todo el archivo. Para ir de la línea actual al final, usa .,$
. El período significa línea actual y $
significa la última línea. Entonces el comando sería:
:.,$s//vBEFORE/AFTER/gc
Pero el .
o se puede suponer una línea actual, por lo tanto, se puede eliminar:
:,$s//vBEFORE/AFTER/gc
Para obtener más ayuda, vea
:h range
%
es un atajo para 1,$
(Vim help => :help :%
igual a 1, $ (el archivo completo).)
.
es la posición del cursor para que pueda hacer
:.,$s//vBEFORE/AFTER/gc
Para reemplazar desde el comienzo del documento hasta el cursor
:1,.s//vBEFORE/AFTER/gc
etc
Le sugiero que lea el manual sobre rango :help range
ya que casi todos los comandos funcionan con un rango.