我正在尝试编写一个Emacs主要模式来处理生物序列数据(即DNA和肽),我想实现语法高亮,其中不同的字母颜色不同。由于该模式需要能够区分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的上下文中是否可能它会完成。关于如何做这样的事情,或者如何以不同的方式实现这个目标的任何想法?
答案 0 :(得分:7)
事实上,Emacs通过font-lock模式的“锚定匹配”功能提供了您需要做的事情。语法有点毛茸茸,但它允许您指定其他“匹配器”(基本上是正则表达式,子表达式标识符和面名称),默认情况下将在主“匹配器”正则表达式完成的位置之后应用。队伍的尽头。有更复杂的方法可以自定义它们适用的文本范围,但这是一般的想法。
这是一个简单的例子,它还展示了如何为此目的定义自己的面孔:
(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
的文档的相关位:
突出显示应该是MATCH-HIGHLIGHT或MATCH-ANCHORED。
[...]
MATCH-ANCHORED应采用以下形式:
(MATCHER PRE-MATCH-FORM POST-MATCH-FORM MATCH-HIGHLIGHT ...)
其中MATCHER是要搜索的正则表达式或要调用的函数名称 搜索,如上面的MATCH-HIGHLIGHT,但有一个例外;见下文。 PRE-MATCH-FORM和POST-MATCH-FORM在第一次和之后进行评估 最后,使用实例MATCH-ANCHORED的MATCHER。因此他们可以 用于初始化之前,并在使用MATCHER之后进行清理。通常情况下, PRE-MATCH-FORM用于移动到相对于原始位置的某个位置 MATCHER,在开始使用MATCH-ANCHORED的MATCHER之前。 POST-MATCH-FORM可能 在用MATCH-ANCHORED的父母的MATCHER重新开始之前用来回去。
上述例外情况如下。 MATCHER搜索的限制 在评估PRE-MATCH-FORM之后,默认为行的结尾。 但是,如果PRE-MATCH-FORM返回的位置大于后面的位置 评估PRE-MATCH-FORM,该位置用作搜索的限制。 返回一个大于结尾的位置通常是一个坏主意 line,即使MATCHER搜索跨越行。
我总是发现在开始对我有意义之前,我必须阅读三次字体锁文档; - )