X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lilypond-font-lock.el;h=7af3b347bc180135c4f03c875f93c40e90d9c0f2;hb=5dac7eb6f51104c105abfa86100ac18b3ec22f64;hp=1cae4a47bcda43306ff6c5575b836daff4eeb9a9;hpb=8aeed120e8c068900ea5ddfe70ef42f7a4820579;p=lilypond.git diff --git a/lilypond-font-lock.el b/lilypond-font-lock.el index 1cae4a47bc..7af3b347bc 100644 --- a/lilypond-font-lock.el +++ b/lilypond-font-lock.el @@ -2,15 +2,16 @@ ;; Copyright (C) 1992,1993,1994 Tim Peters -;; Author: 2001: Heikki Junes +;; Author: 2001-2003: 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: 1.5.50 -;; Last Modified: 6APR2002 +;; Version: 1.9.7 +;; Last Modified: 18SEP2003 ;; Keywords: lilypond languages music notation ;; This software is provided as-is, without express or implied @@ -24,135 +25,99 @@ ;; ;; TODO: -;; - handle lexer modes (\header, \melodic, \lyric) etc. +;; - handle lexer modes (\header, \melodic) etc. (defconst LilyPond-font-lock-keywords - (let* ((keywords '( ; need special order due to over[lapping] of words - -;; all letters are lowercase -"accent" "accepts" "accompany" "\\(add\\)?lyrics" -"\\(aeol\\|dor\\|ion\\|locr\\|\\(mixo\\)?lyd\\|phryg\\)ian" -"alias" "\\(altern\\|rel\\)ative" "apply" "arpeggio" "autochange" "bar" "break" -"breathe" "breve" "beamintervals" "broken" "blend" "\\(bc\\|end\\)incipit" -"ch\\(ar\\)?" "cg" "chord\\(s\\|stest\\|\\(chord\\)?modifiers\\)?" -"clef[ \t]*\\(F\\|G\\|alto\\|baritone\\|bass\\|\\(mezzo\\)?soprano\\|treble\\|violin\\|tenor\\)?" -"clipping" "[cm]m" "coda" "complex" -"\\(command\\)?spanrequest" "consists\\(end\\)?" -"context" "contrabasso" "\\(de\\)?cr" "default" "denies" "different" "dirs" -"down\\(bow\\|prall\\)?" "duration" "\\(dynamic\\|text\\)?script" -"eccentric" "eg" "embeddedps" "elementdescriptions" -"ex\\(treme\\)?" "fermata" "f+" "figures" "font" "flageolet" "fp" "fragment" -"s?fz" "gliss\\(ando\\)?" "gg" "gmsus" "grace" "gr\\(and\\)?staff" -"header" "\\(h\\|v\\)size" "in\\(clude\\|versions\\|visible\\)?" -"key\\(s\\(ignature\\)?\\)?" "lag" "\\(l\\|r\\)heel" "line\\(break\\|prall\\)" -"longa" "lower" "\\(l\\|r\\)toe" -"mark" "marcato" "maxima" "mel\\(isma\\|ody\\)?" "midi" "m\\(aj\\|in\\)or" -"\\(up\\|down\\)?mordent" "monstrous" "multipart" "music" -"\\(musical\\)?pitch" "m\\(p\\|f\\|m\\)?" "name" "newpage" "noise\\(beat\\)?" -"normal\\(key\\|size\\)" "\\(note\\|pitch\\)?names" "notes" "nt?" -"one\\(staff\\)?" "open" "\\(output\\)?property" "over\\(ride\\)?" -"part\\(combine\\|ial\\)" "penalty" "p+" "pt" -"prall\\(down\\|mordent\\|prall\\|up\\)?" "quickmeasure" "rc\\(ed\\)?" "remove" -"repeat[ \t]*\\(\\(un\\)?fold\\|percent\\|\\|tremolo\\|volta\\)?" "rest" -"revert" "\\(reverse\\)?turn" "rfz?" "rhythm" -"right" "scales?" "scheme" "\\(sc\\)?paper" "\\(sc\\)?score" "sd" -"segno" "sequential" "set\\(tings\\)?" "shortlong" -"simultaneous" "singlepart" "skip" "small" "\\(smart\\)?transpose" -"s[pf]+" "staccat\\(issim\\)?o" "staff\\(height\\|space\\)" "start" -"stop\\(ped\\)?" -"st\\(paper\\|score\\)" "stuff" "stylesheet" "su" "tab" "tempo" "tenuto" -"thenotes" "thrd" "threevoice" "thumb" "tilt\\(down\\|up\\)" -"timb" "times?" "tiny" "toeters" "touch" "translator" -"trill" "type" "t\\(wo\\(voice\\(steminvert\\)?\\)?\\)?" -"un\\(der\\|set\\)" "up\\(bow\\|per\\|prall\\)?" "version" -"visible" "voicedefault" "x" - - )) - - (identifiers '( - -;; in principle, have one or more uppercase letters -"\\(\\(BarNumbering\\|Choir\\|Grand\\|HaraKiri\\|OrchestralPart\\|Piano\\|Rhythmic\\)?Staff\\|\\(Cue\\|Lyrics\\)?Voice\\|\\(Orchestral\\)?Score\\|ChordNames\\|Grace\\|Lyrics\\|Staff\\(Group\\)?\\|Thread\\)Context" ; *Context -"\\(script\\|dots\\|dynamic\\|slur\\|stem\\|sustain\\|sostenuto\\|unaCorda\\|treCorde\\|tie\\|tuplet\\)\\(Both\\|Down\\|Up\\)" ; *(Both/Down/Up) -"\\(slur\\|tie\\)\\(Dotted\\|Solid\\)" ; *(Dotted/Solid) -"\\(autoBeam\\|cadenza\\|impro\\|turn\\)\\(Off\\|On\\)" ; *(On/Off) -"\\(empty\\|fat\\)Text" ; *Text -"shift\\(On+\\|Off\\|I\\|II\\|III\\|IV\\|V\\)" ; shift* -"EasyNotation" -"\\(hide\\|show\\)StaffSwitch" -"\\(lower\\|upper\\)Voice" -"voice\\(One\\|Two\\|Three\\|Four\\|B\\|C\\|D\\|E\\)" ; voice* -"paper\\(Eleven\\|Sixteen\\|Thirteen\\|TwentySix\\)" ; paper* -"\\(lower\\|upper\\)\\(Octave\\|One\\)" ; (lower/upper)* -"hairyChord" "\\(Piano\\|Rhythmic\\)\\(Staff\\)?" -"\\(clarinetti\\|fagotti\\|flauti\\|melodic\\|oboi\\|\\(quite\\|rather\\|somewhat\\)LongLyrics\\|violinoII?\\)?\\(Staff\\)?" ; *Staff -"\\(archi\\|bassi\\|legni\\|ottoni\\|timpani\\|viole\\|violini\\)\\(Group\\)" ; *Group -"melisma\\(End\\)?" "staff\\(One\\|Two\\)?" "rests\\(II\\)?" "specialKey" -"noBreak" "paperTwentysix" "endHorizScript" "FontBody" "text(I)+" -"\\(modern\\|forget\\)Accidentals" ; *Accidentals -"noResetKey" "modern\\(Voice\\)?Cautionaries" "unaCorda" "treCorde" - - )) - - (reservedwords '( - -;; Other words which look nicer when colored -"Accidentals" "autoBeamSettings" "BarLine" "Beam" -"ChordName\\([s]?\\|s.[a-zA-Z]*\\)" "DynamicText" -"FiguredBass" "Hairpin" "\\(Grand\\|Piano\\)Staff" -"Slur" "Stem" "SpacingSpanner" "System\\(StartDelimiter\\)?" -"\\(Grace\\|Lyrics\\|Note\\(Head\\|Names\\)\\|Score\\|\\(Rhythmic\\)?Staff\\(Symbol\\)?\\|Thread\\|Voice\\)\\(.[a-zA-Z]*\\)?" ; combine below, if possible -"\\(Grace\\|Lyrics\\|Note\\(Head\\|Names\\)\\|Score\\|\\(Rhythmic\\)?Staff\\(Symbol\\)?\\|Thread\\|Voice\\)[ \t]*\\(.[ \t]*[a-zA-Z]*\\)?" -"TextScript" "TimeSignature" "VerticalAlignment" - - )) - - (kwregex (mapconcat (lambda (x) (concat "\\\\" x)) keywords "\\|")) - (iregex (mapconcat (lambda (x) (concat "\\\\" x)) identifiers "\\|")) - (rwregex (mapconcat (lambda (x) (concat "" x)) reservedwords "\\|")) + (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]*\\(\\\\breve\\|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- comment / string / keyword / builtin / function-name / -;; variable-name / type / constant / warning -face +;; font-lock- (c)omment / (s)tring / (k)eyword / (b)uiltin / (f)unction-name / +;; (v)ariable-name / (t)ype / co(n)stant / (w)arning -face - '("\\([_^-]?\\\\[a-zA-Z][a-zA-Z]*\\)" 1 font-lock-constant-face) - '("\\(\\(#'\\)?[a-zA-Z][_a-zA-Z.\-]*[ \t]*=[ \t]*#\\(#f\\|#t\\)\\)" 1 font-lock-variable-name-face) - '("\\([a-zA-Z][_a-zA-Z.\-]*\\)[ \t]*=[ \t]*" 1 font-lock-variable-name-face) - '("[ \t]*=[ \t]*\\([a-zA-Z][_a-zA-Z]*\\)" 1 font-lock-variable-name-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 -;; other reserved words +;; 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 \[a-zA-Z]+ + '("\\([_^-]?\\\\\\([a-zA-Z][a-zA-Z]*\\)\\)" 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) -;; highlight note names; separate notes from (other than ')'-type) brackets - '("[ <\{[~()\t]\\(\\(\\(\\(do\\|re\\|mi\\|fa\\|sol\\|la\\|si\\)\\(bb?\\|dd?\\|ss?\\)?\\)\\|\\([a-hsrR]\\(flat\\(flat\\)?\\|sharp\\(sharp\\)?\\|ff?\\|ss?\\|is\\(siss\\|s\\|is\\)?\\|es\\(sess\\|s\\|es\\)?\\)?\\)\\|\\(as\\(as\\|es\\)?\\)\\|\\(es\\(es\\)?\\)\\|\\(bb\\)\\)[,']*[?!]?\\(128\\|64\\|32\\|16\\|8\\|4\\|2\\|1\\)?[.]*\\)" 1 font-lock-type-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)) -;; highlight identifiers - (cons (concat "\\([_^-]?\\(" iregex "\\)\\)+\\($\\|[] \t(~{}>\\\\]\\)") '(0 font-lock-function-name-face t)) +;; "on top", ... notes and rests with a long duration + (cons (concat longduration) '(0 font-lock-type-face t)) -;; highlight keywords - (cons (concat "\\([_^-]?\\(" kwregex "\\)\\)+\\($\\|[] \t(~{}>\\\\]\\)") '(0 font-lock-keyword-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) -;; highlight bracketing constructs - '("\\([][}{]\\)" 0 font-lock-warning-face t) - ;; these regexps allow angle-brackets to be highlighted when and only when they delimit simultaneous music - ;; fontify open < but leave crescendos \< alone - '("[^\\]\\(<\\)" 1 font-lock-warning-face t) - ;; fontify the close-brackets in (tenuto) and (marcato) - '("[_^-]\\s-*[-^]\\s-*\\(>\\)" 1 font-lock-warning-face t) - ;; but leave a b c-> (accent) alone, accounting for whitespace - '("\\([^\\t\\n _^-]\\|^\\)\\s-*\\(>\\)" 2 font-lock-warning-face t) - ;; ties ~, slurs (), hairpins \<, \>, end-of-hairpin \!, - '("\\([(~)]\\|\\\\<\\|\\\\!\\|\\\\>\\)" 0 font-lock-builtin-face t) +;; "on top", ... horizontal grouping, also as postfix syntax '-*': +;; - brackets '{[]}' +;; - ties '~' +;; - ligatures \[, \] + '("\\(-?[][~}{]\\|\\\\[][]\\)" 0 font-lock-warning-face t) -;; highlight comments (again) - '("\\(%.*\\)" 0 font-lock-comment-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 highlight in LilyPond mode.") + "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 @@ -163,28 +128,71 @@ (defvar LilyPond-mode-syntax-table nil "Syntax table used in `LilyPond-mode' buffers.") -;; -(if LilyPond-mode-syntax-table - () +(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)) - (mapcar (function - (lambda (x) (modify-syntax-entry - (car x) (cdr x) LilyPond-mode-syntax-table))) - '(( ?\( . "." ) ( ?\) . "." ) - ( ?\[ . "(]" ) ( ?\] . ")[" ) ;; all the other paren characters are now handled by - ( ?\{ . ".2b" ) ;; lily-specific indenting/matching code in lilypond-indent.el - ( ?\} . ".4b" ) - ( ?\< . "." )( ?\> . ".") - ( ?\$ . "." ) ( ?\% . "." ) ( ?\& . "." ) - ( ?\* . "." ) ( ?\+ . "." ) - ( ?\/ . "." ) ( ?\= . "." ) - ( ?\| . "." ) (?\\ . "\\" ) - ( ?\- . "." ) ( ?\_ . "." ) ( ?\^ . "." ) - ( ?\' . "w") - ( ?\" . "\"" ) - ( ?\% . ". 1b3b" ) - ( ?\n . ">") - ( ?\r . ">") - )) - ) - + (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 (char-before (point))) ?\\)) ; found escape-char + ((and (eq (char-syntax (char-before (- (point) 1))) ?\\) + (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 '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ ))) + ))