Cambiare i nomi delle variabili in Vim


96

Sto cercando di leggere un sacco di codice C / Perl tramite Vim che contiene molti nomi di variabili a una sola lettera.

Sarebbe bello avere qualche comando che potrebbe aiutarmi a cambiare il nome di una variabile in qualcosa di più significativo mentre sto leggendo il codice in modo da poter leggere il resto più velocemente.

C'è qualche comando in Vim che potrebbe permettermi di farlo rapidamente?

Non credo che le espressioni regolari funzionerebbero perché:

  1. lo stesso nome di una singola lettera potrebbe avere scopi diversi in diversi blocchi di ambito

  2. la stessa combinazione di lettere potrebbe far parte di un altro nome var più grande, o in una stringa o in un commento ... non vorrebbe modificarli

Eventuali soluzioni note?

Risposte:


198

Di seguito viene illustrato come rinominare una variabile definita nell'ambito corrente {}.

Spostare il cursore sull'utilizzo della variabile. Premere gd. Il che significa: sposta il cursore sulla definizione. Ora premi [{: questo ti porterà all'inizio dell'ambito. Premere V- attiverà la selezione della linea visiva. Premere %- salterà all'opposto }quindi selezionerà l'intero ambito. Premere :s/- inizio del comando sostitutivo. <C-R>/- inserirà un pattern che corrisponde al nome della variabile (quel nome su cui eri prima di premere gd). /newname/gc<CR>- avvierà la ricerca e la sostituzione con la conferma ad ogni corrispondenza.

Ora devi registrare una macro o, ancora meglio, mappare una chiave.

Ecco le mappature finali:

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

Metti questo al tuo .vimrco semplicemente esegui. Dopodiché, premendo grsulla variabile locale verrai portato al :scomando in cui devi semplicemente inserire new_variable_namee premere Enter.


40
+1 per aver imparato più di 5 nuovi trucchi Vim che avrei dovuto conoscere prima. Grazie
Kenny Meyer

6
Nota: gd non funziona per individuare la variabile nell'ambito immediato della definizione in modalità Javascript in macvim. Mi porta al primo utilizzo del nome della variabile in qualche funzione nel file :( Se sei all'interno di un determinato ambito e desideri selezionare tale ambito, "va {" - "visual select around {" - è la strada da percorrere Penso.
Srikumar

3
Una versione leggermente migliorata: gist.github.com/048616a2e3f5d1b5a9ad richiede all'utente, mostra il vecchio nome, ripristina la posizione del cursore dopo la sostituzione
Andy Ray

7
+1 ottimo vimgineering (penso di aver appena coniato un nuovo termine). Nota: in realtà avevo bisogno di premere due :volte i due punti ( ). La prima volta che l'ho premuto, ho visto :'<,'>. Se ho appena digitato s/da lì non ha funzionato; Ho dovuto digitare un altro due punti prima del s/.
Kelvin

6
Nota che non è necessario <C-R>nel comando substitute, semplicemente omettendo la ricerca, vim utilizzerà l'ultimo pattern cercato, che in questo caso è stato creato dal gdcomando. Quindi :s//<newname>/gcsarà sufficiente fare semplicemente .
shangxiao

10

AFAIK, in VIM non è disponibile alcun supporto per il refactoring. Quando eseguo una ridenominazione con l'intento di un refactor, di solito prendo le seguenti precauzioni:

  1. Limita l'ambito della modifica dei marchi di utilizzo.
  2. Quando inserisci la regex, inserisci il nome tra parentesi \ <e>. Ciò farà corrispondere un'intera parola che riduce i tipi di rinomine errate che si verificheranno.
  3. Non eseguire una sostituzione multilinea per ridurre le possibilità di una sostituzione errata
  4. Guarda attentamente il codice diff se è qualcosa di diverso da un piccolo cambiamento.

Il mio cambiamento finale assomiglia a questo

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

Mi piacerebbe sbagliarmi sul fatto che non ci sia uno strumento di refactoring per VIM ma non l'ho visto.


In Perl puoi anche aggiungere il tipo al pattern di ricerca. vale a dire $ per gli scalari, @ per gli array,% per gli hash
Nathan Fellman

@ Nathan: sfortunatamente, è un po 'più difficile in Perl (5.X), poiché il sigillo di array e hash cambia con l'utilizzo:% hash -> hash intero, $ hash {key} -> valore singolo, @hash { qw / ab /} hash slice.
user55400

9

