2014-09-04 4 views
5

In einer ziemlich großen Codebasis mit ein paar Layern gibt es einen Weg in vim oder von der Kommandozeile aus alle Klassen zu finden, die von einer Basis abgeleitet sind Klasse? grep ist eine Option, kann aber langsam sein, da grep nicht indexiert.C++, cscope, ctags und vim: Finden von Klassen, die von dieser Instanz stammen

+0

Ich glaube nicht, cscope und ctags auf der regex basieren aber nicht wie IDE Syntax –

+0

Haben Sie darüber nachgedacht [Ack] (http://beyondgrep.com/), [Ag der Silver Surfer] (https://github.com/ggreer/the_silver_searcher) oder [git grep] (http://git-scm.com/docs/git-grep)? Diese sind in der Regel viel schneller als Grep. –

+0

Ich bin auch daran interessiert. Ich benutze derzeit Eclipse und SlickEdit, um dies zu tun. In Eclipse wird diese Funktionalität als Typhierarchie bezeichnet. Es gibt ein Projekt namens eclim, das die Eclipse-Funktionalität in Vim integriert, das ist das nächste, was ich in Vim gesehen habe. Eclim isst leider viel RAM und stürzt immer wieder in Windows ab, höchstwahrscheinlich aufgrund von Eclipse und der Forderung nach Eclipse tune Speichereinstellungen .. –

Antwort

3

Weder cscope noch ctags uns mit Vererbung direkt behandeln lassen, aber es ist relativ leicht zu umgehen diese Einschränkung, da abgeleiteten Klassen sind auch indiziert.

cscope

In cscope, für "C Symbol" auf der Suche Foobar listet in der Regel der ursprünglichen Klasse und Klassen von ihm erben. Da die Suche gegen eine Datenbank durchgeführt wird, ist sie blitzschnell.

Alternativ können Sie cscope die egrep Suchfunktionen mit einem Muster wie :.*Foobar zur Liste nur Klassen von Foobar vererben verwenden.

Also, auch wenn wir keinen dedizierten Befehl "Klassen von dieser Klasse erben" haben, können wir die Arbeit ohne viel Aufwand erledigen.

ctags

Während ctags Sie mit --fields=+i Vererbungsinformationen enthalten können, können diese Informationen nicht direkt in Vim verwendet werden. Das Feld inherits wird jedoch von Vim analysiert. Daher ist es möglicherweise möglich, eine schnelle und schmutzige Lösung mit taglist() zu erstellen.

ack, ag

Diese beiden Programme funktionieren mehr oder weniger wie grep, aber sie sind in Richtung auf die Suche im Quellcode gezielt so sind sie wirklich schneller als grep.

In meinem Vim Config wird :grep gesetzt grep das ag Programm anstelle des Standard laufen würde so, die Suche nach Klassen abgeleitet aus der Klasse unter dem Cursor wie folgt aussehen: sind

:grep :.*<C-r><C-w><CR> 

Hier werden die entsprechenden Zeilen von meinem ~/.vimrc:

if executable("ag") 
    set grepprg=ag\ --nogroup\ --nocolor\ --ignore-case\ --column 
    set grepformat=%f:%l:%c:%m,%f:%l:%m 
endif 
+0

Ich bemerke etwas beschleunigen mit flüchtigen und vim mit dem ': Ggrep' Befehl. Diese Verbesserung erfordert, dass der Code ein git Repo ist, der in meinem Post nicht erwähnt wurde, aber eine andere Alternative ist. –

2

In lh-cpp definiere ich den Befehl :Children. Es beruht auf einer Ctags-Datenbank und ist daher sehr begrenzt.

Es braucht zwei optionale Parameter: den Namespace, nach dem gesucht werden soll (ich habe keinen Weg gefunden, dies zu vermeiden), und den Namen der Elternklasse ->:Children [!] {namespace} {parent-class}.

Der Befehl versucht, so viele Informationen wie möglich zwischenzuspeichern. Wenn sich relevante Informationen in der Datenbank ctags ändern, muss daher der Cache aktualisiert werden. Es wird durch hämmern den Befehl getan ->:Children!

1

ich glaube nicht, vim das richtige Werkzeug ist, alle untergeordneten Klassen aufzulisten. Stattdessen sollten wir besser das doxygen verwenden, um Dokumentation für den Quellcode zu generieren.Obwohl der Doxygen einige Zeit benötigt, können wir das Dokument/Diagramme für alle Klassen verwenden, was klar und schnell ist.

+0

Dies wird jedoch davon ausgegangen, dass Sie über eine grafische Benutzeroberfläche entwickeln. Manchmal muss ich minty (cygwins terminal) über ssh verwenden, was bedeutet, dass die Dev Box einen Webserver haben müsste, um die doxygen Dateien zu hosten. –

+0

Ja, genau. Und ein Linux/Unix-Server, der bereits SSH zur Verfügung stellt, kann einen Webserver einfach bereitstellen, es wird auch empfohlen, PHP auf dem Webserver zu aktivieren, der eine einfache Suchmaschine in den doxygen-Seiten bereitstellt. – Chandler

+0

Sowohl Eclipse als auch SlickEdit bieten eine Möglichkeit, Vererbungsbäume für Klassen aufzulisten und eine Baumliste von überschriebenen Methoden. Dies wird in Eclipse als Typhierarchie bezeichnet und ist eine der nützlichsten Funktionen in einer IDE beim Codieren in einer OO-Sprache. Doxygen ist wirklich nützlich, aber es ist ein Overkill, wenn Sie nur einen kurzen Blick auf die "Typhierarchie" werfen müssen. –

2

Wenn Sie Ihre Tag-Dateien mit Exuberant CTags unter Verwendung von Vererbungsinformationen (see the --fields option) erstellen, funktioniert das folgende Skript. Es fügt einen :Inherits Befehl hinzu, der entweder den Namen einer Klasse (z. B. :Inherits Foo) oder einen regulären Ausdruck verwendet.

Wie der :tag Befehl, zeigen Sie an, dass Sie die Suche mit einer Regex möchten, indem Sie es mit einem '\' Zeichen, z. :Inherits \Foo.*.

Die Ergebnisse werden in das Fenster der Standortliste setzen, die Sie durchsuchen mit :ll, :lne, :lp usw. VIM scheint nicht Skripte zu ermöglichen, die Tag-Liste zu ändern, das ist, was ich bevorzugen würde.

Wenn Sie sich wundern, warum ich taglist() dafür nicht verwende, ist es, weil taglist() auf großen Tag-Dateien unglaublich langsam ist. Der ursprüngliche Post hatte eine Version mit taglist(), wenn Sie neugierig sind, können Sie den Bearbeitungsverlauf durchsuchen.

" 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>') 
Verwandte Themen