2014-09-04 76 views
5

在一個相當大的代碼庫中有幾層可以在vim或命令行中找到所有從基類派生的類類? grep是一個選項,但可以很慢,因爲grep不會編入索引。C++,cscope,ctags和vim:查找從這個類繼承的類

+0

我不這麼認爲時,cscope和ctags的是基於正則表達式,但沒有類似語法IDE – 2014-09-04 02:35:10

+0

你有沒有考慮[確認](http://beyondgrep.com/),將[Ag銀魔] (https://github.com/ggreer/the_silver_searcher)或[git grep](http://git-scm.com/docs/git-grep)?這些通常比grep快得多。 – 2014-09-04 04:54:07

+0

我也對此感興趣。我目前使用Eclipse和SlickEdit來做到這一點。在Eclipse中,這個功能稱爲Type Hierarchy。有一個名爲eclim的項目,它將Eclipse的功能集成到Vim中,這是Vim中最接近我看到的,不幸的是,eclim吃了很多內存,並且在Windows中不斷崩潰,很可能是由於Eclipse而要求Eclipse精細化調整內存設置.. – 2016-08-08 19:10:24

回答

3

無論是cscope的,也不CTAGS讓我們直接處理繼承,但它相對容易解決這個限制,因爲派生類也收錄。

cscope的

在cscope的,找 「C符號」 Foobar通常列出了原班類從它繼承。由於搜索是針對數據庫完成的,因此它閃電般快速。

或者,你可以使用cscope的egrep的搜索功能與像:.*Foobar模式列出類從Foobar繼承。因此,即使我們沒有專門的「查找從這個類繼承的類」命令,我們也可以毫不費力地完成工作。

CTAGS

雖然CTAGS允許包括與--fields=+i繼承信息,該信息不能直接在Vim中使用。但是,Vim解析了inherits字段,因此可能會使用taglist()構建一個快速且骯髒的解決方案。

ACK,AG

這兩個程序的工作或多或少如grep,但他們都朝源代碼中搜索目標,使他們比grep的速度真的

在我的Vim的配置,:grep設置爲運行ag程序而不是默認的grep所以,尋找從類光標下衍生會是什麼樣子類:

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

下面是相關線路我的~/.vimrc

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

我注意到一些使用':Ggrep'命令使用fugitive和vim的速度。這個改進要求代碼是一個git repo,這在我的文章中沒有提到,但是是另一種選擇。 – 2016-01-26 23:34:15

2

lh-cpp中,我定義了命令:Children。它依賴於ctags數據庫,因此它非常有限。

它需要兩個可選參數:要查找的命名空間(我沒有找到避免這種情況的方法)以及父類的名稱 - >:Children [!] {namespace} {parent-class}

該命令嘗試緩存儘可能多的信息。因此,當相關信息在ctags數據庫中發生變化時,必須更新緩存。它是通過敲打命令完成 - >:Children!

1

我不認爲vim是列出所有子類的正確工具。相反,我們最好使用doxygen爲源代碼生成文檔。雖然doxygen需要一些時間,但我們可以使用所有類的文檔/圖表,這是清晰和快速的。

+0

儘管您正在使用圖形界面進行開發,但這仍然假設。有時候,我必須通過ssh使用minty(cygwins終端),這意味着開發者必須擁有一個web服務器來託管doxygen文件。 – 2014-09-04 17:30:14

+0

是的,確切地說。已經提供SSH的Linux/Unix服務器很容易部署Web服務器,還建議在Web服務器中啓用PHP,在Doxygen頁面內部提供一個簡單的搜索引擎。 – Chandler 2014-09-06 11:22:39

+0

Eclipse和SlickEdit都可以列出類的繼承樹,也可以列出重載方法的樹列表。這在Eclipse中被稱爲Type Hierarchy,當用OO語言進行編碼時,它是IDE中最有用的功能之一。 Doxygen真的很有用,但當你只需要快速瀏覽「Type Hierarchy」時,它就是一種矯枉過正。 – 2016-08-08 19:05:09

2

如果使用繼承信息(see the --fields option)構建帶有Exuberant CTags的標記文件,那麼以下腳本將起作用。它增加了一個:Inherits命令,該命令可以採用類的名稱(例如:Inherits Foo)或正則表達式。

:tag命令類似,您需要在正則表達式前面加上一個'\'字符來指示您搜索,例如, :Inherits \Foo.*

結果放到窗口的位置列表,你用瀏覽:ll:lne:lp等VIM似乎並沒有允許腳本修改標籤列表這就是我喜歡。

如果你想知道爲什麼我不使用taglist(),這是因爲taglist()在大型標籤文件上的速度非常慢。原帖有一個使用taglist()的版本,如果你很好奇,你可以瀏覽編輯歷史。

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