2012-02-26 3 views
12

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

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

Я нашел этот section руководства, которому не хватает примера, и этот emacswiki page с поврежденным кодом.

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

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

ответ

6

В приведенном ниже примере я использую «привязанные» формы ключевых слов для блокировки шрифтов, что позволяет вам искать больше, чем текущая строка. «Уловка» заключается в том, что «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 
+1

В этой [нить] (http://lists.gnu.org/archive/html/help-gnu-emacs/2004-09/msg00534.html) Стефан Моннье говорит, что функция font-lock-multi-line подходит для вещей, которые обычно однострочные, но иногда многострочные. Комментарии? –

+0

Ну, Stefan Monnier является окончательной ссылкой, когда дело доходит до любого связанного с шрифтом-замком, поэтому любые советы от него заслуживают внимания. Использование синтаксической системы, как он предлагает, является одним из способов сделать это. Другим является использование «функции соответствия», а не регулярного выражения, которое может соответствовать всему блоку. Вы должны увидеть мои ответы как прямой ответ на вопрос (укажите пример многострочной функции блокировки шрифтов) и, возможно, не ответ на лучший способ выполнить то, о чем спрашивали оригинальные плакаты. – Lindydancer

3

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

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

4

Я опишу простой основной режим для выделения <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. (Соответствующая документация для этих matchers находится в 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, он должен работать для выделения этих двух типов блоков. Хотя я считаю, что это делает работу, если есть более эффективный или правильный способ обойти это, мне также будет любопытно знать .

Смежные вопросы