14

背景として、私は Emacs Lisp に慣れており、多くの行を書いてきました。しかし、私はメジャー モードを書いたことがないので、フォント ロック メカニズムがどのように機能するかについてはまったくの初心者です。

私の現在のプロジェクトでは、インライン化された JavaScript と CSS の強調表示を に追加したいと思いhtml-modeます。現在、私はMMMモードでこれを行っていますが、それはかさばり、他の機能を使用していないので、マイナーモードを作成したり、sgml-mode-hook単に実行するために追加できるハックさえしたいと思いますハイライト。

私はマニュアルのこのセクションを見つけましたが、これには例が非常に欠けており、壊れたコードのこの emacswikiページがあります。

誰かがこれを行う方法の明確な例を教えてもらえますか?

編集: javascript/css チャンク内でモード固有のフォントロックを見たくないことを明確にする必要があります。唯一の要件は、チャンクに別の面を適用してチャンクを表示できることです。

4

3 に答える 3

10

以下の例では、font-lock キーワードの「アンカー」形式を使用しています。これにより、現在の行よりも多くの検索が可能になります。「トリック」は、「pre」フックが 2 つのことを行うことです。1) ポイントを検索の開始点に配置でき、2) 終了位置を返すことで検索を制限できます。以下の例では、2 番目のプロパティを使用しています。

これは概念実証にすぎないことに注意してください。font-lock-multilinevariable および font-lock キーワードが正しいバッファーに適用されていることを確認する必要があります。

(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 の最初の 2 行が強調表示されますが、最後の行は強調表示されません。

FOO BAR BAR BAR BAR
BAR BAR BAR BAR

BAR BAR BAR BAR
于 2012-02-26T20:15:54.047 に答える
9

<style>(CSS)および <script>(JavaScriptなど)ブロックを強調表示するための単純なメジャーモードの概要を説明します。複数行のフォントロックを適切に機能させるには、まず、に設定 font-lock-multilinetて追加する関数を記述し font-lock-extend-region-functions、関連する検索領域を拡張してより大きなテキストブロックを含めることにより、フォントロックを有効にする必要があります。次に、複数行のマッチャー(正規表現または関数)を記述し、それらをに追加する必要がありますfont-lock-defaults

これは、フォントロックキーワードリスト(ここでは、test-font-lock-keywords)に名前を付け、複数行のフォントロックを有効にし、領域拡張機能を追加 する基本的なメジャーモード定義ですtest-font-lock-extend-region

(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 "\n\n" nil t) (point-min))))
      (goto-char font-lock-end)
      (when (re-search-forward "\n\n" nil t)
        (beginning-of-line)
        (setq font-lock-end (point)))
      (setq font-lock-beg found))))

この関数は、検索領域の開始位置と終了位置を含むグローバル変数font-lock-begとを 調べ、領域を拡張してテキストのブロック全体(空白行またはで区切る)を含めます。font-lock-end"\n\n"

Emacsがより大きな地域で一致を検索するようになったので、リストを設定する必要がありtest-font-lock-keywordsます。複数行の構成を一致させるには、2つの合理的に良い方法があります。行間で一致する正規表現と一致する関数です。両方の例を示します。このキーワードリストには、ブロックを照合するための正規表現<style>と、ブロックを照合するための関数が含まれてい<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.")

リストの最初の項目は単純です。正規表現と、その正規表現の一致を強調表示するための面です。2つ目は少し複雑に見えますが、関数で指定された一致データで定義されたグループごとに異なる面を指定するように一般化できます。ここでは、を使用してグループゼロ(一致全体)を強調表示しfont-lock-keyword-faceます。(これらのマッチャーに関連するドキュメントは、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 ...、0番目のグループ、最初のグループなどの開始と終了を示すフォームのリストです。ここでは、一致したブロック全体にのみ境界を設定しますが、タグとコンテンツに異なる面を設定するなど、より洗練された方法を実行できます。

このすべてのコードを1つのファイルにまとめて実行すると M-x test-mode、これら2つのタイプのブロックを強調表示するために機能するはずです。これでうまくいくと思いますが、もっと効率的または適切な方法があれば、私も知りたいと思います。

于 2013-03-06T05:32:27.047 に答える
4

これはおそらく最良の例ではありませんが、haml-modeがサブモード領域での構文の強調表示の問題をどのように解決したかを見ることができます。これは、高レベルの説明が記載されたブログ投稿です。

haml-mode現在のところ、Emacs 24の互換性に関していくつかの問題がありますが、いくつかのフォークでこれが修正されていることに注意してください。

複数行のフォントロックに関しては、間違った質問をしているのではないかと思います。しかし、基本的に、これは、ユーザーが複数行の構文構造の途中または最後で編集を行った場合にどうするかという問題を解決します。最初に、font-lockはポイントの位置からバッファの再フォント化を開始します。2つのデフォルトのfont-lock-extend-region-functions、、font-lock-extend-region-wholelinesおよびfont-lock-extend-region-multilineは、再フォント化領域の先頭を行の先頭に移動し、プロパティによってはさらにどこかに移動しfont-lock-multilineます。さらに上に移動する必要がある場合は、に別の関数を追加するか、またはfont-lock-region-functions内の特定の構造を解析しながらプログラムでバックトラックするようにしてください。font-lock-region-functionsyntax-propertize-function

後者のアプローチの一例は、Rubyのヒアドキュメントとruby-syntax-propertize-heredocEmacsトランクです。の2か所から呼び出されruby-syntax-propertize-functionます。すでにヒアドキュメントリテラル内にいる場合に初めてケースを処理し、その後、後続のヒアドキュメントを処理します。

于 2012-02-26T20:40:34.533 に答える