Szybkie wyszukiwanie, ograniczone do funkcji C ++

13

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)

Jkerian
źródło

Odpowiedzi:

9

Oto jak bym to zrobił. Dodaj to do swojego.vimrc

vnoremap if [[O][

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

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...
James
źródło
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

Oszczędzam ci kilkaset linii kodu lh#dev#find_function_boundaries()

I dzięki mapowaniu DJ McMayhem

" Note that my vim settings requires two backslashes here instead of one
vnoremap / <esc>/\\%V

możemy zrobić, vif/patternaby wyszukać patternw bieżącej funkcji.

Możemy również usuwać funkcje za pomocą dif, szarpać je za pomocą yifitp.

Oto jak to wygląda po zastosowaniu na realistycznej funkcji C ++ (tzn. Bez wcięcia 0):Screencast: Wybierz funkcję C ++

Luc Hermitte
źródło
4

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>

szukaj w funkcji

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…

romainl
źródło
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:

wprowadź opis zdjęcia tutaj

Funkcja złożona ma wiele zastosowań size, ale nnie poprowadzi mnie do każdego użycia sizetej funkcji.

muru
źródło
3

Inny sposób:

  • użyj ctags itp., aby znaleźć funkcję celu, idź tam
  • przesuń kursor do przodu wewnątrz treści funkcji
  • użyj operatora wyszukiwania Osyo Manga (zależy od vim-operator-użytkownik ), aby przeszukać tylko bieżący blok. Na przykład:

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

VanLaser
źródło