emacs:有没有一个明确的多行字体锁定的例子



有一些背景,我对Emacs Lisp很熟悉,写了很多行。但是我从来没有写过主模式,所以我对字体锁定机制的工作原理还很陌生。

对于我当前的项目,我想将内联javascript和css高亮显示添加到html-mode中。目前,我使用MMM模式来完成这项工作,但它体积庞大,而且我不使用它的其他功能,所以我只想创建一个次要模式,甚至只是一个破解,我可以将其添加到sgml-mode-hook中以进行高亮显示。

我已经找到了手册的这一部分,它非常缺乏一个例子,以及这一页破损的代码。

有人能给我举一个如何做到这一点的明确例子吗?

EDIT:我应该澄清一下,我不想在javascript/css块中看到特定于模式的字体锁定。唯一的要求是,我能够通过对它们应用不同的面来看到块。

我将概述一个简单的主模式,用于突出显示<style>(CSS)和<script>(JavaScript等)块。获取多行字体锁定工作得相当好,您需要首先通过设置font-lock-multilinet,并编写要添加到的函数font-lock-extend-region-functions将扩展相关搜索区域以包含较大的文本块。然后,你需要编写多行匹配器——正则表达式或函数——以及将它们添加到CCD_ 8中。

以下是命名字体锁的基本主模式定义关键字列表(此处为test-font-lock-keywords),启用多行字体锁定,并添加区域扩展功能CCD_ 10。

(define-derived-mode test-mode html-mode "Test"
  "Major mode for highlighting JavaScript and CSS blocks."
  ;; Basic font lock
  (set (make-local-variable 'font-lock-defaults)
       '(test-font-lock-keywords))
  ;; Multiline font lock
  (set (make-local-variable 'font-lock-multiline) t)
  (add-hook 'font-lock-extend-region-functions
            'test-font-lock-extend-region))

区域扩展功能应该是这样的:

(defun test-font-lock-extend-region ()
  "Extend the search region to include an entire block of text."
  ;; Avoid compiler warnings about these global variables from font-lock.el.
  ;; See the documentation for variable `font-lock-extend-region-functions'.
  (eval-when-compile (defvar font-lock-beg) (defvar font-lock-end))
  (save-excursion
    (goto-char font-lock-beg)
    (let ((found (or (re-search-backward "nn" nil t) (point-min))))
      (goto-char font-lock-end)
      (when (re-search-forward "nn" nil t)
        (beginning-of-line)
        (setq font-lock-end (point)))
      (setq font-lock-beg found))))

此函数查看全局变量font-lock-begfont-lock-end,包含搜索区域,并扩展该区域以包含整个块文本(由空行分隔或"nn")。

现在Emacs将在更大的区域中搜索匹配项,我们需要设置CCD_ 14列表。有两个匹配多行构造的合理好方法:跨行匹配的正则表达式作用我将举两个例子。此关键字列表包含用于匹配CCD_ 15块的正则表达式和函数用于匹配<script>块:

(defvar test-font-lock-keywords
  (list
   (cons test-style-block-regexp 'font-lock-string-face)
   (cons 'test-match-script-blocks '((0 font-lock-keyword-face)))
   )
  "Font lock keywords for inline JavaScript and CSS blocks.")

列表中的第一项很简单:正则表达式以及用于突出显示该正则表达式的匹配的面部。第二个看起来有点复杂,但可以概括为中定义的不同组指定不同的面匹配函数指定的数据。在这里,我们只强调使用CCD_ 17分组零(整个匹配)。(这些匹配器位于Emacs手册。)

用于匹配<style>块的基本正则表达式是:

(defconst test-style-block-regexp
  "<style>\(.\|n\)*</style>"
  "Regular expression for matching inline CSS blocks.")

注意,我们必须将n放在内部组中,因为.不匹配换行符。

另一方面,匹配函数需要查找第一个<script>块在从点到单个给定的区域自变量,last:

(defun test-match-script-blocks (last)
  "Match JavaScript blocks from the point to LAST."
  (cond ((search-forward "<script" last t)
         (let ((beg (match-beginning 0)))
           (cond ((search-forward-regexp "</script>" last t)
                  (set-match-data (list beg (point)))
                  t)
                 (t nil))))
        (t nil)))

此函数设置匹配数据,该数据是表单的列表begin-0 end-0 begin-1 end-1 ...给出第零组,第一组,等等。这里,我们只给出匹配的整个区块,但你可以做更多的事情复杂的,例如为标签和目录

如果将所有这些代码组合到一个文件中并运行M-x test-mode,它应该可以突出显示这两种类型块。虽然我相信这能起到作用,但如果有更多我也很好奇我也知道。

在下面的例子中,我使用了字体锁定关键字的"锚定"形式,它允许您搜索比当前行更多的内容。"技巧"是"预"挂钩做两件事:1)它允许您将点定位到搜索的开始位置,2)它允许通过返回结束位置来限制搜索。在下面的示例中,我使用了第二个属性。

请注意,这只是概念的证明。您需要确保font-lock-multiline变量和字体锁定关键字应用于正确的缓冲区。

(defun my-end-of-paragraph-position (&rest foo)
  "Return position of next empty line."
  (save-excursion
    (while (not (or (eobp)             ; Stop at end of buffer.
                    (and (bolp)        ; Or at an empty line.
                         (eolp))))
      (forward-line))
    (point)))
(setq font-lock-multiline t)
(font-lock-add-keywords nil
                        '(("^FOO"
                           (0 font-lock-keyword-face)  ;; Face for FOO
                           ("BAR"
                            (my-end-of-paragraph-position)
                            nil
                            (0 font-lock-variable-name-face)))))

下面,BAR的前两行将突出显示,但不是最后一行:

FOO BAR BAR BAR BAR
BAR BAR BAR BAR
BAR BAR BAR BAR

这可能不是最好的例子,但您可以看看haml模式是如何解决子模式区域中语法突出显示的问题的。这是一篇高级描述的博客文章。

请注意,当前的haml-mode在Emacs24兼容性方面存在一些问题,但一些fork对此进行了修复。

关于多行字体锁定,我认为您可能问错了问题。但基本上,这解决了如果用户在多行语法构造的中间或结尾进行了编辑,该怎么办的问题。最初,字体锁定开始从点的位置重新确定缓冲区。两个默认的font-lock-extend-region-functionsfont-lock-extend-region-wholelinesfont-lock-extend-region-multiline,将重新识别区域的起点移动到行的起点,然后可能移动到更远的地方,这取决于font-lock-multiline属性。如果您需要它进一步向上移动,您可以向font-lock-region-functions添加另一个函数,或者确保在解析font-lock-region-functionsyntax-propertize-function中的某些构造时以编程方式回溯。

后一种方法的一个例子是Ruby的heredoc和Emacs主干中的ruby-syntax-propertize-heredoc。它是从ruby-syntax-propertize-function中的两个位置调用的。当我们已经在一个heredoc文本中时,第一次处理这个案例,然后再处理任何后续的heredoc。

相关内容

  • 没有找到相关文章

最新更新