25b72496bc9a40ee4c42343b2d8b86478580b559
[emacs.git] / .emacs.d / elisp / local / mic-paren.el
1 ;;; mic-paren.el --- advanced highlighting of matching parentheses
2
3 ;;; Copyright (C) 2008, 2012 Thien-Thi Nguyen
4 ;;; Copyright (C) 1997 Mikael Sjödin (mic@docs.uu.se)
5
6 ;; Version: 3.10
7 ;; Released: 2012-07-16
8 ;; Author: Mikael Sjödin (mic@docs.uu.se)
9 ;; Klaus Berndl <berndl@sdm.de>
10 ;; Jonathan Kotta <jpkotta@gmail.com>
11 ;; Maintainer: ttn
12 ;; Keywords: languages, faces, parenthesis, matching
13 ;;
14 ;; This program contains additional code by:
15 ;; - Vinicius Jose Latorre <vinicius@cpqd.br>
16 ;; - Steven L Baur <steve@xemacs.org>
17 ;; - Klaus Berndl <berndl@sdm.de>
18 ;; - ttn
19 ;;
20 ;; mic-paren.el is free software
21 ;;
22 ;; This file is *NOT* (yet?) part of GNU Emacs.
23 ;;
24 ;; This program is free software; you can redistribute it and/or modify
25 ;; it under the terms of the GNU General Public License as published by
26 ;; the Free Software Foundation; either version 3, or (at your option)
27 ;; any later version.
28 ;;
29 ;; This program is distributed in the hope that it will be useful,
30 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
31 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 ;; GNU General Public License for more details.
33 ;;
34 ;; You should have received a copy of the GNU General Public License
35 ;; along with GNU Emacs; see the file COPYING. If not, write to the
36 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
37 ;; Boston, MA 02111-1307, USA.
38
39 ;;; Commentary:
40
41 ;; ----------------------------------------------------------------------
42 ;; Short Description:
43 ;;
44 ;; Load this file, activate it and Emacs will display highlighting on
45 ;; whatever parenthesis (and paired delimiter if you like this) matches
46 ;; the one before or after point. This is an extension to the paren.el
47 ;; file distributed with Emacs. The default behaviour is similar to
48 ;; paren.el but more sophisticated. Normally you can try all default
49 ;; settings to enjoy mic-paren.
50 ;;
51 ;; Some examples to try in your ~/.emacs:
52 ;;
53 ;; (add-hook 'LaTeX-mode-hook
54 ;; (function (lambda ()
55 ;; (paren-toggle-matching-quoted-paren 1)
56 ;; (paren-toggle-matching-paired-delimiter 1))))
57 ;;
58 ;; (add-hook 'c-mode-common-hook
59 ;; (function (lambda ()
60 ;; (paren-toggle-open-paren-context 1))))
61 ;;
62 ;; ----------------------------------------------------------------------
63 ;; Installation:
64 ;;
65 ;; o Place this file in a directory in your `load-path' and byte-compile
66 ;; it. If there are warnings, please report them to ttn.
67 ;; o Put the following in your .emacs file:
68 ;; (require 'mic-paren) ; loading
69 ;; (paren-activate) ; activating
70 ;; ;;; set here any of the customizable variables of mic-paren:
71 ;; ;;; ...
72 ;; o Restart your Emacs; mic-paren is now installed and activated!
73 ;; o To list the possible customizations type `C-h f paren-activate' or
74 ;; go to the customization group `mic-paren-matching'.
75 ;;
76 ;; ----------------------------------------------------------------------
77 ;; Long Description:
78 ;;
79 ;; mic-paren.el is an extension and replacement to the packages paren.el
80 ;; and stig-paren.el for Emacs. When mic-paren is active Emacs normal
81 ;; parenthesis matching is deactivated. Instead parenthesis matching will
82 ;; be performed as soon as the cursor is positioned at a parenthesis. The
83 ;; matching parenthesis (or the entire structured expression between the
84 ;; parentheses) is highlighted until the cursor is moved away from the
85 ;; parenthesis. Features include:
86 ;; o Both forward and backward parenthesis matching (simultaneously if
87 ;; cursor is between two expressions).
88 ;; o Indication of mismatched parentheses.
89 ;; o Recognition of "escaped" (also often called "quoted") parentheses.
90 ;; o Option to match "escaped" parens too, especially in (La)TeX-mode
91 ;; (e.g., matches expressions like "\(foo bar\)" properly).
92 ;; o Offers two functions as replacement for `forward-sexp' and
93 ;; `backward-sexp' which handle properly quoted parens (s.a.). These
94 ;; new functions can automatically be bounded to the original binding
95 ;; of the standard `forward-sexp' and `backward-sexp' functions.
96 ;; o Option to activate matching of paired delimiter (i.e., characters with
97 ;; syntax '$'). This is useful for writing in LaTeX-mode for example.
98 ;; o Option to select in which situations (always, never, if match, if
99 ;; mismatch) the entire expression should be highlighted or only the
100 ;; matching parenthesis.
101 ;; o Message describing the match when the matching parenthesis is off-screen
102 ;; (vertical and/or horizontal). Message contains either the linenumber or
103 ;; the number of lines between the two matching parens. Option to select in
104 ;; which cases this message should be displayed.
105 ;; o Optional delayed highlighting (useful on slow systems),
106 ;; o Functions to activate/deactivate mic-paren.el are provided.
107 ;; o Numerous options to control the behaviour and appearance of
108 ;; mic-paren.el.
109 ;;
110 ;; mic-paren.el was originally developed and tested under Emacs 19.28 -
111 ;; 20.3. Since then, support for Emacs 19 and 20 has bit-rotted (not
112 ;; dropped completely, but not tested against changes, either), and
113 ;; will probably be removed without warning in a future version. This
114 ;; version was developed and tested under Emacs 23.0.60 (wip). XEmacs
115 ;; compatibility has been provided by Steven L Baur <steve@xemacs.org>.
116 ;; Jan Dubois (jaduboi@ibm.net) provided help to get mic-paren to work in
117 ;; OS/2.
118 ;;
119 ;; This file (and other wonderful stuff) can be obtained from
120 ;; the Emacs Wiki: <http://www.emacswiki.org/>
121 ;;
122 ;; ----------------------------------------------------------------------
123 ;; Available customizable options:
124 ;; - `paren-priority'
125 ;; - `paren-overlay-priority'
126 ;; - `paren-sexp-mode'
127 ;; - `paren-highlight-at-point'
128 ;; - `paren-highlight-offscreen'
129 ;; - `paren-display-message'
130 ;; - `paren-message-linefeed-display'
131 ;; - `paren-message-no-match'
132 ;; - `paren-message-show-linenumber'
133 ;; - `paren-message-truncate-lines'
134 ;; - `paren-max-message-length'
135 ;; - `paren-ding-unmatched'
136 ;; - `paren-delay'
137 ;; - `paren-dont-touch-blink'
138 ;; - `paren-match-face'
139 ;; - `paren-mismatch-face'
140 ;; - `paren-no-match-paren'
141 ;; - `paren-bind-modified-sexp-functions'
142 ;; Available customizable faces:
143 ;; - `paren-face-match'
144 ;; - `paren-face-mismatch'
145 ;; - `paren-face-no-match'
146 ;; Available commands:
147 ;; - `paren-activate'
148 ;; - `paren-deactivate'
149 ;; - `paren-toggle-matching-paired-delimiter'
150 ;; - `paren-toggle-matching-quoted-paren'
151 ;; - `paren-toggle-open-paren-context'
152 ;; - `paren-forward-sexp'
153 ;; - `paren-backward-sexp'
154 ;; ----------------------------------------------------------------------
155 ;;
156 ;; IMPORTANT NOTES (important for people who have customized mic-paren
157 ;; from within elisp):
158 ;; - In version >= 3.3 the prefix "mic-" has been removed from the
159 ;; command-names `mic-paren-forward-sexp' and `mic-paren-backward-sexp'.
160 ;; Now all user-functions and -options begin with the prefix "paren-"
161 ;; because this package should be a replacement of the other
162 ;; paren-packages like paren.el and stig-paren.el!
163 ;; - In version >= 3.2 the prefix "mic-" has been removed from the
164 ;; command-names `mic-paren-toggle-matching-quoted-paren' and
165 ;; `mic-paren-toggle-matching-paired-delimiter'.
166 ;; - In versions >= 3.1 mic-paren is NOT auto-activated after loading.
167 ;; - In versions >= 3.0 the variable `paren-face' has been renamed to
168 ;; `paren-match-face'.
169 ;;
170 ;; ----------------------------------------------------------------------
171 ;; Versions:
172 ;; v3.10 + Added message-length clamping (var `paren-max-message-length').
173 ;; Thanks to Jonathan Kotta.
174 ;;
175 ;; v3.9 + Fixed XEmacs bug in `define-mic-paren-nolog-message'.
176 ;; Thanks to Sivaram Neelakantan.
177 ;;
178 ;; v3.8 + Maintainership (crassly) grabbed by ttn.
179 ;; + License now GPLv3+.
180 ;; + Byte-compiler warnings eliminated; if you see one, tell me!
181 ;; + Dropped funcs: mic-char-bytes, mic-char-before.
182 ;; + Docstrings, messages, comments revamped.
183 ;;
184 ;; v3.7 + Removed the message "You should be in LaTeX-mode!".
185 ;; + Fixed a bug in `paren-toggle-matching-quoted-paren'.
186 ;; + Fixed some misspellings in the comments and docs.
187 ;;
188 ;; v3.6 + Fixed a very small bug in `mic-paren-horizontal-pos-visible-p'.
189 ;; + The informational messages like "Matches ... [+28]" which are
190 ;; displayed if the matching paren is offscreen, do not longer
191 ;; wasting the log.
192 ;;
193 ;; v3.5 + No mic-paren-messages are displayed if we are in isearch-mode.
194 ;; + Matching quoted parens is switched on if entering a minibuffer.
195 ;; This is useful for easier inserting regexps, e.g., with
196 ;; `query-replace-regexp'. Now \(...\) will be highlighted
197 ;; in the minibuffer.
198 ;; + New option `paren-message-show-linenumber': You can determine
199 ;; the computation of the offscreen-message-linenumber. Either the
200 ;; number of lines between the two matching parens or the absolute
201 ;; linenumber. (Thank you for the idea and a first implementation
202 ;; to Eliyahu Barzilay <eli@cs.bgu.ac.il>.)
203 ;; + New option `paren-message-truncate-lines': If mic-paren messages
204 ;; should be truncated or not (has only an effect in GNU Emacs 21).
205 ;; (Thank you for the idea and a first implementation to Eliyahu
206 ;; Barzilay <eli@cs.bgu.ac.il>.)
207 ;;
208 ;; v3.4 + Corrected some bugs in the backward-compatibility for older
209 ;; Emacsen. Thanks to Tetsuo Tsukamoto <czkmt@remus.dti.ne.jp>.
210 ;;
211 ;; v3.3 + Now the priority of the paren-overlays can be customized
212 ;; (option `paren-overlay-priority'). For a description of the
213 ;; priority of an overlay see in the emacs-lisp-manual the node
214 ;; "Overlays". This option is mainly useful for experienced
215 ;; users which use many packages using overlays to perform their
216 ;; tasks.
217 ;; + Now you can determine what line-context will be displayed if
218 ;; the matching open paren is offscreen. In functional
219 ;; programming languages like lisp it is useful to display the
220 ;; following line in the echo-area if the opening matching paren
221 ;; has no preceding text in the same line.
222 ;; But in procedural languages like C++ or Java it is convenient
223 ;; to display the first previous non empty line in this case
224 ;; instead of the following line. Look at the new variable
225 ;; `paren-open-paren-context-backward' and the related toggling
226 ;; function `paren-toggle-open-paren-context' for a detailed
227 ;; description of this new feature.
228 ;; + In addition to the previous described new feature you can
229 ;; specify how a linefeed in the message (e.g., if the matching
230 ;; paren is offscreen) is displayed. This is mainly because the
231 ;; standard echo-area display of a linefeed (^J) is bad to read.
232 ;; Look at the option `paren-message-linefeed-display'.
233 ;; + Solved a little bug in the compatibility-code for Emacsen
234 ;; not supporting current customize-feature.
235 ;; + Removed the prefix "mic-" from the commands
236 ;; `mic-paren-forward-sexp' and `mic-paren-backward-sexp'.
237 ;; For an explanation look at comments for version v3.2.
238 ;;
239 ;; v3.2 + The prefix "mic-" has been removed from the commands
240 ;; `mic-paren-toggle-matching-quoted-paren' and
241 ;; `mic-paren-toggle-matching-paired-delimiter'. This is for
242 ;; consistency. Now all user-variables, -faces and -commands
243 ;; begin with the prefix "paren-" and all internal functions
244 ;; and variables begin with the prefix "mic-paren-".
245 ;; + Now you can exactly specify in which situations the whole
246 ;; sexp should be highlighted (option `paren-sexp-mode'):
247 ;; Always, never, if match or if mismatch. Tested with Gnus
248 ;; Emacs >= 20.3.1 and XEmacs >= 21.1.
249 ;;
250 ;; v3.1 + From this version on mic-paren is not autoloaded. To
251 ;; activate it you must call `paren-activate' (either in your
252 ;; .emacs or manually with M-x). Therefore the variable
253 ;; `paren-dont-activate-on-load' ise obsolet and has been
254 ;; removed.
255 ;; + Now mic-paren works also in older Emacsen without the
256 ;; custom-feature. If the actual custom-library is provided
257 ;; mic-paren use them and is full customizable otherwise normal
258 ;; defvars are used for the options.
259 ;; + Fix of a bug displaying a message if the matching paren is
260 ;; horizontal out of view.
261 ;; + All new features are now tested with XEmacs >= 21.1.6.
262 ;;
263 ;; v3.0 + Checking if matching paren is horizontally offscreen (in
264 ;; case of horizontal scrolling). In that case the message is
265 ;; displayed in the echo-area (anlogue to vertical offscreen).
266 ;; In case of horizontal offscreen closing parenthesis the
267 ;; displayed message is probably wider than the frame/window.
268 ;; So you can only read the whole message if you are using a
269 ;; package like mscroll.el (scrolling long messages) in GNU
270 ;; Emacs.
271 ;; + Now full customizable, means all user-options and -faces now
272 ;; can be set with the custom-feature of Emacs. On the other
273 ;; hand, this means this version of mic-paren only works with an
274 ;; Emacs which provides the custom-package!
275 ;; + In case of the matching paren is offscreen now the displayed
276 ;; message contains the linenumber of the matching paren too.
277 ;; This version is only tested with Gnu Emacs >= 20.4 and not with
278 ;; any XEmacs!
279 ;; Implemented by Klaus Berndl <berndl@sdm.de>.
280 ;;
281 ;; v2.3 No additional feature but replacing `char-bytes' and
282 ;; `char-before' with `mic-char-bytes' and `mic-char-before' to
283 ;; prevent a clash in the global-namespace. Now the new
284 ;; features of v2.1 and v2.2 are also tested with XEmacs!
285 ;;
286 ;; v2.2 Adding the new feature for matching paired delimiter. Not
287 ;; tested with XEmacs. Implemented by Klaus Berndl <berndl@sdm.de>
288 ;;
289 ;; v2.1 Adding the new feature for matching escaped parens too. Not
290 ;; tested with XEmacs. Implemented by Klaus Berndl <berndl@sdm.de>.
291 ;;
292 ;; v2.0 Support for MULE and Emacs 20 multibyte characters added.
293 ;; Inspired by the suggestion and code of Saito Takaaki
294 ;; <takaaki@is.s.u-tokyo.ac.jp>.
295 ;;
296 ;; v1.9 Avoids multiple messages/dings when point has not moved. Thus,
297 ;; mic-paren no longer overwrites messages in minibuffer. Inspired by
298 ;; the suggestion and code of Barzilay Eliyahu <eli@cs.bgu.ac.il>.
299 ;;
300 ;; v1.3.1 Some spelling corrected (from Vinicius Jose Latorre
301 ;; <vinicius@cpqd.br> and Steven L Baur <steve@xemacs.org>).
302 ;;
303 ;; v1.3 Added code from Vinicius Jose Latorre <vinicius@cpqd.br> to
304 ;; highlight unmatched parentheses (useful in minibuffer).
305 ;;
306 ;; v1.2.1 Fixed stuff to work with OS/2 emx-emacs:
307 ;; - checks if `x-display-colour-p' is bound before calling it;
308 ;; - changed how X/Lucid Emacs is detected.
309 ;; Added automatic load of the timer-feature (plus variable to
310 ;; disable the loading).
311
312 ;;; Code:
313
314 (defvar mic-paren-version "3.10"
315 "Version of mic-paren.")
316
317 (eval-when-compile (require 'cl))
318
319 ;;; ======================================================================
320 ;; Compatibility stuff
321 ;; BLOB to make custom stuff work even without customize
322 (eval-and-compile
323 (condition-case ()
324 (require 'custom)
325 (error nil))
326 (unless (fboundp 'defgroup)
327 (defmacro defgroup (&rest rest) nil))
328 (unless (fboundp 'defcustom)
329 (defmacro defcustom (sym val str &rest rest)
330 `(defvar ,sym ,val ,str)))
331 (unless (fboundp 'defface)
332 (defmacro defface (sym val str &rest rest)
333 `(defvar ,sym (make-face ',sym) ,str))))
334
335 ;;; ======================================================================
336 ;;; here begin the user options
337
338 (defgroup mic-paren-matching nil
339 "Enable advanced (un)matching of parens and expressions."
340 :prefix "paren-"
341 :group 'paren-matching)
342
343 (defcustom paren-priority 'both
344 "*Control behavior in a \"abutted close-open\" situation.
345 This occurs when point is between a closing and an opening
346 parenthesis, such as: (A B)(C D)
347 ^
348 point
349 close -- highlight the parenthesis matching the close-parenthesis
350 before the point (highlight opening paren before A).
351 open -- highlight the parenthesis matching the open-parenthesis after
352 the point (highlight closing paren after D).
353 both -- highlight both parenthesis matching the parenthesis beside
354 the point (highlight opening before A and closing after D)."
355 :type '(choice (const :tag "Match close" close)
356 (const :tag "Match open" open)
357 (const :tag "Match both" both))
358 :group 'mic-paren-matching)
359
360 (defcustom paren-overlay-priority 999
361 "*Non-negative integer to specify paren overlay priority.
362 For details, see info node `(elisp) Overlays'.
363 Normally you don't want to change the default value!"
364 :set (function
365 (lambda (symbol value)
366 (set symbol (if (< value 0) (* -1 value) value))))
367 :initialize 'custom-initialize-default
368 :type 'integer
369 :group 'mic-paren-matching)
370
371 (defcustom paren-sexp-mode nil
372 "*Control in which situations the whole sexp should be highlighted.
373 This means the whole s-expression between the matching parentheses is
374 highlighted instead of only the matching/mismatching parenthesis.
375
376 t -- Always highlight the whole s-expression.
377 nil -- Never highlight the whole s-expression.
378 match -- Highlight the whole s-expression only if the parens match.
379 mismatch -- Highlight the whole s-expression only if the parens don't match."
380 :type '(choice (const :tag "Never sexp-mode" nil)
381 (const :tag "Always sexp-mode" t)
382 (const :tag "If match" match)
383 (const :tag "If mismatch" mismatch))
384 :group 'mic-paren-matching)
385
386 (defcustom paren-highlight-at-point t
387 "*Non-nil highlights both parens when point is after the close-paren.
388 If nil, only the open parenthesis is highlighted."
389 :type '(choice (const :tag "Highlight both" t)
390 (const :tag "Highlight open" nil))
391 :group 'mic-paren-matching)
392
393 (defcustom paren-highlight-offscreen nil
394 "*Non-nil enables highlighting text not visible in the current buffer.
395
396 This is useful if you regularly display the current buffer in
397 multiple windows or frames (e.g., if you use Follow mode, by
398 andersl@csd.uu.se). Note: this option may slow down your Emacs.
399
400 This variable is ignored (treated as non-nil) if you set
401 `paren-sexp-mode' to non-nil."
402 :type 'boolean
403 :group 'mic-paren-matching)
404
405 (defcustom paren-display-message 'only
406 "*Display message if matching parenthesis is off-screen.
407 Possible settings are:
408 always -- message is always displayed regardless if offscreen or not
409 only -- message is only displayed when matching is offscreen
410 never -- never a message is displayed."
411 :type '(choice (const :tag "Display always" always)
412 (const :tag "Display if offscreen" only)
413 (const :tag "No Message display" never))
414 :group 'mic-paren-matching)
415
416 (defcustom paren-message-linefeed-display " RET "
417 "*String for displaying a linefeed in the matching paren context message.
418 There are three predefined values:
419 - Displays linefeeds with \" RET \" in the message.
420 - Displays linefeeds with a SPACE in the message.
421 - Displays linefeeds in the standard-form, means with \"^J\".
422 But you can also specify any user-defined string for it.
423
424 For further explanations about message displaying look at
425 `paren-display-message'."
426 :type '(choice (const :tag "Display with \"RET\"" :value " RET ")
427 (const :tag "Display with a SPACE" :value " ")
428 (const :tag "Standard" :value "^J")
429 (string :tag "User defined"))
430 :group 'mic-paren-matching)
431
432 (defcustom paren-message-show-linenumber 'sexp
433 "*Determine the computation of the offscreen-message-linenumber.
434
435 If the matching paren is offscreen, then maybe a message with the
436 context of the matching paren and it's linenumber is displayed
437 \(depends on the setting in `paren-display-message'). Here the
438 computation of the linenumber can be determined:
439
440 sexp -- Display the number of lines between the matching parens. Then the
441 number of lines is displayed as negative number if the matching paren
442 is somewhere above. Otherwise the number has a positive sign.
443
444 absolute -- Display the absolute linenumber of the machting paren computed
445 from the beginning of the buffer."
446 :type '(choice (const :tag "Count accros sexp" sexp)
447 (const :tag "Absolute number" absolute))
448 :group 'mic-paren-matching)
449
450 (defcustom paren-message-no-match t
451 "*Display message if no matching parenthesis is found."
452 :type '(choice (const :tag "Display message" t)
453 (const :tag "No message" nil))
454 :group 'mic-paren-matching)
455
456 (defcustom paren-message-truncate-lines t
457 "*Non nil means truncate lines for all messages mic-paren can display.
458 This option has only an effect with GNU Emacs 21.x!"
459 :type 'boolean
460 :group 'mic-paren-matching)
461
462 (defcustom paren-max-message-length 0
463 "*If positive, the max length `mic-paren-nolog-message' should output.
464 The length is reduced by removing the middle section of the message.
465 A value of zero means do not modify the message."
466 :type 'integer
467 :group 'mic-paren-matching)
468
469 (defcustom paren-ding-unmatched nil
470 "*Non-nil means make noise in unmatched situations.
471 An unmatched situation occurs if the cursor is at an unmatched
472 parenthesis or no matching parenthesis is found.
473 Even if nil, typing an unmatched parenthesis produces a ding."
474 :type 'boolean
475 :group 'mic-paren-matching)
476
477 (defcustom paren-delay nil
478 "*This variable controls when highlighting is done.
479 The variable has different meaning in different versions of Emacs.
480
481 In Emacs 19.29 and below:
482 This variable is ignored.
483
484 In Emacs 19.30:
485 A value of nil will make highlighting happen immediately \(this may slow
486 down your Emacs if running on a slow system). Any non-nil value will
487 delay highlighting for the time specified by post-command-idle-delay.
488
489 In Emacs 19.31 and above:
490 A value of nil will make highlighting happen immediately \(this may slow
491 down your Emacs if running on a slow system). If not nil, the value
492 should be a number \(possible a floating point number if your Emacs
493 support floating point numbers). The number is the delay in seconds
494 before mic-paren performs highlighting.
495
496 If you change this variable when mic-paren is active you have to
497 re-activate \(with M-x paren-activate) mic-paren for the change to take
498 effect."
499 :type '(choice (number :tag "Delay time")
500 (const :tag "No delay" nil))
501 :group 'mic-paren-matching)
502
503 (defcustom paren-dont-touch-blink nil
504 "*Non-nil means not to change the value of `blink-matching-paren'.
505 This takes effect when mic-paren is activated or deactivated. If nil
506 mic-paren turns of blinking when activated and turns on blinking when
507 deactivated."
508 :type 'boolean
509 :group 'mic-paren-matching)
510
511 (defcustom paren-dont-load-timer (not (string-match "XEmacs\\|Lucid"
512 emacs-version))
513 "*Non-nil inhibits loading `timer'.
514
515 \(I have no idea why Emacs user ever want to set this to non-nil but I hate
516 packages which loads/activates stuff I don't want to use so I provide this
517 way to prevent the loading if someone doesn't want timers to be loaded.)"
518 :type 'boolean
519 :group 'mic-paren-matching)
520
521 (defcustom paren-bind-modified-sexp-functions t
522 "*Automatic binding of the new sexp-functions to the old bindings.
523 If non nil mic-paren checks at load-time the keybindings for the functions
524 `forward-sexp' and `backward-sexp' and binds the modified sexp-functions
525 `paren-forward-sexp' and `paren-backward-sexp' to exactly these
526 bindings if and only if matching quoted/escaped parens is turned on by
527 `paren-toggle-matching-quoted-paren'. These new bindings are done only
528 in a buffer-local keymap, therefore if you activate the quoted matching
529 only in some modes from within a hook only in these buffers the new
530 bindings are active and in all other not.
531
532 If you deactivate the quoted matching feature by
533 `paren-toggle-matching-quoted-paren' then `forward-sexp' and
534 `backward-sexp' will be bound again to their original key-bindings!"
535 :type 'boolean
536 :group 'mic-paren-matching)
537
538 ;;; ------------------------------
539 ;;; Faces
540 ;;; ------------------------------
541
542 (defface paren-face-match
543 '((((class color)) (:background "turquoise"))
544 (t (:background "gray")))
545 "Mic-paren mode face used for a matching paren."
546 :group 'faces
547 :group 'mic-paren-matching)
548
549 (defface paren-face-mismatch
550 '((((class color)) (:foreground "white" :background "purple"))
551 (t (:reverse-video t)))
552 "Mic-paren mode face used for a mismatching paren."
553 :group 'faces
554 :group 'mic-paren-matching)
555
556 (defface paren-face-no-match
557 '((((class color)) (:foreground "black" :background "yellow"))
558 (t (:reverse-video t)))
559 "Mic-paren mode face used for an unmatched paren."
560 :group 'faces
561 :group 'mic-paren-matching)
562
563 (defcustom paren-match-face 'paren-face-match
564 "*Face to use for showing the matching parenthesis."
565 :type 'face
566 :group 'mic-paren-matching)
567
568 (defcustom paren-mismatch-face 'paren-face-mismatch
569 "*Face to use when highlighting a mismatched parenthesis."
570 :type 'face
571 :group 'mic-paren-matching)
572
573 (defcustom paren-no-match-face 'paren-face-no-match
574 "*Face to use when highlighting an unmatched parenthesis."
575 :type 'face
576 :group 'mic-paren-matching)
577
578 ;;; End of User Options
579 ;;; ======================================================================
580
581 ;;; Below there are only variables and options which either should be not
582 ;;; set directly but with toggle-functions or pure internal variables.
583
584 (defvar paren-match-quoted-paren nil
585 "*Non-nil enables matching properly quoted (or escaped) parens.
586 E.g., \"\\\(x-3y + z = 7\\\)\"\) in a TeX file. GNU Emacs can not match
587 quoted parens, so we must temporally deactivate the quoting until emacs
588 has done its sexp-parsing. Therefore emacs itself does not \(can not!\)
589 take into consideration if either both matched parens are quoted or none.
590 But nevertheless we do this! Only symmetric balanced parens are matched;
591 either both matching parens must be quoted or none, otherwise they we will
592 be highlighted as mismatched.
593
594 This package offers also two slightly modified versions of sexp traversal
595 functions: `paren-forward-sexp' and `paren-backward-sexp'. These versions
596 can also jump to escaped/quoted parens.
597
598 If this variable is not nil and `paren-bind-modified-sexp-functions' is
599 set to non nil, then `paren-toggle-matching-quoted-paren' will also toggle
600 the original binding of `forward-sexp' and `backward-sexp' between the
601 original functions and the modified equivalents.
602
603 Do NOT set this variable directly but use
604 `paren-toggle-matching-quoted-paren' to activate/deactivate/toggle this
605 feature! The best method is to do this in a mode hook, e.g.:
606 \(add-hook \'LaTeX-mode-hook
607 \(function \(lambda \(\)
608 \(paren-toggle-matching-quoted-paren 1\)\)\)\)")
609
610 (make-variable-buffer-local 'paren-match-quoted-paren)
611
612 (defvar paren-match-paired-delimiter nil
613 "*Non-nil enables matching of characters with syntax \"$\".
614 E.g., in LaTeX \"$...$\" is equivalent to \"\\(...\\)\".
615 Unlike to parens quoted/escaped paired delimiter will never match.
616
617 Do NOT set this variable directly but use
618 `paren-toggle-matching-paired-delimiter' to activate/deactivate/toggle
619 this feature! The best method is to do this in a mode hook, e.g.:
620 \(add-hook \'LaTeX-mode-hook
621 \(function \(lambda \(\)
622 \(paren-toggle-matching-paired-delimiter 1\)\)\)\)")
623
624 (make-variable-buffer-local 'paren-match-paired-delimiter)
625
626 (defvar paren-open-paren-context-backward nil
627 "*Controls which context of the matching open paren will be displayed.
628 This takes effect if the matching open paren is offscreen or
629 `paren-display-message' is `always' (see `paren-display-message')
630 and the matching open paren has no previous text in the same line.
631 Possible values:
632 nil -- Contents of the **next** not empty and not whitespace-line will be
633 displayed. This value is useful for example in functional programming
634 languages like (emacs)lisp.
635 not-nil -- Contents of the first **previous** not empty and not only
636 whitespace-line will be displayed. This value is useful for example in
637 procedural programming languages like C, C++, Java etc.
638
639 Lets take a look at a short example:
640 In languages like C++ we often have situations like
641 if \(i > VALUE\)
642 \{
643 // some code
644 \}
645 With a value non nil the displayed opening-brace context would be
646 \"if \(i > VALUE\)^J\{\" but with nil it would be \"\{^J // some code\"
647 which would be in C++ lesser useful as the non nil version.
648 \(The ^J stands for a newline in the buffer\).
649
650 Do NOT set this variable directly but use `paren-toggle-open-paren-context'
651 to change the value of this option! The best method is to do this in a
652 mode hook, e.g.:
653 \(add-hook \'c-common-mode-hook
654 \(function \(lambda \(\)
655 \(paren-toggle-open-paren-context 1\)\)\)\)")
656
657 (make-variable-buffer-local 'paren-open-paren-context-backward)
658
659 (defconst mic-paren-original-keybinding-of-sexp-functions
660 (list (car (where-is-internal 'forward-sexp))
661 (car (where-is-internal 'backward-sexp))))
662
663 ;;; Compatibility.
664 ;;; Try to make mic-paren work in different Emacs flavours.
665
666 ;; XEmacs compatibility (mainly by Steven L Baur <steve@xemacs.org>).
667 (eval-and-compile
668 (if (string-match "\\(Lucid\\|XEmacs\\)" emacs-version)
669 (progn
670 (fset 'mic-make-overlay 'make-extent)
671 (fset 'mic-delete-overlay 'delete-extent)
672 (fset 'mic-overlay-put 'set-extent-property)
673 (fset 'mic-cancel-timer 'delete-itimer)
674 (fset 'mic-run-with-idle-timer 'start-itimer))
675 (fset 'mic-make-overlay 'make-overlay)
676 (fset 'mic-delete-overlay 'delete-overlay)
677 (fset 'mic-overlay-put 'overlay-put)
678 (fset 'mic-cancel-timer 'cancel-timer)
679 (fset 'mic-run-with-idle-timer 'run-with-idle-timer)))
680
681 (defun paren-clamp-string-maybe (str)
682 "Remove the middle of STR if it exceeds `paren-max-message-length'.
683 However, if STR is `nil' or `paren-max-message-length' is zero,
684 simply return STR."
685 (if (or (not str) (zerop paren-max-message-length))
686 str
687 (let ((len (string-width str)))
688 (if (<= len paren-max-message-length)
689 str
690 (let* ((sep "[...]")
691 (cut (ash (- paren-max-message-length
692 (string-width sep))
693 -1)))
694 (concat (substring str 0 cut)
695 sep
696 (substring str (- len cut))))))))
697
698 (eval-when-compile
699 (defmacro define-mic-paren-nolog-message (yes no)
700 `(defun mic-paren-nolog-message (&rest args)
701 "Work like `message' but without logging.
702 See variable `paren-max-message-length'."
703 (let ((msg (paren-clamp-string-maybe
704 (cond ((or (null args)
705 (null (car args)))
706 nil)
707 ((null (cdr args))
708 (car args))
709 (t
710 (apply 'format args))))))
711 (if msg ,yes ,no)
712 msg))))
713
714 (eval-and-compile
715 (if (and (fboundp 'display-message)
716 (fboundp 'clear-message))
717 ;; Some GNU Emacs versions need the `eval' so as to avoid saying:
718 ;; > the following functions are not known to be defined:
719 ;; > display-message, clear-message
720 (eval '(define-mic-paren-nolog-message
721 (display-message 'no-log msg)
722 (clear-message 'no-log)))
723 (define-mic-paren-nolog-message
724 (let (message-log-max) (message "%s" msg))
725 (message nil))))
726
727 ;;; ======================================================================
728 ;;; Pure Internal variables
729
730 (defvar mic-paren-overlays (vector (mic-make-overlay 1 1)
731 (mic-make-overlay 1 1)
732 (mic-make-overlay 1 1))
733 "Vector of of the form [BACKW POINT FOREW].
734
735 BACKW: Overlay for the open-paren which matches the close-paren
736 before point. When in sexp-mode this is the overlay for
737 the expression before point.
738
739 POINT: Overlay for the close-paren before point.
740 This is not used when is sexp-mode.
741
742 FOREW: Overlay for the close-paren which matches the open-paren
743 after point. When in sexp-mode this is the overlay for
744 the expression after point.")
745
746 (defvar mic-paren-idle-timer nil
747 "Idle-timer.
748 Used only in Emacs 19.31 and above (and if paren-delay is nil).")
749
750 (defvar mic-paren-previous-location [nil nil nil]
751 "Where point was the last time mic-paren performed some action.
752 This is is a vector of the form [POINT BUFFER WINDOW].")
753
754 ;;; ======================================================================
755 ;;; User Functions
756
757 ;;;###autoload
758 (defun paren-activate ()
759 "Activate mic-paren parenthesis highlighting.
760 Note: This also deactivates the paren.el
761 and stig-paren.el packages if they are active!
762
763 The following options are available via the customize-feature:
764 `paren-priority'
765 `paren-overlay-priority'
766 `paren-sexp-mode'
767 `paren-highlight-at-point'
768 `paren-highlight-offscreen'
769 `paren-display-message'
770 `paren-message-linefeed-display'
771 `paren-message-no-match'
772 `paren-message-show-linenumber'
773 `paren-message-truncate-lines'
774 `paren-ding-unmatched'
775 `paren-delay'
776 `paren-dont-touch-blink'
777 `paren-match-face'
778 `paren-mismatch-face'
779 `paren-no-match-face'
780 `paren-bind-modified-sexp-functions'
781
782 The following options are settable via toggling functions \(look at the
783 documentation of these options for the names of these functions\):
784 `paren-match-quoted-paren'
785 `paren-match-paired-delimiter'
786 `paren-open-paren-context-backward'"
787 (interactive)
788 ;; Deactivate mic-paren.el (to remove redundant hooks).
789 (paren-deactivate)
790 ;; Deactivate paren.el if loaded.
791 (when (boundp 'post-command-idle-hook)
792 (remove-hook 'post-command-idle-hook 'show-paren-command-hook))
793 (remove-hook 'post-command-hook 'show-paren-command-hook)
794 (and (boundp 'show-paren-overlay)
795 show-paren-overlay
796 (mic-delete-overlay show-paren-overlay))
797 (and (boundp 'show-paren-overlay-1)
798 show-paren-overlay-1
799 (mic-delete-overlay show-paren-overlay-1))
800 ;; Deactivate stig-paren.el if loaded.
801 (when (boundp 'post-command-idle-hook)
802 (remove-hook 'post-command-idle-hook 'stig-paren-command-hook))
803 (remove-hook 'post-command-hook 'stig-paren-command-hook)
804 (remove-hook 'post-command-hook 'stig-paren-safe-command-hook)
805 (remove-hook 'pre-command-hook 'stig-paren-delete-overlay)
806 ;; Deactivate Emacs standard parenthesis blinking.
807 (or paren-dont-touch-blink
808 (setq blink-matching-paren nil))
809
810 (cond(
811 ;; If timers are available use them
812 ;; (Emacs 19.31 and above).
813 (featurep 'timer)
814 (if (numberp paren-delay)
815 (setq mic-paren-idle-timer
816 (mic-run-with-idle-timer paren-delay t
817 'mic-paren-command-idle-hook))
818 (add-hook 'post-command-hook 'mic-paren-command-hook)))
819 ;; If the idle hook exists assume it is functioning and use it
820 ;; (Emacs 19.30).
821 ((and (boundp 'post-command-idle-hook)
822 (boundp 'post-command-idle-delay))
823 (if paren-delay
824 (add-hook 'post-command-idle-hook 'mic-paren-command-idle-hook)
825 (add-hook 'post-command-hook 'mic-paren-command-hook)))
826 ;; Check if we (at least) have `post-comand-hook', and use it
827 ;; (Emacs 19.29 and below).
828 ((boundp 'post-command-hook)
829 (add-hook 'post-command-hook 'mic-paren-command-hook))
830 ;; Not possible to install mic-paren hooks
831 (t (error "Cannot activate mic-paren in this Emacs version")))
832 ;; We want matching quoted parens in the minibuffer to ease inserting
833 ;; paren-expressions in a regexp.
834 (add-hook 'minibuffer-setup-hook
835 'mic-paren-minibuffer-setup-hook)
836 (add-hook 'minibuffer-exit-hook
837 'mic-paren-minibuffer-exit-hook))
838
839 ;;;###autoload
840 (defun paren-deactivate ()
841 "Deactivate mic-paren parenthesis highlighting."
842 (interactive)
843 ;; Deactivate (don't bother to check where/if mic-paren is acivte, just
844 ;; delete all possible hooks and timers).
845 (when (boundp 'post-command-idle-hook)
846 (remove-hook 'post-command-idle-hook 'mic-paren-command-idle-hook))
847 (when mic-paren-idle-timer
848 (mic-cancel-timer mic-paren-idle-timer))
849 (remove-hook 'post-command-hook 'mic-paren-command-hook)
850 (remove-hook 'minibuffer-setup-hook
851 'mic-paren-minibuffer-setup-hook)
852 (remove-hook 'minibuffer-exit-hook
853 'mic-paren-minibuffer-exit-hook)
854 ;; Remove any old highlight.
855 (mic-delete-overlay (aref mic-paren-overlays 0))
856 (mic-delete-overlay (aref mic-paren-overlays 1))
857 (mic-delete-overlay (aref mic-paren-overlays 2))
858
859 ;; Reactivate Emacs standard parenthesis blinking.
860 (or paren-dont-touch-blink
861 (setq blink-matching-paren t)))
862
863 ;;;###autoload
864 (defun paren-toggle-matching-paired-delimiter (arg &optional no-message)
865 "Toggle matching paired delimiter.
866 Force on with positive ARG. Use this in mode hooks to activate or
867 deactivate paired delimiter matching. If optional second argument
868 NO-MESSAGE is non-nil then don't display a message about the
869 current activation state of the paired-delimiter-matching feature."
870 (interactive "P")
871 (setq paren-match-paired-delimiter (if (numberp arg)
872 (> arg 0)
873 (not paren-match-paired-delimiter)))
874 (unless no-message
875 (message "Matching paired delimiter is %s"
876 (if paren-match-paired-delimiter
877 "ON"
878 "OFF"))))
879
880 ;;;###autoload
881 (defun paren-toggle-matching-quoted-paren (arg &optional no-message)
882 "Toggle matching quoted parens.
883 Force on with positive ARG. Use this in mode hooks to activate or
884 deactivate quoted paren matching. If optional second argument
885 NO-MESSAGE is non-nil then don't display a message about the
886 current activation state of the quoted-paren-matching feature."
887 (interactive "P")
888 (setq paren-match-quoted-paren (if (numberp arg)
889 (> arg 0)
890 (not paren-match-quoted-paren)))
891 ;; If matching quoted parens is active now bind the original binding
892 ;; of forward-sexp and backward-sexp to the modified versions
893 ;; `paren-forward-sexp' and `paren-backward-sexp'. If not, bind
894 ;; it back to the original `forward-sexp' and `backward-sexp'.
895 (let ((f (car mic-paren-original-keybinding-of-sexp-functions))
896 (b (cadr mic-paren-original-keybinding-of-sexp-functions))
897 (funs (if paren-match-quoted-paren
898 '(paren-forward-sexp . paren-backward-sexp)
899 '(forward-sexp . backward-sexp))))
900 (when (and paren-bind-modified-sexp-functions b f)
901 (local-set-key f (car funs))
902 (local-set-key b (cdr funs))))
903 (unless no-message
904 (message "Matching quoted parens is %s"
905 (if paren-match-quoted-paren
906 "ON"
907 "OFF"))))
908
909 ;;;###autoload
910 (defun paren-toggle-open-paren-context (arg)
911 "Toggle whether or not to determine context of the matching open-paren.
912 Force backward context with positive ARG. Use this in mode-hooks.
913 See `paren-open-paren-context-backward'."
914 (interactive "P")
915 (setq paren-open-paren-context-backward
916 (if (numberp arg)
917 (> arg 0)
918 (not paren-open-paren-context-backward))))
919
920 ;;;###autoload
921 (defun paren-forward-sexp (&optional arg)
922 "Act like `forward-sexp' but also handle quoted parens.
923 See `paren-match-quoted-paren'."
924 (interactive "p")
925 (or arg (setq arg 1))
926 (let* ((uncharquote-diff (if (< arg 0) 2 1))
927 (match-check-diff (if (< arg 0) 1 2))
928 (charquote (mic-paren-uncharquote (- (point) uncharquote-diff)))
929 match-pos mismatch)
930 ;; We must encapsulate this in condition-case so we regain control
931 ;; after error and we can undo our unquoting if any done before!
932 (condition-case ()
933 (setq match-pos (scan-sexps (point) arg))
934 (error nil))
935 (mic-paren-recharquote charquote)
936 (if (not match-pos)
937 (buffer-end arg)
938 (setq mismatch (mic-paren-fcq-mismatch (- match-pos match-check-diff)
939 charquote))
940 (if mismatch
941 (forward-sexp arg)
942 (goto-char match-pos)))))
943
944 ;;;###autoload
945 (defun paren-backward-sexp (&optional arg)
946 "Act like `backward-sexp' but also match quoted parens.
947 See `paren-match-quoted-paren'."
948 (interactive "p")
949 (or arg (setq arg 1))
950 (paren-forward-sexp (- arg)))
951
952 ;;; ======================================================================
953 ;;; Internal functions
954
955 (defun mic-paren-command-idle-hook ()
956 (condition-case paren-error
957 (mic-paren-highlight)
958 (error
959 (unless (window-minibuffer-p (selected-window))
960 (message "mic-paren caught error (please report): %s"
961 paren-error)))))
962
963 (defun mic-paren-command-hook ()
964 (or executing-kbd-macro
965 ;; NB: This might cause trouble since the function is unreliable.
966 (input-pending-p)
967 (mic-paren-command-idle-hook)))
968
969 (defun mic-paren-minibuffer-setup-hook ()
970 (paren-toggle-matching-quoted-paren 1 t))
971
972 (defun mic-paren-minibuffer-exit-hook ()
973 (paren-toggle-matching-quoted-paren -1 t))
974
975 (defun mic-paren-fcq-mismatch (pos charquote)
976 (not (zerop (logxor (if (mic-paren-is-following-char-quoted pos) 1 0)
977 (if charquote 1 0)))))
978
979 (defun mic-paren-highlight ()
980 "Do everything: highlighting, dinging, messages, cleaning-up.
981 This is the main function of mic-paren."
982 ;; Remove any old highlighting.
983 (mic-delete-overlay (aref mic-paren-overlays 0))
984 (mic-delete-overlay (aref mic-paren-overlays 1))
985 (mic-delete-overlay (aref mic-paren-overlays 2))
986
987 (let ((loc mic-paren-previous-location)
988 charquote two opos matched-paren mismatch face visible)
989
990 (flet ((highlight-p
991 (pos prio which)
992 (let ((fcq (mic-paren-is-following-char-quoted pos))
993 (right-prio (eq prio paren-priority))
994 (get-c-0 (if which 'preceding-char 'following-char))
995 (get-c-1 (if which 'following-char 'preceding-char)))
996 (or (and (eq (char-syntax (funcall get-c-0))
997 (if which ?\) ?\())
998 (not (and (eq (char-syntax (funcall get-c-1))
999 (if which ?\( ?\)))
1000 right-prio))
1001 (or paren-match-quoted-paren
1002 (not fcq)))
1003 (and paren-match-paired-delimiter
1004 (eq (char-syntax (funcall get-c-0)) ?\$)
1005 (not (and (eq (char-syntax (funcall get-c-1)) ?\$)
1006 right-prio))
1007 (not fcq)))))
1008
1009 (find-other-paren
1010 (forwardp)
1011 (let ((mult (if forwardp 1 -1)))
1012 ;; Find the position of the other paren.
1013 (save-excursion
1014 (save-restriction
1015 (when blink-matching-paren-distance
1016 (let ((lim (+ (point) (* blink-matching-paren-distance
1017 mult))))
1018 (narrow-to-region (if forwardp
1019 (point-min)
1020 (max lim (point-min)))
1021 (if forwardp
1022 (min lim (point-max))
1023 (point-max)))))
1024 (condition-case ()
1025 (setq opos (scan-sexps (point) mult))
1026 (error nil))))
1027 ;; We must call matching-paren because `scan-sexps' doesn't
1028 ;; care about the kind of paren (e.g., matches '( and '}).
1029 ;; However, `matching-paren' only returns the character
1030 ;; displaying the matching paren in buffer's syntax-table
1031 ;; (regardless of the buffer's current contents!). Below we
1032 ;; compare the results of `scan-sexps' and `matching-paren'
1033 ;; and if different we display a mismatch.
1034 (let ((c (funcall (if forwardp
1035 'following-char
1036 'preceding-char))))
1037 (setq matched-paren (matching-paren c))
1038 ;; matching-paren can only handle chars with syntax ) or (.
1039 (when (eq (char-syntax c) ?\$)
1040 (setq matched-paren c)))
1041 ;; If we have changed the syntax of the escape or quote-char
1042 ;; we must undo this and we can do this first now.
1043 (mic-paren-recharquote charquote)
1044 opos))
1045
1046 (nov
1047 (place b e face)
1048 (let ((ov (mic-make-overlay b e)))
1049 (mic-overlay-put ov 'face face)
1050 (mic-overlay-put ov 'priority paren-overlay-priority)
1051 (aset mic-paren-overlays
1052 (cdr (assq place '((backw . 0)
1053 (point . 1)
1054 (forew . 2))))
1055 ov)))
1056
1057 (new-location-p
1058 ()
1059 (not (and (eq (point) (aref loc 0))
1060 (eq (current-buffer) (aref loc 1))
1061 (eq (selected-window) (aref loc 2)))))
1062
1063 (ding-maybe
1064 (ok)
1065 (and ok paren-ding-unmatched
1066 (new-location-p)
1067 (ding)))
1068
1069 (sorry
1070 (place b e)
1071 ;; Highlight unmatched paren.
1072 (nov place b e paren-no-match-face)
1073 ;; Print no-match message.
1074 (and paren-message-no-match
1075 (not (window-minibuffer-p (selected-window)))
1076 (not isearch-mode)
1077 (new-location-p)
1078 (mic-paren-nolog-message "No %sing parenthesis found"
1079 (if (eq 'backw place)
1080 "open"
1081 "clos")))
1082 (ding-maybe paren-message-no-match))
1083
1084 (set-mismatch/face/visible
1085 (c-at ofs)
1086 (setq mismatch (or (not matched-paren)
1087 (/= matched-paren (funcall c-at opos))
1088 (mic-paren-fcq-mismatch (+ opos ofs) charquote))
1089 face (if mismatch
1090 paren-mismatch-face
1091 paren-match-face)
1092 visible (when (pos-visible-in-window-p opos)
1093 (save-excursion
1094 (goto-char opos)
1095 (let ((hrel (- (current-column)
1096 (window-hscroll))))
1097 (and (< -1 hrel)
1098 (> (window-width) hrel)))))))
1099
1100 (sexp-mode-p
1101 ()
1102 (case paren-sexp-mode
1103 (match (not mismatch))
1104 (mismatch mismatch)
1105 ((nil t) paren-sexp-mode)))
1106
1107 (finish
1108 (get-message)
1109 ;; Print messages if match is offscreen.
1110 (and (not (eq paren-display-message 'never))
1111 (or (not visible) (eq paren-display-message 'always))
1112 (not (window-minibuffer-p (selected-window)))
1113 (not isearch-mode)
1114 (new-location-p)
1115 (let ((message-truncate-lines paren-message-truncate-lines))
1116 (mic-paren-nolog-message
1117 "%s %s"
1118 (if mismatch "MISMATCH:" "Matches")
1119 (funcall get-message opos))))
1120 ;; Ding if mismatch.
1121 (ding-maybe mismatch)))
1122
1123 ;; Handle backward highlighting.
1124 (when (highlight-p (- (point) 2) 'open t)
1125 (setq charquote (mic-paren-uncharquote (- (point) 2)))
1126 (if (not (find-other-paren nil))
1127 (sorry 'backw (point) (1- (point)))
1128 (set-mismatch/face/visible 'char-after -1)
1129 (when (or visible paren-highlight-offscreen paren-sexp-mode)
1130 (let ((sexp-mismatch (sexp-mode-p)))
1131 (nov 'backw opos (if sexp-mismatch
1132 (point)
1133 (1+ opos))
1134 face)
1135 (when (and (not sexp-mismatch)
1136 paren-highlight-at-point)
1137 (nov 'point (1- (point)) (point) face))))
1138 (finish 'mic-paren-get-matching-open-text)))
1139
1140 ;; Handle forward highlighting.
1141 (when (highlight-p (1- (point)) 'close nil)
1142 (setq charquote (mic-paren-uncharquote (1- (point))))
1143 (if (not (find-other-paren t))
1144 (sorry 'forew (point) (1+ (point)))
1145 (set-mismatch/face/visible 'char-before -2)
1146 (when (or visible paren-highlight-offscreen paren-sexp-mode)
1147 (nov 'forew (if (sexp-mode-p)
1148 (point)
1149 (1- opos))
1150 opos face))
1151 (finish 'mic-paren-get-matching-close-text))))
1152
1153 ;; Store the point's position.
1154 (unless (window-minibuffer-p (selected-window))
1155 (aset loc 0 (point))
1156 (aset loc 1 (current-buffer))
1157 (aset loc 2 (selected-window)))))
1158
1159 (defun mic-paren-get-matching-open-text (open)
1160 "Return a string with the context around OPEN-paren.
1161 If there's stuff on this line preceding the paren, then
1162 display text from beginning of line to paren.
1163
1164 If, however, the paren is at the beginning of a line (means only
1165 whitespace before the paren), then skip whitespace forward and
1166 display text from paren to end of the next line containing
1167 non-space text. But if `paren-open-paren-context-backward' is
1168 non-nil, then skip whitespaces backward and display text from
1169 beginning of previous line to paren."
1170 (let* ((loc (if (eq paren-message-show-linenumber 'sexp)
1171 (point) (point-min)))
1172 (str (save-excursion
1173 (goto-char open)
1174 (if (save-excursion
1175 (skip-chars-backward " \t")
1176 (not (bolp)))
1177 (progn
1178 (beginning-of-line)
1179 (format "%s... [%s%d-]"
1180 (buffer-substring (point) (1+ open))
1181 (if (eq paren-message-show-linenumber 'sexp)
1182 "-" "")
1183 (count-lines loc open)))
1184 (let (paren-context-string)
1185 (if (not paren-open-paren-context-backward)
1186 (progn
1187 (forward-char 1)
1188 (skip-chars-forward "\n \t")
1189 (end-of-line)
1190 (setq paren-context-string
1191 (buffer-substring open (point))))
1192 (skip-chars-backward "\n \t")
1193 (beginning-of-line)
1194 (setq paren-context-string
1195 (buffer-substring (point) (1+ open))))
1196 (format "%s [%s%d]"
1197 paren-context-string
1198 (if (eq paren-message-show-linenumber 'sexp)
1199 "-" "")
1200 (count-lines loc open)))))))
1201 (while (string-match "[\n]" str)
1202 (setq str (replace-match paren-message-linefeed-display nil t str)))
1203 str))
1204
1205 (defun mic-paren-get-matching-close-text (close)
1206 "Return a string with the context around CLOSE-paren.
1207 The whole line up until the close-paren with \"...\"
1208 appended if there is more text after the close-paren."
1209 (let* ((loc (if (eq paren-message-show-linenumber 'sexp)
1210 (point) (point-min)))
1211 (str (save-excursion
1212 (goto-char close)
1213 (forward-char -1)
1214 (skip-chars-backward "\n \t")
1215 (beginning-of-line)
1216 (format "%s%s [%s%d]"
1217 (buffer-substring (point) close)
1218 (progn
1219 (goto-char close)
1220 (if (looking-at "[ \t]*$")
1221 ""
1222 "..."))
1223 (if (eq paren-message-show-linenumber 'sexp)
1224 "+" "")
1225 (count-lines loc close)))))
1226 (while (string-match "[\n]" str)
1227 (setq str (replace-match paren-message-linefeed-display nil t str)))
1228 str))
1229
1230 (defun mic-paren-is-following-char-quoted (pos)
1231 "Return t if character at POS escapes or quotes the following char."
1232 (let ((n 0))
1233 (while (and (<= (point-min) pos)
1234 (memq (char-syntax (char-after pos)) '(?\\ ?/)))
1235 (setq n (1+ n)
1236 pos (1- pos)))
1237 (not (zerop (% n 2)))))
1238
1239 (defun mic-paren-uncharquote (pos)
1240 "Modify syntax of character at POS, maybe.
1241 If the syntax of character C at POS is escape or quote and if the
1242 character is not escaped or quoted itself then modify its syntax to
1243 punctuation and return the list (C SYNTAX-STRING-OF-C); otherwise nil."
1244 (when (and (<= (point-min) pos)
1245 paren-match-quoted-paren
1246 (mic-paren-is-following-char-quoted pos))
1247 (let ((c (char-after pos)))
1248 (modify-syntax-entry c ".")
1249 (list c (char-to-string (char-syntax c))))))
1250
1251 (defun mic-paren-recharquote (charquote)
1252 "Modify syntax entry according to CHARQUOTE.
1253 If CHARQUOTE is nil, do nothing. Otherwise, it
1254 should be a list of the form (CHAR SYNTAX-STRING)."
1255 (when charquote
1256 (apply 'modify-syntax-entry charquote)))
1257
1258 ;;; ======================================================================
1259 ;;; Initialization when loading
1260
1261 ;;; Try to load the timer feature if it's not already loaded.
1262 (or paren-dont-load-timer
1263 (featurep 'timer)
1264 (condition-case ()
1265 (require 'timer)
1266 (error nil)))
1267
1268 (provide 'mic-paren)
1269 (provide 'paren)
1270
1271 ;;; Local variables:
1272 ;;; coding: utf-8
1273 ;;; End:
1274 ;;; mic-paren.el ends here