;;; Variables for customising indentation style
+;;; TODO:
+;;; * emulate show-paren-mode, i.e., highlight the matching bracket if
+;;; - the cursor is on the matching opening bracket
+;;; - the cursor is after the matching closing bracket
+;;; * separate '('- and ')'-slurs from '\('- and '\)'-slurs.
+;;; * separate '['- and ']'-slurs from '\['- and '\]'-slurs.
+
(defcustom LilyPond-indent-level 4
"*Indentation of lilypond statements with respect to containing block.")
"*Extra indentation for open angled brackets .
Compares with other text in same context.")
+(defcustom LilyPond-square-offset 0
+ "*Extra indentation for open square brackets .
+Compares with other text in same context.")
+
(defcustom LilyPond-scheme-paren-offset 0
"*Extra indentation for open scheme parens .
Compares with other text in same context.")
(defcustom LilyPond-close-angle-offset 0
"*Extra indentation for closing angle brackets.")
+(defcustom LilyPond-close-square-offset 0
+ "*Extra indentation for closing square brackets.")
+
(defcustom LilyPond-close-scheme-paren-offset 0
"*Extra indentation for closing scheme parens.")
LilyPond-brace-offset)
((= (following-char) ?<)
LilyPond-angle-offset)
+ ((= (following-char) ?[)
+ LilyPond-square-offset)
((= (following-char) ?\))
LilyPond-scheme-paren-offset)
(t
(setq indent (+ indent (- LilyPond-close-brace-offset LilyPond-indent-level))))
((= (following-char) ?>)
(setq indent (+ indent (- LilyPond-close-angle-offset LilyPond-indent-level))))
+ ((= (following-char) ?])
+ (setq indent (+ indent (- LilyPond-close-square-offset LilyPond-indent-level))))
((and (= (following-char) ?\)) (LilyPond-inside-scheme-p))
(setq indent (+ indent (- LilyPond-close-scheme-paren-offset LilyPond-indent-level))))
((= (following-char) ?{)
(setq indent (+ indent LilyPond-brace-offset)))
((= (following-char) ?<)
(setq indent (+ indent LilyPond-angle-offset)))
+ ((= (following-char) ?[)
+ (setq indent (+ indent LilyPond-square-offset)))
((and (= (following-char) ?\() (LilyPond-inside-scheme-p))
(setq indent (+ indent LilyPond-scheme-paren-offset)))
))))
;; Key: Type of bracket (character).
-;; Value: Pair of regexps representing the corresponding open and close bracket"
-;; () are treated specially (need to indent in Scheme but not in music), and []
-;; are handled by the syntax table
+;; Value: Pair of regexps representing the corresponding open and close bracket
+;; () are treated specially (need to indent in Scheme but not in music)
(defconst LilyPond-parens-regexp-alist
- `( ( ?> . ("[^\\]<" . "[^ \\n\\t_^-]\\s-*>\\|[_^-]\\s-*[-^]\\s-*>"))
+ `( ( ?> . ("\\([^\\]\\|^\\)<" . "[^ \\n\\t_^-]\\s-*>\\|[_^-]\\s-*[-^]\\s-*>"))
;; a b c->, a b c^> and a b c_> are not close-angle-brackets, they're accents
;; but a b c^-> and a b c^^> are close brackets with tenuto/marcato before them
;; also \> and \< are hairpins
( ?} . ("{" . "}"))
+ ;; ligatures '\[ ... \]' are skipped in the following expression
+ ( ?] . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)[[]" . "\\([^\\]\\([\\][\\]\\)*\\|^\\)[]]"))
+ ;; ( "\\]" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][[]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][]]"))
+ ;; ( "\\)" . ("\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][(]" . "\\([^\\]\\|^\\)\\([\\][\\]\\)*[\\][)]"))
))
(defconst LilyPond-parens-alist
`( ( ?< . ?> )
( ?{ . ?} )
+ ( ?[ . ?] )
+ ( "\\[" . "\\]" )
( ?\( . ?\) )
+ ( "\\(" . "\\)" )
))
(defun LilyPond-matching-paren (bracket-type)
"Returns the open corresponding to the close specified by bracket-type, or vice versa"
- (cond ( (memq bracket-type (mapcar 'car LilyPond-parens-alist))
+ (cond ( (member bracket-type (mapcar 'car LilyPond-parens-alist))
(cdr (assoc bracket-type LilyPond-parens-alist)) )
- ( (memq bracket-type (mapcar 'cdr LilyPond-parens-alist))
+ ( (member bracket-type (mapcar 'cdr LilyPond-parens-alist))
(car (rassoc bracket-type LilyPond-parens-alist)) )
nil))
parentheses are considered to be matching pairs, but slurs are not.
slur-paren-p defaults to nil.
"
- (interactive)
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
(let ( (level 1)
(regexp-alist LilyPond-parens-regexp-alist)
(oldpos (point) ) )
(if (LilyPond-inside-scheme-p)
(setq paren-regexp "(\\|)")
(if slur-paren-p
- (setq regexp-alist (cons '( ?\) . ("(" . ")")) regexp-alist)))
- (if (memq bracket-type (mapcar 'car regexp-alist))
+ ;; expressional slurs '\( ... \)' are not taken into account
+ (setq regexp-alist (cons '( ?\) . ("\\([^\\]\\([\\][\\]\\)*\\|^\\)(" . "\\([^\\]\\([\\][\\]\\)*\\|^\\))")) regexp-alist)))
+ (if (member bracket-type (mapcar 'car regexp-alist))
(progn (setq paren-regexp (cdr (assoc bracket-type regexp-alist)))
(setq paren-regexp (concat (car paren-regexp) "\\|" (cdr paren-regexp))))
(setq paren-regexp (concat (mapconcat 'car (mapcar 'cdr regexp-alist) "\\|") "\\|"
(setq match (char-before (match-end 0))))
(if (not (save-excursion (goto-char (match-end 0))
(LilyPond-inside-string-or-comment-p)))
- (if (memq match '(?} ?> ?\)))
+ (if (memq match '(?} ?> ?] ?\)))
(progn (setq level (1+ level))
(if (and (= match ?>)
- (looking-at ".\\s-+>\\|\\({\\|}\\|<\\|>\\|(\\|)\\)>"))
+ (looking-at ".\\s-+>\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)>"))
(forward-char 1)))
(progn (setq level (1- level))
(if (and (= match ?<)
- (looking-at ".\\s-+<\\|\\({\\|}\\|<\\|>\\|(\\|)\\)<"))
+ (looking-at ".\\s-+<\\|\\({\\|}\\|<\\|>\\|(\\|)\\|[][]\\)<"))
(forward-char 1))))))
- (if (looking-at ".<\\|.>") (forward-char 1))
+ ;; somehow here two-char brackets \<, \>, \[, \], \(, \) are handled
+ (if (looking-at ".<\\|.>\\|.[][)(]") (forward-char 1))
(if (= level 0)
(point)
(progn (goto-char oldpos)
(defun LilyPond-inside-scheme-p ()
"Tests if point is inside embedded Scheme code"
- (interactive)
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
(let ( (test-point (point))
(level 0) )
(save-excursion
(defun LilyPond-blink-matching-open (bracket-type)
"Move cursor momentarily to the beginning of the sexp before
-point. In lilypond files this is used for closing ), } and >, whereas the
-builtin 'blink-matching-open' is used for closing ], which is in
-the syntax table"
- (interactive)
+point. In lilypond files this is used for closing ), ], } and >, whereas the
+builtin 'blink-matching-open' is not used. In syntax table, see
+`lilypond-font-lock.el', all brackets are punctuation characters."
+;;; An user does not call this function directly, or by a key sequence.
+ ;; (interactive)
(let ( (oldpos (point))
(level 0)
(mismatch) )
+ ;; Test if a ligature \] or expressional slur \) was encountered;
+ ;; the result is now in backslashed-close-char, BUT
+ ;; the result should also be used -- match also \] or \) !
+ ;; Thus, update: LilyPond-parens-regexp-alist, LilyPond-blink-matching-open
+ (setq char-before-bracket-type nil)
+ (if (memq close-char '(?] ?\)))
+ (progn
+ (setq np -1)
+ (while (eq (char-before (- (point) (setq np (+ np 1)))) ?\\)
+ (setq char-before-bracket-type (if char-before-bracket-type nil ?\\)))))
+ (if (eq char-before-bracket-type ?\\)
+ (if (eq bracket-type ?])
+ (message "trying to match ligatures \\[ ... \\]")
+ (message "trying to match slurs \\( ... \\)")))
(save-restriction
(if blink-matching-paren-distance
(narrow-to-region (max (point-min)
(- (point) blink-matching-paren-distance))
oldpos)))
- (if (memq bracket-type '(?> ?}))
- ;; < { need to be mutually balanced and nested, so search backwards for both of these bracket types
+ (if (memq bracket-type '(?> ?} ?]))
+ ;; < { [ need to be mutually balanced and nested, so search backwards for both of these bracket types
(LilyPond-beginning-of-containing-sexp nil nil)
;; whereas ( ) slurs within music don't, so only need to search for ( )
(LilyPond-beginning-of-containing-sexp bracket-type t))
(defun LilyPond-electric-close-paren ()
- "Blink on the matching open paren when a > or ) is inserted"
+ "Blink on the matching open paren when a >, ), } or ] is inserted"
(interactive)
(let ((oldpos (point)))
(self-insert-command 1)
(progn (backward-char 1)
(LilyPond-blink-matching-open close-char)
(forward-char 1)))))
-
-
-;;; TODO:
-;;; emulate show-paren-mode