lilypond-mode

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

lilypond-mode.el (43229B)


      1 ;;;; lilypond-mode.el -- Major mode for editing GNU LilyPond music scores
      2 ;;;; This file is part of LilyPond, the GNU music typesetter.
      3 ;;;;
      4 ;;;; Copyright (C) 1999--2015 Jan Nieuwenhuizen <janneke@gnu.org>
      5 ;;;; Changed 2001--2003 Heikki Junes <heikki.junes@hut.fi>
      6 ;;;;    * Add PS-compilation, PS-viewing and MIDI-play (29th Aug 2001)
      7 ;;;;    * Keyboard shortcuts (12th Sep 2001)
      8 ;;;;    * Inserting tags, inspired on sgml-mode (11th Oct 2001)
      9 ;;;;    * Autocompletion & Info (23rd Nov 2002)
     10 ;;;;
     11 ;;;; LilyPond is free software: you can redistribute it and/or modify
     12 ;;;; it under the terms of the GNU General Public License as published by
     13 ;;;; the Free Software Foundation, either version 3 of the License, or
     14 ;;;; (at your option) any later version.
     15 ;;;;
     16 ;;;; LilyPond is distributed in the hope that it will be useful,
     17 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19 ;;;; GNU General Public License for more details.
     20 ;;;;
     21 ;;;; You should have received a copy of the GNU General Public License
     22 ;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
     23 
     24 
     25 ;;; Inspired on auctex
     26 
     27 ;;; Look lilypond-init.el or Documentation/topdocs/INSTALL.texi
     28 ;;; for installing instructions.
     29 
     30 (require 'easymenu)
     31 (require 'compile)
     32 
     33 (defconst LilyPond-version "2.5.20"
     34   "`LilyPond-mode' version number.")
     35 
     36 (defconst LilyPond-help-address "bug-lilypond@gnu.org"
     37   "Address accepting submission of bug reports.")
     38 
     39 (defvar LilyPond-mode-hook nil
     40   "*Hook called by `LilyPond-mode'.")
     41 
     42 (defvar LilyPond-region-file-prefix "emacs-lily"
     43   "File prefix for commands on buffer or region.")
     44 
     45 (defvar LilyPond-master-file nil
     46   "Master file that LilyPond will be run on.")
     47 
     48 ;; FIXME: find ``\score'' in buffers / make settable?
     49 (defun LilyPond-get-master-file ()
     50   (or LilyPond-master-file
     51       (buffer-file-name)))
     52 
     53 (defvar LilyPond-kick-xdvi nil
     54   "If true, no simultaneous xdvi's are started, but reload signal is sent.")
     55 
     56 (defvar LilyPond-command-history nil
     57   "Command history list.")
     58 
     59 (defvar LilyPond-regexp-alist
     60   '(("\\([a-zA-Z]?:?[^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2))
     61   "Regexp used to match LilyPond errors.  See `compilation-error-regexp-alist'.")
     62 
     63 (defvar LilyPond-imenu nil
     64   "A flag to tell whether LilyPond-imenu is turned on.")
     65 (make-variable-buffer-local 'LilyPond-imenu)
     66 
     67 (defcustom LilyPond-include-path ".:/tmp"
     68   "* LilyPond include path."
     69   :type 'string
     70   :group 'LilyPond)
     71 
     72 (defun LilyPond-words-filename ()
     73   "The file containing LilyPond \keywords \Identifiers and ReservedWords.
     74 Finds file lilypond-words.el from load-path."
     75   (let ((fn nil)
     76 	(lp load-path)
     77 	(words-file "lilypond-words.el"))
     78     (while (and (> (length lp) 0) (not fn))
     79       (setq fn (concat (car lp) "/" words-file))
     80       (if (not (file-readable-p fn))
     81 	  (progn (setq fn nil) (setq lp (cdr lp)))))
     82     (if (not fn)
     83 	(progn (message "Warning: `lilypond-words.el' not found in `load-path'. See `lilypond-init.el'.")
     84 	       (sit-for 5 0)))
     85     fn))
     86 
     87 (defun LilyPond-add-dictionary-word (x)
     88   "Contains all words: \keywords \Identifiers and ReservedWords."
     89   (nconc '(("" . 1)) x))
     90 
     91 (if (> emacs-major-version 20)
     92     (defun get-buffer-size (b) (buffer-size b))
     93   (defun get-buffer-size (b)
     94     (let (size (current-buffer (current-buffer)))
     95       (set-buffer b)
     96       (setq size (buffer-size))
     97       (set-buffer current-buffer)
     98       size)))
     99 
    100 ;; creates dictionary if empty
    101 (if (and (eq (length (LilyPond-add-dictionary-word ())) 1)
    102 	 (not (eq (LilyPond-words-filename) nil)))
    103     (progn
    104       (setq b (find-file-noselect (LilyPond-words-filename) t t))
    105       (setq m (set-marker (make-marker) 1 (get-buffer b)))
    106       (setq i 1)
    107       (while (> (get-buffer-size b) (marker-position m))
    108 	(setq i (+ i 1))
    109 	(setq copy (copy-alist (list (eval (symbol-name (read m))))))
    110 	(setcdr copy i)
    111 	(LilyPond-add-dictionary-word (list copy)))
    112       (kill-buffer b)))
    113 
    114 (defvar LilyPond-insert-tag-current ""
    115   "The last command selected from the LilyPond-Insert -menu.")
    116 
    117 (defconst LilyPond-menu-keywords
    118   (let ((wordlist '())
    119 	(co (all-completions "" (LilyPond-add-dictionary-word ())))
    120 	(currword ""))
    121     (progn
    122       (while (> (length co) 0)
    123 	(setq currword (car co))
    124 	(if (string-equal "-" (car (setq co (cdr co))))
    125 	    (progn
    126 	      (add-to-list 'wordlist currword)
    127 	      (while (and (> (length co) 0)
    128 			  (not (string-equal "-" (car (setq co (cdr co))))))))))
    129       (reverse wordlist)))
    130   "Keywords inserted from LilyPond-Insert-menu.")
    131 
    132 (defconst LilyPond-keywords
    133   (let ((wordlist '("\\score"))
    134 	(co (all-completions "" (LilyPond-add-dictionary-word ())))
    135 	(currword ""))
    136     (progn
    137       (while (> (length co) 0)
    138 	(setq currword (car co))
    139 	(if (> (length currword) 1)
    140 	    (if (and (string-equal "\\" (substring currword 0 1))
    141 	             (string-match "[a-z-]+" currword)
    142 	    	     (= (match-beginning 0) 1)
    143 	    	     (= (match-end 0) (length currword))
    144 		     (not (string-equal "\\longa" currword))
    145 		     (not (string-equal "\\breve" currword))
    146 		     (not (string-equal "\\maxima" currword))
    147 		     (string-equal (downcase currword) currword))
    148 		(add-to-list 'wordlist currword)))
    149 	(if (string-equal "-" (car (setq co (cdr co))))
    150 	    (while (and (> (length co) 0)
    151 			(not (string-equal "-" (car (setq co (cdr co)))))))))
    152       (reverse wordlist)))
    153   "LilyPond \\keywords")
    154 
    155 (defconst LilyPond-identifiers
    156   (let ((wordlist '("\\voiceOne"))
    157 	(co (all-completions "" (LilyPond-add-dictionary-word ()))))
    158     (progn
    159       (while (> (length co) 0)
    160 	(setq currword (car co))
    161 	(if (> (length currword) 1)
    162 	    (if (and (string-equal "\\" (substring currword 0 1))
    163 	             (string-match "[a-zA-Z-]+" currword)
    164 	    	     (= (match-beginning 0) 1)
    165 	    	     (= (match-end 0) (length currword))
    166 		     (not (string-equal (downcase currword) currword)))
    167 		(add-to-list 'wordlist currword)))
    168 	(if (string-equal "-" (car (setq co (cdr co))))
    169 	    (while (and (> (length co) 0)
    170 			(not (string-equal "-" (car (setq co (cdr co)))))))))
    171       (reverse wordlist)))
    172   "LilyPond \\Identifiers")
    173 
    174 (defconst LilyPond-Capitalized-Reserved-Words
    175   (let ((wordlist '("StaffContext"))
    176 	(co (all-completions "" (LilyPond-add-dictionary-word ()))))
    177     (progn
    178       (while (> (length co) 0)
    179 	(setq currword (car co))
    180 	(if (> (length currword) 0)
    181 	    (if (and (string-match "[a-zA-Z_]+" currword)
    182 	    	     (= (match-beginning 0) 0)
    183 	    	     (= (match-end 0) (length currword))
    184 		     (not (string-equal (downcase currword) currword)))
    185 		(add-to-list 'wordlist currword)))
    186 	(if (string-equal "-" (car (setq co (cdr co))))
    187 	    (while (and (> (length co) 0)
    188 			(not (string-equal "-" (car (setq co (cdr co)))))))))
    189       (reverse wordlist)))
    190   "LilyPond ReservedWords")
    191 
    192 (defconst LilyPond-non-capitalized-reserved-words
    193   (let ((wordlist '("cessess"))
    194 	(co (all-completions "" (LilyPond-add-dictionary-word ()))))
    195     (progn
    196       (while (> (length co) 0)
    197 	(setq currword (car co))
    198 	(if (> (length currword) 0)
    199 	    (if (and (string-match "[a-z]+" currword)
    200 	    	     (= (match-beginning 0) 0)
    201 	    	     (= (match-end 0) (length currword))
    202 		     (string-equal (downcase currword) currword))
    203 		(add-to-list 'wordlist currword)))
    204 	(if (string-equal "-" (car (setq co (cdr co))))
    205 	    (while (and (> (length co) 0)
    206 			(not (string-equal "-" (car (setq co (cdr co)))))))))
    207       (reverse wordlist)))
    208   "LilyPond notenames")
    209 
    210 (defun LilyPond-check-files (derived originals extensions)
    211   "Check that DERIVED is newer than any of the ORIGINALS.
    212 Try each original with each member of EXTENSIONS, in all directories
    213 in LilyPond-include-path."
    214   (let ((found nil)
    215 	(regexp (concat "\\`\\("
    216 			(mapconcat (function (lambda (dir)
    217 					       (regexp-quote (expand-file-name dir))))
    218 				   LilyPond-include-path "\\|")
    219 			"\\).*\\("
    220 			(mapconcat 'regexp-quote originals "\\|")
    221 			"\\)\\.\\("
    222 			(mapconcat 'regexp-quote extensions "\\|")
    223 			"\\)\\'"))
    224 	(buffers (buffer-list)))
    225     (while buffers
    226       (let* ((buffer (car buffers))
    227 	     (name (buffer-file-name buffer)))
    228 	(setq buffers (cdr buffers))
    229 	(if (and name (string-match regexp name))
    230 	    (progn
    231 	      (and (buffer-modified-p buffer)
    232 		   (or (not LilyPond-save-query)
    233 		       (y-or-n-p (concat "Save file "
    234 					 (buffer-file-name buffer)
    235 					 "? ")))
    236 		   (save-excursion (set-buffer buffer) (save-buffer)))
    237 	      (if (file-newer-than-file-p name derived)
    238 		  (setq found t))))))
    239     found))
    240 
    241 (defun LilyPond-running ()
    242   "Check the currently running LilyPond compiling jobs."
    243   (let ((process-names (list "lilypond" "tex" "2ps" "2midi"
    244 			     "book" "latex"))
    245 	(running nil))
    246     (while (setq process-name (pop process-names))
    247       (setq process (get-process process-name))
    248       (if (and process
    249 	       (eq (process-status process) 'run))
    250 	  (push process-name running)))
    251     running)) ; return the running jobs
    252 
    253 (defun LilyPond-midi-running ()
    254   "Check the currently running Midi processes."
    255   (let ((process-names (list "midi" "midiall"))
    256 	(running nil))
    257     (while (setq process-name (pop process-names))
    258       (setq process (get-process process-name))
    259       (if (and process
    260 	       (eq (process-status process) 'run))
    261 	  (push process-name running)))
    262     running)) ; return the running jobs
    263 
    264 (defun LilyPond-kill-jobs ()
    265   "Kill the currently running LilyPond compiling jobs."
    266   (interactive)
    267   (let ((process-names (LilyPond-running))
    268 	(killed nil))
    269     (while (setq process-name (pop process-names))
    270       (quit-process (get-process process-name) t)
    271       (push process-name killed))
    272     killed)) ; return the killed jobs
    273 
    274 (defun LilyPond-kill-midi ()
    275   "Kill the currently running midi processes."
    276   (let ((process-names (LilyPond-midi-running))
    277 	(killed nil))
    278     (while (setq process-name (pop process-names))
    279       (quit-process (get-process process-name) t)
    280       (push process-name killed))
    281     killed)) ; return the killed jobs
    282 
    283 ;; URG, should only run LilyPond-compile for LilyPond
    284 ;; not for tex,xdvi (lilypond?)
    285 (defun LilyPond-compile-file (command name)
    286   ;; We maybe should know what we run here (Lily, lilypond, tex)
    287   ;; and adjust our error-matching regex ?
    288   (compilation-start
    289    (if (eq LilyPond-command-current 'LilyPond-command-master)
    290        command
    291      ;; use temporary directory for Commands on Buffer/Region
    292      ;; hm.. the directory is set twice, first to default-dir
    293      (concat "cd " (LilyPond-temp-directory) "; " command))))
    294 
    295 ;; do we still need this, now that we're using compilation-start?
    296 (defun LilyPond-save-buffer ()
    297   "Save buffer and set default command for compiling."
    298   (interactive)
    299   (if (buffer-modified-p)
    300       (progn (save-buffer)
    301 	     (setq LilyPond-command-next LilyPond-command-default))))
    302 
    303 ;;; return (dir base ext)
    304 (defun split-file-name (name)
    305   (let* ((i (string-match "[^/]*$" name))
    306 	 (dir (if (> i 0) (substring name 0 i) "./"))
    307 	 (file (substring name i (length name)))
    308 	 (i (string-match "[^.]*$" file)))
    309     (if (and
    310 	 (> i 0)
    311 	 (< i (length file)))
    312 	(list dir (substring file 0 (- i 1)) (substring file i (length file)))
    313       (list dir file ""))))
    314 
    315 
    316 ;; Should check whether in command-alist?
    317 (defcustom LilyPond-command-default "LilyPond"
    318   "Default command. Must identify a member of LilyPond-command-alist."
    319 
    320   :group 'LilyPond
    321   :type 'string)
    322 ;;;(make-variable-buffer-local 'LilyPond-command-last)
    323 
    324 (defvar LilyPond-command-next LilyPond-command-default)
    325 
    326 (defvar LilyPond-command-current 'LilyPond-command-master)
    327 ;;;(make-variable-buffer-local 'LilyPond-command-master)
    328 
    329 
    330 ;; If non-nil, LilyPond-command-query will return the value of this
    331 ;; variable instead of quering the user.
    332 (defvar LilyPond-command-force nil)
    333 
    334 (defcustom LilyPond-lilypond-command "lilypond"
    335   "Command used to compile LY files."
    336   :group 'LilyPond
    337   :type 'string)
    338 
    339 (defcustom LilyPond-ps-command "gv --watch"
    340   "Command used to display PS files."
    341 
    342   :group 'LilyPond
    343   :type 'string)
    344 
    345 (defcustom LilyPond-pdf-command "xpdf"
    346   "Command used to display PDF files."
    347 
    348   :group 'LilyPond
    349   :type 'string)
    350 
    351 (defcustom LilyPond-midi-command "timidity"
    352   "Command used to play MIDI files."
    353 
    354   :group 'LilyPond
    355   :type 'string)
    356 
    357 (defcustom LilyPond-all-midi-command "timidity -ia"
    358   "Command used to play MIDI files."
    359 
    360   :group 'LilyPond
    361   :type 'string)
    362 
    363 (defun LilyPond-command-current-midi ()
    364   "Play midi corresponding to the current document."
    365   (interactive)
    366   (LilyPond-command (LilyPond-command-menu "Midi") 'LilyPond-get-master-file))
    367 
    368 (defun LilyPond-command-all-midi ()
    369   "Play midi corresponding to the current document."
    370   (interactive)
    371   (LilyPond-command (LilyPond-command-menu "MidiAll") 'LilyPond-get-master-file))
    372 
    373 (defun count-matches-as-number (re)
    374   "Count-matches in emacs 22 backwards-incompatibly returns a number"
    375   (let ((result (count-matches re)))
    376     (if (stringp result)
    377 	(string-to-number result)
    378       result)))
    379 
    380 (defun count-rexp (start end rexp)
    381   "Print number of found regular expressions in the region."
    382   (interactive "r")
    383   (save-excursion
    384     (save-restriction
    385       (narrow-to-region start end)
    386       (goto-char (point-min))
    387       (count-matches-as-number rexp))))
    388 
    389 (defun count-midi-words ()
    390   "Check number of midi-scores before the curser."
    391   (if (eq LilyPond-command-current 'LilyPond-command-region)
    392       (count-rexp (mark t) (point) "\\\\midi")
    393     (count-rexp (point-min) (point-max) "\\\\midi")))
    394 
    395 (defun count-midi-words-backwards ()
    396   "Check number of midi-scores before the curser."
    397   (if (eq LilyPond-command-current 'LilyPond-command-region)
    398       (count-rexp (mark t) (point) "\\\\midi")
    399     (count-rexp (point-min) (point) "\\\\midi")))
    400 
    401 (defun LilyPond-string-current-midi ()
    402   "Check the midi file of the following midi-score in the current document."
    403   (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
    404 			 (substring (LilyPond-get-master-file) 0 -3); suppose ".ly"
    405 		       LilyPond-region-file-prefix))
    406 	(allcount (count-midi-words))
    407 	(count (count-midi-words-backwards)))
    408     (concat  fnameprefix
    409 	     (if (and (> allcount 1) (> count 0)) ; not first score
    410 		 (if (eq count allcount)          ; last score
    411 		     (concat "-" (number-to-string (+ count -1)))
    412 		   (concat "-" (number-to-string count))))
    413 	     ".midi")))
    414 
    415 (defun LilyPond-string-all-midi ()
    416   "Return the midi files of the current document in ascending order."
    417   (let ((fnameprefix (if (eq LilyPond-command-current 'LilyPond-command-master)
    418 			 (substring (LilyPond-get-master-file) 0 -3); suppose ".ly"
    419 		       LilyPond-region-file-prefix))
    420 	(allcount (count-midi-words)))
    421     (concat (if (> allcount 0)  ; at least one midi-score
    422 		(concat fnameprefix ".midi "))
    423 	    (if (> allcount 1)  ; more than one midi-score
    424 		(concat fnameprefix "-[1-9].midi "))
    425 	    (if (> allcount 9)  ; etc.
    426 		(concat fnameprefix "-[1-9][0-9].midi"))
    427 	    (if (> allcount 99) ; not first score
    428 		(concat fnameprefix "-[1-9][0-9][0-9].midi")))))
    429 
    430 ;; This is the major configuration variable.
    431 (defcustom LilyPond-command-alist
    432   ;; Should expand this to include possible keyboard shortcuts which
    433   ;; could then be mapped to define-key and menu.
    434   '(("LilyPond" . ((LilyPond-lilypond-command " %s") "%s" "%l" "View"))
    435     ("2PS" . ((LilyPond-lilypond-command " -f ps %s") "%s" "%p" "ViewPS"))
    436     ("Book" . ("lilypond-book %x" "%x" "%l" "LaTeX"))
    437     ("LaTeX" . ("latex '\\nonstopmode\\input %l'" "%l" "%d" "ViewDVI"))
    438 
    439     ;; refreshes when kicked USR1
    440     ("View" . ((LilyPond-pdf-command " %f")))
    441     ("ViewPDF" . ((LilyPond-pdf-command " %f")))
    442     ("ViewPS" . ((LilyPond-ps-command " %p")))
    443 
    444     ;; The following are refreshed in LilyPond-command:
    445     ;; - current-midi depends on cursor position and
    446     ("Midi" . ("")) ;
    447     ;; - all-midi depends on number of midi-score.
    448     ("MidiAll" . ("")))
    449 
    450   "AList of commands to execute on the current document.
    451 
    452 The key is the name of the command as it will be presented to the
    453 user, the value is a cons of the command string handed to the shell
    454 after being expanded, and the next command to be executed upon
    455 success.  The expansion is done using the information found in
    456 LilyPond-expand-list.
    457 "
    458   :group 'LilyPond
    459   :type '(repeat (cons :tag "Command Item"
    460 		       (string :tag "Key")
    461 		       (cons :tag "How"
    462 			     (string :tag "Command")
    463 			     (string :tag "Next Key")))))
    464 
    465 ;; drop this?
    466 (defcustom LilyPond-file-extension ".ly"
    467   "*File extension used in LilyPond sources."
    468   :group 'LilyPond
    469   :type 'string)
    470 
    471 
    472 (defcustom LilyPond-expand-alist
    473   '(("%s" . ".ly")
    474     ("%t" . ".tex")
    475     ("%d" . ".dvi")
    476     ("%f" . ".pdf")
    477     ("%p" . ".ps")
    478     ("%l" . ".tex")
    479     ("%x" . ".tely")
    480     ("%m" . ".midi"))
    481 
    482   "Alist of expansion strings for LilyPond command names."
    483   :group 'LilyPond
    484   :type '(repeat (cons :tag "Alist item"
    485 		       (string :tag "Symbol")
    486 		       (string :tag "Expansion"))))
    487 
    488 
    489 (defcustom LilyPond-command-Show "View"
    490   "*The default command to show (view or print) a LilyPond file.
    491 Must be the car of an entry in `LilyPond-command-alist'."
    492   :group 'LilyPond
    493   :type 'string)
    494 (make-variable-buffer-local 'LilyPond-command-Show)
    495 
    496 (defcustom LilyPond-command-Print "Print"
    497   "The name of the Print entry in LilyPond-command-Print."
    498   :group 'LilyPond
    499   :type 'string)
    500 
    501 (defun LilyPond-find-required-command (command file)
    502   "Find the first command in the chain that is needed to run
    503  (input file is newer than the output file)"
    504   (let* ((entry (cdr (assoc command LilyPond-command-alist)))
    505 	 (next-command (nth 3 entry)))
    506     (if (null next-command)
    507 	command
    508       (let* ((src-string (nth 1 entry))
    509 	     (input (LilyPond-command-expand src-string file))
    510 	     (output (LilyPond-command-expand (nth 2 entry) file)))
    511 	(if (or (file-newer-than-file-p input output)
    512 		(and (equal "%s" src-string)
    513 		     (not (equal (buffer-name) file))
    514 		     (file-newer-than-file-p (buffer-name)
    515 					     output)))
    516 	    command
    517 	  (LilyPond-find-required-command next-command file))))))
    518 
    519 (defun LilyPond-command-query (name)
    520   "Query the user for what LilyPond command to use."
    521   (cond ((string-equal name LilyPond-region-file-prefix)
    522 	 (LilyPond-check-files (concat name ".tex")
    523 			       (list name)
    524 			       (list LilyPond-file-extension)))
    525 	((verify-visited-file-modtime (current-buffer))
    526 	 (and (buffer-modified-p)
    527 	      (y-or-n-p "Save buffer before next command? ")
    528 	      (LilyPond-save-buffer)))
    529 	((y-or-n-p "The command will be invoked to an already saved buffer. Revert it? ")
    530 	 (revert-buffer t t)))
    531 
    532   (let* ((default (LilyPond-find-required-command LilyPond-command-next name))
    533 	 (completion-ignore-case t)
    534 	 (answer (or LilyPond-command-force
    535 		     (completing-read
    536 		      (concat "Command: (default " default ") ")
    537 		      LilyPond-command-alist nil t nil 'LilyPond-command-history))))
    538 
    539     ;; If the answer is "LilyPond" it will not be expanded to "LilyPond"
    540     (let ((answer (car-safe (assoc answer LilyPond-command-alist))))
    541       (if (and answer
    542 	       (not (string-equal answer "")))
    543 	  answer
    544 	default))))
    545 
    546 (defun LilyPond-command-master ()
    547   "Run command on the current document."
    548   (interactive)
    549   (LilyPond-command-select-master)
    550   (LilyPond-command (LilyPond-command-query (LilyPond-get-master-file))
    551 		    'LilyPond-get-master-file))
    552 
    553 (defun LilyPond-command-lilypond ()
    554   "Run lilypond for the current document."
    555   (interactive)
    556   (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-get-master-file))
    557 
    558 (defun LilyPond-command-formatps ()
    559   "Format the ps output of the current document."
    560   (interactive)
    561   (LilyPond-command (LilyPond-command-menu "2PS") 'LilyPond-get-master-file))
    562 
    563 (defun LilyPond-command-formatmidi ()
    564   "Format the midi output of the current document."
    565   (interactive)
    566   (LilyPond-command (LilyPond-command-menu "2Midi") 'LilyPond-get-master-file))
    567 
    568 (defun LilyPond-command-view ()
    569   "View the output of current document."
    570   (interactive)
    571   (LilyPond-command-viewpdf))
    572 
    573 (defun LilyPond-command-viewpdf ()
    574   "View the ps output of current document."
    575   (interactive)
    576   (LilyPond-command (LilyPond-command-menu "ViewPDF") 'LilyPond-get-master-file))
    577 
    578 (defun LilyPond-command-viewps ()
    579   "View the ps output of current document."
    580   (interactive)
    581   (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-get-master-file))
    582 
    583 ;; FIXME, this is broken
    584 (defun LilyPond-region-file (begin end)
    585   (let (
    586 	;; (dir "./")
    587  	(dir (LilyPond-temp-directory))
    588 	(base LilyPond-region-file-prefix)
    589 	(ext LilyPond-file-extension))
    590     (concat dir base ext)))
    591 
    592 ;;; Commands on Region work if there is an appropriate '\score'.
    593 (defun LilyPond-command-region (begin end)
    594   "Run LilyPond on the current region."
    595   (interactive "r")
    596   (if (or (> begin (point-min)) (< end (point-max)))
    597       (LilyPond-command-select-region))
    598   (write-region begin end (LilyPond-region-file begin end) nil 'nomsg)
    599   (LilyPond-command (LilyPond-command-query
    600 		     (LilyPond-region-file begin end))
    601 		    '(lambda () (LilyPond-region-file begin end)))
    602   ;; Region may deactivate even if buffer was intact, reactivate?
    603   ;; Currently, also deactived regions are used.
    604   )
    605 
    606 (defun LilyPond-command-buffer ()
    607   "Run LilyPond on buffer."
    608   (interactive)
    609   (LilyPond-command-select-buffer)
    610   (LilyPond-command-region (point-min) (point-max)))
    611 
    612 (defun LilyPond-command-expand (arg file)
    613   (cond
    614    ((listp arg)
    615     (mapconcat (lambda (arg) (LilyPond-command-expand arg file))
    616 	       arg
    617 	       ""))
    618    ((and (symbolp arg) (boundp arg)
    619 	 ;; Avoid self-quoting symbols
    620 	 (not (eq (symbol-value arg) arg)))
    621     (LilyPond-command-expand (symbol-value arg) file))
    622    ((stringp arg)
    623     (let ((case-fold-search nil))
    624       (if (string-match "%" arg)
    625 	  (let* ((b (match-beginning 0))
    626 		 (e (+ b 2))
    627 		 (l (split-file-name file))
    628 		 (dir (car l))
    629 		 (base (cadr l)))
    630 	    (concat (substring arg 0 b)
    631 		    (shell-quote-argument (concat dir base))
    632 		    (LilyPond-command-expand
    633 		     (concat
    634 		      (let ((entry (assoc (substring arg b e)
    635 					  LilyPond-expand-alist)))
    636 			(if entry (cdr entry) ""))
    637 		      (substring arg e))
    638 		     file)))
    639 	arg)))
    640    (t (error "Bad expansion `%S'" arg))))
    641 
    642 (defun LilyPond-shell-process (name buffer command)
    643   (let ((old (current-buffer)))
    644     (switch-to-buffer-other-window buffer)
    645     ;; If we empty the buffer don't see messages scroll by.
    646     ;; (erase-buffer)
    647 
    648     (start-process-shell-command name buffer command)
    649     (switch-to-buffer-other-window old)))
    650 
    651 
    652 (defun LilyPond-command (name file)
    653   "Run command NAME on the file you get by calling FILE.
    654 
    655 FILE is a function return a file name.  It has one optional argument,
    656 the extension to use on the file.
    657 
    658 Use the information in LilyPond-command-alist to determine how to run the
    659 command."
    660 
    661   (let ((entry (assoc name LilyPond-command-alist)))
    662     (if entry
    663 	(let ((command (LilyPond-command-expand (cadr entry)
    664 						(apply file nil)))
    665 	      (jobs nil)
    666 	      (job-string "no jobs"))
    667 	  (if (member name (list "View" "ViewPS"))
    668 	      ;; is USR1 a right signal for viewps?
    669 	      (let ((buffer-xdvi (get-buffer-create (concat "*" name "*"))))
    670 		;; what if XEDITOR is set to gedit or so, should we steal it?
    671 		(if (not (getenv "XEDITOR"))
    672 		    (setenv "XEDITOR" "emacsclient --no-wait +%l:%c %f"))
    673 		(if LilyPond-kick-xdvi
    674 		    (let ((process-xdvi (get-buffer-process buffer-xdvi)))
    675 		      (if process-xdvi
    676 			  (signal-process (process-id process-xdvi) 'SIGUSR1)
    677 			(LilyPond-shell-process name buffer-xdvi command)))
    678 		  (LilyPond-shell-process name buffer-xdvi command)))
    679 	    (progn
    680 	      (if (string-equal name "Midi")
    681 		  (progn
    682 		    (setq command (concat LilyPond-midi-command " " (LilyPond-string-current-midi)))
    683 		    (if (LilyPond-kill-midi)
    684 			(setq job-string nil)))) ; either stop or start playing
    685 	      (if (string-equal name "MidiAll")
    686 		  (progn
    687 		    (setq command (concat LilyPond-all-midi-command " " (LilyPond-string-all-midi)))
    688 		    (LilyPond-kill-midi))) ; stop and start playing
    689 	      (if (and (member name (list "Midi" "MidiAll")) job-string)
    690 		  (if (file-newer-than-file-p
    691 		       (LilyPond-get-master-file)
    692 		       (concat (substring (LilyPond-get-master-file) 0 -3) ".midi"))
    693 		      (if (y-or-n-p "Midi older than source. Reformat midi?")
    694 			  (progn
    695 			    (LilyPond-command-formatmidi)
    696 			    (while (LilyPond-running)
    697 			      (message "Starts playing midi once it is built.")
    698 			      (sit-for 0 100))))))
    699 	      (if (member name (list "LilyPond" "TeX" "2Midi" "2PS"
    700 				     "Book" "LaTeX"))
    701 		  (if (setq jobs (LilyPond-running))
    702 		      (progn
    703 			(setq job-string "Process") ; could also suggest compiling after process has ended
    704 			(while jobs
    705 			  (setq job-string (concat job-string " \"" (pop jobs) "\"")))
    706 			(setq job-string (concat job-string " is already running; kill it to proceed "))
    707 			(if (y-or-n-p job-string)
    708 			    (progn
    709 			      (setq job-string "no jobs")
    710 			      (LilyPond-kill-jobs)
    711 			      (while (LilyPond-running)
    712 				(sit-for 0 100)))
    713 			  (setq job-string nil)))))
    714 
    715 	      (setq LilyPond-command-next
    716 		    (let* ((entry (assoc name LilyPond-command-alist))
    717 			   (next-command (nth 3 (cdr entry))))
    718 		      (or next-command
    719 			  LilyPond-command-default)))
    720 
    721 	      (if (string-equal job-string "no jobs")
    722 		  (LilyPond-compile-file command name))))))))
    723 
    724 (defun LilyPond-mark-active ()
    725   "Check if there is an active mark."
    726   (and transient-mark-mode
    727        (if (string-match "XEmacs\\|Lucid" emacs-version) (mark) mark-active)))
    728 
    729 (defun LilyPond-temp-directory ()
    730   "Temporary file directory for Commands on Region."
    731   (interactive)
    732   (if (string-match "XEmacs\\|Lucid" emacs-version)
    733       (concat (temp-directory) "/")
    734     temporary-file-directory))
    735 
    736 ;;; Keymap
    737 
    738 (defvar LilyPond-mode-map ()
    739   "Keymap used in `LilyPond-mode' buffers.")
    740 
    741 ;; Note:  if you make changes to the map, you must do
    742 ;;    M-x set-variable LilyPond-mode-map nil
    743 ;;    M-x eval-buffer
    744 ;;    M-x LilyPond-mode
    745 ;; to let the changest take effect
    746 
    747 (unless LilyPond-mode-map
    748   (setq LilyPond-mode-map (make-sparse-keymap))
    749   ;; Put keys to LilyPond-command-alist and fetch them from there somehow.
    750   (define-key LilyPond-mode-map "\C-c\C-l" 'LilyPond-command-lilypond)
    751   (define-key LilyPond-mode-map "\C-c\C-r" 'LilyPond-command-region)
    752   (define-key LilyPond-mode-map "\C-c\C-b" 'LilyPond-command-buffer)
    753   (define-key LilyPond-mode-map "\C-c\C-k" 'LilyPond-kill-jobs)
    754   (define-key LilyPond-mode-map "\C-c\C-c" 'LilyPond-command-master)
    755   (define-key LilyPond-mode-map "\C-cm" 'LilyPond-command-formatmidi)
    756   (define-key LilyPond-mode-map "\C-c\C-f" 'LilyPond-command-formatps)
    757   (define-key LilyPond-mode-map "\C-c\C-s" 'LilyPond-command-view)
    758   (define-key LilyPond-mode-map "\C-c\C-p" 'LilyPond-command-viewps)
    759   (define-key LilyPond-mode-map [(control c) return] 'LilyPond-command-current-midi)
    760   (define-key LilyPond-mode-map [(control c) (control return)] 'LilyPond-command-all-midi)
    761   (define-key LilyPond-mode-map "\C-x\C-s" 'LilyPond-save-buffer)
    762   (define-key LilyPond-mode-map "\C-cb" 'LilyPond-what-beat)
    763   (define-key LilyPond-mode-map "\C-cf" 'font-lock-fontify-buffer)
    764   (define-key LilyPond-mode-map "\C-ci" 'LilyPond-insert-tag-current)
    765   ;; the following will should be overridden by LilyPond Quick Insert Mode
    766   (define-key LilyPond-mode-map "\C-cq" 'LilyPond-quick-insert-mode)
    767   (define-key LilyPond-mode-map "\C-c;" 'LilyPond-comment-region)
    768   (define-key LilyPond-mode-map ")" 'LilyPond-electric-close-paren)
    769   (define-key LilyPond-mode-map ">" 'LilyPond-electric-close-paren)
    770   (define-key LilyPond-mode-map "}" 'LilyPond-electric-close-paren)
    771   (define-key LilyPond-mode-map "]" 'LilyPond-electric-close-paren)
    772   (define-key LilyPond-mode-map "|" 'LilyPond-electric-bar)
    773   (if (string-match "XEmacs\\|Lucid" emacs-version)
    774       (define-key LilyPond-mode-map [iso-left-tab] 'LilyPond-autocompletion)
    775     (define-key LilyPond-mode-map [(shift iso-lefttab)] 'LilyPond-autocompletion))
    776   (define-key LilyPond-mode-map "\C-c\t" 'LilyPond-info-index-search))
    777 
    778 ;;; Menu Support
    779 
    780 ;;; This mode was originally LilyPond-quick-note-insert by Heikki Junes.
    781 ;;; The original version has been junked since CVS-1.97,
    782 ;;; in order to merge the efforts done by Nicolas Sceaux.
    783 ;;; LilyPond Quick Insert Mode is a major mode, toggled by C-c q.
    784 (defun LilyPond-quick-insert-mode ()
    785   "Insert notes with fewer key strokes by using a simple keyboard piano."
    786   (interactive)
    787   (progn
    788     (message "Invoke (C-c q) from keyboard. If you still see this message,") (sit-for 5 0)
    789     (message "then you have not installed LilyPond Quick Insert Mode (lyqi).") (sit-for 5 0)
    790     (message "Download lyqi from http://nicolas.sceaux.free.fr/lilypond/lyqi.html,") (sit-for 5 0)
    791     (message "see installation instructions from lyqi's README -file.") (sit-for 5 0)
    792     (message "You need also eieio (Enhanced Integration of Emacs Interpreted Objects).") (sit-for 5 0)
    793     (message "Download eieio from http://cedet.sourceforge.net/eieio.shtml,") (sit-for 5 0)
    794     (message "see installation instructions from eieio's INSTALL -file.") (sit-for 5 0)
    795     (message "")))
    796 
    797 (defun LilyPond-pre-word-search ()
    798   "Fetch the alphabetic characters and \\ in front of the cursor."
    799   (let ((pre "")
    800 	(prelen 0)
    801 	(ch (char-before (- (point) 0))))
    802     (while (and ch (or (and (>= ch 65) (<= ch 90))  ; not bolp, A-Z
    803 		       (and (>= ch 97) (<= ch 122)) ; a-z
    804 		       (= ch 92)))                  ; \\
    805       (setq pre (concat (char-to-string ch) pre))
    806       (setq prelen (+ prelen 1))
    807       (setq ch (char-before (- (point) prelen))))
    808     pre))
    809 
    810 (defun LilyPond-post-word-search ()
    811   "Fetch the alphabetic characters behind the cursor."
    812   (let ((post "")
    813 	(postlen 0)
    814 	(ch (char-after (+ (point) 0))))
    815     (while (and ch (or (and (>= ch 65) (<= ch 90))    ; not eolp, A-Z
    816 		       (and (>= ch 97) (<= ch 122)))) ; a-z
    817       (setq post (concat post (char-to-string ch)))
    818       (setq postlen (+ postlen 1))
    819       (setq ch (char-after (+ (point) postlen))))
    820     post))
    821 
    822 (defun LilyPond-autocompletion ()
    823   "Show completions in mini-buffer for the given word."
    824   (interactive)
    825   (let ((pre (LilyPond-pre-word-search))
    826 	(post (LilyPond-post-word-search))
    827 	(compsstr ""))
    828     ;; insert try-completion and show all-completions
    829     (if (> (length pre) 0)
    830 	(progn
    831 	  (setq trycomp (try-completion pre (LilyPond-add-dictionary-word ())))
    832 	  (if (char-or-string-p trycomp)
    833 	      (if (string-equal (concat pre post) trycomp)
    834 		  (goto-char (+ (point) (length post)))
    835 		(progn
    836 		  (delete-region (point) (+ (point) (length post)))
    837 		  (insert (substring trycomp (length pre) nil))))
    838 	    (progn
    839 	      (delete-region (point) (+ (point) (length post)))
    840 	      (font-lock-fontify-buffer))) ; only inserting fontifies
    841 
    842 	  (setq complist (all-completions pre (LilyPond-add-dictionary-word ())))
    843 	  (while (> (length complist) 0)
    844 	    (setq compsstr (concat compsstr "\"" (car complist) "\" "))
    845 	    (setq complist (cdr complist)))
    846 	  (message compsstr)
    847 	  (sit-for 0 100)))))
    848 
    849 (defun LilyPond-info ()
    850   "Launch Info for lilypond."
    851   (interactive)
    852   (info "lilypond"))
    853 
    854 (defun LilyPond-music-glossary-info ()
    855   "Launch Info for music-glossary."
    856   (interactive)
    857   (info "music-glossary"))
    858 
    859 (defun LilyPond-internals-info ()
    860   "Launch Info for lilypond-internals."
    861   (interactive)
    862   (info "lilypond-internals"))
    863 
    864 (defun LilyPond-info-index-search ()
    865   "In `*info*'-buffer, launch `info lilypond --index-search word-under-cursor'"
    866   (interactive)
    867   (let ((str (concat (LilyPond-pre-word-search) (LilyPond-post-word-search))))
    868     (if (and (> (length str) 0)
    869 	     (string-equal (substring str 0 1) "\\"))
    870 	(setq str (substring str 1 nil)))
    871     (LilyPond-info)
    872     (Info-index str)))
    873 
    874 (defun LilyPond-insert-tag-current (&optional word)
    875   "Set the current tag to be inserted."
    876   (interactive)
    877   (if word
    878       (setq LilyPond-insert-tag-current word))
    879   (if (memq LilyPond-insert-tag-current LilyPond-menu-keywords)
    880       (LilyPond-insert-tag)
    881     (message "No tag was selected from LilyPond->Insert tag-menu.")))
    882 
    883 (defun LilyPond-insert-tag ()
    884   "Insert syntax for given tag. The definitions are in LilyPond-words-filename."
    885   (interactive)
    886   (setq b (find-file-noselect (LilyPond-words-filename) t t))
    887   (let ((word LilyPond-insert-tag-current)
    888 	(found nil)
    889 	(p nil)
    890 	(query nil)
    891         (m (set-marker (make-marker) 1 (get-buffer b)))
    892         (distance (if (LilyPond-mark-active)
    893 		      (abs (- (mark-marker) (point-marker))) 0)))
    894     ;; find the place first
    895     (if (LilyPond-mark-active)
    896 	(goto-char (min (mark-marker) (point-marker))))
    897     (while (and (not found) (> (get-buffer-size b) (marker-position m)))
    898       (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
    899       (if (string-equal word copy) (setq found t)))
    900     (if found (insert word))
    901     (if (> (get-buffer-size b) (marker-position m))
    902 	(setq copy (car (copy-alist (list (eval (symbol-name (read m))))))))
    903     (if (not (string-equal "-" copy))
    904 	(setq found nil))
    905     (while (and found (> (get-buffer-size b) (marker-position m)))
    906       ;; find next symbol
    907       (setq copy (car (copy-alist (list (eval (symbol-name (read m)))))))
    908       ;; check whether it is the word, or the word has been found
    909       (cond
    910        ((string-equal "-" copy) (setq found nil))
    911        ((string-equal "%" copy) (insert " " (read-string "Give Arguments: ")))
    912        ((string-equal "_" copy)
    913 	(progn
    914 	  (setq p (point))
    915 	  (goto-char (+ p distance))))
    916        ((string-equal "\?" copy) (setq query t))
    917        ((string-equal "\!" copy) (setq query nil))
    918        ((string-equal "\\n" copy)
    919 	(if (not query)
    920 	    (progn (LilyPond-indent-line) (insert "\n") (LilyPond-indent-line))))
    921        ((string-equal "{" copy)
    922 	(if (not query)
    923 	    (progn (insert " { "))))
    924        ((string-equal "}" copy)
    925 	(if (not query)
    926 	    (progn (insert " } ") (setq query nil) )))
    927        ((not query)
    928 	(insert copy))
    929        (query
    930 	(if (y-or-n-p (concat "Proceed with `" copy "'? "))
    931 	    (progn (insert copy) (setq query nil))))))
    932     (if p (goto-char p))
    933     (kill-buffer b)))
    934 
    935 (defun LilyPond-command-menu-entry (entry)
    936   ;; Return LilyPond-command-alist ENTRY as a menu item.
    937   (let ((name (car entry)))
    938     (cond ((and (string-equal name LilyPond-command-Print)
    939 		LilyPond-printer-list)
    940 	   (let ((command LilyPond-print-command)
    941 		 (lookup 1))
    942 	     (append (list LilyPond-command-Print)
    943 		     (mapcar 'LilyPond-command-menu-printer-entry
    944 			     LilyPond-printer-list))))
    945 	  (t
    946 	   (vector name (list 'LilyPond-command-menu name) t)))))
    947 
    948 
    949 (easy-menu-define LilyPond-command-menu
    950   LilyPond-mode-map
    951   "Menu used in LilyPond mode."
    952   (append '("Command")
    953 	  '(("Command on"
    954 	     [ "Master File" LilyPond-command-select-master
    955 	       :keys "C-c C-c" :style radio
    956 	       :selected (eq LilyPond-command-current 'LilyPond-command-master) ]
    957 	     [ "Buffer" LilyPond-command-select-buffer
    958 	       :keys "C-c C-b" :style radio
    959 	       :selected (eq LilyPond-command-current 'LilyPond-command-buffer) ]
    960 	     [ "Region" LilyPond-command-select-region
    961 	       :keys "C-c C-r" :style radio
    962 	       :selected (eq LilyPond-command-current 'LilyPond-command-region) ]))
    963 ;;;	  (let ((file 'LilyPond-command-on-current))
    964 ;;;	    (mapcar 'LilyPond-command-menu-entry LilyPond-command-alist))
    965 ;;; Some kind of mapping which includes :keys might be more elegant
    966 ;;; Put keys to LilyPond-command-alist and fetch them from there somehow.
    967 	  '([ "LilyPond" LilyPond-command-lilypond t])
    968 	  '([ "2PS" LilyPond-command-formatps t])
    969 	  '([ "2Midi" LilyPond-command-formatmidi t])
    970 	  '([ "Book" (LilyPond-command (LilyPond-command-menu "Book") 'LilyPond-get-master-file) ])
    971 	  '([ "LaTeX" (LilyPond-command (LilyPond-command-menu "LaTeX") 'LilyPond-get-master-file) ])
    972 	  '([ "Kill jobs" LilyPond-kill-jobs t])
    973 	  '("-----")
    974 	  '([ "View" LilyPond-command-view t])
    975 	  '([ "ViewPS" LilyPond-command-viewps t])
    976 	  '("-----")
    977 	  '([ "Midi (toggle)" LilyPond-command-current-midi t])
    978 	  '([ "Midi all" LilyPond-command-all-midi t])))
    979 
    980 (defun LilyPond-menu-keywords-item (arg)
    981   "Make vector for LilyPond-mode-keywords."
    982   (vector arg (list 'LilyPond-insert-tag-current arg) :style 'radio :selected (list 'eq 'LilyPond-insert-tag-current arg)))
    983 
    984 (defun LilyPond-menu-keywords ()
    985   "Make Insert Tag menu.
    986 
    987 The Insert Tag -menu is split into parts if it is long enough."
    988 
    989   (let ((li (mapcar 'LilyPond-menu-keywords-item LilyPond-menu-keywords))
    990 	(w (round (sqrt (length LilyPond-menu-keywords))))
    991 	(split '())
    992 	(imin 0) imax lw rw)
    993     (while (< imin (length LilyPond-menu-keywords))
    994       (setq imax (- (min (+ imin w) (length LilyPond-menu-keywords)) 1))
    995       (setq lw (nth imin LilyPond-menu-keywords))
    996       (setq rw (nth imax LilyPond-menu-keywords))
    997       (add-to-list 'split
    998 		   (let ((l (list (concat (substring lw 0 (min 7 (length lw)))
    999 					  " ... "
   1000 					  (substring rw 0 (min 7 (length rw)))))))
   1001 		     (while (<= imin imax)
   1002 		       (add-to-list 'l (nth imin li))
   1003 		       (setq imin (1+ imin)))
   1004 		     (reverse l))))
   1005     (if (> (length LilyPond-menu-keywords) 12) (reverse split) li)))
   1006 
   1007 ;;; LilyPond-mode-menu should not be interactive, via "M-x LilyPond-<Tab>"
   1008 (easy-menu-define LilyPond-mode-menu
   1009   LilyPond-mode-map
   1010   "Menu used in LilyPond mode."
   1011   (append '("LilyPond")
   1012 	  '(["Add index menu" LilyPond-add-imenu-menu])
   1013 	  (list (cons "Insert tag"
   1014                       (cons ["Previously selected" LilyPond-insert-tag-current t]
   1015 			    (cons "-----"
   1016 				  (LilyPond-menu-keywords)))))
   1017 	  '(("Miscellaneous"
   1018 	     ["Autocompletion"   LilyPond-autocompletion t]
   1019 	     ["(Un)comment Region" LilyPond-comment-region t]
   1020 	     ["Refontify buffer" font-lock-fontify-buffer t]
   1021 	     "-----"
   1022 	     ["Quick Insert Mode"  LilyPond-quick-insert-mode :keys "C-c q"]
   1023  	     ))
   1024 	  '(("Info"
   1025 	     ["LilyPond" LilyPond-info t]
   1026 	     ["LilyPond index-search" LilyPond-info-index-search t]
   1027 	     ["Music Glossary" LilyPond-music-glossary-info t]
   1028 	     ["LilyPond internals" LilyPond-internals-info t]))))
   1029 
   1030 (defconst LilyPond-imenu-generic-re "^\\([a-zA-Z]+\\) *="
   1031   "Regexp matching Identifier definitions.")
   1032 
   1033 (defvar LilyPond-imenu-generic-expression
   1034   (list (list nil LilyPond-imenu-generic-re 1))
   1035   "Expression for imenu")
   1036 
   1037 (defun LilyPond-command-select-master ()
   1038   (interactive)
   1039   (message "Next command will be on the master file")
   1040   (setq LilyPond-command-current 'LilyPond-command-master))
   1041 
   1042 (defun LilyPond-command-select-buffer ()
   1043   (interactive)
   1044   (message "Next command will be on the buffer")
   1045   (setq LilyPond-command-current 'LilyPond-command-buffer))
   1046 
   1047 (defun LilyPond-command-select-region ()
   1048   (interactive)
   1049   (message "Next command will be on the region")
   1050   (setq LilyPond-command-current 'LilyPond-command-region))
   1051 
   1052 (defun LilyPond-command-menu (name)
   1053   ;; Execute LilyPond-command-alist NAME from a menu.
   1054   (let ((LilyPond-command-force name))
   1055     (if (eq LilyPond-command-current 'LilyPond-command-region)
   1056 	(if (eq (mark t) nil)
   1057 	    (progn (message "The mark is not set now") (sit-for 0 500))
   1058 	  (progn (if (not (not (LilyPond-mark-active)))
   1059 		     (progn (message "Region is not active, using region between inactive mark and current point.") (sit-for 0 500)))
   1060 		 (LilyPond-command-region (mark t) (point))))
   1061       (funcall LilyPond-command-current))))
   1062 
   1063 (defun LilyPond-add-imenu-menu ()
   1064   (interactive)
   1065   "Add an imenu menu to the menubar."
   1066   (if (not LilyPond-imenu)
   1067       (progn
   1068 	(imenu-add-to-menubar "Index")
   1069 	(redraw-frame (selected-frame))
   1070 	(setq LilyPond-imenu t))
   1071     (message "%s" "LilyPond-imenu already exists.")))
   1072 (put 'LilyPond-add-imenu-menu 'menu-enable '(not LilyPond-imenu))
   1073 
   1074 (defun LilyPond-mode ()
   1075   "Major mode for editing LilyPond music files.
   1076 
   1077 This mode knows about LilyPond keywords and line comments, not about
   1078 indentation or block comments.  It features easy compilation, error
   1079 finding and viewing of a LilyPond source buffer or region.
   1080 
   1081 COMMANDS
   1082 \\{LilyPond-mode-map}
   1083 VARIABLES
   1084 
   1085 LilyPond-command-alist\t\talist from name to command"
   1086   (interactive)
   1087   ;; set up local variables
   1088   (kill-all-local-variables)
   1089 
   1090   (make-local-variable 'font-lock-defaults)
   1091   (setq font-lock-defaults '(LilyPond-font-lock-keywords))
   1092 
   1093   ;; string and comments are fontified explicitly
   1094   (make-local-variable 'font-lock-keywords-only)
   1095   (setq font-lock-keywords-only t)
   1096 
   1097   ;; Multi-line font-locking needs Emacs 21.1 or newer.
   1098   ;; For older versions there is hotkey "C-c f".
   1099   (make-local-variable 'font-lock-multiline)
   1100   (setq font-lock-multiline t)
   1101 
   1102   (make-local-variable 'paragraph-separate)
   1103   (setq paragraph-separate "^[ \t]*$")
   1104 
   1105   (make-local-variable 'paragraph-start)
   1106   (setq	paragraph-start "^[ \t]*$")
   1107 
   1108   (make-local-variable 'comment-start)
   1109   (setq comment-start "%")
   1110 
   1111   (make-local-variable 'comment-start-skip)
   1112   (setq comment-start-skip "%{? *")
   1113 
   1114   (make-local-variable 'comment-end)
   1115   (setq comment-end "")
   1116 
   1117   (make-local-variable 'block-comment-start)
   1118   (setq block-comment-start "%{")
   1119 
   1120   (make-local-variable 'block-comment-end)
   1121   (setq block-comment-end   "%}")
   1122 
   1123   (make-local-variable 'indent-line-function)
   1124   (setq indent-line-function 'LilyPond-indent-line)
   1125 
   1126   (LilyPond-mode-set-syntax-table '(?\< ?\> ?\{ ?\}))
   1127   (setq major-mode 'LilyPond-mode)
   1128   (setq mode-name "LilyPond")
   1129   (setq local-abbrev-table LilyPond-mode-abbrev-table)
   1130   (use-local-map LilyPond-mode-map)
   1131 
   1132   ;; In XEmacs imenu was synched up with: FSF 20.4
   1133   (make-local-variable 'imenu-generic-expression)
   1134   (setq imenu-generic-expression LilyPond-imenu-generic-expression)
   1135   ;; (imenu-add-to-menubar "Index") ; see LilyPond-add-imenu-menu
   1136 
   1137   ;; In XEmacs one needs to use 'easy-menu-add'.
   1138   (if (string-match "XEmacs\\|Lucid" emacs-version)
   1139       (progn
   1140 	(easy-menu-add LilyPond-mode-menu)
   1141 	(easy-menu-add LilyPond-command-menu)))
   1142 
   1143   ;; Use Command on Region even for inactive mark (region).
   1144   (if (string-match "XEmacs\\|Lucid" emacs-version)
   1145       (progn
   1146 	(setq zmacs-regions nil)
   1147 	(make-local-hook 'post-command-hook)) ; XEmacs requires
   1148     (setq mark-even-if-inactive t))
   1149 
   1150   ;; Context dependent syntax tables in LilyPond-mode
   1151   (add-hook 'post-command-hook 'LilyPond-mode-context-set-syntax-table nil t)
   1152 
   1153   ;; Turn on paren-mode buffer-locally, i.e., in LilyPond-mode
   1154   (if (string-match "XEmacs\\|Lucid" emacs-version)
   1155       (progn
   1156 	(make-local-variable 'paren-mode)
   1157 	(paren-set-mode 'paren)
   1158 	(make-local-variable 'blink-matching-paren)
   1159 	(setq blink-matching-paren t))
   1160     (progn
   1161       (make-local-variable 'blink-matching-paren-on-screen)
   1162       (setq blink-matching-paren-on-screen t)))
   1163 
   1164   ;; run the mode hook. LilyPond-mode-hook use is deprecated
   1165   (run-hooks 'LilyPond-mode-hook))
   1166 
   1167 (defun LilyPond-version ()
   1168   "Echo the current version of `LilyPond-mode' in the minibuffer."
   1169   (interactive)
   1170   (message "Using `LilyPond-mode' version %s" LilyPond-version))
   1171 
   1172 (load-library "lilypond-font-lock")
   1173 (load-library "lilypond-indent")
   1174 (load-library "lilypond-what-beat")
   1175 
   1176 (defun LilyPond-guile ()
   1177   (interactive)
   1178   (require 'ilisp)
   1179   (guile "lilyguile" (LilyPond-command-expand (cadr (assoc "LilyPond" LilyPond-command-alist))
   1180                                               (funcall 'LilyPond-get-master-file)))
   1181   (comint-default-send (ilisp-process) "(define-module (*anonymous-ly-0*))")
   1182   (comint-default-send (ilisp-process) "(set! %load-path (cons \"/usr/share/ilisp/\" %load-path))")
   1183   (comint-default-send (ilisp-process) "(use-modules (guile-user) (guile-ilisp))")
   1184   (comint-default-send (ilisp-process) "(newline)"))
   1185 
   1186 (provide 'lilypond-mode)
   1187 ;;; lilypond-mode.el ends here
   1188