New file.
[bpt/emacs.git] / lisp / paren.el
... / ...
CommitLineData
1;;; paren.el --- highlight matching paren
2
3;; Copyright (C) 1993, 1996, 2001, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
5
6;; Author: rms@gnu.org
7;; Maintainer: FSF
8;; Keywords: languages, faces
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
26
27;;; Commentary:
28
29;; Put this into your ~/.emacs:
30
31;; (show-paren-mode t)
32
33;; It will display highlighting on whatever paren matches the one
34;; before or after point.
35
36;;; Code:
37
38(defgroup paren-showing nil
39 "Showing (un)matching of parens and expressions."
40 :prefix "show-paren-"
41 :group 'paren-matching)
42
43;; This is the overlay used to highlight the matching paren.
44(defvar show-paren-overlay nil)
45;; This is the overlay used to highlight the closeparen right before point.
46(defvar show-paren-overlay-1 nil)
47
48(defcustom show-paren-style 'parenthesis
49 "*Style used when showing a matching paren.
50Valid styles are `parenthesis' (meaning show the matching paren),
51`expression' (meaning show the entire expression enclosed by the paren) and
52`mixed' (meaning show the matching paren if it is visible, and the expression
53otherwise)."
54 :type '(choice (const parenthesis) (const expression) (const mixed))
55 :group 'paren-showing)
56
57(defcustom show-paren-delay
58 (if (featurep 'lisp-float-type) (/ (float 1) (float 8)) 1)
59 "*Time in seconds to delay before showing a matching paren."
60 :type '(number :tag "seconds")
61 :group 'paren-showing)
62
63(defcustom show-paren-priority 1000
64 "*Priority of paren highlighting overlays."
65 :type 'integer
66 :group 'paren-showing
67 :version "21.1")
68
69(defcustom show-paren-ring-bell-on-mismatch nil
70 "*If non-nil, beep if mismatched paren is detected."
71 :type 'boolean
72 :group 'paren-showing
73 :version "20.3")
74
75(defface show-paren-match
76 '((((class color) (background light))
77 :background "turquoise") ; looks OK on tty (becomes cyan)
78 (((class color) (background dark))
79 :background "steelblue3") ; looks OK on tty (becomes blue)
80 (((background dark))
81 :background "grey50")
82 (t
83 :background "gray"))
84 "Show Paren mode face used for a matching paren."
85 :group 'faces
86 :group 'paren-showing)
87;; backward-compatibility alias
88(put 'show-paren-match-face 'face-alias 'show-paren-match)
89
90(defface show-paren-mismatch
91 '((((class color)) (:foreground "white" :background "purple"))
92 (t (:inverse-video t)))
93 "Show Paren mode face used for a mismatching paren."
94 :group 'faces
95 :group 'paren-showing)
96;; backward-compatibility alias
97(put 'show-paren-mismatch-face 'face-alias 'show-paren-mismatch)
98
99(defvar show-paren-highlight-openparen t
100 "*Non-nil turns on openparen highlighting when matching forward.")
101
102(defvar show-paren-idle-timer nil)
103
104;;;###autoload
105(define-minor-mode show-paren-mode
106 "Toggle Show Paren mode.
107With prefix ARG, turn Show Paren mode on if and only if ARG is positive.
108Returns the new status of Show Paren mode (non-nil means on).
109
110When Show Paren mode is enabled, any matching parenthesis is highlighted
111in `show-paren-style' after `show-paren-delay' seconds of Emacs idle time."
112 :global t :group 'paren-showing
113 ;; Turn off the usual paren-matching method
114 ;; when this one is turned on.
115 (if (local-variable-p 'show-paren-mode)
116 (make-local-variable 'blink-matching-paren-on-screen)
117 (kill-local-variable 'blink-matching-paren-on-screen))
118 (setq blink-matching-paren-on-screen (not show-paren-mode))
119
120 ;; Now enable or disable the mechanism.
121 ;; First get rid of the old idle timer.
122 (if show-paren-idle-timer
123 (cancel-timer show-paren-idle-timer))
124 (setq show-paren-idle-timer nil)
125 ;; If show-paren-mode is enabled in some buffer now,
126 ;; set up a new timer.
127 (when (memq t (mapcar (lambda (buffer)
128 (with-current-buffer buffer
129 show-paren-mode))
130 (buffer-list)))
131 (setq show-paren-idle-timer (run-with-idle-timer
132 show-paren-delay t
133 'show-paren-function)))
134 (unless show-paren-mode
135 (and show-paren-overlay
136 (eq (overlay-buffer show-paren-overlay) (current-buffer))
137 (delete-overlay show-paren-overlay))
138 (and show-paren-overlay-1
139 (eq (overlay-buffer show-paren-overlay-1) (current-buffer))
140 (delete-overlay show-paren-overlay-1))))
141
142;; Find the place to show, if there is one,
143;; and show it until input arrives.
144(defun show-paren-function ()
145 (if show-paren-mode
146 (let ((oldpos (point))
147 (dir (cond ((eq (syntax-class (syntax-after (1- (point)))) 5) -1)
148 ((eq (syntax-class (syntax-after (point))) 4) 1)))
149 pos mismatch face)
150 ;;
151 ;; Find the other end of the sexp.
152 (when dir
153 (save-excursion
154 (save-restriction
155 ;; Determine the range within which to look for a match.
156 (when blink-matching-paren-distance
157 (narrow-to-region
158 (max (point-min) (- (point) blink-matching-paren-distance))
159 (min (point-max) (+ (point) blink-matching-paren-distance))))
160 ;; Scan across one sexp within that range.
161 ;; Errors or nil mean there is a mismatch.
162 (condition-case ()
163 (setq pos (scan-sexps (point) dir))
164 (error (setq pos t mismatch t)))
165 ;; Move back the other way and verify we get back to the
166 ;; starting point. If not, these two parens don't really match.
167 ;; Maybe the one at point is escaped and doesn't really count.
168 (when (integerp pos)
169 (unless (condition-case ()
170 (eq (point) (scan-sexps pos (- dir)))
171 (error nil))
172 (setq pos nil)))
173 ;; If found a "matching" paren, see if it is the right
174 ;; kind of paren to match the one we started at.
175 (when (integerp pos)
176 (let ((beg (min pos oldpos)) (end (max pos oldpos)))
177 (unless (eq (syntax-class (syntax-after beg)) 8)
178 (setq mismatch
179 (not (or (eq (char-before end)
180 ;; This can give nil.
181 (cdr (syntax-after beg)))
182 (eq (char-after beg)
183 ;; This can give nil.
184 (cdr (syntax-after (1- end)))))))))))))
185 ;;
186 ;; Highlight the other end of the sexp, or unhighlight if none.
187 (if (not pos)
188 (progn
189 ;; If not at a paren that has a match,
190 ;; turn off any previous paren highlighting.
191 (and show-paren-overlay (overlay-buffer show-paren-overlay)
192 (delete-overlay show-paren-overlay))
193 (and show-paren-overlay-1 (overlay-buffer show-paren-overlay-1)
194 (delete-overlay show-paren-overlay-1)))
195 ;;
196 ;; Use the correct face.
197 (if mismatch
198 (progn
199 (if show-paren-ring-bell-on-mismatch
200 (beep))
201 (setq face 'show-paren-mismatch))
202 (setq face 'show-paren-match))
203 ;;
204 ;; If matching backwards, highlight the closeparen
205 ;; before point as well as its matching open.
206 ;; If matching forward, and the openparen is unbalanced,
207 ;; highlight the paren at point to indicate misbalance.
208 ;; Otherwise, turn off any such highlighting.
209 (if (and (not show-paren-highlight-openparen) (= dir 1) (integerp pos))
210 (when (and show-paren-overlay-1
211 (overlay-buffer show-paren-overlay-1))
212 (delete-overlay show-paren-overlay-1))
213 (let ((from (if (= dir 1)
214 (point)
215 (forward-point -1)))
216 (to (if (= dir 1)
217 (forward-point 1)
218 (point))))
219 (if show-paren-overlay-1
220 (move-overlay show-paren-overlay-1 from to (current-buffer))
221 (setq show-paren-overlay-1 (make-overlay from to)))
222 ;; Always set the overlay face, since it varies.
223 (overlay-put show-paren-overlay-1 'priority show-paren-priority)
224 (overlay-put show-paren-overlay-1 'face face)))
225 ;;
226 ;; Turn on highlighting for the matching paren, if found.
227 ;; If it's an unmatched paren, turn off any such highlighting.
228 (unless (integerp pos)
229 (delete-overlay show-paren-overlay))
230 (let ((to (if (or (eq show-paren-style 'expression)
231 (and (eq show-paren-style 'mixed)
232 (not (pos-visible-in-window-p pos))))
233 (point)
234 pos))
235 (from (if (or (eq show-paren-style 'expression)
236 (and (eq show-paren-style 'mixed)
237 (not (pos-visible-in-window-p pos))))
238 pos
239 (save-excursion
240 (goto-char pos)
241 (forward-point (- dir))))))
242 (if show-paren-overlay
243 (move-overlay show-paren-overlay from to (current-buffer))
244 (setq show-paren-overlay (make-overlay from to))))
245 ;;
246 ;; Always set the overlay face, since it varies.
247 (overlay-put show-paren-overlay 'priority show-paren-priority)
248 (overlay-put show-paren-overlay 'face face)))
249 ;; show-paren-mode is nil in this buffer.
250 (and show-paren-overlay
251 (delete-overlay show-paren-overlay))
252 (and show-paren-overlay-1
253 (delete-overlay show-paren-overlay-1))))
254
255(provide 'paren)
256
257;; arch-tag: d0969b88-7ac0-4bd0-bd53-e73b892b86a9
258;;; paren.el ends here