Emacs: есть ли яркий пример многострочной блокировки шрифтов?
Некоторый фон, мне комфортно с Emacs Lisp, и написал много его строк. Однако я никогда не писал крупный режим, поэтому я довольно новичок в том, как работает механизм блокировки шрифтов.
Для моего текущего проекта я хотел бы добавить выделенные javascript и css выделение в html-mode
. В настоящее время я делаю это с MMM-режимом, но он громоздкий, и я не использую другие его функции, поэтому я просто хотел бы сделать второстепенный режим или даже просто взломать, что я могу добавить в sgml-mode-hook
просто сделать выделение.
Я нашел этот раздел руководства, в котором не хватает примера, и этот emacswiki страница сломанного кода.
Может ли кто-нибудь показать мне ясный пример того, как это можно сделать?
EDIT: я должен уточнить, что я не хочу видеть специфичную для конкретного режима блокировку шрифта в блоках javascript/css. Единственное требование состоит в том, что я могу видеть куски, применяя к ним другое лицо.
Ответы
Ответ 1
В приведенном ниже примере я использую "привязанную" форму ключевых слов для блокировки шрифтов, это позволяет вам искать больше, чем текущая строка. "Уловка" заключается в том, что "pre" hook делает две вещи: 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
Ответ 2
Я опишу простой основной режим выделения <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.")
Первый элемент в списке прост: регулярное выражение
и лицо для выделения совпадений этого регулярного выражения.
Второй выглядит немного сложнее, но может быть обобщен
указать разные грани для разных групп, определенных в
соответствуют данным, указанным функцией. Здесь мы просто выделим
group zero (весь матч) с помощью font-lock-keyword-face
.
(Соответствующая документация для
эти сопоставления находятся в разделе Search-based fontification
руководство 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
Вероятно, это не самый лучший пример, но вы можете посмотреть, как haml-mode решила проблему подсветки синтаксиса в подмодельных областях. Здесь сообщение в блоге с описанием на высоком уровне.
Обратите внимание, что текущий haml-mode
имеет некоторые проблемы с совместимостью Emacs 24, но для этого есть несколько вилок.
Что касается многострочной блокировки шрифтов, я думаю, вы можете задать неправильный вопрос. Но в основном это решает проблему, что делать, если пользователь сделал редактирование в середине или в конце многострочной синтаксической конструкции. Первоначально, lock-lock начинает refontifying буфер от положения точки. Два значения по умолчанию 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 heredoc и ruby-syntax-propertize-heredoc
в магистрали Emacs. Он вызывается из двух мест в ruby-syntax-propertize-function
. Первый раз обрабатывать случай, когда мы уже находимся внутри литерала heredoc, а затем для любых последующих heredocs.