挖掘Emacs Imenu的潛力

吳吉慶發表於2014-12-19
作者: Jolly Wing(jiqingwu@gmail.com)
日期: 2014-05-15
宣告:轉載請保留作者資訊

Imenu介紹

imenu是Emacs自帶的一個工具,它能夠分析當前緩衝區中的定義,並生成索引。

Imenu不僅能分析程式原始檔,也能分析格式化的文件,比如HTML,Tex 以及輕量化標記語言 (rst, markdown, emacs org等)。

對於程式原始檔,它主要生成函式定義的索引。 (WhichFunction模式就是使用了imenu生成的索引資訊,speedbar也使用了imenu生成的資訊)。

對於結構化文件,它生成標題和章節的大綱。

使用Imenu

我們開啟一個C的原始檔,裡面定義了幾個函式。 M-x imenu 回車,imenu會提示你輸入要跳轉到那個符號定義。 我們按TAB,imenu就會把在一個緩衝區中列出所有的函式定義。 我們根據提示輸入某個函式的名字,按回車跳轉到定義處。

這樣似乎不是很方便,我們可以 M-x imenu-add-menubar-index, 這時候選單中多出一個Index的選單,開啟Index,裡面就是imenu生成的索引。 用滑鼠點選就可以導航了,方便多了吧。

我們可以設定在編輯某種主模式的檔案時,imenu的索引自動出現在選單中。 比如,我想在編輯c程式的時候,使用imenu的選單索引。

(add-hook 'c-mode-hook 'imenu-add-menubar-index)

如果想要所有模式下都在選單欄顯示imenu的索引,可以用EmacsWiki上的技巧: 因為你在進入某個主模式後,會執行 font-lock-mode。(注意,假設你已經 (setq global-font-lock-mode t))。 你可以把 imenu-add-menubar-index 加在 font-lock-mode-hook 上。 用下面程式碼,你可以在任何支援imenu的buffer的選單欄加入imenu索引。

(defun try-to-add-imenu ()
  (condition-case nil (imenu-add-to-menubar "Imenu") (error nil)))
(add-hook 'font-lock-mode-hook 'try-to-add-imenu)

我們發現Imenu選單中有個 *Rescan* 項,它的作用是告訴imenu掃描緩衝區,重新生成索引。 有時,當我們更改了檔案,Imenu並沒有更新,這時我們就要按一下 *Rescan*

imenu的擴充套件

  • icicle-imenu: 可以分類瀏覽Index,比如專門看函式、變數、巨集等。
  • imenu+: 擴充imenu,可以支援開關函式,是否按某種方式排序,是否顯示註釋中的索引等。
  • imenu-anywhere: 以IDO的方式 顯示所有開啟的同類buffer中的索引。當你寫只有幾個原始檔的小專案時,這個就差不 多夠用了。

高階用法:自定義Imenu

Imenu能支援很多模式。 但有的主模式並不支援imenu,這是因為在主模式定義時並沒有定義 imenu-generic-expression。 這時,我們可以自己為該模式定義 imenu-generic-expression,不過比較複雜。 看 EmacsWiki 上的例子,為sql模式定義 imenu-generic-expression

(setq sql-imenu-generic-expression
       '(("Comments" "^-- \\(.+\\)" 1)
     ("Function Definitions" "^\\s-*\\(function\\|procedure\\)[ \n\t]+\\([a-z0-9_]+\\)\
 [ \n\t]*([a-z0-9 _,\n\t]*)[ \n\t]*\\(return[ \n\t]+[a-z0-9_]+[ \n\t]+\\)?[ai]s\\b" 2)
     ("Function Prototypes" "^\\s-*\\(function\\|procedure\\)[ \n\t]+\\([a-z0-9_]+\\)\
 [ \n\t]*([a-z0-9 _,\n\t]*)[ \n\t]*\\(return[ \n\t]+[a-z0-9_]+[ \n\t]*\\)?;" 2)
     ("Indexes" "^\\s-*create\\s-+index\\s-+\\(\\w+\\)" 1)
     ("Tables" "^\\s-*create\\s-+table\\s-+\\(\\w+\\)" 1)))

(add-hook 'sql-mode-hook 
        (lambda ()
           (setq imenu-generic-expression sql-imenu-generic-expression)))

總的來說,當我們編寫小的專案和結構化文件時,imenu是個很實用的小工具。

相關文章