24.5 Imenu

Imenu 是一项允许用户在菜单中选择缓冲区中的定义或章节,并直接跳转到缓冲区对应位置的功能。Imenu 的工作原理是构建一个缓冲区索引,列出所有定义或其他具名片段的名称与缓冲区位置;用户可从中选择一项,并将光标移动到该处。主模式可以通过 imenu-add-to-menubar 添加一个菜单栏项以使用 Imenu。

Command: imenu-add-to-menubar name

该函数定义一个名为 name 的局部菜单栏项,用于运行 Imenu。

Emacs 手册中介绍了使用 Imenu 的用户级命令(see Imenu in the Emacs Manual)。本节说明如何针对特定主模式自定义 Imenu 查找定义或缓冲区片段的方式。

最常用且最简单的方式是设置变量 imenu-generic-expression

Variable: imenu-generic-expression

若该变量非 nil,则它是一个指定正则表达式的列表,用于 Imenu 查找定义。imenu-generic-expression 的简单元素格式如下:

(menu-title regexp index)

其中,若 menu-titlenil,表示该元素匹配到的内容将放入缓冲区索引的子菜单中;menu-title 本身指定子菜单名称。若 menu-titlenil,则该元素匹配到的内容直接放在缓冲区索引的顶层。

列表中的第二项 regexp 是一个正则表达式(see Regular Expressions);缓冲区中所有被它匹配到的内容都会被视为一项定义,并在缓冲区索引中列出。第三项 index 是一个非负整数,指明 regexp 中的哪个子表达式匹配定义的名称。

元素也可以采用如下形式:

(menu-title regexp index function arguments...)

该元素的每一次匹配都会创建一个索引项;当用户选中该索引项时,会以索引项名称、缓冲区位置以及 arguments 为参数调用 function

对于 Emacs Lisp 模式,imenu-generic-expression 可以形如:

((nil "^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2)
 ("*Vars*" "^\\s-*(def\\(var\\|const\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2)
 ("*Types*"
  "^\\s-*\
(def\\(type\\|struct\\|class\\|ine-condition\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2))

设置该变量会使其在当前缓冲区中变为局部变量。

Variable: imenu-case-fold-search

该变量控制 imenu-generic-expression 中正则表达式的匹配是否区分大小写:默认值 t 表示不区分大小写。

设置该变量会使其在当前缓冲区中变为局部变量。

Variable: imenu-syntax-alist

该变量是一个语法表修改规则的关联列表,在处理 imenu-generic-expression 时生效,用于覆盖当前缓冲区的语法表。每个元素格式如下:

(characters . syntax-description)

其中 CAR 位置的 characters 可以是一个字符或字符串。该元素表示将指定字符的语法设置为 syntax-description,此描述会传递给 modify-syntax-entry(see Syntax Table Functions)。

该功能通常用于将原本为符号语法的字符设为单词语法,从而简化 imenu-generic-expression 并加快匹配速度。例如 Fortran 模式会这样使用:

(setq imenu-syntax-alist '(("_$" . "w")))

之后 imenu-generic-expression 中的正则表达式就可以使用 ‘\\sw+’ 代替 ‘\\(\\sw\\|\\s_\\)+’。注意,如果某模式需要限制名称首字符的范围小于名称其余字符的允许范围,这种方式可能不太方便。

设置该变量会使其在当前缓冲区中变为局部变量。

为主模式自定义 Imenu 的另一种方式是设置变量 imenu-prev-index-position-functionimenu-extract-index-name-function

Variable: imenu-prev-index-position-function

若该变量非 nil,其值应为一个函数,该函数从光标位置向前扫描缓冲区,查找下一个需要加入缓冲区索引的定义。若在光标前未找到其他定义,则返回 nil。否则应将光标停在找到定义的位置,并返回任意非 nil 值。

设置该变量会使其在当前缓冲区中变为局部变量。

Variable: imenu-extract-index-name-function

若该变量非 nil,其值应为一个函数,用于返回当前定义的名称;调用时光标位置与 imenu-prev-index-position-function 查找完成后的位置一致。

设置该变量会使其在当前缓冲区中变为局部变量。

为主模式自定义 Imenu 的最后一种方式是设置变量 imenu-create-index-function

Variable: imenu-create-index-function

该变量指定用于创建缓冲区索引的函数。该函数应无参数,并返回当前缓冲区的索引关联列表。它会在 save-excursion 中调用,因此光标最终位置无关紧要。

索引关联列表可以包含三类元素。简单元素格式如下:

(index-name . index-position)

选中简单元素会跳转到缓冲区中的 index-position 位置。特殊元素格式如下:

(index-name index-position function arguments...)

选中特殊元素会执行:

(funcall function
         index-name index-position arguments...)

嵌套子列表元素格式如下:

(menu-title . sub-alist)

它会创建一个由 sub-alist 定义、名为 menu-title 的子菜单。

imenu-create-index-function 的默认值为 imenu-default-create-index-function。该函数会调用 imenu-prev-index-position-functionimenu-extract-index-name-function 生成索引关联列表。但若这两个变量中有一个为 nil,默认函数则会改用 imenu-generic-expression

设置该变量会使其在当前缓冲区中变为局部变量。

如果 Emacs 编译时包含 tree-sitter 支持,且主模式设置了相关变量,Emacs 可以自动生成 Imenu 索引。

Variable: treesit-simple-imenu-settings

该变量指示 Emacs 如何生成 Imenu 索引。它应为一个形如 (category regexp pred name-fn) 的列表。

category 应为类别名称,例如“函数”(Function)、 “类”(Class)等。regexp 应为匹配属于 category 类别节点类型的正则表达式。 pred 可以是 nil,也可以是一个接收节点作为参数的函数; 若该节点是 category 类别下的有效节点,则返回非 nil 值,否则返回 nil

category 也可以设为 nil,这种情况下,由 regexppred 匹配到的条目 不会归属于 category 类别分组。

name-fn 可以是 nil,也可以是一个接收定义节点(defun node)并返回该定义名称的函数, 例如接收函数定义节点时返回对应的函数名。若 name-fnnil, 则改用 treesit-defun-name(see Developing major modes with tree-sitter)。

若该变量值非 nil,则 treesit-major-mode-setup(see Developing major modes with tree-sitter) 会自动完成 Imenu 的配置。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike