lilypond-mode

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

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))