2014-09-04 22 views
5

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

+0

Io non la penso così, cscope e ctags si basano sulla espressione regolare, ma non la sintassi come IDE –

+0

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

+0

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

risposta

3

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 
+0

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

2

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!

1

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.

+0

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

+0

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

+0

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

2

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>')