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