我正在尝试编写一个用于处理生物序列数据(即 DNA 和肽)的 Emacs 主要模式,并且我想实现语法突出显示,其中不同的字母以不同的颜色显示。由于该模式需要能够区分 DNA 序列和氨基酸序列并用不同的颜色对它们进行着色,因此我将文件中的每个序列放在一行中,并使用单个字符前缀(+ 或 #)来指示下一行如何应该突出显示。
因此,例如,如果文件包含这样一行:
+AAGATCCCAGATT
“A”的颜色应该与该行的其余部分不同。
我已经尝试了以下作为测试:
(setq dna-keyword
'(("^\+\\([GCT\-]*\\(A\\)\\)*" (2 font-lock-function-name-face))
)
)
(define-derived-mode bioseq-mode fundamental-mode
(setq font-lock-defaults '(dna-keyword))
(setq mode-name "bioseq mode")
)
但这只匹配最后一个 A 而不是所有的。
我的第一个想法是尝试用一个正则表达式匹配整行,然后使用另一个正则表达式来匹配该行中的 A,但我不知道这在 font-lock-mode 的上下文中是否可行或如何它会完成的。关于如何做这样的事情,或者如何以不同的方式完成它,有什么想法吗?
最佳答案
事实上,Emacs 提供了您使用字体锁定模式的“锚定匹配”功能执行此操作所需的功能。语法有点复杂,但它允许您指定额外的“匹配器”(基本上是一个正则表达式、子表达式标识符和面部名称),这些匹配器(默认情况下)将在主要“匹配器”正则表达式完成的位置之后应用队伍的尽头。有更复杂的方法来准确自定义它们适用的文本范围,但这是一般的想法。
这是一个简单的示例,它还展示了如何为此目的定义自己的面孔:
(defface bioseq-mode-a
'((((min-colors 8)) :foreground "red"))
"Face for As in bioseq-mode")
(defface bioseq-mode-g
'((((min-colors 8)) :foreground "blue"))
"Face for Gs in bioseq-mode")
(setq dna-keyword
'(("^\\+" ("A" nil nil (0 'bioseq-mode-a)))
("^\\+" ("G" nil nil (0 'bioseq-mode-g)))))
您还可以为一个主匹配器指定两个或多个锚定匹配器(这里的主匹配器是正则表达式 "^\\+"
)。为了使这项工作有效,第一个之后的每个锚定匹配器都需要在开始搜索之前明确返回到行的开头;否则它只会在上一个锚定匹配器最后一次出现后才开始突出显示。这是通过将(行首)放入 PRE-MATCH-FORM 槽(列表的元素 2;见下文)来实现的。
(setq dna-keyword
'(("^\\+"
("A" nil nil (0 'bioseq-mode-a))
("G" (beginning-of-line) nil (0 'bioseq-mode-g)))))
我认为这主要是您喜欢哪种口味的问题;如果您在一行中有许多不同的锚定匹配器,第二种方法可能会稍微清晰一些代码,但我怀疑是否存在显着的性能差异。
这是font-lock-defaults
文档的相关部分:
HIGHLIGHT should be either MATCH-HIGHLIGHT or MATCH-ANCHORED.
[....]
MATCH-ANCHORED should be of the form:
(MATCHER PRE-MATCH-FORM POST-MATCH-FORM MATCH-HIGHLIGHT ...)
where MATCHER is a regexp to search for or the function name to call to make the search, as for MATCH-HIGHLIGHT above, but with one exception; see below. PRE-MATCH-FORM and POST-MATCH-FORM are evaluated before the first, and after the last, instance MATCH-ANCHORED's MATCHER is used. Therefore they can be used to initialize before, and cleanup after, MATCHER is used. Typically, PRE-MATCH-FORM is used to move to some position relative to the original MATCHER, before starting with MATCH-ANCHORED's MATCHER. POST-MATCH-FORM might be used to move back, before resuming with MATCH-ANCHORED's parent's MATCHER.
The above-mentioned exception is as follows. The limit of the MATCHER search defaults to the end of the line after PRE-MATCH-FORM is evaluated. However, if PRE-MATCH-FORM returns a position greater than the position after PRE-MATCH-FORM is evaluated, that position is used as the limit of the search. It is generally a bad idea to return a position greater than the end of the line, i.e., cause the MATCHER search to span lines.
我总是发现我必须阅读大约三遍 font-lock 文档才能开始对我有意义;-)
关于regex - 嵌套正则表达式的 Emacs 语法高亮显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10368407/