Cambiar los nombres de las variables en Vim

96

Estoy tratando de leer mucho código C / Perl a través de Vim que contiene muchos nombres de variables de una sola letra.

Sería bueno tener algún comando que pudiera ayudarme a cambiar el nombre de una variable a algo más significativo mientras estoy en el proceso de leer el código para poder leer el resto más rápido.

¿Hay algún comando en Vim que me permita hacer esto rápidamente?

No creo que las expresiones regulares funcionen porque:

  1. el mismo nombre de una sola letra puede tener diferentes propósitos en diferentes bloques de alcance

  2. la misma combinación de letras podría ser parte de otro nombre var más grande, o en una cadena o comentario ... no querría modificar esos

¿Alguna solución conocida?

Aditya Mukherji
fuente

Respuestas:

198

A continuación, se explica cómo cambiar el nombre de una variable definida en el ámbito actual {}.

Mueva su cursor a la variable uso. Presione gd. Lo que significa: mueva el cursor a la definición. Ahora presione [{: esto lo llevará al inicio del alcance. Presione V- activará la selección de línea visual. Presione %- saltará al opuesto, }por lo que seleccionará todo el alcance. Pulsar :s/- inicio del comando de sustitución. <C-R>/- insertará un patrón que coincida con el nombre de la variable (el nombre que tenía antes de presionar gd). /newname/gc<CR>- iniciará la búsqueda y reemplazará con confirmación en cada coincidencia.

Ahora tienes que grabar macros o, mejor aún, mapear una clave.

Aquí están las asignaciones finales:

" 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>

Pon esto a tu .vimrcgusto o simplemente ejecútalo. Después de esto, presionar grla variable local lo llevará al :scomando donde simplemente debe ingresar new_variable_namey presionar Enter.

Mykola Golubyev
fuente
40
+1 por aprender más de 5 trucos nuevos de Vim que debería haber conocido antes. Gracias
Kenny Meyer
6
Nota: gd no funciona para ubicar la variable en el ámbito inmediato de definición en modo Javascript en macvim. Me lleva al primer uso del nombre de la variable en alguna función en el archivo :( Si está dentro de algún alcance y desea seleccionar ese alcance, "va {" - "visual select around {" - es el camino a seguir Creo
Srikumar
3
Una versión ligeramente mejorada: gist.github.com/048616a2e3f5d1b5a9ad solicita al usuario, muestra el nombre antiguo, restaura la posición del cursor después de reemplazar
Andy Ray
7
+1 muy buena vimgineering (creo que acabo de acuñar un término nuevo). Nota: De hecho, necesitaba presionar dos puntos ( :) dos veces. La primera vez que lo presioné, lo vi :'<,'>. Si escribía s/desde allí, no funcionaba; Tuve que escribir otros dos puntos antes del s/.
Kelvin
6
Tenga en cuenta que no necesita <C-R>el comando sustituto, simplemente omitir la búsqueda hará que vim use el último patrón buscado, que en este caso se creó a partir del gdcomando. Así que basta con hacerlo :s//<newname>/gc.
shangxiao
10

AFAIK, no hay soporte de refactorización real en VIM. Cuando hago un cambio de nombre con la intención de refactorizar, generalmente tomo las siguientes precauciones:

  1. Limite el alcance del cambio a mis marcas de uso.
  2. Cuando ingrese la expresión regular, coloque entre corchetes el nombre con \ <y>. Esto hará que coincida con una palabra completa, lo que reduce los tipos de cambios de nombre incorrectos que se producirán.
  3. No realice una sustitución de varias líneas para reducir las posibilidades de una mala sustitución
  4. Mire cuidadosamente el código diff si se trata de algo más que un pequeño cambio.

Mi cambio final se parece a esto

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

Me encantaría estar equivocado acerca de que no hay una herramienta de refactorización para VIM, pero no la he visto.

JaredPar
fuente
En Perl también puede agregar el tipo al patrón de búsqueda. es decir, $ para escalares, @ para matrices,% para hashes
Nathan Fellman
@Nathan: desafortunadamente, es un poco más difícil en Perl (5.X), ya que el sigilo de las matrices y los hashes cambia con el uso:% hash -> hash completo, $ hash {clave} -> valor único, @hash { qw / ab /} segmento de hash.
user55400
10

Sé que es una pregunta antigua, y la forma de @ mykola-golubyev obviamente ES la mejor respuesta para el caso particular en la pregunta OP (que, supongo, está pasando por un código ofuscado donde es probable que tenga varios bloques con los mismos nombres de var) ; pero con el nombre de la pregunta como ese, muchas personas que vienen aquí desde las búsquedas de Google probablemente buscan formas menos específicas de la situación para cambiar el nombre de las variables en VIM, y esas pueden ser más concisas

Me sorprende que nadie sugiera de esta manera:

* :s// NUEVO NOMBRE /gc

El *es el mismo que gn- se busca la siguiente aparición de la palabra bajo el cursor y se convierte en el último patrón buscado, por lo que cuando se omite el patrón de búsqueda en el comando sustituto, VIM asume éste es el patrón a buscar.

Para pequeñas cantidades de copias var, una aún más rápida:

* cw NEWNAME <esc> luego repita n.para otras ocurrencias

Buscar ocurrencia, cwes el comando para cambiar palabra , npasa a la siguiente ocurrencia del último término buscado y .repite el último comando (que es cambiar palabra a NEWNAME )

(Los créditos para que yo sepa todo esto van a @doomedbunnies en Reddit )

Otro truco genial es este: ( créditos a @ nobe4 )

* cgn NEWNAME <esc> luego repita .para otras ocurrencias

cgnes "cambiar lo que sea el resultado de (encontrar la siguiente aparición)". Ahora que este es el último comando , no es necesario nque vaya a la siguiente aparición, por lo que de nuevo hay menos trazos y, lo que es más importante, no es necesario alternar ny .. Pero, obviamente, este tiene el inconveniente de no tener una forma de omitir una ocurrencia.

A continuación se muestran algunos beneficios:

  • sin mapeo, sin .vimrc (o init.vim), por lo que puede usarlo en cualquier copia de VIM que encuentre (por ejemplo, una tarea rápida en algún VPS o en la máquina de su amigo donde configurar VIM a su manera frustraría el propósito de 'rápido' )
  • usar *o gnpara la selección de palabras es muy rápido: solo presionar una tecla (bueno, digamos 1.5)
  • usando *o gnse asegura de que no obtenga coincidencias dentro de otras palabras, al igual que lo :%s/<C-R>//gchace. Es mejor que escribir a :%s/\<OLDNAME\>/NEWNAME/gcmano: personalmente, tiendo a olvidar usar las \<cosas para limitar las coincidencias a palabras completas solamente.
  • No usar el alcance solo resultará en unos pocos golpes adicionales de npara omitir coincidencias no deseadas, probablemente incluso menos que los golpes adicionales necesarios para limitar el alcance. En circunstancias normales, lo más probable es que sus variables estén algo localizadas en un determinado bloque de código de todos modos.
Ivan Bartsov
fuente
8

Pon esto en tu .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

Llámalo con :call Rnvar()

expand("<cword>")obtiene la palabra debajo del cursor. Los usos cadena de búsqueda %de archivos en el alcance y los \(\W\)patrones buscan caracteres que no son de texto en el límite de la palabra para reemplazar, y guardarlos en las variables \1y \2de manera que se puede volver a insertar en el patrón de sustitución.

Miguel
fuente
3

Puede usar el modificador 'c' en la búsqueda global y reemplazar que le pediría confirmación para cada reemplazo. Llevaría más tiempo, pero podría funcionar para un archivo de código no enorme:

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

La c significa confirmar.

Adnan
fuente
La i significa ignorar caso. Quieres c, confirma cada cambio.
Michael Kristofik
Ups .. perdón por eso .. Se corrigió la respuesta
Adnan
La respuesta aún no se ha solucionado por completo;)
user55400
¿Te refieres a los $ escapados? Eso es algo que es una especie de preferencia personal mía. $ funciona sin escape y también con y dado que en el mundo de las expresiones regulares y en vi $ tiene un significado especial, me gusta escapar de él solo por claridad.
Adnan
0

En c, es posible que pueda hacer algunos progresos con cscope. Intenta comprender la sintaxis, por lo que tendría la posibilidad de saber cuándo la letra era una variable.

Kim Reece
fuente
0

Si se trata de varios archivos, puede considerar echar un vistazo a sed. Use buscar para tomar sus archivos y xargs más sed para reemplazarlos. Supongamos que desea reemplazar a con a_better_name en todos los archivos que coincidan con * .c, podría hacerlo

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

Tenga en cuenta que esto reemplazará TODAS las apariciones de a, por lo que es posible que desee una expresión regular más sólida.

Dibujó Olson
fuente