| ;;; ftl.el --- fontify velocity template language code |
| |
| ;; Modified from vtl mode by Brian Leonard <brian@brainslug.org> |
| ;; Maintainer: marvin.greenberg@acm.org |
| ;; Keywords: extensions |
| ;; Created: 2003-03-13 |
| ;; Version 0.1 |
| |
| ;;; Commentary: |
| |
| ;;; |
| ;;; Known bugs!: |
| ;;; |
| ;;; Hilighting of strings with escaped quotes will be erroneously terminated at the escaped quote. |
| ;;; Strings are fontified everywhere, not just in interpolations and directives |
| ;;; An occurrence of '>' within a string or expression in a directive or interpolation |
| ;;; will incorrectly terminate highlighting. |
| ;;; An occurrence of '}' within a string argument to a method in an interpolation |
| ;;; will incorrectly terminate highlighting for the interpolation. |
| ;;; |
| |
| ;; One useful way to enable this minor mode is to put the following in your |
| ;; .emacs, assuming you save this in your home directory also: |
| ;; (load-file "~/ftl.el") |
| ;; (autoload 'turn-on-ftl-mode "ftl" nil t) |
| ;; (add-hook 'html-mode-hook 'turn-on-ftl-mode t t) |
| ;; (add-hook 'xml-mode-hook 'turn-on-ftl-mode t t) |
| ;; (add-hook 'text-mode-hook 'turn-on-ftl-mode t t) |
| ;; |
| ;; Also this might be useful |
| ;; |
| ;; (setq auto-mode-alist (cons (cons "\\.ftl$" 'ftl-mode) auto-mode-alist)) |
| |
| ;;; Code: |
| |
| (require 'font-lock) |
| (require 'cl) |
| |
| (defgroup ftl nil |
| "Fontifies FTL code. see http://freemarker.org" |
| :group 'ftl |
| :group 'font-lock |
| :group 'extensions) |
| |
| ;;;###autoload |
| (defcustom ftl-mode nil |
| "*If non-nil, fontify ftl code" |
| :type 'boolean) |
| (make-variable-buffer-local 'ftl-mode) |
| |
| ;;;###autoload |
| (defcustom ftl-minor-mode-string " FTL" |
| "*String to display in mode line when FTL Mode is enabled." |
| :type 'string |
| :group 'ftl) |
| |
| ;;;###autoload |
| (defun turn-on-ftl-mode () |
| "Unequivocally turn on ftl-mode (see variable documentation)." |
| (interactive) |
| (font-lock-mode 1) |
| (ftl-mode 1)) |
| |
| ;; Put minor mode string on the global minor-mode-alist. |
| ;;;###autoload |
| (cond ((fboundp 'add-minor-mode) |
| (add-minor-mode 'ftl-mode 'ftl-minor-mode-string)) |
| ((assq 'ftl-mode (default-value 'minor-mode-alist))) |
| (t |
| (setq-default minor-mode-alist |
| (append (default-value 'minor-mode-alist) |
| '((ftl-mode ftl-minor-mode-string)))))) |
| |
| ;;;###autoload |
| (defun ftl-mode (&optional prefix) |
| "Toggle FTL Mode. |
| |
| If called interactively with no prefix argument, toggle current condition |
| of the mode. |
| If called with a positive or negative prefix argument, enable or disable |
| the mode, respectively." |
| (interactive "P") |
| |
| (setq ftl-mode |
| (if prefix |
| (>= (prefix-numeric-value prefix) 0) |
| (not ftl-mode))) |
| |
| (cond (ftl-mode |
| ;; first, grab default |
| (font-lock-mode 0) |
| (font-lock-set-defaults) |
| |
| ;; add ftl regexps |
| (setq font-lock-keywords |
| (let ((new-keywords |
| (cond ((null font-lock-keywords) |
| ftl-keywords) |
| (t |
| (list* (car font-lock-keywords) |
| (append (cdr font-lock-keywords) |
| ftl-keywords)))))) |
| new-keywords)) |
| |
| ;; and restart font-lock |
| (font-lock-mode 1) |
| (font-lock-fontify-buffer)) |
| |
| (t |
| ;; reset to major mode's defaults |
| (font-lock-mode 0) |
| (font-lock-set-defaults) |
| (font-lock-mode 1) |
| (font-lock-fontify-buffer))) |
| |
| (and (interactive-p) |
| (if ftl-mode |
| (message "ftl-mode is enabled") |
| (message "ftl-mode is disabled"))) |
| ftl-mode) |
| |
| |
| ; |
| ; tried complex, now try simple |
| |
| (setq ftl-keywords |
| (let |
| ( |
| (directive (concat "[<][/]?#\\(assign\\|if\\|elseif\\|else\\|foreach\\|" |
| "list\\|break\\|import\\|include\\|noparse\\|compress\\|" |
| "escape\\|noescape\\|global\\|local\\|setting\\|" |
| "switch\\|case\\|call\\|break\\|" |
| "nested\\|return\\|flush\\|stop\\|macro\\|ftl\\|" |
| "t\\|lt\\|rt\\)" |
| "[^a-zA-Z][^>]*[>]")) |
| (directive-noargs (concat "[<][/]?#\\(assign\\|if\\|elseif\\|else\\|foreach\\|" |
| "list\\|break\\|import\\|include\\|noparse\\|compress\\|" |
| "escape\\|noescape\\|global\\|local\\|setting\\|" |
| "switch\\|case\\|call\\|break\\|" |
| "nested\\|return\\|flush\\|stop\\|macro\\|ftl\\|" |
| "t\\|lt\\|rt\\)" |
| "[>]")) |
| (invalid-directive "\\([<][/]?#[a-zA-Z][a-zA-Z_0-9]*\\)[^>]*\\([>]\\)") |
| (user-directive "[<][/]?@[a-zA-Z_][a-zA-Z0-9_]*[^>]*[>]") |
| (interpolation-all "[#$][{][^}]+[}]") |
| (string "[\"][^\"]*[\"]") |
| (sq-string "[\'][^\']*[\']") |
| (comment "[<]#--[^>]*--[>]")) |
| |
| (list |
| (list user-directive '(0 font-lock-function-name-face t)) |
| (list invalid-directive '(1 font-lock-warning-face t)) |
| (list invalid-directive '(2 font-lock-warning-face t)) |
| (list directive '(0 font-lock-keyword-face t)) |
| (list directive-noargs '(0 font-lock-keyword-face t)) |
| (list interpolation-all '(0 font-lock-type-face t)) |
| (list string '(0 font-lock-string-face t)) |
| (list sq-string '(0 font-lock-string-face t)) |
| (list comment '(0 font-lock-comment-face t))))) |
| |
| ;; This was an attempt to get more granularity, e.g. anything |
| ;; name[(]args[)] would hilight as a function in interpolations or user directives |
| ;; Anything name would highlight as a variable name in interpolations or user directives |
| ;; Syntax in interpolations (.(),+- etc.) would highlight as a differnet face. |
| ;; But I couldn't figure out how to get "recursive" highlights (like a method as an |
| ;; argument to a method...) to match a regex properly... But I have some ideas... |
| ;; |
| ;; (defvar ftl-keywords |
| ;; (let |
| ;; ( |
| ;; (directive (concat "\\([<][/]?#\\(assign\\|if\\|elseif\\|else\\|foreach\\|" |
| ;; "list\\|break\\|import\\|noparse\\|compress\\|" |
| ;; "escape\\|noescape\\|global\\|local\\|setting\\|" |
| ;; "switch\\|case\\|default\\|break\\|" |
| ;; "nested\\|return\\|flush\\|stop\\|macro\\ftl\\|" |
| ;; "t\\|lt\\|rt" |
| ;; ")[^>]*[>]\\)")) |
| ;; (user-directive "\\([<][/]?@[a-zA-Z][a-zA-Z0-9_]*[^>]*[>]\\)") |
| |
| ;; (interpolation-all "\\(\\$[{][^}]+[}]\\)") |
| ;; (interpolation-names "\\$[{]\\(?\\([:alpha:][_[:alnum:]]*\\)[(),. ]*\\)[}]") |
| ;; (interpolation-methods "\\$[{]\\(?\\([:alpha:][_[:alnum:]]*\\)[(][^(}]\\)*[}]") |
| ;; (interpolation-syntax "\\$[{]\\(?[^(),.\"']*\\([.,()\"']\\)\\)*[}]") |
| ;; (string "\\(\"[^\"]*\"\\)") |
| ;; (comment "\\([<]#--[^>]*--[>]\\)")) |
| |
| |
| ;; (list |
| ;; (list interpolation-all '(1 font-lock-type-face t)) |
| ;; (list interpolation-names '(1 font-lock-variable-name-face t)) |
| ;; (list interpolation-methods '(1 font-lock-function-face t)) |
| ;; (list interpolation-syntax '(1 font-lock-warning-face t)) |
| ;; (list user-directive '(0 font-lock-function-name-face t)) |
| ;; (list directive '(0 font-lock-keyword-face t)) |
| ;; (list string '(1 font-lock-string-face t)) |
| ;; (list comment '(0 font-lock-comment-face t))))) |
| |
| (provide 'ftl) |
| |