我使用列出的许多项目:doxygen、etags 等。但是,在大多数情况下,我发现从 emacs 运行经过良好调整的 find-grep 在搜索大型代码库时非常有效。仍在努力设置 CEDET 和 sematic。
这是我为特定源代码树编写的一些 lisp 代码,以及在我的 .emacs 中对这些函数的映射。该代码构建了一个大型 find-grep 命令,该命令从我正在其中工作的源代码树的根目录开始。它遍历文件系统寻找一些指示源树顶部的文件(在我的例子中是makefile)。我对其进行了调整,直到它可以在几秒钟内完成搜索(实际上我编写了一个 python 脚本来帮助我识别导致搜索速度变慢的大型二进制文件类型)。
(global-set-key (quote[f3]) (quote set-fg-suffix))
(global-set-key (quote[f4]) (quote fg))
(defun mkpath (list)
"Return a string which is the concatenation of the list."
(let ( (result "") )
(while list
(setq result (concat result (car list)))
(setq result (concat result "/"))
(setq list (cdr list))
)
result ; Since this is the final evaluation, it's the returned from the function.
)
)
(defun find-best-root (anchor-file &optional empty-on-failure)
"Examines the parent directories of the current buffer. Looks for a parent that contains the
file passed in the anchor-file argument. This is the directory I want."
(if (not buffer-file-name)
;; Certain buffer (e.g., *scratch*) return nil from buffer-file-name. In that case,
;; set the best path to "/" since that's the only path which can be counted on.
(if (eq nil empty-on-failure)
"/"
""
)
(let ((path-depth (safe-length (split-string (file-name-directory buffer-file-name) "/" 1)))
(best-root (if (eq nil empty-on-failure)
(file-name-directory buffer-file-name)
""))
(exclude-from-path 1))
(while (<= exclude-from-path (+ path-depth 1))
(setq path-as-list (butlast (split-string (file-name-directory buffer-file-name) "/") exclude-from-path))
(setq potential-root (mkpath path-as-list))
(message (concat "Checking in " potential-root))
(if (file-exists-p (concat potential-root anchor-file))
(progn (setq best-root potential-root)
(setq exclude-from-path (+ path-depth 2)) ;; Break from the loop.
(message (concat "Found " anchor-file)))
(setq exclude-from-path (+ exclude-from-path 1)))
)
best-root
)
)
)
(if (eq system-type 'gnu/linux)
(progn (setq marker-file "makefile")
(setq find-filters (concat " -type d "
"-path \"*/build\" -prune -o "
"-path \"*/.git\" -prune -o "
"-path \"*/ext\" -prune -o "
"-path \"*/pycommon\" -prune -o "
"\"(\" "
"\! -iname \"BROWSE\" "
"-and \! -iname \"FILES\" "
"-and \! -iname \"TAGS\" "
"-and \! -iname \"*.a\" "
"-and \! -iname \"*.bin\" "
"-and \! -iname \"*.cs\" "
"-and \! -iname \"*.css\" "
"-and \! -iname \"*.d\" "
"-and \! -iname \"*.dat\" "
"-and \! -iname \"*.html\" "
"-and \! -iname \"*.ico\" "
"-and \! -iname \"*.jar\" "
"-and \! -iname \"*.json\" "
"-and \! -iname \"*.o\" "
"-and \! -iname \"*.pdf\" "
"-and \! -iname \"*.php\" "
"-and \! -iname \"*.png\" "
"-and \! -iname \"*.pyc\" "
"-and \! -iname \"*.so\" "
"-and \! -iname \"*.sql\" "
"-and \! -iname \"*.txt\" "
"-and \! -iname \"*.xml\" "
"\")\" "
"-print0 | xargs -0 grep -nHi -e "))
))
(setq custom-find-grep-path-suffix "")
(defun set-fg-suffix (suffix)
"Set an optional suffix for the search. This is useful for more fine grained searching."
(interactive "sEnter Search Suffix: ")
(if (string= "" suffix)
(message "The optional search suffix is now empty.")
(message (concat "The optional search suffix is now '" suffix "'."))
)
(setq custom-find-grep-path-suffix suffix)
)
(defun fg ()
"A custom find grep that dynamically sets the search path based on the buffer.
Regular Expression Examples:
-E \"struct.*hash\" When using special characters, enclose regexp in quotes.
-E \"^text$\" ^ Matches beginning of line, $ matches end of line.
-E \"main\\(.*\\)\" .* Matches everything, parenthesis require escaping."
(interactive)
(let ((fg-tt-filters find-filters ))
(setq my-find-grep-command "find \"")
(setq my-find-grep-command (concat my-find-grep-command (find-best-root marker-file)))
(setq my-find-grep-command (concat my-find-grep-command custom-find-grep-path-suffix))
(setq my-find-grep-command (concat my-find-grep-command "\""))
(setq my-find-grep-command (concat my-find-grep-command fg-tt-filters))
(grep-apply-setting 'grep-find-command my-find-grep-command)
(call-interactively 'find-grep)
)
)