lilypond-indent.el (21572B)
1 ;;; lilypond-indent.el --- Auto-indentation for lilypond code 2 ;;; 3 ;;; Heikki Junes <hjunes@cc.hut.fi> 4 ;;; * ond-char paren matching is handled by context dependent syntax tables 5 ;;; * match two-char slurs '\( ... \)' and '\[ ... \]' separately. 6 ;;; * adopt Emacs' f90-comment-region 7 8 ;;; Chris Jackson <chris@fluffhouse.org.uk> 9 ;;; some code is taken from ESS (Emacs Speaks Statistics) S-mode by A.J.Rossini <rossini@biostat.washington.edu> 10 11 ;;; Variables for customising indentation style 12 13 ;;; TODO: 14 ;;; * currently, in bracket matching one may need a non-bracket 15 ;;; chararacter between the bracket characters, like ( ( ) ) 16 17 (defcustom LilyPond-indent-level 2 18 "*Indentation of lilypond statements with respect to containing block." 19 :group 'LilyPond 20 :type 'integer) 21 22 (defcustom LilyPond-brace-offset 0 23 "*Extra indentation for open braces. 24 Compares with other text in same context." 25 :group 'LilyPond 26 :type 'integer) 27 28 (defcustom LilyPond-angle-offset 0 29 "*Extra indentation for open angled brackets. 30 Compares with other text in same context." 31 :group 'LilyPond 32 :type 'integer) 33 34 (defcustom LilyPond-square-offset 0 35 "*Extra indentation for open square brackets. 36 Compares with other text in same context." 37 :group 'LilyPond 38 :type 'integer) 39 40 (defcustom LilyPond-scheme-paren-offset 0 41 "*Extra indentation for open scheme parens. 42 Compares with other text in same context." 43 :group 'LilyPond 44 :type 'integer) 45 46 (defcustom LilyPond-close-brace-offset 0 47 "*Extra indentation for closing braces." 48 :group 'LilyPond 49 :type 'integer) 50 51 (defcustom LilyPond-close-angle-offset 0 52 "*Extra indentation for closing angle brackets." 53 :group 'LilyPond 54 :type 'integer) 55 56 (defcustom LilyPond-close-square-offset 0 57 "*Extra indentation for closing square brackets." 58 :group 'LilyPond 59 :type 'integer) 60 61 (defcustom LilyPond-close-scheme-paren-offset 0 62 "*Extra indentation for closing scheme parens." 63 :group 'LilyPond 64 :type 'integer) 65 66 (defcustom LilyPond-fancy-comments t 67 "*Non-nil means distiguish between %, %%, and %%% for indentation." 68 :group 'LilyPond 69 :type 'boolean) 70 71 (defcustom LilyPond-comment-region "%%%" 72 "*String inserted by \\[LilyPond-comment-region]\ 73 at start of each line in region." 74 :group 'LilyPond 75 :type 'string) 76 77 (defun LilyPond-comment-region (beg-region end-region) 78 "Comment/uncomment every line in the region. 79 Insert LilyPond-comment-region at the beginning of every line in the region 80 or, if already present, remove it." 81 (interactive "*r") 82 (let ((end (make-marker))) 83 (set-marker end end-region) 84 (goto-char beg-region) 85 (beginning-of-line) 86 (if (looking-at (regexp-quote LilyPond-comment-region)) 87 (delete-region (point) (match-end 0)) 88 (insert LilyPond-comment-region)) 89 (while (and (zerop (forward-line 1)) 90 (< (point) (marker-position end))) 91 (if (looking-at (regexp-quote LilyPond-comment-region)) 92 (delete-region (point) (match-end 0)) 93 (insert LilyPond-comment-region))) 94 (set-marker end nil))) 95 96 (defun LilyPond-calculate-indent () 97 "Return appropriate indentation for current line as lilypond code. 98 In usual case returns an integer: the column to indent to. 99 Returns nil if line starts inside a string" 100 (save-excursion 101 (beginning-of-line) 102 (let ((indent-point (point)) 103 (case-fold-search nil) 104 state) 105 (setq containing-sexp (save-excursion (LilyPond-scan-containing-sexp))) 106 (beginning-of-defun) 107 (while (< (point) indent-point) 108 (setq state (parse-partial-sexp (point) indent-point 0))) 109 ;; (setq containing-sexp (car (cdr state))) is the traditional way for languages 110 ;; with simpler parenthesis delimiters 111 (cond ((nth 3 state) 112 ;; point is in the middle of a string 113 nil) 114 ((nth 4 state) 115 ;; point is in the middle of a block comment 116 (LilyPond-calculate-indent-within-blockcomment)) 117 ((null containing-sexp) 118 ;; Line is at top level - no indent 119 (beginning-of-line) 120 0) 121 (t 122 ;; Find previous non-comment character. 123 (goto-char indent-point) 124 (LilyPond-backward-to-noncomment containing-sexp) 125 ;; Now we get the answer. 126 ;; Position following last unclosed open. 127 (goto-char containing-sexp) 128 (or 129 ;; Is line first statement after an open brace or bracket? 130 ;; If no, find that first statement and indent like it. 131 (save-excursion 132 (forward-char 1) 133 ;; Skip over comments following open brace. 134 (skip-chars-forward " \t\n") 135 (cond ((looking-at "%{") 136 (while (progn 137 (and (not (looking-at "%}")) 138 (< (point) (point-max)))) 139 (forward-line 1) 140 (skip-chars-forward " \t\n")) 141 (forward-line 1) 142 (skip-chars-forward " \t\n")) 143 ((looking-at "%") 144 (while (progn (skip-chars-forward " \t\n") 145 (looking-at "%")) 146 (forward-line 1)))) 147 ;; The first following code counts 148 ;; if it is before the line we want to indent. 149 (and (< (point) indent-point) 150 (current-column))) 151 ;; If no previous statement, 152 ;; indent it relative to line brace is on. 153 ;; For open brace in column zero, don't let statement 154 ;; start there too. If LilyPond-indent-level is zero, use 155 ;; LilyPond-brace-offset instead 156 (+ (if (and (bolp) (zerop LilyPond-indent-level)) 157 (cond ((= (following-char) ?{) 158 LilyPond-brace-offset) 159 ((= (following-char) ?<) 160 LilyPond-angle-offset) 161 ((= (following-char) ?\[) 162 LilyPond-square-offset) 163 ((= (following-char) ?\)) 164 LilyPond-scheme-paren-offset) 165 (t 166 0)) 167 LilyPond-indent-level) 168 (progn 169 (skip-chars-backward " \t") 170 (current-indentation))))))))) 171 172 173 (defun LilyPond-indent-line () 174 "Indent current line as lilypond code. 175 Return the amount the indentation changed by." 176 (let ((indent (LilyPond-calculate-indent)) 177 beg shift-amt 178 (case-fold-search nil) 179 (pos (- (point-max) (point)))) 180 (beginning-of-line) 181 (setq beg (point)) 182 (cond ((eq indent nil) 183 (setq indent (current-indentation))) 184 (t 185 (skip-chars-forward " \t") 186 (if (and LilyPond-fancy-comments (looking-at "%%%\\|%{\\|%}")) 187 (setq indent 0)) 188 (if (and LilyPond-fancy-comments 189 (looking-at "%") 190 (not (looking-at "%%\\|%{\\|%}"))) 191 (setq indent comment-column) 192 (if (eq indent t) (setq indent 0)) 193 (if (listp indent) (setq indent (car indent))) 194 (cond 195 ((= (following-char) ?}) 196 (setq indent (+ indent (- LilyPond-close-brace-offset LilyPond-indent-level)))) 197 ((= (following-char) ?>) 198 (setq indent (+ indent (- LilyPond-close-angle-offset LilyPond-indent-level)))) 199 ((= (following-char) ?\]) 200 (setq indent (+ indent (- LilyPond-close-square-offset LilyPond-indent-level)))) 201 ((and (= (following-char) ?\)) (LilyPond-inside-scheme-p)) 202 (setq indent (+ indent (- LilyPond-close-scheme-paren-offset LilyPond-indent-level)))) 203 ((= (following-char) ?{) 204 (setq indent (+ indent LilyPond-brace-offset))) 205 ((= (following-char) ?<) 206 (setq indent (+ indent LilyPond-angle-offset))) 207 ((= (following-char) ?\[) 208 (setq indent (+ indent LilyPond-square-offset))) 209 ((and (= (following-char) ?\() (LilyPond-inside-scheme-p)) 210 (setq indent (+ indent LilyPond-scheme-paren-offset))))))) 211 (skip-chars-forward " \t") 212 (setq shift-amt (- indent (current-column))) 213 (if (zerop shift-amt) 214 (if (> (- (point-max) pos) (point)) 215 (goto-char (- (point-max) pos))) 216 (delete-region beg (point)) 217 (indent-to indent) 218 ;; If initial point was within line's indentation, 219 ;; position after the indentation. 220 ;; Else stay at same point in text. 221 (if (> (- (point-max) pos) (point)) 222 (goto-char (- (point-max) pos)))) 223 shift-amt)) 224 225 226 (defun LilyPond-inside-comment-p () 227 "Return non-nil if point is inside a line or block comment" 228 (setq this-point (point)) 229 (or (save-excursion (beginning-of-line) 230 (skip-chars-forward " \t") 231 (looking-at "%")) 232 (save-excursion 233 ;; point is in the middle of a block comment 234 (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" (point-min) t))) 235 (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" (point-min) t))) 236 (if (or (and (= (char-before) ?%) (= (char-after) ?{)) 237 (and (= (char-after) ?%) (= (char-after (1+ (point))) ?{))) 238 (setq lastopen (save-excursion (backward-char) (point)))) 239 (and 240 lastopen 241 (or (not lastclose) 242 (<= lastclose lastopen)))))) 243 244 245 (defun LilyPond-inside-string-or-comment-p () 246 "Test if point is inside a string or a comment" 247 (setq this-point (point)) 248 (or (save-excursion (beginning-of-line) 249 (skip-chars-forward " \t") 250 (looking-at "%")) 251 (save-excursion 252 (beginning-of-defun) 253 (while (< (point) this-point) 254 (setq state (parse-partial-sexp (point) this-point 0))) 255 (cond ((nth 3 state) 256 ;; point is in the middle of a string 257 t ) 258 ((nth 4 state) 259 ;; point is in the middle of a block comment 260 t ) 261 (t 262 nil))))) 263 264 265 (defun LilyPond-backward-over-blockcomments (lim) 266 "Move point back to closest non-whitespace character not part of a block comment" 267 (setq lastopen (save-excursion (re-search-backward "%{[ \\t]*" lim t))) 268 (setq lastclose (save-excursion (re-search-backward "%}[ \\t]*" lim t))) 269 (if lastopen 270 (if lastclose 271 (if (<= lastclose lastopen) 272 (goto-char lastopen)) 273 (goto-char lastopen))) 274 (skip-chars-backward " %\t\n\f")) 275 276 277 (defun LilyPond-backward-over-linecomments (lim) 278 "Move point back to the closest non-whitespace character not part of a line comment. 279 Argument LIM limit." 280 (let (opoint stop) 281 (while (not stop) 282 (skip-chars-backward " \t\n\f" lim) 283 (setq opoint (point)) 284 (beginning-of-line) 285 (search-forward "%" opoint 'move) 286 (skip-chars-backward " \t%") 287 (setq stop (or (/= (preceding-char) ?\n) (<= (point) lim))) 288 (if stop (point) 289 (beginning-of-line))))) 290 291 292 (defun LilyPond-backward-to-noncomment (lim) 293 "Move point back to closest non-whitespace character not part of a comment" 294 (LilyPond-backward-over-linecomments lim) 295 (LilyPond-backward-over-blockcomments lim)) 296 297 298 (defun LilyPond-calculate-indent-within-blockcomment () 299 "Return the indentation amount for line inside a block comment." 300 (let (end percent-start) 301 (save-excursion 302 (beginning-of-line) 303 (skip-chars-forward " \t") 304 (skip-chars-backward " \t\n") 305 (setq end (point)) 306 (beginning-of-line) 307 (skip-chars-forward " \t") 308 (and (re-search-forward "%{[ \t]*" end t) 309 (goto-char (1+ (match-beginning 0)))) 310 (if (and (looking-at "[ \t]*$") (= (preceding-char) ?\%)) 311 (1+ (current-column)) 312 (current-column))))) 313 314 315 ;; Key: Type of bracket (character). 316 ;; Value: Pair of regexps representing the corresponding open and close bracket 317 ;; () are treated specially (need to indent in Scheme but not in music) 318 319 (defconst LilyPond-parens-regexp-alist 320 `( ( ?> . ("\\([^\\]\\|^\\)<" . "\\([^ \\n\\t_^-]\\|[_^-][-^]\\|\\s-\\)\\s-*>")) 321 ;; a b c->, a b c^> and a b c_> are not close-angle-brackets, they're accents 322 ;; but a b c^-> and a b c^^> are close brackets with tenuto/marcato before them 323 ;; also \> and \< are hairpins 324 ;; duh .. a single '>', as in chords '<< ... >>', was not matched here 325 ( ?} . ("{" . "}")) 326 ;; ligatures '\[ ... \]' are skipped in the following expression 327 ( ?\] . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)[[]" . "\\([^\\]\\([\\][\\]\\)*\\|^\\)[]]")) 328 ( "\\]" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][[]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][]]")) 329 ( "\\)" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][(]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][)]")))) 330 331 332 (defconst LilyPond-parens-alist 333 `( ( ?< . ?> ) 334 ( ?{ . ?} ) 335 ( ?\[ . ?\] ) 336 ( "\\[" . "\\]" ) 337 ( ?\( . ?\) ) 338 ( "\\(" . "\\)" ))) 339 340 341 (defun LilyPond-matching-paren (bracket-type) 342 "Returns the open corresponding to the close specified by bracket-type, or vice versa" 343 (cond ((member bracket-type (mapcar 'car LilyPond-parens-alist)) 344 (cdr (assoc bracket-type LilyPond-parens-alist)) ) 345 ((member bracket-type (mapcar 'cdr LilyPond-parens-alist)) 346 (car (rassoc bracket-type LilyPond-parens-alist)) ) 347 nil)) 348 349 350 (defun LilyPond-scan-containing-sexp (&optional bracket-type slur-paren-p dir) 351 "Move point to the beginning of the deepest parenthesis pair enclosing point. 352 353 If the optional argument bracket-type, a character representing a 354 close bracket such as ) or }, is specified, then the parenthesis pairs 355 searched are limited to this type. 356 357 If the optional argument slur-paren-p is non-nil, then slur 358 parentheses () are considered as matching pairs. Otherwise Scheme 359 parentheses are considered to be matching pairs, but slurs are not. 360 slur-paren-p defaults to nil. 361 " 362 ;;; An user does not call this function directly, or by a key sequence. 363 ;; (interactive) 364 (let ( (level (if (not (eq dir 1)) 1 -1)) 365 (regexp-alist LilyPond-parens-regexp-alist) 366 (oldpos (point)) 367 (assoc-bracket-type (if (not (eq dir 1)) bracket-type (LilyPond-matching-paren bracket-type)))) 368 369 (if (LilyPond-inside-scheme-p) 370 (setq paren-regexp "(\\|)") 371 (if slur-paren-p 372 ;; expressional slurs '\( ... \)' are not taken into account 373 (setq regexp-alist (cons '( ?\) . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)(" . "\\([^\\]\\([\\][\\]\\)*\\|^\\))")) regexp-alist))) 374 (if (member assoc-bracket-type (mapcar 'car regexp-alist)) 375 (progn (setq paren-regexp (cdr (assoc assoc-bracket-type regexp-alist))) 376 (setq paren-regexp (concat (car paren-regexp) "\\|" (cdr paren-regexp)))) 377 (setq paren-regexp (concat (mapconcat 'car (mapcar 'cdr regexp-alist) "\\|") "\\|" 378 (mapconcat 'cdr (mapcar 'cdr regexp-alist) "\\|"))))) 379 ;; match concurrent one-char opening and closing slurs 380 (if (and (eq dir 1) 381 (not (sequencep bracket-type)) 382 (eq (char-syntax (or (char-after oldpos) 0)) ?\() 383 (not (eq (char-after oldpos) ?<))) 384 ;; anyway do not count open slur, since already level = -1 385 (progn (forward-char 1) 386 (if (eq (following-char) 387 (LilyPond-matching-paren (char-after oldpos))) 388 ;; matching char found, go after it and set level = 0 389 (progn (forward-char 1) 390 (setq level 0))))) 391 ;; browse the code until matching slur is found, or report mismatch 392 (while (and (if (not (eq dir 1)) 393 (> level 0) 394 (< level 0)) 395 ;; dir tells whether to search backward or forward 396 (if (not (eq dir 1)) 397 (re-search-backward paren-regexp nil t) 398 (re-search-forward paren-regexp nil t)) 399 ;; note: in case of two-char bracket only latter is compared 400 (setq match (char-before (match-end 0)))) 401 ;;; (message "%d" level) (sit-for 0 300) 402 (if (not (save-excursion (goto-char (match-end 0)) 403 ;; skip over strings and comments 404 (LilyPond-inside-string-or-comment-p))) 405 (if (memq match '(?} ?> ?\] ?\))) 406 ;; count closing brackets 407 (progn (setq level (1+ level)) 408 ;; slurs may be close to each other, e.g., 409 ;; a single '>' was not matched .. need to be corrected 410 (if (and (eq dir 1) (eq (char-after (match-end 0)) match)) 411 (if (/= level 0) 412 (progn 413 (setq level (1+ level)) 414 (forward-char 1)))) 415 ;;; (message "%d %c" level match) (sit-for 0 300) 416 ;; hmm.. 417 (if (and (= match ?>) 418 (looking-at ".\\s-+>\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)>")) 419 (forward-char 1))) 420 ;; count opening brackets 421 (progn (setq level (1- level)) 422 ;;; (message "%d %c" level match) (sit-for 0 300) 423 ;; hmm.. 424 (if (and (= match ?<) 425 (looking-at ".\\s-+<\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)<")) 426 (forward-char 1)))))) 427 ;; jump to the matching slur 428 (if (not (eq dir 1)) 429 (progn 430 (if (sequencep bracket-type) 431 ;; match the latter char in two-char brackets 432 (if (looking-at "..[][)(]") (forward-char 1))) 433 ;; if the following char is not already a slur 434 (if (and (not (looking-at "[)(]")) 435 ;; match the slur which follows 436 (looking-at ".[][><)(]")) (forward-char 1))) 437 (backward-char 1)) 438 (if (= level 0) 439 (point) 440 (progn (goto-char oldpos) 441 nil)))) 442 443 444 (defun LilyPond-inside-scheme-p () 445 "Tests if point is inside embedded Scheme code" 446 ;;; An user does not call this function directly, or by a key sequence. 447 ;; (interactive) 448 (let ( (test-point (point)) 449 (level 0) ) 450 (save-excursion 451 (if (or (and (eq (char-after (point)) ?\() 452 (save-excursion 453 (skip-chars-backward "'`") 454 (memq (char-before) '(?# ?$)))) 455 (and (re-search-backward "[#$][`']?(" nil t) 456 (progn 457 (search-forward "(") 458 (setq level 1) 459 (while (and (> level 0) 460 (re-search-forward "[()]" test-point t) 461 (setq match (char-after (match-beginning 0))) 462 (<= (point) test-point)) 463 (if (= match ?\() 464 (setq level (1+ level)) 465 (setq level (1- level)))) 466 (> level 0)))) 467 t 468 nil)))) 469 470 471 ;;; Largely taken from the 'blink-matching-open' in lisp/simple.el in 472 ;;; the Emacs distribution. 473 474 (defun LilyPond-blink-matching-paren (&optional dir) 475 "Move cursor momentarily to the beginning of the sexp before 476 point. In lilypond files this is used for closing ), ], } and >, whereas the 477 builtin 'blink-matching-open' is not used. In syntax table, see 478 `lilypond-font-lock.el', all brackets are punctuation characters." 479 ;;; An user does not call this function directly, or by a key sequence. 480 ;; (interactive) 481 (let ( (oldpos (point)) 482 (level 0) 483 (mismatch) ) 484 (if (not (or (equal this-command 'LilyPond-electric-close-paren) 485 (eq dir 1))) 486 (goto-char (setq oldpos (- oldpos 1)))) 487 ;; Test if a ligature \] or expressional slur \) was encountered 488 (setq bracket-type (char-after (point))) 489 (setq char-before-bracket-type nil) 490 (if (memq bracket-type '(?\] ?\) ?\[ ?\()) 491 (progn 492 (setq np -1) 493 (while (eq (char-before (- (point) (setq np (+ np 1)))) ?\\) 494 (setq char-before-bracket-type (if char-before-bracket-type nil ?\\))) 495 (if (eq char-before-bracket-type ?\\) 496 (setq bracket-type (string char-before-bracket-type bracket-type))))) 497 (when blink-matching-paren-distance 498 (narrow-to-region 499 (max (point-min) (- (point) blink-matching-paren-distance)) 500 (min (point-max) (+ (point) blink-matching-paren-distance)))) 501 (if (and (equal this-command 'LilyPond-electric-close-paren) 502 (memq bracket-type '(?> ?} ?< ?{))) 503 ;; < { need to be mutually balanced and nested, so search backwards for both of these bracket types 504 (LilyPond-scan-containing-sexp nil nil dir) 505 ;; whereas ( ) slurs within music don't, so only need to search for ( ) 506 ;; use same mechanism for [ ] slurs 507 (LilyPond-scan-containing-sexp bracket-type t dir)) 508 (setq blinkpos (point)) 509 (setq mismatch 510 (or (null (LilyPond-matching-paren (char-after blinkpos))) 511 (/= (char-after oldpos) 512 (LilyPond-matching-paren (char-after blinkpos))))) 513 (if mismatch (progn (setq blinkpos nil) 514 (message "Mismatched parentheses"))) 515 (if (and blinkpos 516 (equal this-command 'LilyPond-electric-close-paren)) 517 (if (pos-visible-in-window-p) 518 (and blink-matching-paren-on-screen 519 (sit-for blink-matching-delay)) 520 (message 521 "Matches %s" 522 ;; Show what precedes the open in its line, if anything. 523 (if (save-excursion 524 (skip-chars-backward " \t") 525 (not (bolp))) 526 (buffer-substring (progn (beginning-of-line) (point)) 527 (1+ blinkpos)) 528 ;; Show what follows the open in its line, if anything. 529 (if (save-excursion 530 (forward-char 1) 531 (skip-chars-forward " \t") 532 (not (eolp))) 533 (buffer-substring blinkpos 534 (progn (end-of-line) (point))) 535 ;; Otherwise show the previous nonblank line, 536 ;; if there is one. 537 (if (save-excursion 538 (skip-chars-backward "\n \t") 539 (not (bobp))) 540 (concat 541 (buffer-substring (progn 542 (skip-chars-backward "\n \t") 543 (beginning-of-line) 544 (point)) 545 (progn (end-of-line) 546 (skip-chars-backward " \t") 547 (point))) 548 ;; Replace the newline and other whitespace with `...'. 549 "..." 550 (buffer-substring blinkpos (1+ blinkpos))) 551 ;; There is nothing to show except the char itself. 552 (buffer-substring blinkpos (1+ blinkpos)))))))) 553 (if (not (equal this-command 'LilyPond-electric-close-paren)) 554 (goto-char (setq oldpos (+ oldpos 1))) 555 (goto-char oldpos)) 556 (if (not (eq dir 1)) 557 blinkpos 558 (+ blinkpos 1)))) 559 560 561 (defun LilyPond-electric-close-paren () 562 "Blink on the matching open paren when a >, ), } or ] is inserted" 563 (interactive) 564 (let ((oldpos (point))) 565 (self-insert-command 1) 566 ;; Refontify buffer if a block-comment-ender '%}' is inserted 567 (if (and (eq (char-before (point)) ?}) 568 (eq (char-before (- (point) 1)) ?%)) 569 (font-lock-fontify-buffer) 570 ;; Match paren if the cursor is not inside string or comment. 571 (if (and blink-matching-paren 572 (not (LilyPond-inside-string-or-comment-p)) 573 (save-excursion (re-search-backward 574 (concat (mapconcat 'cdr (mapcar 'cdr LilyPond-parens-regexp-alist) "\\|") "\\|)") nil t) 575 (eq oldpos (1- (match-end 0))))) 576 (progn (backward-char 1) 577 (LilyPond-blink-matching-paren) 578 (forward-char 1)))))) 579 580 (defun LilyPond-scan-sexps (pos dir) 581 "This function is redefined to be used in Emacs' show-paren-function and 582 in XEmacs' paren-highlight." 583 (LilyPond-blink-matching-paren dir))