In una base di codice piuttosto ampia con pochi livelli c'è un modo in vim o dalla riga di comando per trovare tutte le classi derivate da una base classe? grep è un'opzione ma può essere lento poiché grep non indicizza.C++, cscope, ctags e vim: ricerca di classi che ereditano da questa
risposta
Né cscope né ctags ci permettono di affrontare con l'ereditarietà direttamente, ma è relativamente facile aggirare questa limitazione perché le classi derivate sono indicizzati.
cscope
In cscope, alla ricerca di "simbolo C" Foobar
solito elenca classe originale e classi che ereditano da essa. Poiché la ricerca viene eseguita su un database, è veloce come un fulmine.
In alternativa, è possibile utilizzare le funzionalità egrep ricerca di cscope con un modello come :.*Foobar
per elencare solo classi che ereditano da Foobar
.
Quindi, anche se non abbiamo un comando dedicato "Trova classi che ereditano da questa classe", possiamo svolgere il lavoro senza grandi sforzi.
ctags
Mentre ctags consente di includere informazioni eredità con --fields=+i
, che le informazioni non possono essere utilizzati direttamente in Vim. Il campo inherits
viene analizzato da Vim, tuttavia, quindi potrebbe essere possibile creare una soluzione rapida e sporca utilizzando taglist()
.
ACK, ag
Questi due programmi funzionano più o meno come grep, ma sono mirati verso la ricerca nel codice sorgente in modo che siano veramente più veloce di grep.
Nel mio config Vim, :grep
è impostato per eseguire il programma ag
invece di quello predefinito grep
così, alla ricerca di classi derivate dalla classe sotto il cursore sarà simile:
:grep :.*<C-r><C-w><CR>
Qui ci sono le linee interessate dal mio ~/.vimrc
:
if executable("ag")
set grepprg=ag\ --nogroup\ --nocolor\ --ignore-case\ --column
set grepformat=%f:%l:%c:%m,%f:%l:%m
endif
Ho notato un po 'di velocità usando fugitive e vim con il comando ': Ggrep'. Questo miglioramento richiede che il codice sia un repo git che non è stato menzionato nel mio post ma è un'altra alternativa. –
In lh-cpp, definisco il comando :Children
. Si basa su un database di ctags e, di conseguenza, è piuttosto limitato.
Sono necessari due parametri facoltativi: lo spazio dei nomi da cercare (non ho trovato un modo per evitarlo) e il nome della classe genitore ->:Children [!] {namespace} {parent-class}
.
Il comando tenta di memorizzare quante più informazioni possibile nella cache. Quindi, quando le informazioni pertinenti cambiano nel database ctags, la cache deve essere aggiornata. E 'fatto da sbattere il comando ->:Children!
non credo vim è lo strumento corretto per elencare tutte le classi figlie. Invece, faremmo meglio a usare doxygen per generare documentazione per il codice sorgente.Sebbene il doxygen abbia bisogno di tempo, possiamo usare il documento/diagrammi per tutte le classi, che è chiaro e veloce.
Ciò presuppone tuttavia che si stia sviluppando utilizzando un'interfaccia grafica. A volte, devo usare minty (cygwins terminal) su ssh il che significa che la dev box dovrebbe avere un web server per ospitare i file doxygen. –
Sì, esattamente. E un server Linux/Unix, che ha già fornito SSH, è facile da implementare un server web, si consiglia inoltre di abilitare PHP nel server web che fornisce un semplice motore di ricerca all'interno delle pagine doxygen. – Chandler
Sia Eclipse che SlickEdit hanno un modo di elencare gli alberi di ereditarietà per le classi e anche un elenco ad albero di metodi sovrascritti. Si chiama Gerarchia di tipi in Eclipse ed è una delle funzioni più utili in un IDE quando si codifica in un linguaggio OO. Doxygen è davvero utile ma è eccessivo quando devi solo dare una rapida occhiata a "Type Hierarchy". –
Se costruisci i file tag con Esuberante CTags utilizzando le informazioni di ereditarietà (see the --fields option), quindi il seguente script funziona. Aggiunge un comando :Inherits
che accetta il nome di una classe (ad esempio :Inherits Foo
) o un'espressione regolare.
Come il comando :tag
, si indica che si desidera la ricerca con un'espressione regolare precedendola con un carattere '\', ad es. :Inherits \Foo.*
.
I risultati sono messi in lista di posizione della finestra, che si sfoglia con :ll
, :lne
, :lp
, ecc VIM non sembra consentire script per modificare l'elenco di tag che è quello che preferisco.
Se vi state chiedendo il motivo per cui io non uso taglist()
per questo, è perché taglist()
è incredibilmente lento su grandi file di tag. Il post originale aveva una versione che utilizzava taglist()
, se sei curioso puoi consultare la cronologia delle modifiche.
" Parse an Exuberant Ctags record using the same format as taglist()
"
" Throws CtagsParseErr if there is a general problem parsing the record
function! ParseCtagsRec(record, tag_dir)
let tag = {}
" Parse the standard fields
let sep_pos = stridx(a:record, "\t")
if sep_pos < 1
throw 'CtagsParseErr'
endif
let tag['name'] = a:record[:sep_pos - 1]
let tail = a:record[sep_pos + 1:]
let sep_pos = stridx(tail, "\t")
if sep_pos < 1
throw 'CtagsParseErr'
endif
" '/' will work as a path separator on most OS's, but there
" should really be an OS independent way to build paths.
let tag['filename'] = a:tag_dir.'/'.tail[:sep_pos - 1]
let tail = tail[sep_pos + 1:]
let sep_pos = stridx(tail, ";\"\t")
if sep_pos < 1
throw 'CtagsParseErr'
endif
let tag['cmd'] = tail[:sep_pos - 1]
" Parse the Exuberant Ctags extension fields
let extensions = tail[sep_pos + 3:]
for extension in split(extensions, '\t')
let sep_pos = stridx(extension, ':')
if sep_pos < 1
if has_key(tag, 'kind')
throw 'CtagsParseErr'
endif
let tag['kind'] = extension
else
let tag[extension[:sep_pos - 1]] = extension[sep_pos + 1:]
endif
endfor
return tag
endfunction
" Find all classes derived from a given class, or a regex (preceded by a '/')
" The results are placed in the current windows location list.
function! Inherits(cls_or_regex)
if a:cls_or_regex[0] == '/'
let regex = a:cls_or_regex[1:]
else
let regex = '\<'.a:cls_or_regex.'\>$'
endif
let loc_list = []
let tfiles = tagfiles()
let tag_count = 0
let found_count = 0
for file in tfiles
let tag_dir = fnamemodify(file, ':p:h')
try
for line in readfile(file)
let tag_count += 1
if tag_count % 10000 == 0
echo tag_count 'tags scanned,' found_count 'matching classes found. Still searching...'
redraw
endif
if line[0] == '!'
continue
endif
let tag = ParseCtagsRec(line, tag_dir)
if has_key(tag, 'inherits')
let baselist = split(tag['inherits'], ',\s*')
for base in baselist
if match(base, regex) != -1
let location = {}
let location['filename'] = tag['filename']
let cmd = tag['cmd']
if cmd[0] == '/' || cmd[0] == '?'
let location['pattern'] = cmd[1:-2]
else
let location['lnum'] = str2nr(cmd)
endif
call add(loc_list, location)
let found_count += 1
endif
endfor
endif
endfor
catch /^OptionErr$/
echo 'Parsing error: Failed to parse an option.'
return
catch /^CtagsParseErr$/
echo 'Parsing error: Tags files does not appear to be an Exuberant Ctags file.'
return
catch
echo 'Could not read tag file:' file
return
endtry
endfor
call setloclist(0, loc_list)
echo tag_count 'tags scanned,' found_count 'matching classes found.'
endfunction
command! -nargs=1 -complete=tag Inherits call Inherits('<args>')
Io non la penso così, cscope e ctags si basano sulla espressione regolare, ma non la sintassi come IDE –
Avete considerato [Ack] (http://beyondgrep.com/), [Ag Silver Surfer] (https://github.com/ggreer/the_silver_searcher) o [git grep] (http://git-scm.com/docs/git-grep)? Questi sono tutti in genere molto più veloci di grep. –
Sono anche interessato a questo. Attualmente utilizzo Eclipse e SlickEdit per farlo. In Eclipse, questa funzionalità è chiamata Gerarchia di tipi. C'è un progetto chiamato eclim che integra le funzionalità di Eclipse in Vim, questo è il più vicino che ho visto a Vim, sfortunatamente, eclim mangia molta RAM e si blocca costantemente in Windows, molto probabilmente a causa di Eclipse e richiede Eclipse per multare sintonizzare le impostazioni di memoria .. –