File size: 10,491 Bytes
f65fe85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
;;;; lilypond-font-lock.el --- syntax coloring for LilyPond mode
;;;;
;;;; This file is part of LilyPond, the GNU music typesetter.
;;;;
;;;; Copyright (C) 1997-2001 Han-Wen Nienhuys <[email protected]>,
;;;;               2001-2006  Heikki Junes <[email protected]>
;;;;
;;;; LilyPond is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation, either version 3 of the License, or
;;;; (at your option) any later version.
;;;;
;;;; LilyPond is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
;;
;; Author: 2001-2006: Heikki Junes
;;  * Emacs-mode: new keywords, reserved words, identifiers, notenames, 
;;    some dynamics and brackets are font-lock-keywords
;;  * context-dependent syntax-tables
;; Author: 1997: Han-Wen Nienhuys
;; Author: 1995-1996 Barry A. Warsaw
;;         1992-1994 Tim Peters
;; Created:       Feb 1992
;; Version:       2.9.29
;; Last Modified: 11NOV2006
;; Keywords: lilypond languages music notation

;; This started out as a cannabalised version of python-mode.el, by hwn
;; For changes see the LilyPond ChangeLog
;;

;; TODO:
;;   - handle lexer modes (\header, \melodic) etc.

(defconst LilyPond-font-lock-keywords
  (let* ((kwregex (mapconcat (lambda (x) (concat "\\" x))  LilyPond-keywords "\\|"))
	 (iregex (mapconcat (lambda (x) (concat "\\" x))  LilyPond-identifiers "\\|"))
	 (ncrwregex (mapconcat (lambda (x) (concat "" x))  LilyPond-non-capitalized-reserved-words "\\|"))
	 (rwregex (mapconcat (lambda (x) (concat "" x))  LilyPond-Capitalized-Reserved-Words "\\|"))
	 (duration "\\([ \t]*\\(128\\|6?4\\|3?2\\|16?\\|8\\)[.]*\\([ \t]*[*][ \t]*[0-9]+\\(/[1-9][0-9]*\\)?\\)?\\)") 
	 (longduration "\\([ \t]*\\(\\\\\\(longa\\|breve\\|maxima\\)\\)[.]*\\([ \t]*[*][ \t]*[0-9]+\\(/[1-9][0-9]*\\)?\\)?\\)") 
)

    (list 
;; Fonts in use (from GNU Emacs Lisp Reference Manual, elisp.ps):
;; font-lock- (c)omment / (s)tring / (k)eyword / (b)uiltin / (f)unction-name / 
;;            (v)ariable-name / (t)ype / co(n)stant / (w)arning -face

;; The order below is designed so that proofreading would be possible.

;; Fontify...
;; ... (f) identifiers and (k) keywords.
;; ... (n) user defined indetifiers
;; ... (v) the right and the left side of '='-marks.
;; ... (v) reserved words, e.g., FiguredBass.
;; ... (t) notes and rests
;; "on top", ... (s) lyrics-mode
;; "on top", ... (w) horizontal grouping
;; "on top", ... (f) vertical grouping
;; "on top", ... (b) expressional grouping
;; "on top", ... (s) (multiline-)scheme; urgh. one should count the slurs
;; "on top", ... (s) strings
;; "on top", ... (c) (multiline-)comments

;; One should note 'font-lock-multiline' has been possible since Emacs 21.1.
;; See, e.g., text in "http://emacs.kldp.org/emacs-21.1/etc/NEWS".

;; ... identifiers (defined above, see iregex)
      (cons (concat "\\(\\([_^-]?\\(" iregex "\\)\\)+\\)\\($\\|[] \t(~{}>\\\\_()^*-]\\)") '(1 font-lock-function-name-face))

;; ... keywords (defined above, see kwregex)
      (cons (concat "\\(\\([_^-]?\\(" kwregex "\\)\\)+\\)\\($\\|[] \t(~{}>\\\\_()^*-]\\)") '(1 font-lock-keyword-face))

;; ... user defined identifiers, roughly  \[a-zA-Z]+ with single - or _ in between.
      '("\\([_^-]?\\\\\\([a-zA-Z[:nonascii:]]\\(?:[-_]?[a-zA-Z[:nonascii:]]\\)*\\)\\)" 1 font-lock-constant-face)

;; ... the left side of '=' -mark
      '("\\([_a-zA-Z.0-9-]+\\)[ \t]*=[ \t]*" 1 font-lock-variable-name-face)

;; ... the right side of '=' -mark
      '("[ \t]*=[ \t]*\\([_a-zA-Z.0-9-]+\\)" 1 font-lock-variable-name-face)

;; ... reserved words (defined above, see rwregex)
      (cons (concat "\\(" rwregex "\\)") 'font-lock-variable-name-face)

;; ... note or rest with (an accidental and) a duration, e.g., b,?16.*3/4
      (cons (concat "\\(^\\|[ <\{[/~(!)\t\\\|]\\)\\(\\(\\(" ncrwregex "\\)[,']*[?!]?\\|[srR]\\)" duration "?\\)") '(2 font-lock-type-face))

;; "on top", ... notes and rests with a long duration
      (cons (concat "\\(^\\|[ <\{[/~(!)\t\\\|]\\)\\(\\(\\(" ncrwregex "\\)[,']*[?!]?\\|[srR]\\)" longduration "\\)") '(2 font-lock-type-face t))

;; "on top", ... lyrics-mode: fontify everything between '<'...'>' or '{'...'}'
;            URGH, does not know anything about inner brackets.
;            Multiple lines may need refontifying (C-c f).
      '("\\(\\\\lyrics[^{<]*\\)\\({[^}]*\\|<[^>]*\\)" 2 font-lock-string-face t)

;; "on top", ... horizontal grouping, also as postfix syntax '-*':
;;               - brackets '{[]}'
;;               - ties '~'
;;               - ligatures \[, \]
      '("\\(-?[][~}{]\\|\\\\[][]\\)" 0 font-lock-reference-face t)

;; "on top", ... vertical grouping:
;;               - '<>'-chord brackets with '\\'-voice sep., not marcato '->'
;;               - '<< a b >>8' -chords
      (cons (concat "\\(\\(-.\\)+\\|[^-^_]\\)\\([<>]+\\(" duration "\\|" longduration "\\)?\\|\\\\\\\\\\)") '(3 font-lock-function-name-face t))

;; "on top", ... expressional grouping, also as postfix syntax '-*':
;;               - slurs ( ), \( \), [-^_][()]
;;               - hairpins \<, \>, \! 
      '("\\(-?\\\\[(<!>)]\\|[-^_]?[()]\\)" 0 font-lock-builtin-face t)

;; "on top", ... (multiline-)scheme: try find slurs up to 7th
      '("[_^-]?#\\(#[ft]\\|-?[0-9.]+\\|\"[^\"]*\"\\|['`]?[a-zA-Z:-]+\\|['`]?([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^()]*\\(([^)]*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*)[^()]*\\)*[^)]*)\\)" 0 font-lock-string-face t)

;; "on top", ... strings, match also unending strings at eof:
;;               if '\n' was not found, it must be '$' which is eof (?).
      '("\\([_^-]?\"\\([^\"\\\\]\\|\\\\.\\|\\\\\n\\)*\\(\"\\|$\\)\\)" 0 font-lock-string-face t)

;; "on top", ... (multiline-)comments
      '("\\(%\\({[^%]*%\\(}\\|\\([^}][^%]*%\\)+}\\)\\|.*\\)\\)" 0 font-lock-comment-face t)

      )
    )
  "Additional expressions to fontify in LilyPond mode.")

;; define a mode-specific abbrev table for those who use such things
(defvar LilyPond-mode-abbrev-table nil
  "Abbrev table in use in `LilyPond-mode' buffers.")

(define-abbrev-table 'LilyPond-mode-abbrev-table nil)

(defvar LilyPond-mode-syntax-table nil
  "Syntax table used in `LilyPond-mode' buffers.")

(defun LilyPond-mode-set-syntax-table (&optional not-punct)
  "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."
  (if (not not-punct) (setq not-punct '()))
  (setq LilyPond-mode-syntax-table (make-syntax-table))
  (let ((defaults 	  
	  '(
	    ;; NOTE: Emacs knows only "13"-style (used), XEmacs knows also "1b3b", etc.
	    ( ?\% . "< 13" )   ; comment starter, 1st char in block-comments
	    ( ?\n . ">")       ; newline: comment ender
	    ( ?\r . ">")       ; formfeed: comment ender
	    ( ?\\ . "\\" )     ; escape characters (as '\n' in strings)
	    ( ?\" . "\"" )     ; string quote characters
	    ;; word constituents (e.g., belonging to a note)
	    ( ?\' . "w") ( ?\, . "w") ; transposing octaves
	    ;; punctuation characters (separate symbols from another)
	    ( ?\$ . "." ) ( ?\& . "." )
	    ( ?\* . "." ) ( ?\+ . "." ) ( ?\/ . "." )  ( ?\= . "." )
	    ( ?\| . "." )      ; bar line
	    )))
    ;; all the paren characters are now handled by lily-specific indenting/matching code in lilypond-indent.el
    (if (or (memq ?\{ not-punct) (memq ?\} not-punct))
	(setq defaults (cons '( ?\{ . "(} 2" ) (cons '( ?\} . "){ 4" ) defaults))) ; begin and end of a block-comment
      (setq defaults (cons '( ?\{ . ". 2" ) (cons '( ?\} . ". 4" ) defaults))))    ; begin and end of a block-comment
    (if (or (memq ?\[ not-punct) (memq ?\] not-punct))
	(setq defaults (cons '( ?\[ . "(]" ) (cons '( ?\] . ")[" ) defaults)))
      (setq defaults (cons '( ?\[ . "." ) (cons '( ?\] . "." ) defaults))))
    (if (or (memq ?\< not-punct) (memq ?\> not-punct))
	(setq defaults (cons '( ?\< . "(>" ) (cons '( ?\> . ")<" ) defaults)))
      (setq defaults (cons '( ?\< . "." ) (cons '( ?\> . "." ) defaults))))
    (if (or (memq ?\( not-punct) (memq ?\) not-punct))
	(setq defaults (cons '( ?\( . "()" ) (cons '( ?\) . ")(" ) defaults)))
      (setq defaults (cons '( ?\( . "." ) (cons '( ?\) . "." ) defaults))))
    ;; In LilyPond the following chars serve as escape chars, e.g., c^> d-) e_( , 
    ;; but they may be set to punctuation chars, since inside strings they should not act as escape chars
    (setq defaults (cons (if (memq ?- not-punct) '( ?\- . "\\" ) '( ?\- . "." ) ) defaults))
    (setq defaults (cons (if (memq ?^ not-punct) '( ?^ . "\\" ) '( ?^ . "." ) ) defaults))
    (setq defaults (cons (if (memq ?\_ not-punct) '( ?\_ . "\\" ) '( ?\_ . "." ) ) defaults))
    (mapcar (function
	     (lambda (x) (modify-syntax-entry
			  (car x) (cdr x) LilyPond-mode-syntax-table)))
	    defaults)
    (set-syntax-table LilyPond-mode-syntax-table)))

