Jak szybko zmienić nazwy zmiennych w Vimie?

96

Używam Vima do czytania wielu kodów C i Perl zawierających wiele jednoliterowych nazw zmiennych.

Byłoby miło mieć jakieś polecenie zmiany nazwy zmiennej na coś bardziej znaczącego, gdy jestem w trakcie czytania kodu, aby móc szybciej przeczytać resztę.

Czy w Vimie jest jakieś polecenie, które pozwoliłoby mi to szybko zrobić?

Myślę, że wyrażenia regularne nie zadziałałyby, ponieważ:

  1. ta sama jednoliterowa nazwa może mieć różne cele w różnych blokach zakresu; i

  2. ta sama kombinacja liter może być częścią innej dłuższej nazwy zmiennej, literału ciągu lub komentarza.

Czy są jakieś znane rozwiązania?

Aditya Mukherji
źródło

Odpowiedzi:

199

Poniżej opisano, jak zmienić nazwę zmiennej zdefiniowanej w bieżącym zakresie {}.

Przesuń kursor do zmiennej użycie. Naciśnij gd. Co oznacza - przesuń kursor do definicji. Teraz naciśnij [{- to przeniesie Cię do początku zakresu. Wciśnij V- włączy wybór linii wizualnej. Wciśnięcie %- przeskoczy w drugą stronę }i wybierze cały zakres. Naciśnięcie :s/- rozpoczęcie polecenia zamiany. <C-R>/- wstawi wzorzec pasujący do nazwy zmiennej (tej, na której byłeś przed naciśnięciem gd). /newname/gc<CR>- zainicjuje wyszukiwanie i zamieni na potwierdzenie przy każdym dopasowaniu.

Teraz musisz nagrać makra lub jeszcze lepiej - zmapować klucz.

Oto końcowe mapowania:

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

Umieść to w swoim .vimrclub po prostu wykonaj. Po tym naciśnięciu grzmiennej lokalnej przeniesiesz się do :spolecenia, w którym po prostu należy wprowadzić new_variable_namei nacisnąć Enter.

Mykoła Golubyev
źródło
40
+1 za nauczenie się więcej niż 5 nowych sztuczek Vima, które powinienem był znać wcześniej. Dzięki
Kenny Meyer,
6
Uwaga: gd nie działa w celu zlokalizowania zmiennej w bezpośrednim zakresie definicji w trybie JavaScript w macvim. Prowadzi mnie do pierwszego użycia nazwy zmiennej w jakiejś funkcji w pliku :( Jeśli jesteś w jakimś zakresie i chcesz go wybrać, "va {" - "wizualny wybór wokół {" - jest drogą do zrobienia Myślę
Srikumar
3
Nieco ulepszona wersja: gist.github.com/048616a2e3f5d1b5a9ad pyta użytkownika, pokazuje starą nazwę, przywraca pozycję kursora po zamianie
Andy Ray
7
+1 bardzo dobre vimgineering (myślę, że właśnie wymyśliłem nowy termin). Uwaga: faktycznie musiałem :dwukrotnie nacisnąć dwukropek ( ). Za pierwszym razem zobaczyłem :'<,'>. Gdybym po prostu s/stamtąd pisał , nie działało; Musiałem wpisać inny dwukropek przed s/.
Kelvin
6
Zauważ, że nie potrzebujesz <C-R>w poleceniu substitute, po prostu pominięcie wyszukiwania spowoduje, że vim użyje ostatnio szukanego wzorca, który w tym przypadku został utworzony z gdpolecenia. Tak więc po prostu :s//<newname>/gcwystarczy.
shangxiao
11

Wiem, że to stare pytanie, a droga @ mykola-golubyev JEST oczywiście najlepszą odpowiedzią dla konkretnego przypadku w pytaniu OP (które, jak zakładam, przechodzi przez zaciemniony kod, w którym prawdopodobnie będziesz mieć wiele bloków o tych samych nazwach var) ; ale przy takiej nazwie pytania wiele osób przychodzących tutaj z wyszukiwań w Google prawdopodobnie szuka mniej specyficznych dla sytuacji sposobów zmiany nazw zmiennych w VIM - a te mogą być bardziej zwięzłe

Jestem zaskoczony, że nikt nie zasugerował w ten sposób:

* :s// NOWE IMIE /gc

To *jest to samo co gn- wyszukuje następne wystąpienie słowa pod kursorem ORAZ staje się ostatnim szukanym wzorcem, więc kiedy pominiesz wzorzec wyszukiwania w poleceniu substytucji, VIM zakłada, że ​​jest to wzorzec do wyszukania.

W przypadku małych ilości kopii var, jeszcze szybsza:

* cw NEWNAME, <esc> a następnie powtórz n.dla innych wystąpień

Szukaj wystąpienia, cwto polecenie zmiany słowa , nprzechodzi do następnego wystąpienia ostatnio wyszukiwanego terminu i .powtarza ostatnie polecenie (czyli zmień słowo na NOWA NAZWA )

(Podziękowania dla mnie, wiedząc o tym wszystkim, trafiają do @doomedbunnies na Reddit )

Kolejna fajna sztuczka to: ( Podziękowania dla @ nobe4 )

* cgn NEWNAME, <esc> a następnie powtórz .dla innych wystąpień

cgnto „zmień wszystko, co jest wynikiem (znajdź następne wystąpienie)”. Teraz, gdy jest to ostatnie polecenie , nie potrzebujesz, naby przejść do następnego wystąpienia, więc ponownie mniej pociągnięć i, co ważniejsze, nie ma potrzeby zmiany ni .. Ale oczywiście ma tę wadę, że nie ma sposobu, aby pominąć wystąpienie.

Oto kilka korzyści:

  • bez mapowania, bez .vimrc (lub init.vim), więc możesz go użyć w dowolnej napotkanej kopii VIM (np. szybkie zadanie na jakimś VPS lub komputerze twojego przyjaciela, gdzie skonfigurowanie VIM na swój sposób zniweczy cel `` szybkiego '' )
  • używanie *lub gndo zaznaczania słów jest bardzo szybkie - wystarczy jedno naciśnięcie klawisza (cóż, powiedzmy 1,5)
  • używając *lub gnupewnia się, że nie dostaniesz żadnych dopasowań w innych słowach, tak samo jak :%s/<C-R>//gc. Pokonuje :%s/\<OLDNAME\>/NEWNAME/gcręczne wpisywanie : osobiście często zapominam \<o ograniczaniu dopasowań tylko do całych słów.
  • Nieużywanie zakresu spowoduje tylko kilka dodatkowych pociągnięć, naby pominąć niechciane dopasowania - prawdopodobnie nawet mniej niż dodatkowe pociągnięcia potrzebne do ograniczenia zakresu. W normalnych okolicznościach Twoje zmienne są najprawdopodobniej nieco zlokalizowane w określonym bloku kodu.
Ivan Bartsov
źródło
10

AFAIK, w VIM nie ma rzeczywistej obsługi refaktoryzacji. Podczas zmiany nazwy z zamiarem refaktora zwykle podejmuję następujące środki ostrożności:

  1. Ogranicz zakres zmiany za pomocą znaków.
  2. Przy wprowadzaniu wyrażenia regularnego, nawiasuj nazwę za pomocą \ <i>. To sprawi, że będzie pasował do całego słowa, co zmniejszy typy nieprawidłowych zmian, które wystąpią.
  3. Nie wykonuj wymiany wielowierszowej, aby zmniejszyć szanse na złą wymianę
  4. Przejrzyj dokładnie różnicę w kodzie, jeśli jest to coś innego niż niewielka zmiana.

Moja końcowa zmiana wygląda mniej więcej tak

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

Chciałbym się mylić co do tego, że nie ma narzędzia do refaktoryzacji dla VIM, ale go nie widziałem.

JaredPar
źródło
W Perlu możesz również dodać typ do wzorca wyszukiwania. czyli $ dla skalarów, @ dla tablic,% dla skrótów
Nathan Fellman
@Nathan: niestety w Perlu (5.X) jest trochę trudniej, ponieważ sigil tablic i skrótów zmienia się wraz z użyciem:% hash -> cały hash, $ hash {klucz} -> pojedyncza wartość, @hash { qw / ab /} hasz.
user55400
8

Umieść to w swoim .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

Zadzwoń za pomocą :call Rnvar()

expand("<cword>")pobiera słowo pod kursorem. Zastosowania ciąg wyszukiwania %dla file-zakresu i \(\W\)wzory szukać znaków spoza tekstu na granicy słowa do zastąpienia, i zapisać je w zmiennych \1i \2tak być ponownie umieszczona w strukturze zastępczej.

Mikrofon
źródło
3

Możesz użyć modyfikatora 'c' w wyszukiwaniu globalnym i zastąpić, który poprosiłby Cię o potwierdzenie każdej zamiany. Zajmie to więcej czasu, ale może zadziałać w przypadku niehumongicznego pliku kodu:

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

C oznacza potwierdzenie.

Adnan
źródło
I oznacza ignorowanie przypadku. Chcesz c, potwierdź każdą zmianę.
Michael Kristofik
ups .. przepraszam za to .. Naprawiono odpowiedź
Adnan
Odpowiedź nadal nie została do końca poprawiona;)
user55400
czy miałeś na myśli uciekających $? To jest coś w rodzaju moich osobistych preferencji. $ działa bez ucieczki, a także z i ponieważ w świecie wyrażeń regularnych i w vi $ ma specjalne znaczenie, lubię uciec od tego tylko dla przejrzystości.
Adnan
0

W c możesz poczynić postępy przy użyciu cscope. Podejmuje próbę zrozumienia składni, więc miałby szansę dowiedzieć się, kiedy litera jest zmienną.

Kim Reece
źródło
0

Jeśli dotyczy to wielu plików, możesz rozważyć przyjrzenie się sedowi. Użyj find, aby pobrać pliki i xargs plus sed do wymiany. Powiedzmy, że chcesz zastąpić a_better_name we wszystkich plikach pasujących do * .c, możesz to zrobić

odnaleźć . -name "* .c" | xargs sed -i -e 's / a / a_ lepsza_nazwa / g'

Pamiętaj, że spowoduje to zastąpienie WSZYSTKICH wystąpień a, więc możesz potrzebować bardziej niezawodnego wyrażenia regularnego.

Drew Olson
źródło