Ricerca rapida, limitata a una funzione C ++


13

Lavoro su un progetto C ++ piuttosto ampio. Uno degli aspetti più frustranti della sua organizzazione sono le funzioni molto grandi collocate all'interno di file ridicolmente grandi.

Spesso voglio cercare qualsiasi istanza di una particolare variabile globale o chiamata di funzione, limitata alla funzione corrente. Esiste una formula ragionevolmente semplice per raggiungere questo obiettivo?

(Ho installato i tag e utilizzo Tagbar ... che potrebbe essere utile per questo)

Risposte:


9

Ecco come lo farei. Aggiungi questo al tuo.vimrc

vnoremap if [[O][

Spiegazione: vnoremap significa mappare il lato sinistro ifsul lato destro [[mO][mentre si è in modalità visiva. ifsignifica In Funzione , anche se puoi rinominarlo se vuoi. [[salta all'inizio della funzione. Osi sposta all'altra estremità del testo visivamente selezionato, quindi si ][sposta alla fine della funzione.

Quindi, se si desidera cercare in una funzione, ora si entra in modalità visiva con ve si seleziona l'intera funzione con if. Ora esci dalla modalità visiva con <esc>e cerca con /\%V. \%Vlimita la ricerca al testo precedentemente selezionato. Se non vuoi colpire <esc>/\%Vpuoi anche aggiungere questo al tuo .vimrc:

vnoremap / <esc>/\%V

Quindi, la sequenza di sequenze di tasti sarebbe simile a:

vif/foo<enter>

e questo troverà tutte le occorrenze di pippo nella funzione corrente.


L'unico aspetto negativo di questo metodo è che si aspetta che le parentesi graffe di apertura e chiusura abbiano entrambi un rientro 0. Se lavori regolarmente con codice che non ha questo, ad es

int foo() {
    bar()
}

allora questa versione leggermente più complicata funzionerà:

vnoremap if ][ma%O'a

Questo si aspetta solo che la parentesi graffa di chiusura abbia 0 rientri. Se la parentesi graffa di apertura ha dei rientri, funziona ancora, anche se occupa un segno. Se usi regolarmente il segno "a", puoi spostarlo ad es

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...

Purtroppo questo non funziona bene con le funzioni C ++. A differenza delle funzioni C, è probabile che siano rientrate (è il caso delle funzioni dei membri inline definite nella definizione della loro classe e con il rientro predefinito delle funzioni all'interno degli spazi dei nomi). Tuttavia, la tua idea può essere costruita grazie all'intervallo di definizione delle funzioni che può essere ottenuto con tag. Lo faccio nella funzione lh#dev#find_function_boundariesdi lh-dev
Luc Hermitte,

3
Bel approccio. Se riesci a trovare in modo affidabile la riga superiore della funzione, puoi spostarti su {e quindi utilizzare %per raggiungere la riga inferiore. Non sono sicuro di come potresti trovare l'avvio della funzione in C ++, ma per Javascript funziona bene:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle,

1
Per quanto riguarda la tua ultima modifica. CTRL-]passa al tag sotto il cursore. Non all'inizio della funzione corrente. Non aiuterà.
Luc Hermitte,

Per quanto riguarda la nuova modifica. Non è così semplice La difficoltà è far conoscere a vim l'attuale funzione. Se avesse le informazioni, non richiederebbe aiuto ctags. L'unico modo per ottenere le informazioni (da ctags) è analizzare i comandi di salto a dichiarazione prodotti da ctags. Se questi comandi fossero :linenumber, vim potrebbe fare quello che faccio nel mio plugin. Ma non esiste alcuna garanzia e questi comandi possono invece essere ricerche /pattern: Vim non può testare tutti i pattern per sapere quale corrisponde alla funzione corrente. ORA, non sono a conoscenza di alcuna azione di VIM per saltare all'inizio della corrente funzione
Luc Hermitte,

6

La soluzione di DJ McMayhem mi ha ispirato a scrivere il mio che si basa su tag e matchit per fare una corretta analisi dei confini delle funzioni.

La parte difficile è già stata fatta da lh-dev e lh-tag da diversi anni:

  • il file corrente viene analizzato tramite tag con le giuste opzioni
  • cerchiamo tutte le definizioni delle funzioni nel database dei tag che è limitato ai tag ottenuti per il file corrente
  • grazie al DB, abbiamo i numeri della linea di partenza per tutte le funzioni (beh, la parte templatee inlinepuò essere mancata dai tag)
  • con una semplice ricerca iterativa (avrebbe potuto essere eseguita una ricerca binaria, ma si suppone che i file siano "brevi"), si trova l'inizio della funzione corrente
  • E grazie al plug-in matchit, viene trovata anche la sua riga finale - vedo che ctags universali offre un endcampo che può essere usato con C, C ++, Python e Vim che potrebbe anche essere usato per trovare la fine di una funzione.

Si noti che qualsiasi parte di questo algoritmo potrebbe essere sovrascritta in base al tipo di file. cioè il rilevamento dei limiti delle funzioni di Python potrebbe cercare defe analizzare il rientro, potremmo semplicemente cercare functionin javascript e così via - In altre parole, la versione corrente funziona anche con Java, Vim e alcune altre lingue (ho ancora del lavoro fare per Python)

Quindi definisco ora due nuovi mapping: un mapping in modalità visiva e un mapping in modalità operatore in sospeso:

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

Che si basano su:

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

Ti risparmio le diverse centinaia di righe di codice di lh#dev#find_function_boundaries()

E grazie alla mappatura di DJ McMayhem

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

possiamo fare un vif/patternper cercare patternnella funzione corrente.

Possiamo anche eliminare le funzioni con dif, strapparle con yif, ecc.

Ecco come appare se applicato su una funzione C ++ realistica (ovvero non indentata):Screencast: selezionare la funzione C ++


4

Trovare l'inizio e la fine di una funzione può essere difficile, specialmente in una lingua senza una functionparola chiave ... e molti stili di rientro contrastanti.

Se la tua funzione termina con una parentesi graffa chiusa da sola sulla sua stessa linea (come in 10 dei 13 stili elencati qui ), puoi selezionarla visivamente con qualcosa del genere:

xnoremap if /^\s*}<CR><Esc>V%

Da lì, la ricerca fooall'interno della tua funzione è solo una questione di:

:'<,'>g/foo/#

Mettendo tutto insieme, possiamo ottenere una mappatura piuttosto piacevole:

xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>

cerca in funzione

Detto questo, la mappatura della modalità visiva verrebbe probabilmente facilmente ingannata da un whileo un ifquindi trarrebbe probabilmente beneficio da un po 'di lucidatura. Inoltre, mantenere la selezione visiva potrebbe non essere un'ottima idea ...


Questo seleziona solo il blocco successivo che può trovare. Non funziona affatto una volta aggiunto if, for, while, ecc
James

3

Una soluzione imperfetta sta usando le pieghe . Piega tutto:

set foldmethod=syntax
set foldlevel=0
set foldminlines=0

Di 'a Vim di non aprire le aree piegate per i risultati della ricerca:

set foldopen-=search

E quindi apri la piega sulla funzione in questione ( zO).

Ora, tutti i risultati per la ricerca del testo in una regione piegata comporteranno Vim che salta sulla linea di piegatura una volta, quindi passa al colpo successivo.

Ad esempio, nel caso seguente:

inserisci qui la descrizione dell'immagine

La funzione piegata ha molti usi di size, ma nnon mi guiderà ad ogni uso di sizequella funzione.


3

Un altro modo:

  • usa i tag ecc. per trovare la funzione target, vai lì
  • sposta il cursore in avanti all'interno del corpo della funzione
  • usa l' operatore di ricerca di Osyo Manga (dipende da vim-operator-user ) per cercare solo all'interno del blocco corrente. Per esempio:

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

... ora puoi inserire il termine di ricerca al prompt indicato; premere nper vedere come i risultati della ricerca sono limitati al movimento / oggetto di testo attualmente forniti. Dato che si tratta di un operatore Vim (cioè compostabile), se si dispone di una buona funzione oggetto-testo, non è nemmeno necessario spostarsi all'interno del corpo della definizione prima di cercare, ma utilizzare direttamente qualcosa di simile g/ifo simile.

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.