Pracuję nad dość dużym projektem C ++. Jednym z bardziej frustrujących aspektów jego organizacji są bardzo duże funkcje umieszczone w śmiesznie dużych plikach.
Często chcę wyszukać dowolne wystąpienie określonej zmiennej globalnej lub wywołania funkcji, ograniczone do bieżącej funkcji. Czy istnieje dość prosty sposób na osiągnięcie tego?
(Mam zainstalowane ctagi i używam Tagbar ... co może być do tego pomocne)
Objaśnienie: vnoremap oznacza odwzorowanie lewej strony ifna prawą, [[mO][gdy jesteś w trybie wizualnym. ifoznacza W funkcji , chociaż możesz zmienić nazwę, jeśli chcesz. [[przeskakuje na początek funkcji. Oprzesuwa się na drugi koniec wizualnie zaznaczonego tekstu, a następnie ][przechodzi na koniec funkcji.
Tak więc, jeśli chcesz wyszukać w funkcji, teraz wejdź w tryb wizualny za pomocą vi wybierz całą funkcję za pomocą if. Teraz wyjdź z trybu wizualnego za pomocą <esc>i wyszukaj za pomocą /\%V. \%Vogranicza wyszukiwanie do wcześniej zaznaczonego tekstu. Jeśli nie chcesz uderzać, <esc>/\%Vmożesz również dodać to do .vimrc:
vnoremap / <esc>/\%V
Następnie sekwencja naciśnięć klawiszy wyglądałaby następująco:
vif/foo<enter>
i to znajdzie wszystkie wystąpienia foo w bieżącej funkcji.
Jedynym minusem tej metody jest to, że oczekuje, że otwierające i zamykające nawiasy klamrowe będą miały 0 wcięć. Jeśli regularnie pracujesz z kodem, który go nie ma, np
int foo() {
bar()
}
wtedy ta nieco bardziej skomplikowana wersja będzie działać:
vnoremap if ][ma%O'a
To tylko oczekuje, że nawias zamykający będzie miał 0 wcięć. Jeśli nawias otwierający ma wcięcia, nadal działa, chociaż zajmuje znak. Jeśli regularnie używasz znaku „a”, możesz go przenieść np
Niestety nie działa to dobrze z funkcjami C ++. W przeciwieństwie do funkcji C, prawdopodobnie będą wcięte (tak jest w przypadku funkcji elementów wbudowanych zdefiniowanych w definicji ich klasy i domyślnym wcięciem funkcji w przestrzeniach nazw). Twój pomysł można jednak zbudować dzięki zakresowi definicji funkcji, który można uzyskać za pomocą tagów ctag. Robię to w funkcji lh#dev#find_function_boundariesod lh-dev
Luc Hermitte
3
Niezłe podejście. Jeśli możesz niezawodnie znaleźć górną linię funkcji, możesz przejść do, {a następnie użyć, %aby dotrzeć do dolnej linii. Nie wiem, jak możesz znaleźć tę funkcję, uruchom w C ++, ale działa to vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
poprawnie
1
Odnośnie twojej ostatniej edycji. CTRL-]przeskakuje do znacznika pod kursorem. Nie do początku bieżącej funkcji. To nie pomoże
Luc Hermitte
Odnośnie nowej edycji. To nie jest takie proste. Trudność polega na tym, aby vim znał bieżącą funkcję. Gdyby miał te informacje, nie wymagałby pomocy tagów. Jedynym sposobem na uzyskanie informacji (z ctags) jest analiza poleceń skoku do deklaracji wygenerowanych przez ctags. Gdyby te polecenia były :linenumber, vim mógłby zrobić to, co robię w mojej wtyczce. Ale nie ma gwarancji, a te polecenia mogą być zamiast tego wyszukiwane /pattern- Vim nie może przetestować wszystkich wzorców, aby dowiedzieć się, który pasuje do bieżącej funkcji. IOW, nie jestem świadomy żadnej akcji vim, aby przejść do początku bieżącego funkcja
Luc Hermitte
6
Rozwiązanie DJ McMayhem zainspirowało mnie do napisania własnego, który opiera się na znakach ctag i matchit do prawidłowej analizy granic funkcji.
Trudna część została już wykonana przez lh-dev i lh-tags od kilku lat:
bieżący plik jest analizowany przez ctags z odpowiednimi opcjami
szukamy wszystkich definicji funkcji w bazie danych znaczników, która jest ograniczona do znaczników uzyskanych dla bieżącego pliku
dzięki DB mamy numery linii początkowej dla wszystkich funkcji (cóż, templatea inlineczęść może zostać pominięta przez ctags)
z prostym wyszukiwaniem iteracyjnym (można było przeprowadzić wyszukiwanie binarne, ale pliki powinny być „krótkie”), znaleziono początek bieżącej funkcji
Dzięki wtyczce matchit znajduje się również jej ostatnia linia - widzę, że uniwersalne ctags oferuje endpole, które może być używane z C, C ++, Python i Vim, które może być również użyte do znalezienia końca funkcji.
Zauważ, że wszelkie części tego algorytmu można zastąpić na podstawie typu pliku. tzn. wykrywanie granic funkcji Pythona może wyszukiwać defi analizować wcięcia, możemy po prostu szukać functionw javascript i tak dalej - innymi słowy, bieżąca wersja działa również z Javą, Vimem i innymi językami (wciąż mam trochę pracy zrobić dla Pythona)
Definiuję teraz dwa nowe mapowania: mapowanie w trybie wizualnym i mapowanie w trybie oczekiwania operatora:
onoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr>
xnoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr><esc>gv
Które polegają na:
function! lh#dev#_select_current_function() abort
let fn = lh#dev#find_function_boundaries(line('.'))
exe fn.lines[0]
normal! v
exe fn.lines[1]
endfunction
Znalezienie początku i końca funkcji może być trudne, szczególnie w języku bez functionsłowa kluczowego ... i wielu sprzecznych stylów wcięć.
Jeśli twoja funkcja kończy się samą nawiasem zamykającym na własnej linii (jak w 10 z 13 stylów wymienionych tutaj ), możesz wizualnie wybrać ją za pomocą czegoś takiego:
xnoremap if /^\s*}<CR><Esc>V%
Stamtąd wyszukiwanie w fooramach Twojej funkcji jest tylko kwestią:
:'<,'>g/foo/#
Podsumowując, możemy uzyskać całkiem niezłe mapowanie:
xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>
To powiedziawszy, mapowanie trybu wizualnego byłoby prawdopodobnie łatwe do oszukiwania przez a while, ifwięc prawdopodobnie skorzystałoby z odrobiny dopracowania. Zachowanie selekcji wizualnej może nie być zbyt dobrym pomysłem…
To po prostu wybiera następny blok, który można znaleźć. To nie działa w ogóle po dodaniu if, for, while, itd.
James
3
Niedoskonałym rozwiązaniem jest stosowanie fałd . Złożyć wszystko:
set foldmethod=syntax
set foldlevel=0
set foldminlines=0
Powiedz Vimowi, aby nie otwierał zagiętych obszarów dla wyników wyszukiwania:
set foldopen-=search
A następnie otwórz zakładkę na funkcji, o której mowa ( zO).
Teraz wszystkie trafienia dla wyszukiwanego tekstu w złożonym obszarze spowodują, że Vim przeskoczy raz do linii składania, a następnie przejdzie do następnego trafienia.
Na przykład w poniższym przypadku:
Funkcja złożona ma wiele zastosowań size, ale nnie poprowadzi mnie do każdego użycia sizetej funkcji.
" configure the plugin (once, vimrc):
map g/ <Plug>(operator-search)
" 1. use ctags etc. to jump to the beginning of the target function;
" 2. move cursor inside the function definition, then:
g/i{
... teraz możesz wstawić wyszukiwane hasło w podanym monicie; naciśnij, naby zobaczyć, w jaki sposób wyniki wyszukiwania są ograniczone do aktualnie udostępnianego obiektu ruchu / tekstu. Ponieważ jest to operator Vima (tzn. Kompozycyjny), jeśli masz dobry obiekt tekstowy, nie musisz nawet poruszać się w treści definicji przed wyszukiwaniem, ale bezpośrednio używasz czegoś podobnego g/iflub podobnego.
lh#dev#find_function_boundaries
od lh-dev{
a następnie użyć,%
aby dotrzeć do dolnej linii. Nie wiem, jak możesz znaleźć tę funkcję, uruchom w C ++, ale działa tovnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
CTRL-]
przeskakuje do znacznika pod kursorem. Nie do początku bieżącej funkcji. To nie pomoże:linenumber
, vim mógłby zrobić to, co robię w mojej wtyczce. Ale nie ma gwarancji, a te polecenia mogą być zamiast tego wyszukiwane/pattern
- Vim nie może przetestować wszystkich wzorców, aby dowiedzieć się, który pasuje do bieżącej funkcji. IOW, nie jestem świadomy żadnej akcji vim, aby przejść do początku bieżącego funkcjaRozwiązanie DJ McMayhem zainspirowało mnie do napisania własnego, który opiera się na znakach ctag i matchit do prawidłowej analizy granic funkcji.
Trudna część została już wykonana przez lh-dev i lh-tags od kilku lat:
template
ainline
część może zostać pominięta przez ctags)end
pole, które może być używane z C, C ++, Python i Vim, które może być również użyte do znalezienia końca funkcji.Zauważ, że wszelkie części tego algorytmu można zastąpić na podstawie typu pliku. tzn. wykrywanie granic funkcji Pythona może wyszukiwać
def
i analizować wcięcia, możemy po prostu szukaćfunction
w javascript i tak dalej - innymi słowy, bieżąca wersja działa również z Javą, Vimem i innymi językami (wciąż mam trochę pracy zrobić dla Pythona)Definiuję teraz dwa nowe mapowania: mapowanie w trybie wizualnym i mapowanie w trybie oczekiwania operatora:
Które polegają na:
Oszczędzam ci kilkaset linii kodu
lh#dev#find_function_boundaries()
I dzięki mapowaniu DJ McMayhem
możemy zrobić,
vif/pattern
aby wyszukaćpattern
w bieżącej funkcji.Możemy również usuwać funkcje za pomocą
dif
, szarpać je za pomocąyif
itp.Oto jak to wygląda po zastosowaniu na realistycznej funkcji C ++ (tzn. Bez wcięcia 0):
źródło
Znalezienie początku i końca funkcji może być trudne, szczególnie w języku bez
function
słowa kluczowego ... i wielu sprzecznych stylów wcięć.Jeśli twoja funkcja kończy się samą nawiasem zamykającym na własnej linii (jak w 10 z 13 stylów wymienionych tutaj ), możesz wizualnie wybrać ją za pomocą czegoś takiego:
Stamtąd wyszukiwanie w
foo
ramach Twojej funkcji jest tylko kwestią:Podsumowując, możemy uzyskać całkiem niezłe mapowanie:
To powiedziawszy, mapowanie trybu wizualnego byłoby prawdopodobnie łatwe do oszukiwania przez a
while
,if
więc prawdopodobnie skorzystałoby z odrobiny dopracowania. Zachowanie selekcji wizualnej może nie być zbyt dobrym pomysłem…źródło
if
,for
,while
, itd.Niedoskonałym rozwiązaniem jest stosowanie fałd . Złożyć wszystko:
Powiedz Vimowi, aby nie otwierał zagiętych obszarów dla wyników wyszukiwania:
A następnie otwórz zakładkę na funkcji, o której mowa (
zO
).Teraz wszystkie trafienia dla wyszukiwanego tekstu w złożonym obszarze spowodują, że Vim przeskoczy raz do linii składania, a następnie przejdzie do następnego trafienia.
Na przykład w poniższym przypadku:
Funkcja złożona ma wiele zastosowań
size
, alen
nie poprowadzi mnie do każdego użyciasize
tej funkcji.źródło
Inny sposób:
użyj operatora wyszukiwania Osyo Manga (zależy od vim-operator-użytkownik ), aby przeszukać tylko bieżący blok. Na przykład:
... teraz możesz wstawić wyszukiwane hasło w podanym monicie; naciśnij,
n
aby zobaczyć, w jaki sposób wyniki wyszukiwania są ograniczone do aktualnie udostępnianego obiektu ruchu / tekstu. Ponieważ jest to operator Vima (tzn. Kompozycyjny), jeśli masz dobry obiekt tekstowy, nie musisz nawet poruszać się w treści definicji przed wyszukiwaniem, ale bezpośrednio używasz czegoś podobnegog/if
lub podobnego.źródło