So che è una vecchia domanda, e il modo di @ mykola-golubyev è ovviamente la migliore risposta per il caso particolare nella domanda OP (che, presumo stia attraversando un codice offuscato in cui è probabile che tu abbia più blocchi con gli stessi nomi var) ; ma con il nome della domanda come quello molte persone che vengono qui dalle ricerche su Google probabilmente cercano modi meno specifici per la situazione per rinominare le variabili in VIM - e quelli possono essere più concisi

Sono sorpreso che nessuno abbia suggerito in questo modo:

* :s// NUOVO NOME /gc

Lo *è lo stesso che gn- esso cerca la prossima occorrenza della parola sotto il cursore e diventa l'ultimo ricercato modello, in modo che quando si omette il modello di ricerca nel comando sostituto, VIM assume questo è il modello da cercare.

Per piccole quantità di copie var, anche più veloce:

* cw NEWNAME <esc> quindi ripetere n.per altre occorrenze

Cerca occorrenza, cwè il comando per cambiare parola , nva alla prossima occorrenza dell'ultimo termine cercato e .ripete l'ultimo comando (che è cambia parola in NUOVONOME )

(I crediti per me che so tutto questo vanno a @doomedbunnies su Reddit )

Un altro trucco interessante è questo: ( crediti a @ nobe4 )

* cgn NEWNAME <esc> quindi ripetere .per altre occorrenze

cgnè "cambia qualunque sia il risultato di (trova la prossima occorrenza)". Ora che questo è l' ultimo comando , non è necessario nche passi all'occorrenza successiva, quindi di nuovo meno tratti e, cosa più importante, non è necessario alternare ne .. Ma, ovviamente, questo ha l'inconveniente di non avere un modo per saltare un evento.

Ecco alcuni vantaggi:

  • nessuna mappatura, nessun .vimrc (o init.vim), quindi puoi usarlo in qualsiasi copia VIM che incontri (ad esempio un'attività rapida su alcuni VPS o sulla macchina di un tuo amico in cui configurare VIM a modo tuo vanificherebbe lo scopo di 'veloce' )
  • usare *o gnper la selezione delle parole è molto veloce: basta premere un tasto (beh, diciamo 1.5)
  • usando *o gnsi assicura di non ottenere corrispondenze all'interno di altre parole, proprio come :%s/<C-R>//gcfa. Beats digitando :%s/\<OLDNAME\>/NEWNAME/gca mano: personalmente tendo a dimenticare di usare le \<cose per limitare le corrispondenze solo a parole intere.
  • Il mancato utilizzo dell'oscilloscopio comporterà solo alcuni colpi extra nper saltare le corrispondenze indesiderate, probabilmente anche meno dei colpi extra necessari per limitare l'ambito. In circostanze normali, le tue variabili sono molto probabilmente localizzate comunque in un certo blocco di codice.

8

Mettilo nel tuo .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

Chiamalo con :call Rnvar()

expand("<cword>")ottiene la parola sotto il cursore. La stringa di ricerca utilizza %per l'ambito del file e gli \(\W\)schemi cercano caratteri non al confine della parola da sostituire e li salvano in variabili\1 e in \2modo da essere reinseriti nel modello di sostituzione.


3

È possibile utilizzare il modificatore "c" nella ricerca e sostituzione globale che richiederebbe conferma per ogni sostituzione. Ci vorrebbe più tempo ma potrebbe funzionare per un file di codice non gigantesco:

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

La c sta per confermare.


I sta per ignora-case. Vuoi c, conferma ogni modifica.
Michael Kristofik,

oops .. mi dispiace .. Corretta la risposta
Adnan

Risposta ancora non risolta completamente;)
user55400

intendevi il $ fuggito? È qualcosa che è una specie di mia preferenza personale. $ funziona senza scampo e anche con e poiché nel mondo delle regex e in vi $ ha un significato speciale, mi piace sfuggirgli solo per chiarezza.
Adnan

0

In c, potresti essere in grado di fare dei progressi usando cscope. Fa un tentativo di comprendere la sintassi, quindi avrebbe la possibilità di sapere quando la lettera era una variabile.


0

Se questo è su più file, potresti considerare di dare un'occhiata a sed. Usa find per prendere i tuoi file e xargs plus sed per una sostituzione. Supponi di voler sostituire a con a_better_name in tutti i file che corrispondono a * .c, potresti farlo

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

Tieni presente che questo sostituirà TUTTE le occorrenze di a, quindi potresti volere una regex più robusta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.