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