lilypond-mode

Emacs mode for editing LilyPond source
git clone https://git.jamzattack.xyz/lilypond-mode
Log | Files | Refs

lilypond-font-lock.el (9796B)


      1 ;;; lilypond-font-lock.el --- syntax coloring for LilyPond mode
      2 
      3 ;; Author: 2001-2006: Heikki Junes
      4 ;;  * Emacs-mode: new keywords, reserved words, identifiers, notenames,
      5 ;;    some dynamics and brackets are font-lock-keywords
      6 ;;  * context-dependent syntax-tables
      7 ;; Author: 1997: Han-Wen Nienhuys
      8 ;; Author: 1995-1996 Barry A. Warsaw
      9 ;;         1992-1994 Tim Peters
     10 ;; Created:       Feb 1992
     11 ;; Version:       2.9.29
     12 ;; Last Modified: 11NOV2006
     13 ;; Keywords: lilypond languages music notation
     14 
     15 ;; This started out as a cannabalised version of python-mode.el, by hwn
     16 ;; For changes see the LilyPond ChangeLog
     17 ;;
     18 
     19 ;; TODO:
     20 ;;   - handle lexer modes (\header, \melodic) etc.
     21 
     22 (defconst LilyPond-font-lock-keywords
     23   (let* ((kwregex (mapconcat (lambda (x) (concat "\\" x))  LilyPond-keywords "\\|"))
     24 	 (iregex (mapconcat (lambda (x) (concat "\\" x))  LilyPond-identifiers "\\|"))
     25 	 (ncrwregex (mapconcat (lambda (x) (concat "" x))  LilyPond-non-capitalized-reserved-words "\\|"))
     26 	 (rwregex (mapconcat (lambda (x) (concat "" x))  LilyPond-Capitalized-Reserved-Words "\\|"))
     27 	 (duration "\\([ \t]*\\(128\\|6?4\\|3?2\\|16?\\|8\\)[.]*\\([ \t]*[*][ \t]*[0-9]+\\(/[1-9][0-9]*\\)?\\)?\\)")
     28 	 (longduration "\\([ \t]*\\(\\\\\\(longa\\|breve\\|maxima\\)\\)[.]*\\([ \t]*[*][ \t]*[0-9]+\\(/[1-9][0-9]*\\)?\\)?\\)"))
     29     (list
     30      ;; Fonts in use (from GNU Emacs Lisp Reference Manual, elisp.ps):
     31      ;; font-lock- (c)omment / (s)tring / (k)eyword / (b)uiltin / (f)unction-name /
     32      ;;            (v)ariable-name / (t)ype / co(n)stant / (w)arning -face
     33 
     34      ;; The order below is designed so that proofreading would be possible.
     35 
     36      ;; Fontify...
     37      ;; ... (f) identifiers and (k) keywords.
     38      ;; ... (n) user defined indetifiers
     39      ;; ... (v) the right and the left side of '='-marks.
     40      ;; ... (v) reserved words, e.g., FiguredBass.
     41      ;; ... (t) notes and rests
     42      ;; "on top", ... (s) lyrics-mode
     43      ;; "on top", ... (w) horizontal grouping
     44      ;; "on top", ... (f) vertical grouping
     45      ;; "on top", ... (b) expressional grouping
     46      ;; "on top", ... (s) (multiline-)scheme; urgh. one should count the slurs
     47      ;; "on top", ... (s) strings
     48      ;; "on top", ... (c) (multiline-)comments
     49 
     50      ;; One should note 'font-lock-multiline' has been possible since Emacs 21.1.
     51      ;; See, e.g., text in "http://emacs.kldp.org/emacs-21.1/etc/NEWS".
     52 
     53      ;; ... identifiers (defined above, see iregex)
     54      (cons (concat "\\(\\([_^-]?\\(" iregex "\\)\\)+\\)\\($\\|[] \t(~{}>\\\\_()^*-]\\)") '(1 font-lock-function-name-face))
     55 
     56      ;; ... keywords (defined above, see kwregex)
     57      (cons (concat "\\(\\([_^-]?\\(" kwregex "\\)\\)+\\)\\($\\|[] \t(~{}>\\\\_()^*-]\\)") '(1 font-lock-keyword-face))
     58 
     59      ;; ... user defined identifiers, roughly  \[a-zA-Z]+ with single - or _ in between.
     60      '("\\([_^-]?\\\\\\([a-zA-Z[:nonascii:]]\\(?:[-_]?[a-zA-Z[:nonascii:]]\\)*\\)\\)" 1 font-lock-constant-face)
     61 
     62      ;; ... the left side of '=' -mark
     63      '("\\([_a-zA-Z.0-9-]+\\)[ \t]*=[ \t]*" 1 font-lock-variable-name-face)
     64 
     65      ;; ... the right side of '=' -mark
     66      '("[ \t]*=[ \t]*\\([_a-zA-Z.0-9-]+\\)" 1 font-lock-variable-name-face)
     67 
     68      ;; ... reserved words (defined above, see rwregex)
     69      (cons (concat "\\(" rwregex "\\)") 'font-lock-variable-name-face)
     70 
     71      ;; ... note or rest with (an accidental and) a duration, e.g., b,?16.*3/4
     72      (cons (concat "\\(^\\|[ <\{[/~(!)\t\\\|]\\)\\(\\(\\(" ncrwregex "\\)[,']*[?!]?\\|[srR]\\)" duration "?\\)") '(2 font-lock-type-face))
     73 
     74      ;; "on top", ... notes and rests with a long duration
     75      (cons (concat "\\(^\\|[ <\{[/~(!)\t\\\|]\\)\\(\\(\\(" ncrwregex "\\)[,']*[?!]?\\|[srR]\\)" longduration "\\)") '(2 font-lock-type-face t))
     76 
     77      ;; "on top", ... lyrics-mode: fontify everything between '<'...'>' or '{'...'}'
     78 					;            URGH, does not know anything about inner brackets.
     79 					;            Multiple lines may need refontifying (C-c f).
     80      '("\\(\\\\lyrics[^{<]*\\)\\({[^}]*\\|<[^>]*\\)" 2 font-lock-string-face t)
     81 
     82      ;; "on top", ... horizontal grouping, also as postfix syntax '-*':
     83      ;;               - brackets '{[]}'
     84      ;;               - ties '~'
     85      ;;               - ligatures \[, \]
     86      '("\\(-?[][~}{]\\|\\\\[][]\\)" 0 font-lock-reference-face t)
     87 
     88      ;; "on top", ... vertical grouping:
     89      ;;               - '<>'-chord brackets with '\\'-voice sep., not marcato '->'
     90      ;;               - '<< a b >>8' -chords
     91      (cons (concat "\\(\\(-.\\)+\\|[^-^_]\\)\\([<>]+\\(" duration "\\|" longduration "\\)?\\|\\\\\\\\\\)") '(3 font-lock-function-name-face t))
     92 
     93      ;; "on top", ... expressional grouping, also as postfix syntax '-*':
     94      ;;               - slurs ( ), \( \), [-^_][()]
     95      ;;               - hairpins \<, \>, \!
     96      '("\\(-?\\\\[(<!>)]\\|[-^_]?[()]\\)" 0 font-lock-builtin-face t)
     97 
     98      ;; "on top", ... (multiline-)scheme: try find slurs up to 7th
     99      '("[_^-]?#\\(#[ft]\\|-?[0-9.]+\\|\"[^\"]*\"\\|['`]?[a-zA-Z:-]+\\|['`]?([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^)]*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*[^)]*)\\)" 0 font-lock-string-face t)
    100 
    101      ;; "on top", ... strings, match also unending strings at eof:
    102      ;;               if '\n' was not found, it must be '$' which is eof (?).
    103      '("\\([_^-]?\"\\([^\"\\\\]\\|\\\\.\\|\\\\\n\\)*\\(\"\\|$\\)\\)" 0 font-lock-string-face t)
    104 
    105      ;; "on top", ... (multiline-)comments
    106      '("\\(%\\({[^%]*%\\(}\\|\\([^}][^%]*%\\)+}\\)\\|.*\\)\\)" 0 font-lock-comment-face t)))
    107   "Additional expressions to fontify in LilyPond mode.")
    108 
    109 ;; define a mode-specific abbrev table for those who use such things
    110 (defvar LilyPond-mode-abbrev-table nil
    111   "Abbrev table in use in `LilyPond-mode' buffers.")
    112 
    113 (define-abbrev-table 'LilyPond-mode-abbrev-table nil)
    114 
    115 (defvar LilyPond-mode-syntax-table nil
    116   "Syntax table used in `LilyPond-mode' buffers.")
    117 
    118 (defun LilyPond-mode-set-syntax-table (&optional not-punct)
    119   "Change syntax table according to the argument `not-punct' which contains characters which are given a context dependent non-punctuation syntax: parentheses may be set to parenthesis syntax and characters `-', `^' and `_' may be set to escape syntax."
    120   (if (not not-punct) (setq not-punct '()))
    121   (setq LilyPond-mode-syntax-table (make-syntax-table))
    122   (let ((defaults
    123 	  '(
    124 	    ;; NOTE: Emacs knows only "13"-style (used), XEmacs knows also "1b3b", etc.
    125 	    ( ?\% . "< 13" )   ; comment starter, 1st char in block-comments
    126 	    ( ?\n . ">")       ; newline: comment ender
    127 	    ( ?\r . ">")       ; formfeed: comment ender
    128 	    ( ?\\ . "\\" )     ; escape characters (as '\n' in strings)
    129 	    ( ?\" . "\"" )     ; string quote characters
    130 	    ;; word constituents (e.g., belonging to a note)
    131 	    ( ?\' . "w") ( ?\, . "w") ; transposing octaves
    132 	    ;; punctuation characters (separate symbols from another)
    133 	    ( ?\$ . "." ) ( ?\& . "." )
    134 	    ( ?\* . "." ) ( ?\+ . "." ) ( ?\/ . "." )  ( ?\= . "." )
    135 	    ;; bar-line
    136 	    ( ?\| . "." ))))
    137     ;; all the paren characters are now handled by lily-specific indenting/matching code in lilypond-indent.el
    138     (if (or (memq ?\{ not-punct) (memq ?\} not-punct))
    139 	(setq defaults (cons '( ?\{ . "(} 2" ) (cons '( ?\} . "){ 4" ) defaults))) ; begin and end of a block-comment
    140       (setq defaults (cons '( ?\{ . ". 2" ) (cons '( ?\} . ". 4" ) defaults))))    ; begin and end of a block-comment
    141     (if (or (memq ?\[ not-punct) (memq ?\] not-punct))
    142 	(setq defaults (cons '( ?\[ . "(]" ) (cons '( ?\] . ")[" ) defaults)))
    143       (setq defaults (cons '( ?\[ . "." ) (cons '( ?\] . "." ) defaults))))
    144     (if (or (memq ?\< not-punct) (memq ?\> not-punct))
    145 	(setq defaults (cons '( ?\< . "(>" ) (cons '( ?\> . ")<" ) defaults)))
    146       (setq defaults (cons '( ?\< . "." ) (cons '( ?\> . "." ) defaults))))
    147     (if (or (memq ?\( not-punct) (memq ?\) not-punct))
    148 	(setq defaults (cons '( ?\( . "()" ) (cons '( ?\) . ")(" ) defaults)))
    149       (setq defaults (cons '( ?\( . "." ) (cons '( ?\) . "." ) defaults))))
    150     ;; In LilyPond the following chars serve as escape chars, e.g., c^> d-) e_( ,
    151     ;; but they may be set to punctuation chars, since inside strings they should not act as escape chars
    152     (setq defaults (cons (if (memq ?- not-punct) '( ?\- . "\\" ) '( ?\- . "." ) ) defaults))
    153     (setq defaults (cons (if (memq ?^ not-punct) '( ?^ . "\\" ) '( ?^ . "." ) ) defaults))
    154     (setq defaults (cons (if (memq ?\_ not-punct) '( ?\_ . "\\" ) '( ?\_ . "." ) ) defaults))
    155     (mapcar (function
    156 	     (lambda (x) (modify-syntax-entry
    157 			  (car x) (cdr x) LilyPond-mode-syntax-table)))
    158 	    defaults)
    159     (set-syntax-table LilyPond-mode-syntax-table)))
    160 
    161 (defun LilyPond-mode-context-set-syntax-table ()
    162   "Change syntax table according to current context."
    163   (interactive)
    164   ;; default syntax table sets parentheses to punctuation characters
    165   (LilyPond-mode-set-syntax-table)
    166   ;; find current context
    167   (setq context (parse-partial-sexp (point-min) (point)))
    168   (cond ((nth 3 context)) ; inside string
    169 	((nth 4 context)) ; inside a comment
    170 	((eq (char-syntax (or (char-before (point)) 0)) ?\\)) ; found escape-char
    171 	((and (eq (char-syntax (or (char-before (- (point) 1)) 0)) ?\\)
    172 	      (memq (char-before (point)) '( ?\) ?\] )))) ; found escape-char
    173 	((memq (char-before (point)) '( ?\) ))
    174 	 (LilyPond-mode-set-syntax-table '( ?\( ?\) )))
    175 	((memq (char-before (point)) '( ?\] ))
    176 	 (LilyPond-mode-set-syntax-table '( ?\[ ?\] )))
    177 	((memq (char-before (point)) '( ?\> ?\} ))
    178 	 (LilyPond-mode-set-syntax-table '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))
    179 	((memq (char-after (point)) '( ?\( ))
    180 	 (LilyPond-mode-set-syntax-table '( ?\( ?\) )))
    181 	((memq (char-after (point)) '( ?\[ ))
    182 	 (LilyPond-mode-set-syntax-table '( ?\[ ?\] )))
    183 	((memq (char-after (point)) '( ?\< ?\{ ))
    184 	 (LilyPond-mode-set-syntax-table '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))))