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