(defun LilyPond-mode-context-set-syntax-table ()
  "Change syntax table according to current context."
  (interactive)
  ;; default syntax table sets parentheses to punctuation characters
  (LilyPond-mode-set-syntax-table) 
  ;; find current context
  (setq context (parse-partial-sexp (point-min) (point)))
  (cond ((nth 3 context)) ; inside string
	((nth 4 context)) ; inside a comment
	((eq (char-syntax (or (char-before (point)) 0)) ?\\)) ; found escape-char
	((and (eq (char-syntax (or (char-before (- (point) 1)) 0)) ?\\)
	      (memq (char-before (point)) '( ?\) ?\] )))) ; found escape-char
	((memq (char-before (point)) '( ?\) ))
	 (LilyPond-mode-set-syntax-table '( ?\( ?\) )))
	((memq (char-before (point)) '( ?\] ))
	 (LilyPond-mode-set-syntax-table '( ?\[ ?\] )))
	((memq (char-before (point)) '( ?\> ?\} ))
	 (LilyPond-mode-set-syntax-table '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))
	((memq (char-after (point)) '( ?\( ))
	 (LilyPond-mode-set-syntax-table '( ?\( ?\) )))
	((memq (char-after (point)) '( ?\[ ))
	 (LilyPond-mode-set-syntax-table '( ?\[ ?\] )))
	((memq (char-after (point)) '( ?\< ?\{ ))
	 (LilyPond-mode-set-syntax-table '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))
	))