Подтвердить что ты не робот

Emacs: есть ли яркий пример многострочной блокировки шрифтов?

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

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

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

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

EDIT: я должен уточнить, что я не хочу видеть специфичную для конкретного режима блокировку шрифта в блоках javascript/css. Единственное требование состоит в том, что я могу видеть куски, применяя к ним другое лицо.

4b9b3361

Ответ 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.