2003-09-23 Jan Nieuwenhuizen <janneke@gnu.org>
+ * GNUmakefile.in (SUBDIRS): Add elisp.
+
+ * elisp/lilypond-mode.el:
+ * elisp/lilypond-init.el:
+ * elisp/lilypond-indent.el:
+ * elisp/lilypond-font-lock.el: Move from top dir.
+
+ * stepmake/stepmake/elisp-vars.make: New file.
+
+ * config.make.in (elispdir): Add.
+
* Documentation/topdocs/INSTALL.texi: Typo.
* make/ly-rules.make: Test for files instead of touching void and
# descent order into subdirectories
#
SUBDIRS = buildscripts python scripts \
+ elisp \
flower lily \
mf ly tex ps scm \
po make \
Documentation input
#
-SCRIPTS = configure aclocal.m4 autogen.sh
+SCRIPTS = configure aclocal.m4 autogen.sh lexer-gcc-3.1.sh
README_FILES = ChangeLog COPYING DEDICATION ROADMAP THANKS
README_TXT_FILES = AUTHORS.txt README.txt INSTALL.txt NEWS.txt
IN_FILES := $(wildcard *.in)
-EXTRA_DIST_FILES = $(wildcard *.el) VERSION lilypond.vim vimrc $(README_FILES) $(SCRIPTS) $(IN_FILES) emacsclient.patch server.el.patch darwin.patch .cvsignore lexer-gcc-3.1.sh
+PATCH_FILES = emacsclient.patch server.el.patch darwin.patch
+VIM_FILES = vimrc lilypond.vim
+EXTRA_DIST_FILES = VERSION .cvsignore $(README_FILES) $(SCRIPTS) $(IN_FILES) \
+ $(PATCH_FILES) $(VIM_FILES)
NON_ESSENTIAL_DIST_FILES = $(README_TXT_FILES)
INSTALLATION_DIR=$(local_lilypond_datadir)
INSTALLATION_FILES=$(config_make) VERSION
doc:
$(MAKE) -C Documentation
-LILYPOND_WORDS = $(outdir)/lilypond.words.el $(outdir)/lilypond.words.vim
-$(LILYPOND_WORDS): $(srcdir)/lily/my-lily-lexer.cc $(buildscript-dir)/lilypond.words.py $(srcdir)/scm/new-markup.scm $(srcdir)/ly/engraver-init.ly
- cd $(builddir) && $(PYTHON) $(buildscript-dir)/lilypond.words.py $(outdir)
-
-all: $(LILYPOND_WORDS)
-
web-install:
-$(INSTALL) -m 755 -d $(webdir)
tar -C $(webdir)/ -xzf $(outdir)/web.tar.gz
ln -s ../../../mf/$(outconfbase) tfm && \
ln -s ../../../mf/$(outconfbase) type1
cd $(builddir)/share/lilypond/elisp && \
- ln -sf ../../../$(outconfbase)/lilypond.words.el . && \
- ln -s $(abs-srcdir)/*.el .
+ ln -sf ../../../elisp/$(outconfbase)/lilypond.words.el . && \
+ ln -s $(abs-srcdir)/elisp/*.el .
$(foreach i,$(CATALOGS), \
mkdir -p $(builddir)/share/locale/$i/LC_MESSAGES && \
cd $(builddir)/share/locale/$i/LC_MESSAGES && \
stepmake = @stepmake@
docdir = $(datadir)/doc/
omfdir = $(datadir)/omf/
+elispdir = $(datadir)/site-lisp
# move out of config.make.in?
package_datadir = $(datadir)/$(package)
binary-arch: build install
dh_testdir
dh_testroot
- cp -av lilypond-mode.el lilypond-font-lock.el lilypond-indent.el \
- out/lilypond.words.el \
- $(r)/usr/share/emacs/site-lisp/
dh_installdocs AUTHORS.txt NEWS.txt README.txt \
DEDICATION THANKS
--- /dev/null
+depth = ..
+
+elispdir = $(datadir)/emacs/site-lisp
+
+INSTALLATION_DIR=$(elispdir)
+INSTALLATION_FILES=$(EL_FILES)
+
+INSTALLATION_OUT_DIR=$(elispdir)
+INSTALLATION_OUT_FILES=$(outdir)/lilypond.words.el
+
+STEPMAKE_TEMPLATES=elisp install install-out
+
+include $(depth)/make/stepmake.make
+
+LILYPOND_WORDS = $(outdir)/lilypond.words.el $(outdir)/lilypond.words.vim
+LILYPOND_WORDS_DEPENDS =\
+ $(topdir)/lily/my-lily-lexer.cc \
+ $(buildscript-dir)/lilypond.words.py \
+ $(topdir)/scm/new-markup.scm \
+ $(topdir)/ly/engraver-init.ly
+
+$(LILYPOND_WORDS):
+ cd $(topdir) && $(PYTHON) buildscripts/lilypond.words.py $(builddir)/elisp/$(outconfbase)
+
+all: $(LILYPOND_WORDS)
--- /dev/null
+;;; lilypond-font-lock.el --- syntax coloring for LilyPond mode
+
+;; Copyright (C) 1992,1993,1994 Tim Peters
+
+;; 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.9.9
+;; Last Modified: 23SEP2003
+;; Keywords: lilypond languages music notation
+
+;; This software is provided as-is, without express or implied
+;; warranty. Permission to use, copy, modify, distribute or sell this
+;; software, without fee, for any purpose and by any individual or
+;; organization, is hereby granted, provided that the above copyright
+;; notice and this paragraph appear in all copies.
+
+;; 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 \[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)
+
+;; ... 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-warning-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 (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 '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))
+ ))
--- /dev/null
+;;; lilypond-indent.el --- Auto-indentation for lilypond code
+;;;
+;;; Heikki Junes <hjunes@cc.hut.fi>
+;;; * ond-char paren matching is handled by context dependent syntax tables
+;;; * match two-char slurs '\( ... \)' and '\[ ... \]' separately.
+;;; * adopt Emacs' f90-comment-region
+
+;;; Chris Jackson <chris@fluffhouse.org.uk>
+;;; some code is taken from ESS (Emacs Speaks Statistics) S-mode by A.J.Rossini <rossini@biostat.washington.edu>
+
+;;; Variables for customising indentation style
+
+;;; TODO:
+;;; * currently, in bracket matching one may need a non-bracket
+;;; chararacter between the bracket characters, like ( ( ) )
+
+(defcustom LilyPond-indent-level 4
+ "*Indentation of lilypond statements with respect to containing block.")
+
+(defcustom LilyPond-brace-offset 0
+ "*Extra indentation for open braces.
+Compares with other text in same context.")
+
+(defcustom LilyPond-angle-offset 0
+ "*Extra indentation for open angled brackets.
+Compares with other text in same context.")
+
+(defcustom LilyPond-square-offset 0
+ "*Extra indentation for open square brackets.
+Compares with other text in same context.")
+
+(defcustom LilyPond-scheme-paren-offset 0
+ "*Extra indentation for open scheme parens.
+Compares with other text in same context.")
+
+(defcustom LilyPond-close-brace-offset 0
+ "*Extra indentation for closing braces.")
+
+(defcustom LilyPond-close-angle-offset 0
+ "*Extra indentation for closing angle brackets.")
+
+(defcustom LilyPond-close-square-offset 0
+ "*Extra indentation for closing square brackets.")
+
+(defcustom LilyPond-close-scheme-paren-offset 0
+ "*Extra indentation for closing scheme parens.")
+
+(defcustom LilyPond-fancy-comments t
+ "*Non-nil means distiguish between %, %%, and %%% for indentation.")
+
+(defcustom LilyPond-comment-region "%%$"
+ "*String inserted by \\[LilyPond-comment-region]\
+ at start of each line in region.")
+
+(defun LilyPond-comment-region (beg-region end-region)
+ "Comment/uncomment every line in the region.
+Insert LilyPond-comment-region at the beginning of every line in the region
+or, if already present, remove it."
+ (interactive "*r")
+ (let ((end (make-marker)))
+ (set-marker end end-region)
+ (goto-char beg-region)
+ (beginning-of-line)
+ (if (looking-at (regexp-quote LilyPond-comment-region))
+ (delete-region (point) (match-end 0))
+ (insert LilyPond-comment-region))
+ (while (and (zerop (forward-line 1))
+ (< (point) (marker-position end)))
+ (if (looking-at (regexp-quote LilyPond-comment-region))
+ (delete-region (point) (match-end 0))
+ (insert LilyPond-comment-region)))
+ (set-marker end nil)))
+
+(defun LilyPond-calculate-indent ()
+ "Return appropriate indentation for current line as lilypond code.
+In usual case returns an integer: the column to indent to.
+Returns nil if line starts inside a string"
+ (save-excursion
+ (beginning-of-line)
+ (let ((indent-point (point))
+ (case-fold-search nil)
+ state)
+ (setq containing-sexp (save-excursion (LilyPond-scan-containing-sexp)))
+ (beginning-of-defun)
+ (while (< (point) indent-point)
+ (setq state (parse-partial-sexp (point) indent-point 0)))
+ ;; (setq containing-sexp (car (cdr state))) is the traditional way for languages
+ ;; with simpler parenthesis delimiters
+ (cond ((nth 3 state)
+ ;; point is in the middle of a string
+ nil)
+ ((nth 4 state)
+ ;; point is in the middle of a block comment
+ (LilyPond-calculate-indent-within-blockcomment))
+ ((null containing-sexp)
+ ;; Line is at top level - no indent
+ (beginning-of-line)
+ 0)
+ (t
+ ;; Find previous non-comment character.
+ (goto-char indent-point)
+ (LilyPond-backward-to-noncomment containing-sexp)
+ ;; Now we get the answer.
+ ;; Position following last unclosed open.
+ (goto-char containing-sexp)
+ (or
+ ;; Is line first statement after an open brace or bracket?
+ ;; If no, find that first statement and indent like it.
+ (save-excursion
+ (forward-char 1)
+ ;; Skip over comments following open brace.
+ (skip-chars-forward " \t\n")
+ (cond ((looking-at "%{")
+ (while (progn
+ (and (not (looking-at "%}"))
+ (< (point) (point-max))))
+ (forward-line 1)
+ (skip-chars-forward " \t\n"))
+ (forward-line 1)
+ (skip-chars-forward " \t\n"))
+ ((looking-at "%")
+ (while (progn (skip-chars-forward " \t\n")
+ (looking-at "%"))
+ (forward-line 1))))
+ ;; The first following code counts
+ ;; if it is before the line we want to indent.
+ (and (< (point) indent-point)
+ (current-column)))
+ ;; If no previous statement,
+ ;; indent it relative to line brace is on.
+ ;; For open brace in column zero, don't let statement
+ ;; start there too. If LilyPond-indent-level is zero, use
+ ;; LilyPond-brace-offset instead
+ (+ (if (and (bolp) (zerop LilyPond-indent-level))
+ (cond ((= (following-char) ?{)
+ LilyPond-brace-offset)
+ ((= (following-char) ?<)
+ LilyPond-angle-offset)
+ ((= (following-char) ?[)
+ LilyPond-square-offset)
+ ((= (following-char) ?\))
+ LilyPond-scheme-paren-offset)
+ (t
+ 0))
+ LilyPond-indent-level)
+ (progn
+ (skip-chars-backward " \t")
+ (current-indentation)))))))))
+
+
+(defun LilyPond-indent-line ()
+ "Indent current line as lilypond code.
+Return the amount the indentation changed by."
+ (let ((indent (LilyPond-calculate-indent))
+ beg shift-amt
+ (case-fold-search nil)
+ (pos (- (point-max) (point))))
+ (beginning-of-line)
+ (setq beg (point))
+ (cond ((eq indent nil)
+ (setq indent (current-indentation)))
+ (t
+ (skip-chars-forward " \t")
+ (if (and LilyPond-fancy-comments (looking-at "%%%\\|%{\\|%}"))
+ (setq indent 0))
+ (if (and LilyPond-fancy-comments
+ (looking-at "%")
+ (not (looking-at "%%\\|%{\\|%}")))
+ (setq indent comment-column)
+ (if (eq indent t) (setq indent 0))
+ (if (listp indent) (setq indent (car indent)))
+ (cond
+ ((= (following-char) ?})
+ (setq indent (+ indent (- LilyPond-close-brace-offset LilyPond-indent-level))))
+ ((= (following-char) ?>)
+ (setq indent (+ indent (- LilyPond-close-angle-offset LilyPond-indent-level))))
+ ((= (following-char) ?])
+ (setq indent (+ indent (- LilyPond-close-square-offset LilyPond-indent-level))))
+ ((and (= (following-char) ?\)) (LilyPond-inside-scheme-p))
+ (setq indent (+ indent (- LilyPond-close-scheme-paren-offset LilyPond-indent-level))))
+ ((= (following-char) ?{)
+ (setq indent (+ indent LilyPond-brace-offset)))
+ ((= (following-char) ?<)
+ (setq indent (+ indent LilyPond-angle-offset)))
+ ((= (following-char) ?[)
+ (setq indent (+ indent LilyPond-square-offset)))
+ ((and (= (following-char) ?\() (LilyPond-inside-scheme-p))
+ (setq indent (+ indent LilyPond-scheme-paren-offset)))
+ ))))
+ (skip-chars-forward " \t")
+ (setq shift-amt (- indent (current-column)))
+ (if (zerop shift-amt)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos)))
+ (delete-region beg (point))
+ (indent-to indent)
+ ;; If initial point was within line's indentation,
+ ;; position after the indentation.
+ ;; Else stay at same point in text.
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos))))
+ shift-amt))
+
+
+(defun LilyPond-inside-comment-p ()
+ "Return non-nil if point is inside a line or block comment"
+ (setq this-point (point))
+ (or (save-excursion (beginning-of-line)
+ (skip-chars-forward " \t")
+ (looking-at "%"))
+ (save-excursion
+ ;; point is in the middle of a block comment
+ (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" (point-min) t)))
+ (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" (point-min) t)))
+ (if (or (and (= (char-before) ?%) (= (char-after) ?{))
+ (and (= (char-after) ?%) (= (char-after (1+ (point))) ?{)))
+ (setq lastopen (save-excursion (backward-char) (point))))
+ (and
+ lastopen
+ (or (not lastclose)
+ (<= lastclose lastopen))))
+ ))
+
+
+(defun LilyPond-inside-string-or-comment-p ()
+ "Test if point is inside a string or a comment"
+ (setq this-point (point))
+ (or (save-excursion (beginning-of-line)
+ (skip-chars-forward " \t")
+ (looking-at "%"))
+ (save-excursion
+ (beginning-of-defun)
+ (while (< (point) this-point)
+ (setq state (parse-partial-sexp (point) this-point 0)))
+ (cond ((nth 3 state)
+ ;; point is in the middle of a string
+ t )
+ ((nth 4 state)
+ ;; point is in the middle of a block comment
+ t )
+ (t
+ nil)))))
+
+
+(defun LilyPond-backward-over-blockcomments (lim)
+ "Move point back to closest non-whitespace character not part of a block comment"
+ (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" lim t)))
+ (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" lim t)))
+ (if lastopen
+ (if lastclose
+ (if (<= lastclose lastopen)
+ (goto-char lastopen))
+ (goto-char lastopen)))
+ (skip-chars-backward " %\t\n\f"))
+
+
+(defun LilyPond-backward-over-linecomments (lim)
+ "Move point back to the closest non-whitespace character not part of a line comment.
+Argument LIM limit."
+ (let (opoint stop)
+ (while (not stop)
+ (skip-chars-backward " \t\n\f" lim)
+ (setq opoint (point))
+ (beginning-of-line)
+ (search-forward "%" opoint 'move)
+ (skip-chars-backward " \t%")
+ (setq stop (or (/= (preceding-char) ?\n) (<= (point) lim)))
+ (if stop (point)
+ (beginning-of-line)))))
+
+
+(defun LilyPond-backward-to-noncomment (lim)
+ "Move point back to closest non-whitespace character not part of a comment"
+ (LilyPond-backward-over-linecomments lim)
+ (LilyPond-backward-over-blockcomments lim))
+
+
+(defun LilyPond-calculate-indent-within-blockcomment ()
+ "Return the indentation amount for line inside a block comment."
+ (let (end percent-start)
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (skip-chars-backward " \t\n")
+ (setq end (point))
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (and (re-search-forward "%{[ \t]*" end t)
+ (goto-char (1+ (match-beginning 0))))
+ (if (and (looking-at "[ \t]*$") (= (preceding-char) ?\%))
+ (1+ (current-column))
+ (current-column)))))
+
+
+;; Key: Type of bracket (character).
+;; Value: Pair of regexps representing the corresponding open and close bracket
+;; () are treated specially (need to indent in Scheme but not in music)
+
+(defconst LilyPond-parens-regexp-alist
+ `( ( ?> . ("\\([^\\]\\|^\\)<" . "\\([^ \\n\\t_^-]\\|[_^-][-^]\\|\\s-\\)\\s-*>"))
+ ;; a b c->, a b c^> and a b c_> are not close-angle-brackets, they're accents
+ ;; but a b c^-> and a b c^^> are close brackets with tenuto/marcato before them
+ ;; also \> and \< are hairpins
+ ;; duh .. a single '>', as in chords '<< ... >>', was not matched here
+ ( ?} . ("{" . "}"))
+ ;; ligatures '\[ ... \]' are skipped in the following expression
+ ( ?] . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)[[]" . "\\([^\\]\\([\\][\\]\\)*\\|^\\)[]]"))
+ ( "\\]" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][[]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][]]"))
+ ( "\\)" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][(]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][)]"))
+ ))
+
+
+(defconst LilyPond-parens-alist
+ `( ( ?< . ?> )
+ ( ?{ . ?} )
+ ( ?[ . ?] )
+ ( "\\[" . "\\]" )
+ ( ?\( . ?\) )
+ ( "\\(" . "\\)" )
+ ))
+
+
+(defun LilyPond-matching-paren (bracket-type)
+ "Returns the open corresponding to the close specified by bracket-type, or vice versa"
+ (cond ( (member bracket-type (mapcar 'car LilyPond-parens-alist))
+ (cdr (assoc bracket-type LilyPond-parens-alist)) )
+ ( (member bracket-type (mapcar 'cdr LilyPond-parens-alist))
+ (car (rassoc bracket-type LilyPond-parens-alist)) )
+ nil))
+
+
+(defun LilyPond-scan-containing-sexp (&optional bracket-type slur-paren-p dir)
+ "Move point to the beginning of the deepest parenthesis pair enclosing point.
+
+If the optional argument bracket-type, a character representing a
+close bracket such as ) or }, is specified, then the parenthesis pairs
+searched are limited to this type.
+
+If the optional argument slur-paren-p is non-nil, then slur
+parentheses () are considered as matching pairs. Otherwise Scheme
+parentheses are considered to be matching pairs, but slurs are not.
+slur-paren-p defaults to nil.
+"
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
+ (let ( (level (if (not (eq dir 1)) 1 -1))
+ (regexp-alist LilyPond-parens-regexp-alist)
+ (oldpos (point))
+ (assoc-bracket-type (if (not (eq dir 1)) bracket-type (LilyPond-matching-paren bracket-type))))
+
+ (if (LilyPond-inside-scheme-p)
+ (setq paren-regexp "(\\|)")
+ (if slur-paren-p
+ ;; expressional slurs '\( ... \)' are not taken into account
+ (setq regexp-alist (cons '( ?\) . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)(" . "\\([^\\]\\([\\][\\]\\)*\\|^\\))")) regexp-alist)))
+ (if (member assoc-bracket-type (mapcar 'car regexp-alist))
+ (progn (setq paren-regexp (cdr (assoc assoc-bracket-type regexp-alist)))
+ (setq paren-regexp (concat (car paren-regexp) "\\|" (cdr paren-regexp))))
+ (setq paren-regexp (concat (mapconcat 'car (mapcar 'cdr regexp-alist) "\\|") "\\|"
+ (mapconcat 'cdr (mapcar 'cdr regexp-alist) "\\|")))))
+ ;; match concurrent one-char opening and closing slurs
+ (if (and (eq dir 1)
+ (not (sequencep bracket-type))
+ (eq (char-syntax (char-after oldpos)) ?\()
+ (not (eq (char-after oldpos) ?<)))
+ ;; anyway do not count open slur, since already level = -1
+ (progn (forward-char 1)
+ (if (eq (following-char)
+ (LilyPond-matching-paren (char-after oldpos)))
+ ;; matching char found, go after it and set level = 0
+ (progn (forward-char 1)
+ (setq level 0)))))
+ ;; browse the code until matching slur is found, or report mismatch
+ (while (and (if (not (eq dir 1))
+ (> level 0)
+ (< level 0))
+ ;; dir tells whether to search backward or forward
+ (if (not (eq dir 1))
+ (re-search-backward paren-regexp nil t)
+ (re-search-forward paren-regexp nil t))
+ ;; note: in case of two-char bracket only latter is compared
+ (setq match (char-before (match-end 0))))
+;;; (message "%d" level) (sit-for 0 300)
+ (if (not (save-excursion (goto-char (match-end 0))
+ ;; skip over strings and comments
+ (LilyPond-inside-string-or-comment-p)))
+ (if (memq match '(?} ?> ?] ?\)))
+ ;; count closing brackets
+ (progn (setq level (1+ level))
+ ;; slurs may be close to each other, e.g.,
+ ;; a single '>' was not matched .. need to be corrected
+ (if (and (eq dir 1) (eq (char-after (match-end 0)) match))
+ (if (/= level 0)
+ (progn
+ (setq level (1+ level))
+ (forward-char 1))))
+;;; (message "%d %c" level match) (sit-for 0 300)
+ ;; hmm..
+ (if (and (= match ?>)
+ (looking-at ".\\s-+>\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)>"))
+ (forward-char 1)))
+ ;; count opening brackets
+ (progn (setq level (1- level))
+;;; (message "%d %c" level match) (sit-for 0 300)
+ ;; hmm..
+ (if (and (= match ?<)
+ (looking-at ".\\s-+<\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)<"))
+ (forward-char 1))))))
+ ;; jump to the matching slur
+ (if (not (eq dir 1))
+ (progn
+ (if (sequencep bracket-type)
+ ;; match the latter char in two-char brackets
+ (if (looking-at "..[][)(]") (forward-char 1)))
+ ;; if the following char is not already a slur
+ (if (and (not (looking-at "[)(]"))
+ ;; match the slur which follows
+ (looking-at ".[][><)(]")) (forward-char 1)))
+ (backward-char 1))
+ (if (= level 0)
+ (point)
+ (progn (goto-char oldpos)
+ nil))))
+
+
+(defun LilyPond-inside-scheme-p ()
+ "Tests if point is inside embedded Scheme code"
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
+ (let ( (test-point (point))
+ (level 0) )
+ (save-excursion
+ (if (or (and (/= (point) (point-max))
+ (= (char-after (point)) ?\()
+ (or (= (char-after (- (point) 1)) ?#)
+ (and (= (char-after (- (point) 2)) ?#)
+ (= (char-after (- (point) 1)) ?`))))
+ (and (re-search-backward "#(\\|#`(" nil t)
+ (progn
+ (search-forward "(")
+ (setq level 1)
+ (while (and (> level 0)
+ (re-search-forward "(\\|)" test-point t)
+ (setq match (char-after (match-beginning 0)))
+ (<= (point) test-point))
+ (if (= match ?\()
+ (setq level (1+ level))
+ (setq level (1- level))))
+ (> level 0))))
+ t
+ nil))))
+
+
+;;; Largely taken from the 'blink-matching-open' in lisp/simple.el in
+;;; the Emacs distribution.
+
+(defun LilyPond-blink-matching-paren (&optional dir)
+ "Move cursor momentarily to the beginning of the sexp before
+point. In lilypond files this is used for closing ), ], } and >, whereas the
+builtin 'blink-matching-open' is not used. In syntax table, see
+`lilypond-font-lock.el', all brackets are punctuation characters."
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
+ (let ( (oldpos (point))
+ (level 0)
+ (mismatch) )
+ (if (not (or (equal this-command 'LilyPond-electric-close-paren)
+ (eq dir 1)))
+ (goto-char (setq oldpos (- oldpos 1))))
+ ;; Test if a ligature \] or expressional slur \) was encountered
+ (setq bracket-type (char-after (point)))
+ (setq char-before-bracket-type nil)
+ (if (memq bracket-type '(?] ?\) ?[ ?\())
+ (progn
+ (setq np -1)
+ (while (eq (char-before (- (point) (setq np (+ np 1)))) ?\\)
+ (setq char-before-bracket-type (if char-before-bracket-type nil ?\\)))
+ (if (eq char-before-bracket-type ?\\)
+ (setq bracket-type (string char-before-bracket-type bracket-type)))))
+ (when blink-matching-paren-distance
+ (narrow-to-region
+ (max (point-min) (- (point) blink-matching-paren-distance))
+ (min (point-max) (+ (point) blink-matching-paren-distance))))
+ (if (and (equal this-command 'LilyPond-electric-close-paren)
+ (memq bracket-type '(?> ?} ?< ?{)))
+ ;; < { need to be mutually balanced and nested, so search backwards for both of these bracket types
+ (LilyPond-scan-containing-sexp nil nil dir)
+ ;; whereas ( ) slurs within music don't, so only need to search for ( )
+ ;; use same mechanism for [ ] slurs
+ (LilyPond-scan-containing-sexp bracket-type t dir))
+ (setq blinkpos (point))
+ (setq mismatch
+ (or (null (LilyPond-matching-paren (char-after blinkpos)))
+ (/= (char-after oldpos)
+ (LilyPond-matching-paren (char-after blinkpos)))))
+ (if mismatch (progn (setq blinkpos nil)
+ (message "Mismatched parentheses")))
+ (if (and blinkpos
+ (equal this-command 'LilyPond-electric-close-paren))
+ (if (pos-visible-in-window-p)
+ (and blink-matching-paren-on-screen
+ (sit-for blink-matching-delay))
+ (message
+ "Matches %s"
+ ;; Show what precedes the open in its line, if anything.
+ (if (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp)))
+ (buffer-substring (progn (beginning-of-line) (point))
+ (1+ blinkpos))
+ ;; Show what follows the open in its line, if anything.
+ (if (save-excursion
+ (forward-char 1)
+ (skip-chars-forward " \t")
+ (not (eolp)))
+ (buffer-substring blinkpos
+ (progn (end-of-line) (point)))
+ ;; Otherwise show the previous nonblank line,
+ ;; if there is one.
+ (if (save-excursion
+ (skip-chars-backward "\n \t")
+ (not (bobp)))
+ (concat
+ (buffer-substring (progn
+ (skip-chars-backward "\n \t")
+ (beginning-of-line)
+ (point))
+ (progn (end-of-line)
+ (skip-chars-backward " \t")
+ (point)))
+ ;; Replace the newline and other whitespace with `...'.
+ "..."
+ (buffer-substring blinkpos (1+ blinkpos)))
+ ;; There is nothing to show except the char itself.
+ (buffer-substring blinkpos (1+ blinkpos))))))))
+ (if (not (equal this-command 'LilyPond-electric-close-paren))
+ (goto-char (setq oldpos (+ oldpos 1)))
+ (goto-char oldpos))
+ (if (not (eq dir 1))
+ blinkpos
+ (+ blinkpos 1))))
+
+
+(defun LilyPond-electric-close-paren ()
+ "Blink on the matching open paren when a >, ), } or ] is inserted"
+ (interactive)
+ (let ((oldpos (point)))
+ (self-insert-command 1)
+ ;; Refontify buffer if a block-comment-ender '%}' is inserted
+ (if (and (eq (char-before (point)) ?})
+ (eq (char-before (- (point) 1)) ?%))
+ (font-lock-fontify-buffer)
+ ;; Match paren if the cursor is not inside string or comment.
+ (if (and blink-matching-paren
+ (not (LilyPond-inside-string-or-comment-p))
+ (save-excursion (re-search-backward
+ (concat (mapconcat 'cdr (mapcar 'cdr LilyPond-parens-regexp-alist) "\\|") "\\|)") nil t)
+ (eq oldpos (1- (match-end 0)))))
+ (progn (backward-char 1)
+ (LilyPond-blink-matching-paren)
+ (forward-char 1))))))
+
+(defun LilyPond-scan-sexps (pos dir)
+ "This function is redefined to be used in Emacs' show-paren-function and
+in XEmacs' paren-highlight."
+ (LilyPond-blink-matching-paren dir))
--- /dev/null
+;;; lilypond-init.el --- Startup code for LilyPond mode
+;;
+;; Instructions, extracted from Documentation/topdocs/INSTALL.texi:
+
+;; Emacs mode for entering music and running LilyPond is contained in
+;; the source archive as `lilypond-mode.el', `lilypond-indent.el',
+;; `lilypond-font-lock.el' and `lilypond.words.el'. You should install
+;; these files to a directory included in your `load-path'.
+;; File `lilypond-init.el' should be placed to `load-path/site-start.d/'
+;; or appended to your `~/.emacs' or `~/.emacs.el'.
+
+;; As a user, you may want add your source path or, e.g., `~/site-lisp/' to
+;; your `load-path'. Append the following line (modified) to your `~/.emacs':
+
+;(setq load-path (append (list (expand-file-name "~/site-lisp")) load-path))
+
+(autoload 'LilyPond-mode "lilypond-mode" "LilyPond Editing Mode" t)
+(add-to-list 'auto-mode-alist '("\\.ly$" . LilyPond-mode))
+(add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
+
--- /dev/null
+;;;
+;;; lilypond-mode.el --- Major mode for editing GNU LilyPond music scores
+;;;
+;;; source file of the GNU LilyPond music typesetter
+;;;
+;;; (c) 1999--2003 Jan Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; Changed 2001--2003 Heikki Junes <heikki.junes@hut.fi>
+;;; * Add PS-compilation, PS-viewing and MIDI-play (29th Aug 2001)
+;;; * Keyboard shortcuts (12th Sep 2001)
+;;; * Inserting tags, inspired on sgml-mode (11th Oct 2001)
+;;; * Autocompletion & Info (23rd Nov 2002)
+
+;;; Inspired on auctex
+
+;;; Look lilypond-init.el or Documentation/topdocs/INSTALL.texi
+;;; for installing instructions.
+
+(require 'easymenu)
+(require 'compile)
+
+(defconst LilyPond-version "1.9.9"
+ "`LilyPond-mode' version number.")
+
+(defconst LilyPond-help-address "bug-lilypond@gnu.org"
+ "Address accepting submission of bug reports.")
+
+(defvar LilyPond-mode-hook nil
+ "*Hook called by `LilyPond-mode'.")
+
+(defvar LilyPond-region-file-prefix "emacs-lily"
+ "File prefix for commands on buffer or region.")
+
+;; FIXME: find ``\score'' in buffers / make settable?
+(defun LilyPond-master-file ()
+ ;; duh
+ (buffer-file-name))
+
+(defvar LilyPond-kick-xdvi nil
+ "If true, no simultaneous xdvi's are started, but reload signal is sent.")
+
+(defvar LilyPond-command-history nil
+ "Command history list.")
+
+(defvar LilyPond-regexp-alist
+ '(("\\([a-zA-Z]?:?[^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2))
+ "Regexp used to match LilyPond errors. See `compilation-error-regexp-alist'.")
+
+(defvar LilyPond-imenu nil
+ "A flag to tell whether LilyPond-imenu is turned on.")
+(make-variable-buffer-local 'LilyPond-imenu)
+
+(defcustom LilyPond-include-path ".:/tmp"
+ "* LilyPond include path."
+ :type 'string
+ :group 'LilyPond)
+
+(defun LilyPond-words-filename ()
+ "The file containing LilyPond \keywords \Identifiers and ReservedWords.
+Finds file lilypond-words.el from load-path."
+ (let ((fn nil)
+ (lp load-path)
+ (words-file "lilypond.words.el"))
+ (while (and (> (length lp) 0) (not fn))
+ (setq fn (concat (car lp) "/" words-file))
+ (if (not (file-readable-p fn))
+ (progn (setq fn nil) (setq lp (cdr lp)))))
+ (if (not fn)
+ (progn (message "Warning: `lilypond.words.el' not found in `load-path'. See `lilypond-init.el'.")
+ (sit-for 5 0)))
+ fn))
+
+(defun LilyPond-add-dictionary-word (x)
+ "Contains all words: \keywords \Identifiers and ReservedWords."
+ (nconc '(("" . 1)) x))
+
+;; creates dictionary if empty
+(if (and (eq (length (LilyPond-add-dictionary-word ())) 1)
+ (not (eq (LilyPond-words-filename) nil)))
+ (progn
+ (setq b (find-file-noselect (LilyPond-words-filename) t t))
+ (setq m (set-marker (make-marker) 1 (get-buffer b)))
+ (setq i 1)
+ (while (> (buffer-size b) (marker-position m))
+ (setq i (+ i 1))
+ (setq copy (copy-alist (list (eval (symbol-name (read m))))))
+ (setcdr copy i)
+ (LilyPond-add-dictionary-word (list copy)))
+ (kill-buffer b)))
+
+(defvar LilyPond-insert-tag-current ""
+ "The last command selected from the LilyPond-Insert -menu.")
+
+(defconst LilyPond-menu-keywords
+ (let ((wordlist '())
+ (co (all-completions "" (LilyPond-add-dictionary-word ())))
+ (currword ""))
+ (progn
+ (while (> (length co) 0)
+ (setq currword (car co))
+ (if (string-equal "-" (car (setq co (cdr co))))
+ (progn
+ (add-to-list 'wordlist currword)
+ (while (and (> (length co) 0)
+ (not (string-equal "-" (car (setq co (cdr co))))))))))
+ (reverse wordlist)))
+ "Keywords inserted from LilyPond-Insert-menu.")
+
+(defconst LilyPond-keywords
+ (let ((wordlist '("\\score"))
+ (co (all-completions "" (LilyPond-add-dictionary-word ())))
+ (currword ""))
+ (progn
+ (while (> (length co) 0)
+ (setq currword (car co))
+ (if (> (length currword) 1)
+ (if (and (string-equal "\\" (substring currword 0 1))
+ (string-match "[a-z-]+" currword)
+ (= (match-beginning 0) 1)
+ (= (match-end 0) (length currword))
+ (not (string-equal "\\longa" currword))
+ (not (string-equal "\\breve" currword))
+ (not (string-equal "\\maxima" currword))
+ (string-equal (downcase currword) currword))
+ (add-to-list 'wordlist currword)))
+ (if (string-equal "-" (car (setq co (cdr co))))
+ (while (and (> (length co) 0)
+ (not (string-equal "-" (car (setq co (cdr co)))))))))
+ (reverse wordlist)))
+ "LilyPond \\keywords")
+
+(defconst LilyPond-identifiers
+ (let ((wordlist '("\\voiceOne"))
+ (co (all-completions "" (LilyPond-add-dictionary-word ()))))
+ (progn
+ (while (> (length co) 0)
+ (setq currword (car co))
+ (if (> (length currword) 1)
+ (if (and (string-equal "\\" (substring currword 0 1))
+ (string-match "[a-zA-Z-]+" currword)
+ (= (match-beginning 0) 1)
+ (= (match-end 0) (length currword))
+ (not (string-equal (downcase currword) currword)))
+ (add-to-list 'wordlist currword)))
+ (if (string-equal "-" (car (setq co (cdr co))))
+ (while (and (> (length co) 0)
+ (not (string-equal "-" (car (setq co (cdr co)))))))))
+ (reverse wordlist)))
+ "LilyPond \\Identifiers")
+
+(defconst LilyPond-Capitalized-Reserved-Words
+ (let ((wordlist '("StaffContext"))
+ (co (all-completions "" (LilyPond-add-dictionary-word ()))))
+ (progn
+ (while (> (length co) 0)
+ (setq currword (car co))
+ (if (> (length currword) 0)
+ (if (and (string-match "[a-zA-Z_]+" currword)
+ (= (match-beginning 0) 0)
+ (= (match-end 0) (length currword))
+ (not (string-equal (downcase currword) currword)))
+ (add-to-list 'wordlist currword)))
+ (if (string-equal "-" (car (setq co (cdr co))))
+ (while (and (> (length co) 0)
+ (not (string-equal "-" (car (setq co (cdr co)))))))))
+ (reverse wordlist)))
+ "LilyPond ReservedWords")
+
+(defconst LilyPond-non-capitalized-reserved-words
+ (let ((wordlist '("cessess"))
+ (co (all-completions "" (LilyPond-add-dictionary-word ()))))
+ (progn
+ (while (> (length co) 0)
+ (setq currword (car co))
+ (if (> (length currword) 0)
+ (if (and (string-match "[a-z]+" currword)
+ (= (match-beginning 0) 0)
+ (= (match-end 0) (length currword))
+ (string-equal (downcase currword) currword))
+ (add-to-list 'wordlist currword)))
+ (if (string-equal "-" (car (setq co (cdr co))))
+ (while (and (> (length co) 0)
+ (not (string-equal "-" (car (setq co (cdr co)))))))))
+ (reverse wordlist)))
+ "LilyPond notenames")
+
+(defun LilyPond-check-files (derived originals extensions)
+ "Check that DERIVED is newer than any of the ORIGINALS.
+Try each original with each member of EXTENSIONS, in all directories
+in LilyPond-include-path."
+ (let ((found nil)
+ (regexp (concat "\\`\\("
+ (mapconcat (function (lambda (dir)
+ (regexp-quote (expand-file-name dir))))
+ LilyPond-include-path "\\|")
+ "\\).*\\("
+ (mapconcat 'regexp-quote originals "\\|")
+ "\\)\\.\\("
+ (mapconcat 'regexp-quote extensions "\\|")
+ "\\)\\'"))
+ (buffers (buffer-list)))
+ (while buffers
+ (let* ((buffer (car buffers))
+ (name (buffer-file-name buffer)))
+ (setq buffers (cdr buffers))
+ (if (and name (string-match regexp name))
+ (progn
+ (and (buffer-modified-p buffer)
+ (or (not LilyPond-save-query)
+ (y-or-n-p (concat "Save file "
+ (buffer-file-name buffer)
+ "? ")))
+ (save-excursion (set-buffer buffer) (save-buffer)))
+ (if (file-newer-than-file-p name derived)
+ (setq found t))))))
+ found))
+
+(defun LilyPond-running ()
+ "Check the currently running LilyPond compiling jobs."
+ (let ((process-names (list "lilypond" "tex" "2dvi" "2ps" "2midi"
+ "book" "latex"))
+ (running nil))
+ (while (setq process-name (pop process-names))
+ (setq process (get-process process-name))
+ (if (and process
+ (eq (process-status process) 'run))
+ (push process-name running)))
+ running)) ; return the running jobs
+
+(defun LilyPond-midi-running ()
+ "Check the currently running Midi processes."
+ (let ((process-names (list "midi" "midiall"))
+ (running nil))
+ (while (setq process-name (pop process-names))
+ (setq process (get-process process-name))
+ (if (and process
+ (eq (process-status process) 'run))
+ (push process-name running)))
+ running)) ; return the running jobs
+
+(defun LilyPond-kill-jobs ()
+ "Kill the currently running LilyPond compiling jobs."
+ (interactive)
+ (let ((process-names (LilyPond-running))
+ (killed nil))
+ (while (setq process-name (pop process-names))
+ (quit-process (get-process process-name) t)
+ (push process-name killed))
+ killed)) ; return the killed jobs
+
+(defun LilyPond-kill-midi ()
+ "Kill the currently running midi processes."
+ (let ((process-names (LilyPond-midi-running))
+ (killed nil))
+ (while (setq process-name (pop process-names))
+ (quit-process (get-process process-name) t)
+ (push process-name killed))
+ killed)) ; return the killed jobs
+
+;; URG, should only run LilyPond-compile for LilyPond
+;; not for tex,xdvi (ly2dvi?)
+(defun LilyPond-compile-file (command name)
+ ;; We maybe should know what we run here (Lily, ly2dvi, tex)
+ ;; and adjust our error-matching regex ?
+ (compile-internal
+ (if (eq LilyPond-command-current 'LilyPond-command-master)
+ command
+ ;; use temporary directory for Commands on Buffer/Region
+ ;; hm.. the directory is set twice, first to default-dir
+ (concat "cd " (LilyPond-temp-directory) "; " command))
+ "No more errors" name))
+
+;; do we still need this, now that we're using compile-internal?
+(defun LilyPond-save-buffer ()
+ "Save buffer and set default command for compiling."
+ (interactive)
+ (if (buffer-modified-p)
+ (progn (save-buffer)
+ (setq LilyPond-command-default "LilyPond"))))
+
+;;; return (dir base ext)
+(defun split-file-name (name)
+ (let* ((i (string-match "[^/]*$" name))
+ (dir (if (> i 0) (substring name 0 i) "./"))
+ (file (substring name i (length name)))
+ (i (string-match "[^.]*$" file)))
+ (if (and
+ (> i 0)
+ (< i (length file)))
+ (list dir (substring file 0 (- i 1)) (substring file i (length file)))
+ (list dir file ""))))
+
+
+;; Should check whether in command-alist?
+(defcustom LilyPond-command-default "LilyPond"
+ "Default command. Must identify a member of LilyPond-command-alist."
+
+ :group 'LilyPond
+ :type 'string)
+;;;(make-variable-buffer-local 'LilyPond-command-last)
+
+(defvar LilyPond-command-current 'LilyPond-command-master)
+;;;(make-variable-buffer-local 'LilyPond-command-master)
+
+
+;; If non-nil, LilyPond-command-query will return the value of this
+;; variable instead of quering the user.
+(defvar LilyPond-command-force nil)
+
+(defcustom LilyPond-xdvi-command "xdvi"
+ "Command used to display DVI files."
+
+ :group 'LilyPond
+ :type 'string)
+
+(defcustom LilyPond-gv-command "gv -watch"
+ "Command used to display PS files."
+
+ :group 'LilyPond
+ :type 'string)
+
+(defcustom LilyPond-midi-command "timidity"
+ "Command used to play MIDI files."
+
+ :group 'LilyPond
+ :type 'string)
+
+(defcustom LilyPond-all-midi-command "timidity -ia"
+ "Command used to play MIDI files."
+
+ :group 'LilyPond
+ :type 'string)
+
+(defun LilyPond-command-current-midi ()
+ "Play midi corresponding to the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "Midi") 'LilyPond-master-file))
+
+(defun LilyPond-command-all-midi ()
+ "Play midi corresponding to the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "MidiAll") 'LilyPond-master-file))
+
+(defun count-rexp (start end rexp)
+ "Print number of found regular expressions in the region."
+ (interactive "r")
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char (point-min))
+ (count-matches rexp))))
+
+(defun count-midi-words ()
+ "Check number of midi-scores before the curser."
+ (if (eq LilyPond-command-current 'LilyPond-command-region)
+ (count-rexp (mark t) (point) "\\\\midi")
+ (count-rexp (point-min) (point-max) "\\\\midi")))
+
+(defun count-midi-words-backwards ()
+ "Check number of midi-scores before the curser."
+ (if (eq LilyPond-command-current 'LilyPond-command-region)
+ (count-rexp (mark t) (point) "\\\\midi")
+ (count-rexp (point-min) (point) "\\\\midi")))
+
+(defun LilyPond-string-current-midi ()
+ "Check the midi file of the following midi-score in the current document."
+ (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
+ (substring (LilyPond-master-file) 0 -3); suppose ".ly"
+ LilyPond-region-file-prefix))
+ (allcount (string-to-number (substring (count-midi-words) 0 -12)))
+ (count (string-to-number (substring (count-midi-words-backwards) 0 -12))))
+ (concat fnameprefix
+ (if (and (> allcount 1) (> count 0)) ; not first score
+ (if (eq count allcount) ; last score
+ (concat "-" (number-to-string (+ count -1)))
+ (concat "-" (number-to-string count))))
+ ".midi")))
+
+(defun LilyPond-string-all-midi ()
+ "Return the midi files of the current document in ascending order."
+ (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
+ (substring (LilyPond-master-file) 0 -3); suppose ".ly"
+ LilyPond-region-file-prefix))
+ (allcount (string-to-number (substring (count-midi-words) 0 -12))))
+ (concat (if (> allcount 0) ; at least one midi-score
+ (concat fnameprefix ".midi "))
+ (if (> allcount 1) ; more than one midi-score
+ (concat fnameprefix "-[1-9].midi "))
+ (if (> allcount 9) ; etc.
+ (concat fnameprefix "-[1-9][0-9].midi"))
+ (if (> allcount 99) ; not first score
+ (concat fnameprefix "-[1-9][0-9][0-9].midi")))))
+
+;; This is the major configuration variable.
+(defcustom LilyPond-command-alist
+ ;; Should expand this to include possible keyboard shortcuts which
+ ;; could then be mapped to define-key and menu.
+ `(
+ ("LilyPond" . ("lilypond-bin %s" . "LaTeX"))
+ ("TeX" . ("tex '\\nonstopmode\\input %t'" . "View"))
+
+ ("2Dvi" . ("lilypond %s" . "View"))
+ ("2PS" . ("lilypond -P %s" . "ViewPS"))
+ ("2Midi" . ("lilypond -m %s" . "View"))
+
+ ("Book" . ("lilypond-book %x" . "LaTeX"))
+ ("LaTeX" . ("latex '\\nonstopmode\\input %l'" . "View"))
+
+ ;; point-n-click (arg: exits upop USR1)
+ ("SmartView" . ("xdvi %d" . "LilyPond"))
+
+ ;; refreshes when kicked USR1
+ ("View" . (,(concat LilyPond-xdvi-command " %d") . "LilyPond"))
+ ("ViewPS" . (,(concat LilyPond-gv-command " %p") . "LilyPond"))
+
+ ;; The following are refreshed in LilyPond-command:
+ ;; - current-midi depends on cursor position and
+ ("Midi" . (,(concat LilyPond-midi-command " " (LilyPond-string-current-midi)) . "LilyPond" )) ;
+ ;; - all-midi depends on number of midi-score.
+ ("MidiAll" . (,(concat LilyPond-all-midi-command " " (LilyPond-string-all-midi)) . "LilyPond"))
+ )
+
+ "AList of commands to execute on the current document.
+
+The key is the name of the command as it will be presented to the
+user, the value is a cons of the command string handed to the shell
+after being expanded, and the next command to be executed upon
+success. The expansion is done using the information found in
+LilyPond-expand-list.
+"
+ :group 'LilyPond
+ :type '(repeat (cons :tag "Command Item"
+ (string :tag "Key")
+ (cons :tag "How"
+ (string :tag "Command")
+ (string :tag "Next Key")))))
+
+;; drop this?
+(defcustom LilyPond-file-extension ".ly"
+ "*File extension used in LilyPond sources."
+ :group 'LilyPond
+ :type 'string)
+
+
+(defcustom LilyPond-expand-alist
+ '(
+ ("%s" . ".ly")
+ ("%t" . ".tex")
+ ("%d" . ".dvi")
+ ("%p" . ".ps")
+ ("%l" . ".tex")
+ ("%x" . ".tely")
+ ("%m" . ".midi")
+ )
+
+ "Alist of expansion strings for LilyPond command names."
+ :group 'LilyPond
+ :type '(repeat (cons :tag "Alist item"
+ (string :tag "Symbol")
+ (string :tag "Expansion"))))
+
+
+(defcustom LilyPond-command-Show "View"
+ "*The default command to show (view or print) a LilyPond file.
+Must be the car of an entry in `LilyPond-command-alist'."
+ :group 'LilyPond
+ :type 'string)
+ (make-variable-buffer-local 'LilyPond-command-Show)
+
+(defcustom LilyPond-command-Print "Print"
+ "The name of the Print entry in LilyPond-command-Print."
+ :group 'LilyPond
+ :type 'string)
+
+(defun xLilyPond-compile-sentinel (process msg)
+ (if (and process
+ (= 0 (process-exit-status process)))
+ (setq LilyPond-command-default
+ (cddr (assoc LilyPond-command-default LilyPond-command-alist)))))
+
+;; FIXME: shouldn't do this for stray View/xdvi
+(defun LilyPond-compile-sentinel (buffer msg)
+ (if (string-match "^finished" msg)
+ (setq LilyPond-command-default
+ (cddr (assoc LilyPond-command-default LilyPond-command-alist)))))
+
+;;(make-variable-buffer-local 'compilation-finish-function)
+(setq compilation-finish-function 'LilyPond-compile-sentinel)
+
+(defun LilyPond-command-query (name)
+ "Query the user for what LilyPond command to use."
+ (let* ((default (cond ((if (string-equal name LilyPond-region-file-prefix)
+ (LilyPond-check-files (concat name ".tex")
+ (list name)
+ (list LilyPond-file-extension))
+ (if (verify-visited-file-modtime (current-buffer))
+ (if (buffer-modified-p)
+ (if (y-or-n-p "Save buffer before next command? ")
+ (LilyPond-save-buffer)))
+ (if (y-or-n-p "The command will be invoked to an already saved buffer. Revert it? ")
+ (revert-buffer t t)))
+ ;;"LilyPond"
+ LilyPond-command-default))
+ (t LilyPond-command-default)))
+
+ (completion-ignore-case t)
+
+ (answer (or LilyPond-command-force
+ (completing-read
+ (concat "Command: (default " default ") ")
+ LilyPond-command-alist nil t nil 'LilyPond-command-history))))
+
+ ;; If the answer is "LilyPond" it will not be expanded to "LilyPond"
+ (let ((answer (car-safe (assoc answer LilyPond-command-alist))))
+ (if (and answer
+ (not (string-equal answer "")))
+ answer
+ default))))
+
+(defun LilyPond-command-master ()
+ "Run command on the current document."
+ (interactive)
+ (LilyPond-command-select-master)
+ (LilyPond-command (LilyPond-command-query (LilyPond-master-file))
+ 'LilyPond-master-file))
+
+(defun LilyPond-command-lilypond ()
+ "Run lilypond for the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-formatdvi ()
+ "Format the dvi output of the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "2Dvi") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-formatps ()
+ "Format the ps output of the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "2PS") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-formatmidi ()
+ "Format the midi output of the current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "2Midi") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-smartview ()
+ "View the dvi output of current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "SmartView") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-view ()
+ "View the dvi output of current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "View") 'LilyPond-master-file)
+)
+
+(defun LilyPond-command-viewps ()
+ "View the ps output of current document."
+ (interactive)
+ (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file)
+)
+
+;; FIXME, this is broken
+(defun LilyPond-region-file (begin end)
+ (let (
+ ;; (dir "./")
+ (dir (LilyPond-temp-directory))
+ (base LilyPond-region-file-prefix)
+ (ext LilyPond-file-extension))
+ (concat dir base ext)))
+
+;;; Commands on Region work if there is an appropriate '\score'.
+(defun LilyPond-command-region (begin end)
+ "Run LilyPond on the current region."
+ (interactive "r")
+ (if (or (> begin (point-min)) (< end (point-max)))
+ (LilyPond-command-select-region))
+ (write-region begin end (LilyPond-region-file begin end) nil 'nomsg)
+ (LilyPond-command (LilyPond-command-query
+ (LilyPond-region-file begin end))
+ '(lambda () (LilyPond-region-file begin end)))
+ ;; Region may deactivate even if buffer was intact, reactivate?
+ ;; Currently, also deactived regions are used.
+ )
+
+(defun LilyPond-command-buffer ()
+ "Run LilyPond on buffer."
+ (interactive)
+ (LilyPond-command-select-buffer)
+ (LilyPond-command-region (point-min) (point-max)))
+
+(defun LilyPond-command-expand (string file)
+ (let ((case-fold-search nil))
+ (if (string-match "%" string)
+ (let* ((b (match-beginning 0))
+ (e (+ b 2))
+ (l (split-file-name file))
+ (dir (car l))
+ (base (cadr l)))
+ (LilyPond-command-expand
+ (concat (substring string 0 b)
+ dir
+ base
+ (let ((entry (assoc (substring string b e)
+ LilyPond-expand-alist)))
+ (if entry (cdr entry) ""))
+ (substring string e))
+ file))
+ string)))
+
+(defun LilyPond-shell-process (name buffer command)
+ (let ((old (current-buffer)))
+ (switch-to-buffer-other-window buffer)
+ ;; If we empty the buffer don't see messages scroll by.
+ ;; (erase-buffer)
+
+ (start-process-shell-command name buffer command)
+ (switch-to-buffer-other-window old)))
+
+
+(defun LilyPond-command (name file)
+ "Run command NAME on the file you get by calling FILE.
+
+FILE is a function return a file name. It has one optional argument,
+the extension to use on the file.
+
+Use the information in LilyPond-command-alist to determine how to run the
+command."
+
+ (let ((entry (assoc name LilyPond-command-alist)))
+ (if entry
+ (let ((command (LilyPond-command-expand (cadr entry)
+ (apply file nil)))
+ (jobs nil)
+ (job-string "no jobs"))
+ (if (member name (list "View" "ViewPS"))
+ ;; is USR1 a right signal for viewps?
+ (let ((buffer-xdvi (get-buffer-create (concat "*" name "*"))))
+ (if LilyPond-kick-xdvi
+ (let ((process-xdvi (get-buffer-process buffer-xdvi)))
+ (if process-xdvi
+ (signal-process (process-id process-xdvi) 'SIGUSR1)
+ (LilyPond-shell-process name buffer-xdvi command)))
+ (LilyPond-shell-process name buffer-xdvi command)))
+ (progn
+ (if (string-equal name "Midi")
+ (progn
+ (setq command (concat LilyPond-midi-command " " (LilyPond-string-current-midi)))
+ (if (LilyPond-kill-midi)
+ (setq job-string nil)))) ; either stop or start playing
+ (if (string-equal name "MidiAll")
+ (progn
+ (setq command (concat LilyPond-all-midi-command " " (LilyPond-string-all-midi)))
+ (LilyPond-kill-midi))) ; stop and start playing
+ (if (and (member name (list "Midi" "MidiAll")) job-string)
+ (if (file-newer-than-file-p
+ (LilyPond-master-file)
+ (concat (substring (LilyPond-master-file) 0 -3) ".midi"))
+ (if (y-or-n-p "Midi older than source. Reformat midi?")
+ (progn
+ (LilyPond-command-formatmidi)
+ (while (LilyPond-running)
+ (message "Starts playing midi once it is built.")
+ (sit-for 0 100))))))
+ (if (member name (list "LilyPond" "TeX" "2Midi" "2PS" "2Dvi"
+ "Book" "LaTeX"))
+ (if (setq jobs (LilyPond-running))
+ (progn
+ (setq job-string "Process") ; could also suggest compiling after process has ended
+ (while jobs
+ (setq job-string (concat job-string " \"" (pop jobs) "\"")))
+ (setq job-string (concat job-string " is already running; kill it to proceed "))
+ (if (y-or-n-p job-string)
+ (progn
+ (setq job-string "no jobs")
+ (LilyPond-kill-jobs)
+ (while (LilyPond-running)
+ (sit-for 0 100)))
+ (setq job-string nil)))))
+
+ (setq LilyPond-command-default name)
+ (if (string-equal job-string "no jobs")
+ (LilyPond-compile-file command name))))))))
+
+(defun LilyPond-mark-active ()
+ "Check if there is an active mark."
+ (and transient-mark-mode
+ (if (string-match "XEmacs\\|Lucid" emacs-version) (mark) mark-active)))
+
+(defun LilyPond-temp-directory ()
+ "Temporary file directory for Commands on Region."
+ (interactive)
+ (if (string-match "XEmacs\\|Lucid" emacs-version)
+ (concat (temp-directory) "/")
+ temporary-file-directory))
+
+;;; Keymap
+
+(defvar LilyPond-mode-map ()
+ "Keymap used in `LilyPond-mode' buffers.")
+
+;; Note: if you make changes to the map, you must do
+;; M-x set-variable LilyPond-mode-map nil
+;; M-x eval-buffer
+;; M-x LilyPond-mode
+;; to let the changest take effect
+
+(if LilyPond-mode-map
+ ()
+ (setq LilyPond-mode-map (make-sparse-keymap))
+ ;; Put keys to LilyPond-command-alist and fetch them from there somehow.
+ (define-key LilyPond-mode-map "\C-c\C-l" 'LilyPond-command-lilypond)
+ (define-key LilyPond-mode-map "\C-c\C-r" 'LilyPond-command-region)
+ (define-key LilyPond-mode-map "\C-c\C-b" 'LilyPond-command-buffer)
+ (define-key LilyPond-mode-map "\C-c\C-k" 'LilyPond-kill-jobs)
+ (define-key LilyPond-mode-map "\C-c\C-c" 'LilyPond-command-master)
+ (define-key LilyPond-mode-map "\C-cm" 'LilyPond-command-formatmidi)
+ (define-key LilyPond-mode-map "\C-c\C-d" 'LilyPond-command-formatdvi)
+ (define-key LilyPond-mode-map "\C-c\C-f" 'LilyPond-command-formatps)
+ (define-key LilyPond-mode-map "\C-c\C-s" 'LilyPond-command-smartview)
+ (define-key LilyPond-mode-map "\C-c\C-v" 'LilyPond-command-view)
+ (define-key LilyPond-mode-map "\C-c\C-p" 'LilyPond-command-viewps)
+ (define-key LilyPond-mode-map [(control c) return] 'LilyPond-command-current-midi)
+ (define-key LilyPond-mode-map [(control c) (control return)] 'LilyPond-command-all-midi)
+ (define-key LilyPond-mode-map "\C-x\C-s" 'LilyPond-save-buffer)
+ (define-key LilyPond-mode-map "\C-cf" 'font-lock-fontify-buffer)
+ (define-key LilyPond-mode-map "\C-ci" 'LilyPond-insert-tag-current)
+ ;; the following will should be overriden by Lilypond Quick Insert Mode
+ (define-key LilyPond-mode-map "\C-cq" 'LilyPond-quick-insert-mode)
+ (define-key LilyPond-mode-map "\C-c;" 'LilyPond-comment-region)
+ (define-key LilyPond-mode-map ")" 'LilyPond-electric-close-paren)
+ (define-key LilyPond-mode-map ">" 'LilyPond-electric-close-paren)
+ (define-key LilyPond-mode-map "}" 'LilyPond-electric-close-paren)
+ (define-key LilyPond-mode-map "]" 'LilyPond-electric-close-paren)
+ (if (string-match "XEmacs\\|Lucid" emacs-version)
+ (define-key LilyPond-mode-map [iso-left-tab] 'LilyPond-autocompletion)
+ (define-key LilyPond-mode-map [iso-lefttab] 'LilyPond-autocompletion))
+ (define-key LilyPond-mode-map "\C-c\t" 'LilyPond-info-index-search)
+ )
+
+;;; Menu Support
+
+;;; This mode was originally LilyPond-quick-note-insert by Heikki Junes.
+;;; The original version has been junked since CVS-1.97,
+;;; in order to merge the efforts done by Nicolas Sceaux.
+;;; LilyPond Quick Insert Mode is a major mode, toggled by C-c q.
+(defun LilyPond-quick-insert-mode ()
+ "Insert notes with fewer key strokes by using a simple keyboard piano."
+ (interactive)
+ (progn
+ (message "Invoke (C-c q) from keyboard. If you still see this message,") (sit-for 5 0)
+ (message "then you have not installed LilyPond Quick Insert Mode (lyqi).") (sit-for 5 0)
+ (message "Download lyqi from http://nicolas.sceaux.free.fr/lilypond/lyqi.html,") (sit-for 5 0)
+ (message "see installation instructions from lyqi's README -file.") (sit-for 5 0)
+ (message "You need also eieio (Enhanced Integration of Emacs Interpreted Objects).") (sit-for 5 0)
+ (message "Download eieio from http://cedet.sourceforge.net/eieio.shtml,") (sit-for 5 0)
+ (message "see installation instructions from eieio's INSTALL -file.") (sit-for 5 0)
+ (message "")
+ ))
+
+(defun LilyPond-pre-word-search ()
+ "Fetch the alphabetic characters and \\ in front of the cursor."
+ (let ((pre "")
+ (prelen 0)
+ (ch (char-before (- (point) 0))))
+ (while (and ch (or (and (>= ch 65) (<= ch 90)) ; not bolp, A-Z
+ (and (>= ch 97) (<= ch 122)) ; a-z
+ (= ch 92))) ; \\
+ (setq pre (concat (char-to-string ch) pre))
+ (setq prelen (+ prelen 1))
+ (setq ch (char-before (- (point) prelen))))
+ pre))
+
+(defun LilyPond-post-word-search ()
+ "Fetch the alphabetic characters behind the cursor."
+ (let ((post "")
+ (postlen 0)
+ (ch (char-after (+ (point) 0))))
+ (while (and ch (or (and (>= ch 65) (<= ch 90)) ; not eolp, A-Z
+ (and (>= ch 97) (<= ch 122)))) ; a-z
+ (setq post (concat post (char-to-string ch)))
+ (setq postlen (+ postlen 1))
+ (setq ch (char-after (+ (point) postlen))))
+ post))
+
+(defun LilyPond-autocompletion ()
+ "Show completions in mini-buffer for the given word."
+ (interactive)
+ (let ((pre (LilyPond-pre-word-search))
+ (post (LilyPond-post-word-search))
+ (compsstr ""))
+ ;; insert try-completion and show all-completions
+ (if (> (length pre) 0)
+ (progn
+ (setq trycomp (try-completion pre (LilyPond-add-dictionary-word ())))
+ (if (char-or-string-p trycomp)
+ (if (string-equal (concat pre post) trycomp)
+ (goto-char (+ (point) (length post)))
+ (progn
+ (delete-region (point) (+ (point) (length post)))
+ (insert (substring trycomp (length pre) nil))))
+ (progn
+ (delete-region (point) (+ (point) (length post)))
+ (font-lock-fontify-buffer))) ; only inserting fontifies
+
+ (setq complist (all-completions pre (LilyPond-add-dictionary-word ())))
+ (while (> (length complist) 0)
+ (setq compsstr (concat compsstr "\"" (car complist) "\" "))
+ (setq complist (cdr complist)))
+ (message compsstr)
+ (sit-for 0 100)))))
+
+(defun LilyPond-info ()
+ "Launch Info for lilypond."
+ (interactive)
+ (info "lilypond"))
+
+(defun LilyPond-music-glossary-info ()
+ "Launch Info for music-glossary."
+ (interactive)
+ (info "music-glossary"))
+
+(defun LilyPond-internals-info ()
+ "Launch Info for lilypond-internals."
+ (interactive)
+ (info "lilypond-internals"))
+
+(defun LilyPond-info-index-search ()
+ "In `*info*'-buffer, launch `info lilypond --index-search word-under-cursor'"
+ (interactive)
+ (let ((str (concat (LilyPond-pre-word-search) (LilyPond-post-word-search))))
+ (if (and (> (length str) 0)
+ (string-equal (substring str 0 1) "\\"))
+ (setq str (substring str 1 nil)))
+ (LilyPond-info)
+ (Info-index str)))
+
+(defun LilyPond-insert-tag-current (&optional word)
+ "Set the current tag to be inserted."
+ (interactive)
+ (if word
+ (setq LilyPond-insert-tag-current word))
+ (if (memq LilyPond-insert-tag-current LilyPond-menu-keywords)
+ (LilyPond-insert-tag)
+ (message "No tag was selected from LilyPond->Insert tag-menu.")))
+
+(defun LilyPond-insert-tag ()
+ "Insert syntax for given tag. The definitions are in LilyPond-words-filename."
+ (interactive)
+ (setq b (find-file-noselect (LilyPond-words-filename) t t))
+ (let ((word LilyPond-insert-tag-current)
+ (found nil)
+ (p nil)
+ (query nil)
+ (m (set-marker (make-marker) 1 (get-buffer b)))
+ (distance (if (LilyPond-mark-active)
+ (abs (- (mark-marker) (point-marker))) 0))
+ )
+ ;; find the place first
+ (if (LilyPond-mark-active)
+ (goto-char (min (mark-marker) (point-marker))))
+ (while (and (not found) (> (buffer-size b) (marker-position m)))
+ (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
+ (if (string-equal word copy) (setq found t)))
+ (if found (insert word))
+ (if (> (buffer-size b) (marker-position m))
+ (setq copy (car (copy-alist (list (eval (symbol-name (read m))))))))
+ (if (not (string-equal "-" copy))
+ (setq found nil))
+ (while (and found (> (buffer-size b) (marker-position m)))
+ ;; find next symbol
+ (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
+ ;; check whether it is the word, or the word has been found
+ (cond
+ ((string-equal "-" copy) (setq found nil))
+ ((string-equal "%" copy) (insert " " (read-string "Give Arguments: ")))
+ ((string-equal "_" copy)
+ (progn
+ (setq p (point))
+ (goto-char (+ p distance))))
+ ((string-equal "\?" copy) (setq query t))
+ ((string-equal "\!" copy) (setq query nil))
+ ((string-equal "\\n" copy)
+ (if (not query)
+ (progn (LilyPond-indent-line) (insert "\n") (LilyPond-indent-line))))
+ ((string-equal "{" copy)
+ (if (not query)
+ (progn (insert " { "))))
+ ((string-equal "}" copy)
+ (if (not query)
+ (progn (insert " } ") (setq query nil) )))
+ ((not query)
+ (insert copy))
+ (query
+ (if (y-or-n-p (concat "Proceed with `" copy "'? "))
+ (progn (insert copy) (setq query nil))))
+ ))
+ (if p (goto-char p))
+ (kill-buffer b))
+)
+
+(defun LilyPond-command-menu-entry (entry)
+ ;; Return LilyPond-command-alist ENTRY as a menu item.
+ (let ((name (car entry)))
+ (cond ((and (string-equal name LilyPond-command-Print)
+ LilyPond-printer-list)
+ (let ((command LilyPond-print-command)
+ (lookup 1))
+ (append (list LilyPond-command-Print)
+ (mapcar 'LilyPond-command-menu-printer-entry
+ LilyPond-printer-list))))
+ (t
+ (vector name (list 'LilyPond-command-menu name) t)))))
+
+
+(easy-menu-define LilyPond-command-menu
+ LilyPond-mode-map
+ "Menu used in LilyPond mode."
+ (append '("Command")
+ '(("Command on"
+ [ "Master File" LilyPond-command-select-master
+ :keys "C-c C-c" :style radio
+ :selected (eq LilyPond-command-current 'LilyPond-command-master) ]
+ [ "Buffer" LilyPond-command-select-buffer
+ :keys "C-c C-b" :style radio
+ :selected (eq LilyPond-command-current 'LilyPond-command-buffer) ]
+ [ "Region" LilyPond-command-select-region
+ :keys "C-c C-r" :style radio
+ :selected (eq LilyPond-command-current 'LilyPond-command-region) ]))
+;;; (let ((file 'LilyPond-command-on-current))
+;;; (mapcar 'LilyPond-command-menu-entry LilyPond-command-alist))
+;;; Some kind of mapping which includes :keys might be more elegant
+;;; Put keys to LilyPond-command-alist and fetch them from there somehow.
+ '([ "LilyPond" LilyPond-command-lilypond t])
+ '([ "TeX" (LilyPond-command (LilyPond-command-menu "TeX") 'LilyPond-master-file) ])
+ '([ "2Dvi" LilyPond-command-formatdvi t])
+ '([ "2PS" LilyPond-command-formatps t])
+ '([ "2Midi" LilyPond-command-formatmidi t])
+ '([ "Book" (LilyPond-command (LilyPond-command-menu "Book") 'LilyPond-master-file) ])
+ '([ "LaTeX" (LilyPond-command (LilyPond-command-menu "LaTeX") 'LilyPond-master-file) ])
+ '([ "Kill jobs" LilyPond-kill-jobs t])
+ '("-----")
+ '([ "SmartView" LilyPond-command-smartview t])
+ '([ "View" LilyPond-command-view t])
+ '([ "ViewPS" LilyPond-command-viewps t])
+ '("-----")
+ '([ "Midi (toggle)" LilyPond-command-current-midi t])
+ '([ "Midi all" LilyPond-command-all-midi t])
+ ))
+
+(defun LilyPond-menu-keywords-item (arg)
+ "Make vector for LilyPond-mode-keywords."
+ (vector arg (list 'LilyPond-insert-tag-current arg) :style 'radio :selected (list 'eq 'LilyPond-insert-tag-current arg)))
+
+(defun LilyPond-menu-keywords ()
+ "Make Insert Tag menu.
+
+The Insert Tag -menu is splitted into parts if it is long enough."
+
+ (let ((li (mapcar 'LilyPond-menu-keywords-item LilyPond-menu-keywords))
+ (w (round (sqrt (length LilyPond-menu-keywords))))
+ (splitted '())
+ (imin 0) imax lw rw)
+ (while (< imin (length LilyPond-menu-keywords))
+ (setq imax (- (min (+ imin w) (length LilyPond-menu-keywords)) 1))
+ (setq lw (nth imin LilyPond-menu-keywords))
+ (setq rw (nth imax LilyPond-menu-keywords))
+ (add-to-list 'splitted
+ (let ((l (list (concat (substring lw 0 (min 7 (length lw)))
+ " ... "
+ (substring rw 0 (min 7 (length rw)))))))
+ (while (<= imin imax)
+ (add-to-list 'l (nth imin li))
+ (setq imin (1+ imin)))
+ (reverse l))))
+ (if (> (length LilyPond-menu-keywords) 12) (reverse splitted) li)))
+
+;;; LilyPond-mode-menu should not be interactive, via "M-x LilyPond-<Tab>"
+(easy-menu-define LilyPond-mode-menu
+ LilyPond-mode-map
+ "Menu used in LilyPond mode."
+ (append '("LilyPond")
+ '(["Add index menu" LilyPond-add-imenu-menu])
+ (list (cons "Insert tag"
+ (cons ["Previously selected" LilyPond-insert-tag-current t]
+ (cons "-----"
+ (LilyPond-menu-keywords)))))
+ '(("Miscellaneous"
+ ["Autocompletion" LilyPond-autocompletion t]
+ ["(Un)comment Region" LilyPond-comment-region t]
+ ["Refontify buffer" font-lock-fontify-buffer t]
+ "-----"
+ ["Quick Insert Mode" LilyPond-quick-insert-mode :keys "C-c q"]
+ ))
+ '(("Info"
+ ["LilyPond" LilyPond-info t]
+ ["LilyPond index-search" LilyPond-info-index-search t]
+ ["Music Glossary" LilyPond-music-glossary-info t]
+ ["LilyPond internals" LilyPond-internals-info t]
+ ))
+ ))
+
+(defconst LilyPond-imenu-generic-re "^\\([a-zA-Z]+\\) *="
+ "Regexp matching Identifier definitions.")
+
+(defvar LilyPond-imenu-generic-expression
+ (list (list nil LilyPond-imenu-generic-re 1))
+ "Expression for imenu")
+
+(defun LilyPond-command-select-master ()
+ (interactive)
+ (message "Next command will be on the master file")
+ (setq LilyPond-command-current 'LilyPond-command-master))
+
+(defun LilyPond-command-select-buffer ()
+ (interactive)
+ (message "Next command will be on the buffer")
+ (setq LilyPond-command-current 'LilyPond-command-buffer))
+
+(defun LilyPond-command-select-region ()
+ (interactive)
+ (message "Next command will be on the region")
+ (setq LilyPond-command-current 'LilyPond-command-region))
+
+(defun LilyPond-command-menu (name)
+ ;; Execute LilyPond-command-alist NAME from a menu.
+ (let ((LilyPond-command-force name))
+ (if (eq LilyPond-command-current 'LilyPond-command-region)
+ (if (eq (mark t) nil)
+ (progn (message "The mark is not set now") (sit-for 0 500))
+ (progn (if (not (not (LilyPond-mark-active)))
+ (progn (message "Region is not active, using region between inactive mark and current point.") (sit-for 0 500)))
+ (LilyPond-command-region (mark t) (point))))
+ (funcall LilyPond-command-current))))
+
+(defun LilyPond-add-imenu-menu ()
+ (interactive)
+ "Add an imenu menu to the menubar."
+ (if (not LilyPond-imenu)
+ (progn
+ (imenu-add-to-menubar "Index")
+ (redraw-frame (selected-frame))
+ (setq LilyPond-imenu t))
+ (message "%s" "LilyPond-imenu already exists.")))
+(put 'LilyPond-add-imenu-menu 'menu-enable '(not LilyPond-imenu))
+
+(defun LilyPond-mode ()
+ "Major mode for editing LilyPond music files.
+
+This mode knows about LilyPond keywords and line comments, not about
+indentation or block comments. It features easy compilation, error
+finding and viewing of a LilyPond source buffer or region.
+
+COMMANDS
+\\{LilyPond-mode-map}
+VARIABLES
+
+LilyPond-command-alist\t\talist from name to command
+LilyPond-xdvi-command\t\tcommand to display dvi files -- bit superfluous"
+ (interactive)
+ ;; set up local variables
+ (kill-all-local-variables)
+
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(LilyPond-font-lock-keywords))
+
+ ;; string and comments are fontified explicitly
+ (make-local-variable 'font-lock-keywords-only)
+ (setq font-lock-keywords-only t)
+
+ ;; Multi-line font-locking needs Emacs 21.1 or newer.
+ ;; For older versions there is hotkey "C-c f".
+ (make-local-variable 'font-lock-multiline)
+ (setq font-lock-multiline t)
+
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate "^[ \t]*$")
+
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start "^[ \t]*$")
+
+ (make-local-variable 'comment-start)
+ (setq comment-start "%")
+
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "%{? *")
+
+ (make-local-variable 'comment-end)
+ (setq comment-end "")
+
+ (make-local-variable 'block-comment-start)
+ (setq block-comment-start "%{")
+
+ (make-local-variable 'block-comment-end)
+ (setq block-comment-end "%}")
+
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'LilyPond-indent-line)
+
+ (LilyPond-mode-set-syntax-table '(?\< ?\> ?\{ ?\}))
+ (setq major-mode 'LilyPond-mode)
+ (setq mode-name "LilyPond")
+ (setq local-abbrev-table LilyPond-mode-abbrev-table)
+ (use-local-map LilyPond-mode-map)
+
+ ;; In XEmacs imenu was synched up with: FSF 20.4
+ (make-local-variable 'imenu-generic-expression)
+ (setq imenu-generic-expression LilyPond-imenu-generic-expression)
+ ;; (imenu-add-to-menubar "Index") ; see LilyPond-add-imenu-menu
+
+ ;; In XEmacs one needs to use 'easy-menu-add'.
+ (if (string-match "XEmacs\\|Lucid" emacs-version)
+ (progn
+ (easy-menu-add LilyPond-mode-menu)
+ (easy-menu-add LilyPond-command-menu)))
+
+ ;; Use Command on Region even for inactive mark (region).
+ (if (string-match "XEmacs\\|Lucid" emacs-version)
+ (setq zmacs-regions nil)
+ (setq mark-even-if-inactive t))
+
+ ;; Context dependent syntax tables in LilyPond-mode
+ (make-local-hook 'post-command-hook) ; XEmacs requires
+ (add-hook 'post-command-hook 'LilyPond-mode-context-set-syntax-table nil t)
+
+ ;; Turn on paren-mode buffer-locally, i.e., in LilyPond-mode
+ (if (string-match "XEmacs\\|Lucid" emacs-version)
+ (progn
+ (make-local-variable 'paren-mode)
+ (paren-set-mode 'paren)
+ (make-local-variable 'blink-matching-paren)
+ (setq blink-matching-paren t)
+ )
+ (progn
+ (make-local-variable 'blink-matching-paren-on-screen)
+ (setq blink-matching-paren-on-screen t)
+ ))
+
+ ;; run the mode hook. LilyPond-mode-hook use is deprecated
+ (run-hooks 'LilyPond-mode-hook))
+
+(defun LilyPond-version ()
+ "Echo the current version of `LilyPond-mode' in the minibuffer."
+ (interactive)
+ (message "Using `LilyPond-mode' version %s" LilyPond-version))
+
+(load-library "lilypond-font-lock")
+(load-library "lilypond-indent")
+
+(provide 'lilypond-mode)
+;;; lilypond-mode.el ends here
+
+++ /dev/null
-;;; lilypond-font-lock.el --- syntax coloring for LilyPond mode
-
-;; Copyright (C) 1992,1993,1994 Tim Peters
-
-;; 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.9.9
-;; Last Modified: 23SEP2003
-;; Keywords: lilypond languages music notation
-
-;; This software is provided as-is, without express or implied
-;; warranty. Permission to use, copy, modify, distribute or sell this
-;; software, without fee, for any purpose and by any individual or
-;; organization, is hereby granted, provided that the above copyright
-;; notice and this paragraph appear in all copies.
-
-;; 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 \[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)
-
-;; ... 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-warning-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 (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 '( ?\< ?\> ?\{ ?\} ?\^ ?\- ?\_ )))
- ))
+++ /dev/null
-;;; lilypond-indent.el --- Auto-indentation for lilypond code
-;;;
-;;; Heikki Junes <hjunes@cc.hut.fi>
-;;; * ond-char paren matching is handled by context dependent syntax tables
-;;; * match two-char slurs '\( ... \)' and '\[ ... \]' separately.
-;;; * adopt Emacs' f90-comment-region
-
-;;; Chris Jackson <chris@fluffhouse.org.uk>
-;;; some code is taken from ESS (Emacs Speaks Statistics) S-mode by A.J.Rossini <rossini@biostat.washington.edu>
-
-;;; Variables for customising indentation style
-
-;;; TODO:
-;;; * currently, in bracket matching one may need a non-bracket
-;;; chararacter between the bracket characters, like ( ( ) )
-
-(defcustom LilyPond-indent-level 4
- "*Indentation of lilypond statements with respect to containing block.")
-
-(defcustom LilyPond-brace-offset 0
- "*Extra indentation for open braces.
-Compares with other text in same context.")
-
-(defcustom LilyPond-angle-offset 0
- "*Extra indentation for open angled brackets.
-Compares with other text in same context.")
-
-(defcustom LilyPond-square-offset 0
- "*Extra indentation for open square brackets.
-Compares with other text in same context.")
-
-(defcustom LilyPond-scheme-paren-offset 0
- "*Extra indentation for open scheme parens.
-Compares with other text in same context.")
-
-(defcustom LilyPond-close-brace-offset 0
- "*Extra indentation for closing braces.")
-
-(defcustom LilyPond-close-angle-offset 0
- "*Extra indentation for closing angle brackets.")
-
-(defcustom LilyPond-close-square-offset 0
- "*Extra indentation for closing square brackets.")
-
-(defcustom LilyPond-close-scheme-paren-offset 0
- "*Extra indentation for closing scheme parens.")
-
-(defcustom LilyPond-fancy-comments t
- "*Non-nil means distiguish between %, %%, and %%% for indentation.")
-
-(defcustom LilyPond-comment-region "%%$"
- "*String inserted by \\[LilyPond-comment-region]\
- at start of each line in region.")
-
-(defun LilyPond-comment-region (beg-region end-region)
- "Comment/uncomment every line in the region.
-Insert LilyPond-comment-region at the beginning of every line in the region
-or, if already present, remove it."
- (interactive "*r")
- (let ((end (make-marker)))
- (set-marker end end-region)
- (goto-char beg-region)
- (beginning-of-line)
- (if (looking-at (regexp-quote LilyPond-comment-region))
- (delete-region (point) (match-end 0))
- (insert LilyPond-comment-region))
- (while (and (zerop (forward-line 1))
- (< (point) (marker-position end)))
- (if (looking-at (regexp-quote LilyPond-comment-region))
- (delete-region (point) (match-end 0))
- (insert LilyPond-comment-region)))
- (set-marker end nil)))
-
-(defun LilyPond-calculate-indent ()
- "Return appropriate indentation for current line as lilypond code.
-In usual case returns an integer: the column to indent to.
-Returns nil if line starts inside a string"
- (save-excursion
- (beginning-of-line)
- (let ((indent-point (point))
- (case-fold-search nil)
- state)
- (setq containing-sexp (save-excursion (LilyPond-scan-containing-sexp)))
- (beginning-of-defun)
- (while (< (point) indent-point)
- (setq state (parse-partial-sexp (point) indent-point 0)))
- ;; (setq containing-sexp (car (cdr state))) is the traditional way for languages
- ;; with simpler parenthesis delimiters
- (cond ((nth 3 state)
- ;; point is in the middle of a string
- nil)
- ((nth 4 state)
- ;; point is in the middle of a block comment
- (LilyPond-calculate-indent-within-blockcomment))
- ((null containing-sexp)
- ;; Line is at top level - no indent
- (beginning-of-line)
- 0)
- (t
- ;; Find previous non-comment character.
- (goto-char indent-point)
- (LilyPond-backward-to-noncomment containing-sexp)
- ;; Now we get the answer.
- ;; Position following last unclosed open.
- (goto-char containing-sexp)
- (or
- ;; Is line first statement after an open brace or bracket?
- ;; If no, find that first statement and indent like it.
- (save-excursion
- (forward-char 1)
- ;; Skip over comments following open brace.
- (skip-chars-forward " \t\n")
- (cond ((looking-at "%{")
- (while (progn
- (and (not (looking-at "%}"))
- (< (point) (point-max))))
- (forward-line 1)
- (skip-chars-forward " \t\n"))
- (forward-line 1)
- (skip-chars-forward " \t\n"))
- ((looking-at "%")
- (while (progn (skip-chars-forward " \t\n")
- (looking-at "%"))
- (forward-line 1))))
- ;; The first following code counts
- ;; if it is before the line we want to indent.
- (and (< (point) indent-point)
- (current-column)))
- ;; If no previous statement,
- ;; indent it relative to line brace is on.
- ;; For open brace in column zero, don't let statement
- ;; start there too. If LilyPond-indent-level is zero, use
- ;; LilyPond-brace-offset instead
- (+ (if (and (bolp) (zerop LilyPond-indent-level))
- (cond ((= (following-char) ?{)
- LilyPond-brace-offset)
- ((= (following-char) ?<)
- LilyPond-angle-offset)
- ((= (following-char) ?[)
- LilyPond-square-offset)
- ((= (following-char) ?\))
- LilyPond-scheme-paren-offset)
- (t
- 0))
- LilyPond-indent-level)
- (progn
- (skip-chars-backward " \t")
- (current-indentation)))))))))
-
-
-(defun LilyPond-indent-line ()
- "Indent current line as lilypond code.
-Return the amount the indentation changed by."
- (let ((indent (LilyPond-calculate-indent))
- beg shift-amt
- (case-fold-search nil)
- (pos (- (point-max) (point))))
- (beginning-of-line)
- (setq beg (point))
- (cond ((eq indent nil)
- (setq indent (current-indentation)))
- (t
- (skip-chars-forward " \t")
- (if (and LilyPond-fancy-comments (looking-at "%%%\\|%{\\|%}"))
- (setq indent 0))
- (if (and LilyPond-fancy-comments
- (looking-at "%")
- (not (looking-at "%%\\|%{\\|%}")))
- (setq indent comment-column)
- (if (eq indent t) (setq indent 0))
- (if (listp indent) (setq indent (car indent)))
- (cond
- ((= (following-char) ?})
- (setq indent (+ indent (- LilyPond-close-brace-offset LilyPond-indent-level))))
- ((= (following-char) ?>)
- (setq indent (+ indent (- LilyPond-close-angle-offset LilyPond-indent-level))))
- ((= (following-char) ?])
- (setq indent (+ indent (- LilyPond-close-square-offset LilyPond-indent-level))))
- ((and (= (following-char) ?\)) (LilyPond-inside-scheme-p))
- (setq indent (+ indent (- LilyPond-close-scheme-paren-offset LilyPond-indent-level))))
- ((= (following-char) ?{)
- (setq indent (+ indent LilyPond-brace-offset)))
- ((= (following-char) ?<)
- (setq indent (+ indent LilyPond-angle-offset)))
- ((= (following-char) ?[)
- (setq indent (+ indent LilyPond-square-offset)))
- ((and (= (following-char) ?\() (LilyPond-inside-scheme-p))
- (setq indent (+ indent LilyPond-scheme-paren-offset)))
- ))))
- (skip-chars-forward " \t")
- (setq shift-amt (- indent (current-column)))
- (if (zerop shift-amt)
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))
- (delete-region beg (point))
- (indent-to indent)
- ;; If initial point was within line's indentation,
- ;; position after the indentation.
- ;; Else stay at same point in text.
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos))))
- shift-amt))
-
-
-(defun LilyPond-inside-comment-p ()
- "Return non-nil if point is inside a line or block comment"
- (setq this-point (point))
- (or (save-excursion (beginning-of-line)
- (skip-chars-forward " \t")
- (looking-at "%"))
- (save-excursion
- ;; point is in the middle of a block comment
- (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" (point-min) t)))
- (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" (point-min) t)))
- (if (or (and (= (char-before) ?%) (= (char-after) ?{))
- (and (= (char-after) ?%) (= (char-after (1+ (point))) ?{)))
- (setq lastopen (save-excursion (backward-char) (point))))
- (and
- lastopen
- (or (not lastclose)
- (<= lastclose lastopen))))
- ))
-
-
-(defun LilyPond-inside-string-or-comment-p ()
- "Test if point is inside a string or a comment"
- (setq this-point (point))
- (or (save-excursion (beginning-of-line)
- (skip-chars-forward " \t")
- (looking-at "%"))
- (save-excursion
- (beginning-of-defun)
- (while (< (point) this-point)
- (setq state (parse-partial-sexp (point) this-point 0)))
- (cond ((nth 3 state)
- ;; point is in the middle of a string
- t )
- ((nth 4 state)
- ;; point is in the middle of a block comment
- t )
- (t
- nil)))))
-
-
-(defun LilyPond-backward-over-blockcomments (lim)
- "Move point back to closest non-whitespace character not part of a block comment"
- (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" lim t)))
- (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" lim t)))
- (if lastopen
- (if lastclose
- (if (<= lastclose lastopen)
- (goto-char lastopen))
- (goto-char lastopen)))
- (skip-chars-backward " %\t\n\f"))
-
-
-(defun LilyPond-backward-over-linecomments (lim)
- "Move point back to the closest non-whitespace character not part of a line comment.
-Argument LIM limit."
- (let (opoint stop)
- (while (not stop)
- (skip-chars-backward " \t\n\f" lim)
- (setq opoint (point))
- (beginning-of-line)
- (search-forward "%" opoint 'move)
- (skip-chars-backward " \t%")
- (setq stop (or (/= (preceding-char) ?\n) (<= (point) lim)))
- (if stop (point)
- (beginning-of-line)))))
-
-
-(defun LilyPond-backward-to-noncomment (lim)
- "Move point back to closest non-whitespace character not part of a comment"
- (LilyPond-backward-over-linecomments lim)
- (LilyPond-backward-over-blockcomments lim))
-
-
-(defun LilyPond-calculate-indent-within-blockcomment ()
- "Return the indentation amount for line inside a block comment."
- (let (end percent-start)
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (skip-chars-backward " \t\n")
- (setq end (point))
- (beginning-of-line)
- (skip-chars-forward " \t")
- (and (re-search-forward "%{[ \t]*" end t)
- (goto-char (1+ (match-beginning 0))))
- (if (and (looking-at "[ \t]*$") (= (preceding-char) ?\%))
- (1+ (current-column))
- (current-column)))))
-
-
-;; Key: Type of bracket (character).
-;; Value: Pair of regexps representing the corresponding open and close bracket
-;; () are treated specially (need to indent in Scheme but not in music)
-
-(defconst LilyPond-parens-regexp-alist
- `( ( ?> . ("\\([^\\]\\|^\\)<" . "\\([^ \\n\\t_^-]\\|[_^-][-^]\\|\\s-\\)\\s-*>"))
- ;; a b c->, a b c^> and a b c_> are not close-angle-brackets, they're accents
- ;; but a b c^-> and a b c^^> are close brackets with tenuto/marcato before them
- ;; also \> and \< are hairpins
- ;; duh .. a single '>', as in chords '<< ... >>', was not matched here
- ( ?} . ("{" . "}"))
- ;; ligatures '\[ ... \]' are skipped in the following expression
- ( ?] . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)[[]" . "\\([^\\]\\([\\][\\]\\)*\\|^\\)[]]"))
- ( "\\]" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][[]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][]]"))
- ( "\\)" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][(]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][)]"))
- ))
-
-
-(defconst LilyPond-parens-alist
- `( ( ?< . ?> )
- ( ?{ . ?} )
- ( ?[ . ?] )
- ( "\\[" . "\\]" )
- ( ?\( . ?\) )
- ( "\\(" . "\\)" )
- ))
-
-
-(defun LilyPond-matching-paren (bracket-type)
- "Returns the open corresponding to the close specified by bracket-type, or vice versa"
- (cond ( (member bracket-type (mapcar 'car LilyPond-parens-alist))
- (cdr (assoc bracket-type LilyPond-parens-alist)) )
- ( (member bracket-type (mapcar 'cdr LilyPond-parens-alist))
- (car (rassoc bracket-type LilyPond-parens-alist)) )
- nil))
-
-
-(defun LilyPond-scan-containing-sexp (&optional bracket-type slur-paren-p dir)
- "Move point to the beginning of the deepest parenthesis pair enclosing point.
-
-If the optional argument bracket-type, a character representing a
-close bracket such as ) or }, is specified, then the parenthesis pairs
-searched are limited to this type.
-
-If the optional argument slur-paren-p is non-nil, then slur
-parentheses () are considered as matching pairs. Otherwise Scheme
-parentheses are considered to be matching pairs, but slurs are not.
-slur-paren-p defaults to nil.
-"
-;;; An user does not call this function directly, or by a key sequence.
- ;; (interactive)
- (let ( (level (if (not (eq dir 1)) 1 -1))
- (regexp-alist LilyPond-parens-regexp-alist)
- (oldpos (point))
- (assoc-bracket-type (if (not (eq dir 1)) bracket-type (LilyPond-matching-paren bracket-type))))
-
- (if (LilyPond-inside-scheme-p)
- (setq paren-regexp "(\\|)")
- (if slur-paren-p
- ;; expressional slurs '\( ... \)' are not taken into account
- (setq regexp-alist (cons '( ?\) . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)(" . "\\([^\\]\\([\\][\\]\\)*\\|^\\))")) regexp-alist)))
- (if (member assoc-bracket-type (mapcar 'car regexp-alist))
- (progn (setq paren-regexp (cdr (assoc assoc-bracket-type regexp-alist)))
- (setq paren-regexp (concat (car paren-regexp) "\\|" (cdr paren-regexp))))
- (setq paren-regexp (concat (mapconcat 'car (mapcar 'cdr regexp-alist) "\\|") "\\|"
- (mapconcat 'cdr (mapcar 'cdr regexp-alist) "\\|")))))
- ;; match concurrent one-char opening and closing slurs
- (if (and (eq dir 1)
- (not (sequencep bracket-type))
- (eq (char-syntax (char-after oldpos)) ?\()
- (not (eq (char-after oldpos) ?<)))
- ;; anyway do not count open slur, since already level = -1
- (progn (forward-char 1)
- (if (eq (following-char)
- (LilyPond-matching-paren (char-after oldpos)))
- ;; matching char found, go after it and set level = 0
- (progn (forward-char 1)
- (setq level 0)))))
- ;; browse the code until matching slur is found, or report mismatch
- (while (and (if (not (eq dir 1))
- (> level 0)
- (< level 0))
- ;; dir tells whether to search backward or forward
- (if (not (eq dir 1))
- (re-search-backward paren-regexp nil t)
- (re-search-forward paren-regexp nil t))
- ;; note: in case of two-char bracket only latter is compared
- (setq match (char-before (match-end 0))))
-;;; (message "%d" level) (sit-for 0 300)
- (if (not (save-excursion (goto-char (match-end 0))
- ;; skip over strings and comments
- (LilyPond-inside-string-or-comment-p)))
- (if (memq match '(?} ?> ?] ?\)))
- ;; count closing brackets
- (progn (setq level (1+ level))
- ;; slurs may be close to each other, e.g.,
- ;; a single '>' was not matched .. need to be corrected
- (if (and (eq dir 1) (eq (char-after (match-end 0)) match))
- (if (/= level 0)
- (progn
- (setq level (1+ level))
- (forward-char 1))))
-;;; (message "%d %c" level match) (sit-for 0 300)
- ;; hmm..
- (if (and (= match ?>)
- (looking-at ".\\s-+>\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)>"))
- (forward-char 1)))
- ;; count opening brackets
- (progn (setq level (1- level))
-;;; (message "%d %c" level match) (sit-for 0 300)
- ;; hmm..
- (if (and (= match ?<)
- (looking-at ".\\s-+<\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)<"))
- (forward-char 1))))))
- ;; jump to the matching slur
- (if (not (eq dir 1))
- (progn
- (if (sequencep bracket-type)
- ;; match the latter char in two-char brackets
- (if (looking-at "..[][)(]") (forward-char 1)))
- ;; if the following char is not already a slur
- (if (and (not (looking-at "[)(]"))
- ;; match the slur which follows
- (looking-at ".[][><)(]")) (forward-char 1)))
- (backward-char 1))
- (if (= level 0)
- (point)
- (progn (goto-char oldpos)
- nil))))
-
-
-(defun LilyPond-inside-scheme-p ()
- "Tests if point is inside embedded Scheme code"
-;;; An user does not call this function directly, or by a key sequence.
- ;; (interactive)
- (let ( (test-point (point))
- (level 0) )
- (save-excursion
- (if (or (and (/= (point) (point-max))
- (= (char-after (point)) ?\()
- (or (= (char-after (- (point) 1)) ?#)
- (and (= (char-after (- (point) 2)) ?#)
- (= (char-after (- (point) 1)) ?`))))
- (and (re-search-backward "#(\\|#`(" nil t)
- (progn
- (search-forward "(")
- (setq level 1)
- (while (and (> level 0)
- (re-search-forward "(\\|)" test-point t)
- (setq match (char-after (match-beginning 0)))
- (<= (point) test-point))
- (if (= match ?\()
- (setq level (1+ level))
- (setq level (1- level))))
- (> level 0))))
- t
- nil))))
-
-
-;;; Largely taken from the 'blink-matching-open' in lisp/simple.el in
-;;; the Emacs distribution.
-
-(defun LilyPond-blink-matching-paren (&optional dir)
- "Move cursor momentarily to the beginning of the sexp before
-point. In lilypond files this is used for closing ), ], } and >, whereas the
-builtin 'blink-matching-open' is not used. In syntax table, see
-`lilypond-font-lock.el', all brackets are punctuation characters."
-;;; An user does not call this function directly, or by a key sequence.
- ;; (interactive)
- (let ( (oldpos (point))
- (level 0)
- (mismatch) )
- (if (not (or (equal this-command 'LilyPond-electric-close-paren)
- (eq dir 1)))
- (goto-char (setq oldpos (- oldpos 1))))
- ;; Test if a ligature \] or expressional slur \) was encountered
- (setq bracket-type (char-after (point)))
- (setq char-before-bracket-type nil)
- (if (memq bracket-type '(?] ?\) ?[ ?\())
- (progn
- (setq np -1)
- (while (eq (char-before (- (point) (setq np (+ np 1)))) ?\\)
- (setq char-before-bracket-type (if char-before-bracket-type nil ?\\)))
- (if (eq char-before-bracket-type ?\\)
- (setq bracket-type (string char-before-bracket-type bracket-type)))))
- (when blink-matching-paren-distance
- (narrow-to-region
- (max (point-min) (- (point) blink-matching-paren-distance))
- (min (point-max) (+ (point) blink-matching-paren-distance))))
- (if (and (equal this-command 'LilyPond-electric-close-paren)
- (memq bracket-type '(?> ?} ?< ?{)))
- ;; < { need to be mutually balanced and nested, so search backwards for both of these bracket types
- (LilyPond-scan-containing-sexp nil nil dir)
- ;; whereas ( ) slurs within music don't, so only need to search for ( )
- ;; use same mechanism for [ ] slurs
- (LilyPond-scan-containing-sexp bracket-type t dir))
- (setq blinkpos (point))
- (setq mismatch
- (or (null (LilyPond-matching-paren (char-after blinkpos)))
- (/= (char-after oldpos)
- (LilyPond-matching-paren (char-after blinkpos)))))
- (if mismatch (progn (setq blinkpos nil)
- (message "Mismatched parentheses")))
- (if (and blinkpos
- (equal this-command 'LilyPond-electric-close-paren))
- (if (pos-visible-in-window-p)
- (and blink-matching-paren-on-screen
- (sit-for blink-matching-delay))
- (message
- "Matches %s"
- ;; Show what precedes the open in its line, if anything.
- (if (save-excursion
- (skip-chars-backward " \t")
- (not (bolp)))
- (buffer-substring (progn (beginning-of-line) (point))
- (1+ blinkpos))
- ;; Show what follows the open in its line, if anything.
- (if (save-excursion
- (forward-char 1)
- (skip-chars-forward " \t")
- (not (eolp)))
- (buffer-substring blinkpos
- (progn (end-of-line) (point)))
- ;; Otherwise show the previous nonblank line,
- ;; if there is one.
- (if (save-excursion
- (skip-chars-backward "\n \t")
- (not (bobp)))
- (concat
- (buffer-substring (progn
- (skip-chars-backward "\n \t")
- (beginning-of-line)
- (point))
- (progn (end-of-line)
- (skip-chars-backward " \t")
- (point)))
- ;; Replace the newline and other whitespace with `...'.
- "..."
- (buffer-substring blinkpos (1+ blinkpos)))
- ;; There is nothing to show except the char itself.
- (buffer-substring blinkpos (1+ blinkpos))))))))
- (if (not (equal this-command 'LilyPond-electric-close-paren))
- (goto-char (setq oldpos (+ oldpos 1)))
- (goto-char oldpos))
- (if (not (eq dir 1))
- blinkpos
- (+ blinkpos 1))))
-
-
-(defun LilyPond-electric-close-paren ()
- "Blink on the matching open paren when a >, ), } or ] is inserted"
- (interactive)
- (let ((oldpos (point)))
- (self-insert-command 1)
- ;; Refontify buffer if a block-comment-ender '%}' is inserted
- (if (and (eq (char-before (point)) ?})
- (eq (char-before (- (point) 1)) ?%))
- (font-lock-fontify-buffer)
- ;; Match paren if the cursor is not inside string or comment.
- (if (and blink-matching-paren
- (not (LilyPond-inside-string-or-comment-p))
- (save-excursion (re-search-backward
- (concat (mapconcat 'cdr (mapcar 'cdr LilyPond-parens-regexp-alist) "\\|") "\\|)") nil t)
- (eq oldpos (1- (match-end 0)))))
- (progn (backward-char 1)
- (LilyPond-blink-matching-paren)
- (forward-char 1))))))
-
-(defun LilyPond-scan-sexps (pos dir)
- "This function is redefined to be used in Emacs' show-paren-function and
-in XEmacs' paren-highlight."
- (LilyPond-blink-matching-paren dir))
+++ /dev/null
-;;; lilypond-init.el --- Startup code for LilyPond mode
-;;
-;; Instructions, extracted from Documentation/topdocs/INSTALL.texi:
-
-;; Emacs mode for entering music and running LilyPond is contained in
-;; the source archive as `lilypond-mode.el', `lilypond-indent.el',
-;; `lilypond-font-lock.el' and `lilypond.words.el'. You should install
-;; these files to a directory included in your `load-path'.
-;; File `lilypond-init.el' should be placed to `load-path/site-start.d/'
-;; or appended to your `~/.emacs' or `~/.emacs.el'.
-
-;; As a user, you may want add your source path or, e.g., `~/site-lisp/' to
-;; your `load-path'. Append the following line (modified) to your `~/.emacs':
-
-;(setq load-path (append (list (expand-file-name "~/site-lisp")) load-path))
-
-(autoload 'LilyPond-mode "lilypond-mode" "LilyPond Editing Mode" t)
-(add-to-list 'auto-mode-alist '("\\.ly$" . LilyPond-mode))
-(add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
-
+++ /dev/null
-;;;
-;;; lilypond-mode.el --- Major mode for editing GNU LilyPond music scores
-;;;
-;;; source file of the GNU LilyPond music typesetter
-;;;
-;;; (c) 1999--2003 Jan Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; Changed 2001--2003 Heikki Junes <heikki.junes@hut.fi>
-;;; * Add PS-compilation, PS-viewing and MIDI-play (29th Aug 2001)
-;;; * Keyboard shortcuts (12th Sep 2001)
-;;; * Inserting tags, inspired on sgml-mode (11th Oct 2001)
-;;; * Autocompletion & Info (23rd Nov 2002)
-
-;;; Inspired on auctex
-
-;;; Look lilypond-init.el or Documentation/topdocs/INSTALL.texi
-;;; for installing instructions.
-
-(require 'easymenu)
-(require 'compile)
-
-(defconst LilyPond-version "1.9.9"
- "`LilyPond-mode' version number.")
-
-(defconst LilyPond-help-address "bug-lilypond@gnu.org"
- "Address accepting submission of bug reports.")
-
-(defvar LilyPond-mode-hook nil
- "*Hook called by `LilyPond-mode'.")
-
-(defvar LilyPond-region-file-prefix "emacs-lily"
- "File prefix for commands on buffer or region.")
-
-;; FIXME: find ``\score'' in buffers / make settable?
-(defun LilyPond-master-file ()
- ;; duh
- (buffer-file-name))
-
-(defvar LilyPond-kick-xdvi nil
- "If true, no simultaneous xdvi's are started, but reload signal is sent.")
-
-(defvar LilyPond-command-history nil
- "Command history list.")
-
-(defvar LilyPond-regexp-alist
- '(("\\([a-zA-Z]?:?[^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2))
- "Regexp used to match LilyPond errors. See `compilation-error-regexp-alist'.")
-
-(defvar LilyPond-imenu nil
- "A flag to tell whether LilyPond-imenu is turned on.")
-(make-variable-buffer-local 'LilyPond-imenu)
-
-(defcustom LilyPond-include-path ".:/tmp"
- "* LilyPond include path."
- :type 'string
- :group 'LilyPond)
-
-(defun LilyPond-words-filename ()
- "The file containing LilyPond \keywords \Identifiers and ReservedWords.
-Finds file lilypond-words.el from load-path."
- (let ((fn nil)
- (lp load-path)
- (words-file "lilypond.words.el"))
- (while (and (> (length lp) 0) (not fn))
- (setq fn (concat (car lp) "/" words-file))
- (if (not (file-readable-p fn))
- (progn (setq fn nil) (setq lp (cdr lp)))))
- (if (not fn)
- (progn (message "Warning: `lilypond.words.el' not found in `load-path'. See `lilypond-init.el'.")
- (sit-for 5 0)))
- fn))
-
-(defun LilyPond-add-dictionary-word (x)
- "Contains all words: \keywords \Identifiers and ReservedWords."
- (nconc '(("" . 1)) x))
-
-;; creates dictionary if empty
-(if (and (eq (length (LilyPond-add-dictionary-word ())) 1)
- (not (eq (LilyPond-words-filename) nil)))
- (progn
- (setq b (find-file-noselect (LilyPond-words-filename) t t))
- (setq m (set-marker (make-marker) 1 (get-buffer b)))
- (setq i 1)
- (while (> (buffer-size b) (marker-position m))
- (setq i (+ i 1))
- (setq copy (copy-alist (list (eval (symbol-name (read m))))))
- (setcdr copy i)
- (LilyPond-add-dictionary-word (list copy)))
- (kill-buffer b)))
-
-(defvar LilyPond-insert-tag-current ""
- "The last command selected from the LilyPond-Insert -menu.")
-
-(defconst LilyPond-menu-keywords
- (let ((wordlist '())
- (co (all-completions "" (LilyPond-add-dictionary-word ())))
- (currword ""))
- (progn
- (while (> (length co) 0)
- (setq currword (car co))
- (if (string-equal "-" (car (setq co (cdr co))))
- (progn
- (add-to-list 'wordlist currword)
- (while (and (> (length co) 0)
- (not (string-equal "-" (car (setq co (cdr co))))))))))
- (reverse wordlist)))
- "Keywords inserted from LilyPond-Insert-menu.")
-
-(defconst LilyPond-keywords
- (let ((wordlist '("\\score"))
- (co (all-completions "" (LilyPond-add-dictionary-word ())))
- (currword ""))
- (progn
- (while (> (length co) 0)
- (setq currword (car co))
- (if (> (length currword) 1)
- (if (and (string-equal "\\" (substring currword 0 1))
- (string-match "[a-z-]+" currword)
- (= (match-beginning 0) 1)
- (= (match-end 0) (length currword))
- (not (string-equal "\\longa" currword))
- (not (string-equal "\\breve" currword))
- (not (string-equal "\\maxima" currword))
- (string-equal (downcase currword) currword))
- (add-to-list 'wordlist currword)))
- (if (string-equal "-" (car (setq co (cdr co))))
- (while (and (> (length co) 0)
- (not (string-equal "-" (car (setq co (cdr co)))))))))
- (reverse wordlist)))
- "LilyPond \\keywords")
-
-(defconst LilyPond-identifiers
- (let ((wordlist '("\\voiceOne"))
- (co (all-completions "" (LilyPond-add-dictionary-word ()))))
- (progn
- (while (> (length co) 0)
- (setq currword (car co))
- (if (> (length currword) 1)
- (if (and (string-equal "\\" (substring currword 0 1))
- (string-match "[a-zA-Z-]+" currword)
- (= (match-beginning 0) 1)
- (= (match-end 0) (length currword))
- (not (string-equal (downcase currword) currword)))
- (add-to-list 'wordlist currword)))
- (if (string-equal "-" (car (setq co (cdr co))))
- (while (and (> (length co) 0)
- (not (string-equal "-" (car (setq co (cdr co)))))))))
- (reverse wordlist)))
- "LilyPond \\Identifiers")
-
-(defconst LilyPond-Capitalized-Reserved-Words
- (let ((wordlist '("StaffContext"))
- (co (all-completions "" (LilyPond-add-dictionary-word ()))))
- (progn
- (while (> (length co) 0)
- (setq currword (car co))
- (if (> (length currword) 0)
- (if (and (string-match "[a-zA-Z_]+" currword)
- (= (match-beginning 0) 0)
- (= (match-end 0) (length currword))
- (not (string-equal (downcase currword) currword)))
- (add-to-list 'wordlist currword)))
- (if (string-equal "-" (car (setq co (cdr co))))
- (while (and (> (length co) 0)
- (not (string-equal "-" (car (setq co (cdr co)))))))))
- (reverse wordlist)))
- "LilyPond ReservedWords")
-
-(defconst LilyPond-non-capitalized-reserved-words
- (let ((wordlist '("cessess"))
- (co (all-completions "" (LilyPond-add-dictionary-word ()))))
- (progn
- (while (> (length co) 0)
- (setq currword (car co))
- (if (> (length currword) 0)
- (if (and (string-match "[a-z]+" currword)
- (= (match-beginning 0) 0)
- (= (match-end 0) (length currword))
- (string-equal (downcase currword) currword))
- (add-to-list 'wordlist currword)))
- (if (string-equal "-" (car (setq co (cdr co))))
- (while (and (> (length co) 0)
- (not (string-equal "-" (car (setq co (cdr co)))))))))
- (reverse wordlist)))
- "LilyPond notenames")
-
-(defun LilyPond-check-files (derived originals extensions)
- "Check that DERIVED is newer than any of the ORIGINALS.
-Try each original with each member of EXTENSIONS, in all directories
-in LilyPond-include-path."
- (let ((found nil)
- (regexp (concat "\\`\\("
- (mapconcat (function (lambda (dir)
- (regexp-quote (expand-file-name dir))))
- LilyPond-include-path "\\|")
- "\\).*\\("
- (mapconcat 'regexp-quote originals "\\|")
- "\\)\\.\\("
- (mapconcat 'regexp-quote extensions "\\|")
- "\\)\\'"))
- (buffers (buffer-list)))
- (while buffers
- (let* ((buffer (car buffers))
- (name (buffer-file-name buffer)))
- (setq buffers (cdr buffers))
- (if (and name (string-match regexp name))
- (progn
- (and (buffer-modified-p buffer)
- (or (not LilyPond-save-query)
- (y-or-n-p (concat "Save file "
- (buffer-file-name buffer)
- "? ")))
- (save-excursion (set-buffer buffer) (save-buffer)))
- (if (file-newer-than-file-p name derived)
- (setq found t))))))
- found))
-
-(defun LilyPond-running ()
- "Check the currently running LilyPond compiling jobs."
- (let ((process-names (list "lilypond" "tex" "2dvi" "2ps" "2midi"
- "book" "latex"))
- (running nil))
- (while (setq process-name (pop process-names))
- (setq process (get-process process-name))
- (if (and process
- (eq (process-status process) 'run))
- (push process-name running)))
- running)) ; return the running jobs
-
-(defun LilyPond-midi-running ()
- "Check the currently running Midi processes."
- (let ((process-names (list "midi" "midiall"))
- (running nil))
- (while (setq process-name (pop process-names))
- (setq process (get-process process-name))
- (if (and process
- (eq (process-status process) 'run))
- (push process-name running)))
- running)) ; return the running jobs
-
-(defun LilyPond-kill-jobs ()
- "Kill the currently running LilyPond compiling jobs."
- (interactive)
- (let ((process-names (LilyPond-running))
- (killed nil))
- (while (setq process-name (pop process-names))
- (quit-process (get-process process-name) t)
- (push process-name killed))
- killed)) ; return the killed jobs
-
-(defun LilyPond-kill-midi ()
- "Kill the currently running midi processes."
- (let ((process-names (LilyPond-midi-running))
- (killed nil))
- (while (setq process-name (pop process-names))
- (quit-process (get-process process-name) t)
- (push process-name killed))
- killed)) ; return the killed jobs
-
-;; URG, should only run LilyPond-compile for LilyPond
-;; not for tex,xdvi (ly2dvi?)
-(defun LilyPond-compile-file (command name)
- ;; We maybe should know what we run here (Lily, ly2dvi, tex)
- ;; and adjust our error-matching regex ?
- (compile-internal
- (if (eq LilyPond-command-current 'LilyPond-command-master)
- command
- ;; use temporary directory for Commands on Buffer/Region
- ;; hm.. the directory is set twice, first to default-dir
- (concat "cd " (LilyPond-temp-directory) "; " command))
- "No more errors" name))
-
-;; do we still need this, now that we're using compile-internal?
-(defun LilyPond-save-buffer ()
- "Save buffer and set default command for compiling."
- (interactive)
- (if (buffer-modified-p)
- (progn (save-buffer)
- (setq LilyPond-command-default "LilyPond"))))
-
-;;; return (dir base ext)
-(defun split-file-name (name)
- (let* ((i (string-match "[^/]*$" name))
- (dir (if (> i 0) (substring name 0 i) "./"))
- (file (substring name i (length name)))
- (i (string-match "[^.]*$" file)))
- (if (and
- (> i 0)
- (< i (length file)))
- (list dir (substring file 0 (- i 1)) (substring file i (length file)))
- (list dir file ""))))
-
-
-;; Should check whether in command-alist?
-(defcustom LilyPond-command-default "LilyPond"
- "Default command. Must identify a member of LilyPond-command-alist."
-
- :group 'LilyPond
- :type 'string)
-;;;(make-variable-buffer-local 'LilyPond-command-last)
-
-(defvar LilyPond-command-current 'LilyPond-command-master)
-;;;(make-variable-buffer-local 'LilyPond-command-master)
-
-
-;; If non-nil, LilyPond-command-query will return the value of this
-;; variable instead of quering the user.
-(defvar LilyPond-command-force nil)
-
-(defcustom LilyPond-xdvi-command "xdvi"
- "Command used to display DVI files."
-
- :group 'LilyPond
- :type 'string)
-
-(defcustom LilyPond-gv-command "gv -watch"
- "Command used to display PS files."
-
- :group 'LilyPond
- :type 'string)
-
-(defcustom LilyPond-midi-command "timidity"
- "Command used to play MIDI files."
-
- :group 'LilyPond
- :type 'string)
-
-(defcustom LilyPond-all-midi-command "timidity -ia"
- "Command used to play MIDI files."
-
- :group 'LilyPond
- :type 'string)
-
-(defun LilyPond-command-current-midi ()
- "Play midi corresponding to the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "Midi") 'LilyPond-master-file))
-
-(defun LilyPond-command-all-midi ()
- "Play midi corresponding to the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "MidiAll") 'LilyPond-master-file))
-
-(defun count-rexp (start end rexp)
- "Print number of found regular expressions in the region."
- (interactive "r")
- (save-excursion
- (save-restriction
- (narrow-to-region start end)
- (goto-char (point-min))
- (count-matches rexp))))
-
-(defun count-midi-words ()
- "Check number of midi-scores before the curser."
- (if (eq LilyPond-command-current 'LilyPond-command-region)
- (count-rexp (mark t) (point) "\\\\midi")
- (count-rexp (point-min) (point-max) "\\\\midi")))
-
-(defun count-midi-words-backwards ()
- "Check number of midi-scores before the curser."
- (if (eq LilyPond-command-current 'LilyPond-command-region)
- (count-rexp (mark t) (point) "\\\\midi")
- (count-rexp (point-min) (point) "\\\\midi")))
-
-(defun LilyPond-string-current-midi ()
- "Check the midi file of the following midi-score in the current document."
- (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
- (substring (LilyPond-master-file) 0 -3); suppose ".ly"
- LilyPond-region-file-prefix))
- (allcount (string-to-number (substring (count-midi-words) 0 -12)))
- (count (string-to-number (substring (count-midi-words-backwards) 0 -12))))
- (concat fnameprefix
- (if (and (> allcount 1) (> count 0)) ; not first score
- (if (eq count allcount) ; last score
- (concat "-" (number-to-string (+ count -1)))
- (concat "-" (number-to-string count))))
- ".midi")))
-
-(defun LilyPond-string-all-midi ()
- "Return the midi files of the current document in ascending order."
- (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
- (substring (LilyPond-master-file) 0 -3); suppose ".ly"
- LilyPond-region-file-prefix))
- (allcount (string-to-number (substring (count-midi-words) 0 -12))))
- (concat (if (> allcount 0) ; at least one midi-score
- (concat fnameprefix ".midi "))
- (if (> allcount 1) ; more than one midi-score
- (concat fnameprefix "-[1-9].midi "))
- (if (> allcount 9) ; etc.
- (concat fnameprefix "-[1-9][0-9].midi"))
- (if (> allcount 99) ; not first score
- (concat fnameprefix "-[1-9][0-9][0-9].midi")))))
-
-;; This is the major configuration variable.
-(defcustom LilyPond-command-alist
- ;; Should expand this to include possible keyboard shortcuts which
- ;; could then be mapped to define-key and menu.
- `(
- ("Raw LilyPond" . ("lilypond-bin %s" . "LaTeX"))
- ("TeX" . ("tex '\\nonstopmode\\input %t'" . "View"))
-
- ("2Dvi" . ("lilypond %s" . "View"))
- ("2PS" . ("lilypond -P %s" . "ViewPS"))
- ("2Midi" . ("lilypond -m %s" . "View"))
-
- ("Book" . ("lilypond-book %x" . "LaTeX"))
- ("LaTeX" . ("latex '\\nonstopmode\\input %l'" . "View"))
-
- ;; point-n-click (arg: exits upop USR1)
- ("SmartView" . ("xdvi %d" . "LilyPond"))
-
- ;; refreshes when kicked USR1
- ("View" . (,(concat LilyPond-xdvi-command " %d") . "LilyPond"))
- ("ViewPS" . (,(concat LilyPond-gv-command " %p") . "LilyPond"))
-
- ;; The following are refreshed in LilyPond-command:
- ;; - current-midi depends on cursor position and
- ("Midi" . (,(concat LilyPond-midi-command " " (LilyPond-string-current-midi)) . "LilyPond" )) ;
- ;; - all-midi depends on number of midi-score.
- ("MidiAll" . (,(concat LilyPond-all-midi-command " " (LilyPond-string-all-midi)) . "LilyPond"))
- )
-
- "AList of commands to execute on the current document.
-
-The key is the name of the command as it will be presented to the
-user, the value is a cons of the command string handed to the shell
-after being expanded, and the next command to be executed upon
-success. The expansion is done using the information found in
-LilyPond-expand-list.
-"
- :group 'LilyPond
- :type '(repeat (cons :tag "Command Item"
- (string :tag "Key")
- (cons :tag "How"
- (string :tag "Command")
- (string :tag "Next Key")))))
-
-;; drop this?
-(defcustom LilyPond-file-extension ".ly"
- "*File extension used in LilyPond sources."
- :group 'LilyPond
- :type 'string)
-
-
-(defcustom LilyPond-expand-alist
- '(
- ("%s" . ".ly")
- ("%t" . ".tex")
- ("%d" . ".dvi")
- ("%p" . ".ps")
- ("%l" . ".tex")
- ("%x" . ".tely")
- ("%m" . ".midi")
- )
-
- "Alist of expansion strings for LilyPond command names."
- :group 'LilyPond
- :type '(repeat (cons :tag "Alist item"
- (string :tag "Symbol")
- (string :tag "Expansion"))))
-
-
-(defcustom LilyPond-command-Show "View"
- "*The default command to show (view or print) a LilyPond file.
-Must be the car of an entry in `LilyPond-command-alist'."
- :group 'LilyPond
- :type 'string)
- (make-variable-buffer-local 'LilyPond-command-Show)
-
-(defcustom LilyPond-command-Print "Print"
- "The name of the Print entry in LilyPond-command-Print."
- :group 'LilyPond
- :type 'string)
-
-(defun xLilyPond-compile-sentinel (process msg)
- (if (and process
- (= 0 (process-exit-status process)))
- (setq LilyPond-command-default
- (cddr (assoc LilyPond-command-default LilyPond-command-alist)))))
-
-;; FIXME: shouldn't do this for stray View/xdvi
-(defun LilyPond-compile-sentinel (buffer msg)
- (if (string-match "^finished" msg)
- (setq LilyPond-command-default
- (cddr (assoc LilyPond-command-default LilyPond-command-alist)))))
-
-;;(make-variable-buffer-local 'compilation-finish-function)
-(setq compilation-finish-function 'LilyPond-compile-sentinel)
-
-(defun LilyPond-command-query (name)
- "Query the user for what LilyPond command to use."
- (let* ((default (cond ((if (string-equal name LilyPond-region-file-prefix)
- (LilyPond-check-files (concat name ".tex")
- (list name)
- (list LilyPond-file-extension))
- (if (verify-visited-file-modtime (current-buffer))
- (if (buffer-modified-p)
- (if (y-or-n-p "Save buffer before next command? ")
- (LilyPond-save-buffer)))
- (if (y-or-n-p "The command will be invoked to an already saved buffer. Revert it? ")
- (revert-buffer t t)))
- ;;"LilyPond"
- LilyPond-command-default))
- (t LilyPond-command-default)))
-
- (completion-ignore-case t)
-
- (answer (or LilyPond-command-force
- (completing-read
- (concat "Command: (default " default ") ")
- LilyPond-command-alist nil t nil 'LilyPond-command-history))))
-
- ;; If the answer is "LilyPond" it will not be expanded to "LilyPond"
- (let ((answer (car-safe (assoc answer LilyPond-command-alist))))
- (if (and answer
- (not (string-equal answer "")))
- answer
- default))))
-
-(defun LilyPond-command-master ()
- "Run command on the current document."
- (interactive)
- (LilyPond-command-select-master)
- (LilyPond-command (LilyPond-command-query (LilyPond-master-file))
- 'LilyPond-master-file))
-
-(defun LilyPond-command-lilypond ()
- "Run lilypond for the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-formatdvi ()
- "Format the dvi output of the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "2Dvi") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-formatps ()
- "Format the ps output of the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "2PS") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-formatmidi ()
- "Format the midi output of the current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "2Midi") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-smartview ()
- "View the dvi output of current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "SmartView") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-view ()
- "View the dvi output of current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "View") 'LilyPond-master-file)
-)
-
-(defun LilyPond-command-viewps ()
- "View the ps output of current document."
- (interactive)
- (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file)
-)
-
-;; FIXME, this is broken
-(defun LilyPond-region-file (begin end)
- (let (
- ;; (dir "./")
- (dir (LilyPond-temp-directory))
- (base LilyPond-region-file-prefix)
- (ext LilyPond-file-extension))
- (concat dir base ext)))
-
-;;; Commands on Region work if there is an appropriate '\score'.
-(defun LilyPond-command-region (begin end)
- "Run LilyPond on the current region."
- (interactive "r")
- (if (or (> begin (point-min)) (< end (point-max)))
- (LilyPond-command-select-region))
- (write-region begin end (LilyPond-region-file begin end) nil 'nomsg)
- (LilyPond-command (LilyPond-command-query
- (LilyPond-region-file begin end))
- '(lambda () (LilyPond-region-file begin end)))
- ;; Region may deactivate even if buffer was intact, reactivate?
- ;; Currently, also deactived regions are used.
- )
-
-(defun LilyPond-command-buffer ()
- "Run LilyPond on buffer."
- (interactive)
- (LilyPond-command-select-buffer)
- (LilyPond-command-region (point-min) (point-max)))
-
-(defun LilyPond-command-expand (string file)
- (let ((case-fold-search nil))
- (if (string-match "%" string)
- (let* ((b (match-beginning 0))
- (e (+ b 2))
- (l (split-file-name file))
- (dir (car l))
- (base (cadr l)))
- (LilyPond-command-expand
- (concat (substring string 0 b)
- dir
- base
- (let ((entry (assoc (substring string b e)
- LilyPond-expand-alist)))
- (if entry (cdr entry) ""))
- (substring string e))
- file))
- string)))
-
-(defun LilyPond-shell-process (name buffer command)
- (let ((old (current-buffer)))
- (switch-to-buffer-other-window buffer)
- ;; If we empty the buffer don't see messages scroll by.
- ;; (erase-buffer)
-
- (start-process-shell-command name buffer command)
- (switch-to-buffer-other-window old)))
-
-
-(defun LilyPond-command (name file)
- "Run command NAME on the file you get by calling FILE.
-
-FILE is a function return a file name. It has one optional argument,
-the extension to use on the file.
-
-Use the information in LilyPond-command-alist to determine how to run the
-command."
-
- (let ((entry (assoc name LilyPond-command-alist)))
- (if entry
- (let ((command (LilyPond-command-expand (cadr entry)
- (apply file nil)))
- (jobs nil)
- (job-string "no jobs"))
- (if (member name (list "View" "ViewPS"))
- ;; is USR1 a right signal for viewps?
- (let ((buffer-xdvi (get-buffer-create (concat "*" name "*"))))
- (if LilyPond-kick-xdvi
- (let ((process-xdvi (get-buffer-process buffer-xdvi)))
- (if process-xdvi
- (signal-process (process-id process-xdvi) 'SIGUSR1)
- (LilyPond-shell-process name buffer-xdvi command)))
- (LilyPond-shell-process name buffer-xdvi command)))
- (progn
- (if (string-equal name "Midi")
- (progn
- (setq command (concat LilyPond-midi-command " " (LilyPond-string-current-midi)))
- (if (LilyPond-kill-midi)
- (setq job-string nil)))) ; either stop or start playing
- (if (string-equal name "MidiAll")
- (progn
- (setq command (concat LilyPond-all-midi-command " " (LilyPond-string-all-midi)))
- (LilyPond-kill-midi))) ; stop and start playing
- (if (and (member name (list "Midi" "MidiAll")) job-string)
- (if (file-newer-than-file-p
- (LilyPond-master-file)
- (concat (substring (LilyPond-master-file) 0 -3) ".midi"))
- (if (y-or-n-p "Midi older than source. Reformat midi?")
- (progn
- (LilyPond-command-formatmidi)
- (while (LilyPond-running)
- (message "Starts playing midi once it is built.")
- (sit-for 0 100))))))
- (if (member name (list "LilyPond" "TeX" "2Midi" "2PS" "2Dvi"
- "Book" "LaTeX"))
- (if (setq jobs (LilyPond-running))
- (progn
- (setq job-string "Process") ; could also suggest compiling after process has ended
- (while jobs
- (setq job-string (concat job-string " \"" (pop jobs) "\"")))
- (setq job-string (concat job-string " is already running; kill it to proceed "))
- (if (y-or-n-p job-string)
- (progn
- (setq job-string "no jobs")
- (LilyPond-kill-jobs)
- (while (LilyPond-running)
- (sit-for 0 100)))
- (setq job-string nil)))))
-
- (setq LilyPond-command-default name)
- (if (string-equal job-string "no jobs")
- (LilyPond-compile-file command name))))))))
-
-(defun LilyPond-mark-active ()
- "Check if there is an active mark."
- (and transient-mark-mode
- (if (string-match "XEmacs\\|Lucid" emacs-version) (mark) mark-active)))
-
-(defun LilyPond-temp-directory ()
- "Temporary file directory for Commands on Region."
- (interactive)
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- (concat (temp-directory) "/")
- temporary-file-directory))
-
-;;; Keymap
-
-(defvar LilyPond-mode-map ()
- "Keymap used in `LilyPond-mode' buffers.")
-
-;; Note: if you make changes to the map, you must do
-;; M-x set-variable LilyPond-mode-map nil
-;; M-x eval-buffer
-;; M-x LilyPond-mode
-;; to let the changest take effect
-
-(if LilyPond-mode-map
- ()
- (setq LilyPond-mode-map (make-sparse-keymap))
- ;; Put keys to LilyPond-command-alist and fetch them from there somehow.
- (define-key LilyPond-mode-map "\C-c\C-l" 'LilyPond-command-lilypond)
- (define-key LilyPond-mode-map "\C-c\C-r" 'LilyPond-command-region)
- (define-key LilyPond-mode-map "\C-c\C-b" 'LilyPond-command-buffer)
- (define-key LilyPond-mode-map "\C-c\C-k" 'LilyPond-kill-jobs)
- (define-key LilyPond-mode-map "\C-c\C-c" 'LilyPond-command-master)
- (define-key LilyPond-mode-map "\C-cm" 'LilyPond-command-formatmidi)
- (define-key LilyPond-mode-map "\C-c\C-d" 'LilyPond-command-formatdvi)
- (define-key LilyPond-mode-map "\C-c\C-f" 'LilyPond-command-formatps)
- (define-key LilyPond-mode-map "\C-c\C-s" 'LilyPond-command-smartview)
- (define-key LilyPond-mode-map "\C-c\C-v" 'LilyPond-command-view)
- (define-key LilyPond-mode-map "\C-c\C-p" 'LilyPond-command-viewps)
- (define-key LilyPond-mode-map [(control c) return] 'LilyPond-command-current-midi)
- (define-key LilyPond-mode-map [(control c) (control return)] 'LilyPond-command-all-midi)
- (define-key LilyPond-mode-map "\C-x\C-s" 'LilyPond-save-buffer)
- (define-key LilyPond-mode-map "\C-cf" 'font-lock-fontify-buffer)
- (define-key LilyPond-mode-map "\C-ci" 'LilyPond-insert-tag-current)
- ;; the following will should be overriden by Lilypond Quick Insert Mode
- (define-key LilyPond-mode-map "\C-cq" 'LilyPond-quick-insert-mode)
- (define-key LilyPond-mode-map "\C-c;" 'LilyPond-comment-region)
- (define-key LilyPond-mode-map ")" 'LilyPond-electric-close-paren)
- (define-key LilyPond-mode-map ">" 'LilyPond-electric-close-paren)
- (define-key LilyPond-mode-map "}" 'LilyPond-electric-close-paren)
- (define-key LilyPond-mode-map "]" 'LilyPond-electric-close-paren)
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- (define-key LilyPond-mode-map [iso-left-tab] 'LilyPond-autocompletion)
- (define-key LilyPond-mode-map [iso-lefttab] 'LilyPond-autocompletion))
- (define-key LilyPond-mode-map "\C-c\t" 'LilyPond-info-index-search)
- )
-
-;;; Menu Support
-
-;;; This mode was originally LilyPond-quick-note-insert by Heikki Junes.
-;;; The original version has been junked since CVS-1.97,
-;;; in order to merge the efforts done by Nicolas Sceaux.
-;;; LilyPond Quick Insert Mode is a major mode, toggled by C-c q.
-(defun LilyPond-quick-insert-mode ()
- "Insert notes with fewer key strokes by using a simple keyboard piano."
- (interactive)
- (progn
- (message "Invoke (C-c q) from keyboard. If you still see this message,") (sit-for 5 0)
- (message "then you have not installed LilyPond Quick Insert Mode (lyqi).") (sit-for 5 0)
- (message "Download lyqi from http://nicolas.sceaux.free.fr/lilypond/lyqi.html,") (sit-for 5 0)
- (message "see installation instructions from lyqi's README -file.") (sit-for 5 0)
- (message "You need also eieio (Enhanced Integration of Emacs Interpreted Objects).") (sit-for 5 0)
- (message "Download eieio from http://cedet.sourceforge.net/eieio.shtml,") (sit-for 5 0)
- (message "see installation instructions from eieio's INSTALL -file.") (sit-for 5 0)
- (message "")
- ))
-
-(defun LilyPond-pre-word-search ()
- "Fetch the alphabetic characters and \\ in front of the cursor."
- (let ((pre "")
- (prelen 0)
- (ch (char-before (- (point) 0))))
- (while (and ch (or (and (>= ch 65) (<= ch 90)) ; not bolp, A-Z
- (and (>= ch 97) (<= ch 122)) ; a-z
- (= ch 92))) ; \\
- (setq pre (concat (char-to-string ch) pre))
- (setq prelen (+ prelen 1))
- (setq ch (char-before (- (point) prelen))))
- pre))
-
-(defun LilyPond-post-word-search ()
- "Fetch the alphabetic characters behind the cursor."
- (let ((post "")
- (postlen 0)
- (ch (char-after (+ (point) 0))))
- (while (and ch (or (and (>= ch 65) (<= ch 90)) ; not eolp, A-Z
- (and (>= ch 97) (<= ch 122)))) ; a-z
- (setq post (concat post (char-to-string ch)))
- (setq postlen (+ postlen 1))
- (setq ch (char-after (+ (point) postlen))))
- post))
-
-(defun LilyPond-autocompletion ()
- "Show completions in mini-buffer for the given word."
- (interactive)
- (let ((pre (LilyPond-pre-word-search))
- (post (LilyPond-post-word-search))
- (compsstr ""))
- ;; insert try-completion and show all-completions
- (if (> (length pre) 0)
- (progn
- (setq trycomp (try-completion pre (LilyPond-add-dictionary-word ())))
- (if (char-or-string-p trycomp)
- (if (string-equal (concat pre post) trycomp)
- (goto-char (+ (point) (length post)))
- (progn
- (delete-region (point) (+ (point) (length post)))
- (insert (substring trycomp (length pre) nil))))
- (progn
- (delete-region (point) (+ (point) (length post)))
- (font-lock-fontify-buffer))) ; only inserting fontifies
-
- (setq complist (all-completions pre (LilyPond-add-dictionary-word ())))
- (while (> (length complist) 0)
- (setq compsstr (concat compsstr "\"" (car complist) "\" "))
- (setq complist (cdr complist)))
- (message compsstr)
- (sit-for 0 100)))))
-
-(defun LilyPond-info ()
- "Launch Info for lilypond."
- (interactive)
- (info "lilypond"))
-
-(defun LilyPond-music-glossary-info ()
- "Launch Info for music-glossary."
- (interactive)
- (info "music-glossary"))
-
-(defun LilyPond-internals-info ()
- "Launch Info for lilypond-internals."
- (interactive)
- (info "lilypond-internals"))
-
-(defun LilyPond-info-index-search ()
- "In `*info*'-buffer, launch `info lilypond --index-search word-under-cursor'"
- (interactive)
- (let ((str (concat (LilyPond-pre-word-search) (LilyPond-post-word-search))))
- (if (and (> (length str) 0)
- (string-equal (substring str 0 1) "\\"))
- (setq str (substring str 1 nil)))
- (LilyPond-info)
- (Info-index str)))
-
-(defun LilyPond-insert-tag-current (&optional word)
- "Set the current tag to be inserted."
- (interactive)
- (if word
- (setq LilyPond-insert-tag-current word))
- (if (memq LilyPond-insert-tag-current LilyPond-menu-keywords)
- (LilyPond-insert-tag)
- (message "No tag was selected from LilyPond->Insert tag-menu.")))
-
-(defun LilyPond-insert-tag ()
- "Insert syntax for given tag. The definitions are in LilyPond-words-filename."
- (interactive)
- (setq b (find-file-noselect (LilyPond-words-filename) t t))
- (let ((word LilyPond-insert-tag-current)
- (found nil)
- (p nil)
- (query nil)
- (m (set-marker (make-marker) 1 (get-buffer b)))
- (distance (if (LilyPond-mark-active)
- (abs (- (mark-marker) (point-marker))) 0))
- )
- ;; find the place first
- (if (LilyPond-mark-active)
- (goto-char (min (mark-marker) (point-marker))))
- (while (and (not found) (> (buffer-size b) (marker-position m)))
- (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
- (if (string-equal word copy) (setq found t)))
- (if found (insert word))
- (if (> (buffer-size b) (marker-position m))
- (setq copy (car (copy-alist (list (eval (symbol-name (read m))))))))
- (if (not (string-equal "-" copy))
- (setq found nil))
- (while (and found (> (buffer-size b) (marker-position m)))
- ;; find next symbol
- (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
- ;; check whether it is the word, or the word has been found
- (cond
- ((string-equal "-" copy) (setq found nil))
- ((string-equal "%" copy) (insert " " (read-string "Give Arguments: ")))
- ((string-equal "_" copy)
- (progn
- (setq p (point))
- (goto-char (+ p distance))))
- ((string-equal "\?" copy) (setq query t))
- ((string-equal "\!" copy) (setq query nil))
- ((string-equal "\\n" copy)
- (if (not query)
- (progn (LilyPond-indent-line) (insert "\n") (LilyPond-indent-line))))
- ((string-equal "{" copy)
- (if (not query)
- (progn (insert " { "))))
- ((string-equal "}" copy)
- (if (not query)
- (progn (insert " } ") (setq query nil) )))
- ((not query)
- (insert copy))
- (query
- (if (y-or-n-p (concat "Proceed with `" copy "'? "))
- (progn (insert copy) (setq query nil))))
- ))
- (if p (goto-char p))
- (kill-buffer b))
-)
-
-(defun LilyPond-command-menu-entry (entry)
- ;; Return LilyPond-command-alist ENTRY as a menu item.
- (let ((name (car entry)))
- (cond ((and (string-equal name LilyPond-command-Print)
- LilyPond-printer-list)
- (let ((command LilyPond-print-command)
- (lookup 1))
- (append (list LilyPond-command-Print)
- (mapcar 'LilyPond-command-menu-printer-entry
- LilyPond-printer-list))))
- (t
- (vector name (list 'LilyPond-command-menu name) t)))))
-
-
-(easy-menu-define LilyPond-command-menu
- LilyPond-mode-map
- "Menu used in LilyPond mode."
- (append '("Command")
- '(("Command on"
- [ "Master File" LilyPond-command-select-master
- :keys "C-c C-c" :style radio
- :selected (eq LilyPond-command-current 'LilyPond-command-master) ]
- [ "Buffer" LilyPond-command-select-buffer
- :keys "C-c C-b" :style radio
- :selected (eq LilyPond-command-current 'LilyPond-command-buffer) ]
- [ "Region" LilyPond-command-select-region
- :keys "C-c C-r" :style radio
- :selected (eq LilyPond-command-current 'LilyPond-command-region) ]))
-;;; (let ((file 'LilyPond-command-on-current))
-;;; (mapcar 'LilyPond-command-menu-entry LilyPond-command-alist))
-;;; Some kind of mapping which includes :keys might be more elegant
-;;; Put keys to LilyPond-command-alist and fetch them from there somehow.
- '([ "LilyPond" LilyPond-command-lilypond t])
- '([ "TeX" (LilyPond-command (LilyPond-command-menu "TeX") 'LilyPond-master-file) ])
- '([ "2Dvi" LilyPond-command-formatdvi t])
- '([ "2PS" LilyPond-command-formatps t])
- '([ "2Midi" LilyPond-command-formatmidi t])
- '([ "Book" (LilyPond-command (LilyPond-command-menu "Book") 'LilyPond-master-file) ])
- '([ "LaTeX" (LilyPond-command (LilyPond-command-menu "LaTeX") 'LilyPond-master-file) ])
- '([ "Kill jobs" LilyPond-kill-jobs t])
- '("-----")
- '([ "SmartView" LilyPond-command-smartview t])
- '([ "View" LilyPond-command-view t])
- '([ "ViewPS" LilyPond-command-viewps t])
- '("-----")
- '([ "Midi (toggle)" LilyPond-command-current-midi t])
- '([ "Midi all" LilyPond-command-all-midi t])
- ))
-
-(defun LilyPond-menu-keywords-item (arg)
- "Make vector for LilyPond-mode-keywords."
- (vector arg (list 'LilyPond-insert-tag-current arg) :style 'radio :selected (list 'eq 'LilyPond-insert-tag-current arg)))
-
-(defun LilyPond-menu-keywords ()
- "Make Insert Tag menu.
-
-The Insert Tag -menu is splitted into parts if it is long enough."
-
- (let ((li (mapcar 'LilyPond-menu-keywords-item LilyPond-menu-keywords))
- (w (round (sqrt (length LilyPond-menu-keywords))))
- (splitted '())
- (imin 0) imax lw rw)
- (while (< imin (length LilyPond-menu-keywords))
- (setq imax (- (min (+ imin w) (length LilyPond-menu-keywords)) 1))
- (setq lw (nth imin LilyPond-menu-keywords))
- (setq rw (nth imax LilyPond-menu-keywords))
- (add-to-list 'splitted
- (let ((l (list (concat (substring lw 0 (min 7 (length lw)))
- " ... "
- (substring rw 0 (min 7 (length rw)))))))
- (while (<= imin imax)
- (add-to-list 'l (nth imin li))
- (setq imin (1+ imin)))
- (reverse l))))
- (if (> (length LilyPond-menu-keywords) 12) (reverse splitted) li)))
-
-;;; LilyPond-mode-menu should not be interactive, via "M-x LilyPond-<Tab>"
-(easy-menu-define LilyPond-mode-menu
- LilyPond-mode-map
- "Menu used in LilyPond mode."
- (append '("LilyPond")
- '(["Add index menu" LilyPond-add-imenu-menu])
- (list (cons "Insert tag"
- (cons ["Previously selected" LilyPond-insert-tag-current t]
- (cons "-----"
- (LilyPond-menu-keywords)))))
- '(("Miscellaneous"
- ["Autocompletion" LilyPond-autocompletion t]
- ["(Un)comment Region" LilyPond-comment-region t]
- ["Refontify buffer" font-lock-fontify-buffer t]
- "-----"
- ["Quick Insert Mode" LilyPond-quick-insert-mode :keys "C-c q"]
- ))
- '(("Info"
- ["LilyPond" LilyPond-info t]
- ["LilyPond index-search" LilyPond-info-index-search t]
- ["Music Glossary" LilyPond-music-glossary-info t]
- ["LilyPond internals" LilyPond-internals-info t]
- ))
- ))
-
-(defconst LilyPond-imenu-generic-re "^\\([a-zA-Z]+\\) *="
- "Regexp matching Identifier definitions.")
-
-(defvar LilyPond-imenu-generic-expression
- (list (list nil LilyPond-imenu-generic-re 1))
- "Expression for imenu")
-
-(defun LilyPond-command-select-master ()
- (interactive)
- (message "Next command will be on the master file")
- (setq LilyPond-command-current 'LilyPond-command-master))
-
-(defun LilyPond-command-select-buffer ()
- (interactive)
- (message "Next command will be on the buffer")
- (setq LilyPond-command-current 'LilyPond-command-buffer))
-
-(defun LilyPond-command-select-region ()
- (interactive)
- (message "Next command will be on the region")
- (setq LilyPond-command-current 'LilyPond-command-region))
-
-(defun LilyPond-command-menu (name)
- ;; Execute LilyPond-command-alist NAME from a menu.
- (let ((LilyPond-command-force name))
- (if (eq LilyPond-command-current 'LilyPond-command-region)
- (if (eq (mark t) nil)
- (progn (message "The mark is not set now") (sit-for 0 500))
- (progn (if (not (not (LilyPond-mark-active)))
- (progn (message "Region is not active, using region between inactive mark and current point.") (sit-for 0 500)))
- (LilyPond-command-region (mark t) (point))))
- (funcall LilyPond-command-current))))
-
-(defun LilyPond-add-imenu-menu ()
- (interactive)
- "Add an imenu menu to the menubar."
- (if (not LilyPond-imenu)
- (progn
- (imenu-add-to-menubar "Index")
- (redraw-frame (selected-frame))
- (setq LilyPond-imenu t))
- (message "%s" "LilyPond-imenu already exists.")))
-(put 'LilyPond-add-imenu-menu 'menu-enable '(not LilyPond-imenu))
-
-(defun LilyPond-mode ()
- "Major mode for editing LilyPond music files.
-
-This mode knows about LilyPond keywords and line comments, not about
-indentation or block comments. It features easy compilation, error
-finding and viewing of a LilyPond source buffer or region.
-
-COMMANDS
-\\{LilyPond-mode-map}
-VARIABLES
-
-LilyPond-command-alist\t\talist from name to command
-LilyPond-xdvi-command\t\tcommand to display dvi files -- bit superfluous"
- (interactive)
- ;; set up local variables
- (kill-all-local-variables)
-
- (make-local-variable 'font-lock-defaults)
- (setq font-lock-defaults '(LilyPond-font-lock-keywords))
-
- ;; string and comments are fontified explicitly
- (make-local-variable 'font-lock-keywords-only)
- (setq font-lock-keywords-only t)
-
- ;; Multi-line font-locking needs Emacs 21.1 or newer.
- ;; For older versions there is hotkey "C-c f".
- (make-local-variable 'font-lock-multiline)
- (setq font-lock-multiline t)
-
- (make-local-variable 'paragraph-separate)
- (setq paragraph-separate "^[ \t]*$")
-
- (make-local-variable 'paragraph-start)
- (setq paragraph-start "^[ \t]*$")
-
- (make-local-variable 'comment-start)
- (setq comment-start "%")
-
- (make-local-variable 'comment-start-skip)
- (setq comment-start-skip "%{? *")
-
- (make-local-variable 'comment-end)
- (setq comment-end "")
-
- (make-local-variable 'block-comment-start)
- (setq block-comment-start "%{")
-
- (make-local-variable 'block-comment-end)
- (setq block-comment-end "%}")
-
- (make-local-variable 'indent-line-function)
- (setq indent-line-function 'LilyPond-indent-line)
-
- (LilyPond-mode-set-syntax-table '(?\< ?\> ?\{ ?\}))
- (setq major-mode 'LilyPond-mode)
- (setq mode-name "LilyPond")
- (setq local-abbrev-table LilyPond-mode-abbrev-table)
- (use-local-map LilyPond-mode-map)
-
- ;; In XEmacs imenu was synched up with: FSF 20.4
- (make-local-variable 'imenu-generic-expression)
- (setq imenu-generic-expression LilyPond-imenu-generic-expression)
- ;; (imenu-add-to-menubar "Index") ; see LilyPond-add-imenu-menu
-
- ;; In XEmacs one needs to use 'easy-menu-add'.
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- (progn
- (easy-menu-add LilyPond-mode-menu)
- (easy-menu-add LilyPond-command-menu)))
-
- ;; Use Command on Region even for inactive mark (region).
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- (setq zmacs-regions nil)
- (setq mark-even-if-inactive t))
-
- ;; Context dependent syntax tables in LilyPond-mode
- (make-local-hook 'post-command-hook) ; XEmacs requires
- (add-hook 'post-command-hook 'LilyPond-mode-context-set-syntax-table nil t)
-
- ;; Turn on paren-mode buffer-locally, i.e., in LilyPond-mode
- (if (string-match "XEmacs\\|Lucid" emacs-version)
- (progn
- (make-local-variable 'paren-mode)
- (paren-set-mode 'paren)
- (make-local-variable 'blink-matching-paren)
- (setq blink-matching-paren t)
- )
- (progn
- (make-local-variable 'blink-matching-paren-on-screen)
- (setq blink-matching-paren-on-screen t)
- ))
-
- ;; run the mode hook. LilyPond-mode-hook use is deprecated
- (run-hooks 'LilyPond-mode-hook))
-
-(defun LilyPond-version ()
- "Echo the current version of `LilyPond-mode' in the minibuffer."
- (interactive)
- (message "Using `LilyPond-mode' version %s" LilyPond-version))
-
-(load-library "lilypond-font-lock")
-(load-library "lilypond-indent")
-
-(provide 'lilypond-mode)
-;;; lilypond-mode.el ends here
-
%endif
mkdir -p $RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp/site-start.d
-install -m 644 lilypond-mode.el lilypond-font-lock.el lilypond-indent.el out/lilypond.words.el $RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp/
-install -m 644 lilypond-init.el $RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp/site-start.d
+install -m 644 elisp/lilypond-init.el $RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp/site-start.d
bzip2 $RPM_BUILD_ROOT%{_mandir}/man1/*
%endif
mkdir -p $RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp/site-start.d
-install -m 644 lilypond-mode.el lilypond-font-lock.el lilypond-indent.el out/lilypond.words.el $RPM_BUILD_ROOT/%{_datadir}/emacs/site-lisp/
-
-install -m 644 lilypond-init.el $RPM_BUILD_ROOT/%{_datadir}/emacs/site-lisp/site-start.d
+install -m 644 elisp/lilypond-init.el $RPM_BUILD_ROOT/%{_datadir}/emacs/site-lisp/site-start.d
gzip -9fn $RPM_BUILD_ROOT%{_mandir}/man1/*
--- /dev/null
+
+EL_FILES := $(wildcard *.el)
+SOURCE_FILES += $(EL_FILES)