emacs: есть ли явный пример многострочной блокировки шрифтов? - PullRequest
12 голосов
/ 26 февраля 2012

Немного предыстории, мне удобно с Emacs Lisp, и я написал много строк об этом.Однако я никогда не писал основной режим, поэтому я довольно новичок в том, как работает механизм блокировки шрифтов.

Для моего текущего проекта я хотел бы добавить встроенный JavaScript и подсветку CSS к html-mode.В настоящее время я делаю это с MMM-режимом, но он громоздкий, и я не использую его другие функции, поэтому я просто хотел бы сделать второстепенный режим или даже просто взлом, который я могу добавить к sgml-mode-hookчтобы просто сделать выделение.

Я нашел этот раздел руководства, в котором очень не хватает примера, и этот emacswiki страница неработающего кода.

Может кто-нибудь показать мне наглядный пример того, как это можно сделать?

РЕДАКТИРОВАТЬ: я должен уточнить, что я не хочу видеть зависящую от режима блокировку шрифта в чанках javascript / css,Единственное требование - чтобы я мог видеть куски, применяя к ним другое лицо.

Ответы [ 3 ]

9 голосов
/ 27 февраля 2012

В приведенном ниже примере я использую «заякоренную» форму ключевых слов font-lock, которая позволяет вам искать больше, чем текущая строка. Хитрость заключается в том, что ловушка «pre» делает две вещи: 1) она позволяет вам позиционировать точку в начале поиска и 2) она позволяет ограничить поиск, возвращая конечную позицию. В приведенном ниже примере я использовал второе свойство.

Обратите внимание, что это только подтверждение концепции. Вам необходимо убедиться, что переменная font-lock-multiline и ключевые слова 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, но не последняя:

FOO BAR BAR BAR BAR
BAR BAR BAR BAR

BAR BAR BAR BAR
7 голосов
/ 06 марта 2013

Я выделю простой основной режим для выделения <style> (CSS) и <script> (JavaScript и др.) Блоки. Чтобы получить блокировку многострочного шрифта работает достаточно хорошо, вам нужно сначала включить его, установив font-lock-multiline до t и написать функцию для добавления 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. Есть два достаточно хорошие способы сопоставления многострочных конструкций: регулярное выражение, которое будет соответствовать между строками и соответствием функция. Я приведу примеры обоих. Этот список ключевых слов содержит регулярное выражение для сопоставления <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.")

Первый элемент в списке прост: регулярное выражение и лицо для выделения совпадений этого регулярного выражения. Второй выглядит немного сложнее, но может быть обобщен указать разные лица для разных групп, определенных в сопоставить данные, указанные функцией. Здесь мы просто выделяем группа ноль (полное совпадение), используя 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 ... дает начало и конец нулевая группа, первая группа и так далее. Здесь мы даем только ограничения на весь блок, который был сопоставлен, но вы могли бы сделать что-то еще сложные, такие как установка различных граней для тегов и содержание.

Если вы объедините весь этот код в один файл и запустите M-x test-mode, это должно работать для выделения этих двух типов блоков. Хотя я считаю, что это делает работу, если есть более эффективный или правильный способ сделать это, я также хотел бы знаю также.

3 голосов
/ 27 февраля 2012

Вероятно, это не самый лучший пример, но вы можете посмотреть, как haml-mode решил проблему подсветки синтаксиса в подрежимных областях.Вот пост в блоге с описанием высокого уровня.

Обратите внимание, что у текущего haml-mode есть некоторые проблемы с совместимостью с Emacs 24, но в нескольких вилках есть исправления.*

Что касается многострочной блокировки шрифтов, я думаю, что вы задаете не тот вопрос.Но в основном это решает проблему того, что делать, если пользователь выполнил редактирование в середине или конце многострочной синтаксической конструкции.Изначально font-lock начинает переопределять буфер с позиции точки.Два значения по умолчанию 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-function или syntax-propertize-function.

Один из примеров последнегоподход был бы наследником Руби и ruby-syntax-propertize-heredoc в стволе Emacs.Он вызывается из двух мест в ruby-syntax-propertize-function.Первый раз для обработки случая, когда мы уже находимся внутри литерала heredoc, а затем для любых последующих heredocs.

...