[Emacs] Support font-locking in haml-mode :filter blocks.

This commit is contained in:
Steve Purcell
2010-02-02 12:19:52 -08:00
committed by Nathan Weizenbaum
parent 5611fe2022
commit 94a8228e86

View File

@@ -25,6 +25,13 @@
(eval-when-compile (require 'cl))
(require 'ruby-mode)
;; Additional (optional) libraries for fontification
(require 'css-mode nil nil)
(require 'textile-mode nil nil)
(require 'markdown-mode nil nil)
(require 'javascript-mode "javascript" nil)
;; User definable variables
(defgroup haml nil
@@ -92,22 +99,28 @@ The line containing RE is matched, as well as all lines indented beneath it."
(defconst haml-font-lock-keywords
`((,(haml-nested-regexp "\\(?:-#\\|/\\).*") 0 font-lock-comment-face)
(,(haml-nested-regexp ":\\w+") 0 font-lock-string-face)
(haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
(haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
(haml-highlight-ruby-script 1 font-lock-preprocessor-face)
("^ *\\(\t\\)" 1 'haml-tab-face)
("^!!!.*" 0 font-lock-constant-face)
("| *$" 0 font-lock-string-face)))
(haml-highlight-ruby-filter-block 1 font-lock-preprocessor-face)
(haml-highlight-css-filter-block 1 font-lock-preprocessor-face)
(haml-highlight-textile-filter-block 1 font-lock-preprocessor-face)
(haml-highlight-markdown-filter-block 1 font-lock-preprocessor-face)
(haml-highlight-js-filter-block 1 font-lock-preprocessor-face)
(haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
(haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
(haml-highlight-ruby-script 1 font-lock-preprocessor-face)
("^ *\\(\t\\)" 1 'haml-tab-face)
("^!!!.*" 0 font-lock-constant-face)
("| *$" 0 font-lock-string-face)))
(defconst haml-filter-re "^ *:\\w+")
(defconst haml-comment-re "^ *\\(?:-\\#\\|/\\)")
(defun haml-fontify-region-as-ruby (beg end)
"Use Ruby's font-lock variables to fontify the region between BEG and END."
(defun haml-fontify-region (beg end keywords syntax-table syntactic-keywords)
(save-excursion
(save-match-data
(let ((font-lock-keywords ruby-font-lock-keywords)
(font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)
(let ((font-lock-keywords keywords)
(font-lock-syntax-table syntax-table)
(font-lock-syntactic-keywords syntactic-keywords)
(font-lock-multiline 'undecided)
font-lock-keywords-only
font-lock-extend-region-functions
font-lock-keywords-case-fold-search)
@@ -115,6 +128,70 @@ The line containing RE is matched, as well as all lines indented beneath it."
;; so we have to move the beginning back one char
(font-lock-fontify-region (- beg 1) end)))))
(defun haml-fontify-region-as-ruby (beg end)
"Use Ruby's font-lock variables to fontify the region between BEG and END."
(haml-fontify-region beg end ruby-font-lock-keywords nil
ruby-font-lock-syntactic-keywords))
(defun haml-handle-filter (filter-name limit fn)
"Call `fn' with `beg' and `end' params if a :filter-name block is found."
(when (re-search-forward (haml-nested-regexp (concat ":" filter-name)) limit t)
(funcall fn (+ 2 (match-beginning 2)) (match-end 2))))
(defun haml-fontify-filter-region (filter-name limit &rest fontify-region-args)
"Find a filter block of type `filter-name' and call `haml-fontify-region'
with the provided args."
(haml-handle-filter filter-name limit
(lambda (beg end)
(apply 'haml-fontify-region
(append (list beg end)
fontify-region-args)))))
(defun haml-highlight-ruby-filter-block (limit)
"Highlight a Ruby script expression inside ':ruby' filter block."
(haml-handle-filter "ruby" limit 'haml-fontify-region-as-ruby))
(defun haml-highlight-css-filter-block (limit)
"Highlight CSS inside ':css' filter block.
For this to work, 'css-mode.el' must be available, as is automatically
the case in Emacs 23."
(if (boundp 'css-font-lock-keywords)
(haml-fontify-filter-region "css" limit css-font-lock-keywords nil nil)))
(defun haml-highlight-js-filter-block (limit)
"Highlight Javascript inside ':javascript' filter block.
For this to work, Karl Landström's 'javascript.el' must be available,
e.g. by installing it from ELPA."
(if (boundp 'js-font-lock-keywords-3)
(haml-fontify-filter-region "javascript"
limit
js-font-lock-keywords-3
javascript-mode-syntax-table
nil)))
(defun haml-highlight-textile-filter-block (limit)
"Highlight Textile inside ':textile' filter block.
Note that the results are not perfect, since textile-mode expects
certain constructs such as 'h1.' to be at the beginning of a line,
and indented haml filter blocks always have leading whitespace.
For this to work, 'textile-mode.el' must be available."
(if (boundp 'textile-font-lock-keywords)
(haml-fontify-filter-region "textile" limit textile-font-lock-keywords nil nil)))
(defun haml-highlight-markdown-filter-block (limit)
"Highlight Markdown inside ':markdown' filter block.
For this to work, 'markdown-mode.el' must be available."
(if (boundp 'markdown-mode-font-lock-keywords)
(haml-fontify-filter-region "markdown" limit
markdown-mode-font-lock-keywords
markdown-mode-syntax-table
nil)))
(defun haml-highlight-ruby-script (limit)
"Highlight a Ruby script expression (-, =, or ~).
LIMIT works as it does in `re-search-forward'."
@@ -263,7 +340,7 @@ With ARG, do it that many times."
;; Move through multiline attrs
(when (eq (char-before) ?,)
(save-excursion
(while (progn (end-of-line) (eq (char-before) ?,) (not (eobp)))
(while (progn (end-of-line) (and (eq (char-before) ?,) (not (eobp))))
(forward-line))
(forward-line -1)
@@ -497,7 +574,7 @@ beginning the hash."
(save-excursion
(while t
(beginning-of-line)
(if (looking-at (eval-when-compile (concat haml-tag-beg-re "\\([{(]\\)")))
(if (looking-at (concat haml-tag-beg-re "\\([{(]\\)"))
(progn
(goto-char (- (match-end 0) 1))
(haml-limited-forward-sexp (save-excursion (end-of-line) (point)))