Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suite.rc syntax lexers: improve emacs support #2784

Merged
merged 5 commits into from
Oct 31, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 111 additions & 40 deletions etc/syntax/cylc-mode.el
Original file line number Diff line number Diff line change
@@ -1,47 +1,118 @@
;; Simple syntax highlighting for cylc suite definition files.
;; Author: Luis Kornblueh, 2012
;; ____________________________________________________________________________
;;
;; 1. copy this file to $HOME/.emacs.d/lisp
;; 2. add in $HOME/.emacs the following lines:
;; = cylc-mode.el =
;; Emacs syntax highlighting mode for Cylc suite definition (suite.rc) files
;; ____________________________________________________________________________
;;
;; (add-to-list 'load-path "~/.emacs.d/lisp/")
;; (require 'cylc-mode)
;; (setq auto-mode-alist (append auto-mode-alist
;; (list '("\\.rc$" . cylc-mode))))
;; (global-font-lock-mode t)
;;______________________________________________________________________________

(defconst cylc-mode-version "0.1")

(setq cylc-font-lock-keywords
'(("{%[[:alnum:], _=\\(\\)]*%}" . font-lock-constant-face)
("{#[^\}]+#}" . font-lock-comment-face)
("#.*" . font-lock-comment-face)
("{{[[:alnum:] ]*}}" . font-lock-constant-face)
("\\[\\[\\[[[:alnum:], _]+\\]\\]\\]" . font-lock-type-face)
("\\[\\[\\[[[:alnum:], _]+" . font-lock-type-face)
("\\]\\]\\]" . font-lock-type-face)
("\\[\\[[[:alnum:], _]*\\]\\]" . font-lock-function-name-face)
("\\[\\[[[:alnum:], _]*" . font-lock-function-name-face)
("\\]\\]" . font-lock-function-name-face)
("\\[[[:alnum:], ]+\\]" . font-lock-warning-face)
("^[[:alnum:] -_]*=" . font-lock-variable-name-face)
))

;; define the mode
;; = Instructions =
;; Place this file in a directory on your emacs load path (or symlink it)
;; e.g.
;; mkdir -p $HOME/.emacs.d/lisp
;; ln -s $CYLC_HOME/etc/cylc-mode.el ~/.emacs.d/lisp/
;;
;; and in your $HOME/.emacs file add the following lines:
;;
;; (add-to-list 'load-path "~/.emacs.d/lisp/")
;; (require 'cylc-mode)
;;
;; ____________________________________________________________________________

(defvar cylc-mode-hook nil)

;; Extend region hook to ensure correct re-fontifying of the multi-line region
(defun cylc-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))))

;; Define the mode and the syntax highlighting for it
(define-derived-mode cylc-mode fundamental-mode
"cylc mode"
"Major mode for editing CYLC .cylc files"
"suite.rc" "Major mode for editing Cylc suite definition files"

;; code for syntax highlighting
(setq font-lock-defaults '(cylc-font-lock-keywords))
;; Note: ordered according to reverse application precendence, where
;; specification order for faces changes resultant highlighting

)
;; Assignment and dependency characters, but only outside of Jinja2
(font-lock-add-keywords nil '(("=+" . font-lock-preprocessor-face)))
(font-lock-add-keywords nil '(("=>" . font-lock-keyword-face)))

(provide 'cylc-mode)
;; Cylc setting keys/names
(font-lock-add-keywords nil
'(("^\\( *[a-zA-Z0-9\-]+ *\\)=+" 1 font-lock-variable-name-face t)))

;; Account for section headings (see below) with internal patterns, e.g. a
;; Jinja2 statement, inside by matching start and end heading groups. Note:
;; must be applied here to get correct 'pure' header & ICD highlighting.
(font-lock-add-keywords nil
'(("\\[\\( *[ a-zA-Z0-9\-\_,.]*\\)" . font-lock-warning-face)))
(font-lock-add-keywords nil
'(("\\( *[ a-zA-Z0-9\-\_,.]*\\)\\]" . font-lock-warning-face)))
(font-lock-add-keywords nil
'(("\\[\\[\\( *[ a-zA-Z0-9\-\_,.]*\\)" . font-lock-function-name-face)))
(font-lock-add-keywords nil
'(("\\( *[ a-zA-Z0-9\-\_,.]*\\)\\]\\]" . font-lock-function-name-face)))
(font-lock-add-keywords nil
'(("\\[\\[\\[\\( *[ a-zA-Z0-9\-\_,.]*\\)" . font-lock-type-face)))
(font-lock-add-keywords nil
'(("\\( *[ a-zA-Z0-9\-\_,.]*\\)\\]\\]\\]" . font-lock-type-face)))

;; Inter-cycle dependencies (distinguish from top-level section headings)
(font-lock-add-keywords nil '(("\\[.*\\]" . font-lock-string-face)))

;; All 'pure' Cylc section (of any level e.g. sub-, sub-sub-) headings:
;; ... Top-level headings, enclosed in single square brackets
(font-lock-add-keywords nil '(("^ *\\[.*\\]$" . font-lock-warning-face)))
;; ... Second-level (sub-) section headings, enclosed in double brackets
(font-lock-add-keywords nil
'(("^ *\\[\\[.*\\]\\]$" . font-lock-function-name-face)))
;; ... Third-level (sub-sub-) section headings, enclosed in triple brackets
(font-lock-add-keywords nil
'(("^ *\\[\\[\\[.*\\]\\]\\]$" . font-lock-type-face)))

(add-hook 'cylc-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("\\({%[[:alnum:], _=\\(\\)]*%}\\|{{[[:alnum:] ]*}}\\)" 0
font-lock-constant-face t)))))
;; All comments: standard ('# ... ') and Jinja2 ('{# ... #}')
(font-lock-add-keywords nil
'(("#.*$" . font-lock-comment-face))) ;; in-line only, by precendece
;; Stop interference. No regex lookarounds in Emacs Lisp; ugly workaround
(font-lock-add-keywords nil
'(("^#\\(\\([^{].{2}\\|.[^#]\\).*\\|.{0,1}\\)$"
. font-lock-comment-face)))
(font-lock-add-keywords nil
'(("{#\\(\n?.?\\)*?.*#}" . font-lock-comment-face))) ;; not in-line

;; All Jinja2 excl. comments: '{% ... %}' and '{{ ... }}' incl. multiline
(font-lock-add-keywords nil
'(("{%\\(\n?.?\\)*?.*%}" . font-lock-constant-face)))
(font-lock-add-keywords nil '(("{{.*?}}" . font-lock-constant-face)))

;; Highlight triple quotes for a multi-line setting value
(font-lock-add-keywords nil '(("\"\"\"" . 'font-lock-builtin-face)))

;; Add the extend region hook to deal with the multiline matching above
(add-hook 'font-lock-extend-region-functions 'cylc-font-lock-extend-region)

;; Make sure jit-lock scans larger multiline regions correctly
(set (make-local-variable 'jit-lock-contextually) t)

;; Force any other fundamental mode inherit font-locking to be ignored, this
;; previously caused double-quotes to break the multiline highlighting
(set (make-local-variable 'font-lock-keywords-only) t)

;; We need multiline mode
(set (make-local-variable 'font-lock-multiline) t)

;; Run the mode hooks to allow a user to execute mode-specific actions
(run-hooks 'cylc-mode-hook))

;;;###autoload
(add-to-list 'auto-mode-alist '("suite*.rc" . cylc-mode))

(provide 'cylc-mode)