;;; mic-paren.el --- advanced highlighting of matching parentheses.;; Version: 3.3 - 2000-08-04;; Author: Mikael Sjödin (mic@docs.uu.se);; Klaus Berndl <berndl@sdm.de>;; Keywords: languages, faces, parenthesis, matching;;;; Additional info:;; Copyright (C) 1997 Mikael Sjödin (mic@docs.uu.se);; Maintenance and development (since v2.1): Klaus Berndl <berndl@sdm.de>;; Original author: Mikael Sjödin -- mic@docs.uu.se;; Additional code by: Vinicius Jose Latorre <vinicius@cpqd.br>;; Steven L Baur <steve@xemacs.org>;; Klaus Berndl <berndl@sdm.de>;;;; This file is *NOT* (yet?) part of GNU Emacs.;;;; This program is free software; you can redistribute it and/or modify;; it under the terms of the GNU General Public License as published by;; the Free Software Foundation; either version 2, or (at your option);; any later version.;;;; This program is distributed in the hope that it will be useful,;; but WITHOUT ANY WARRANTY; without even the implied warranty of;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;; GNU General Public License for more details.;;;; You should have received a copy of the GNU General Public License;; along with GNU Emacs; see the file COPYING. If not, write to the;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;;; Commentary;; ----------------------------------------------------------------------;; Short Description:;;;; Load this file, activate it and Emacs will display highlighting on;; whatever parenthesis (and paired delimiter if you like this) matches;; the one before or after point. This is an extension to the paren.el;; file distributed with Emacs. The default behaviour is similar to;; paren.el but more sophisticated. Normally you can try all default;; settings to enjoy mic-paren.;;;; Or - if you are a LaTeX writer like the current maintainer - try the;; following additional setup in your .emacs:;;;; ;; In LaTeX-mode we want this;; (add-hook 'LaTeX-mode-hook;; (function (lambda ();; (paren-toggle-matching-quoted-paren 1);; (paren-toggle-matching-paired-delimiter 1))));;;; Or - if you are programming in C like languages - try also:;; (add-hook 'c-mode-common-hook;; (function (lambda ();; (paren-toggle-open-paren-context 1))));; ----------------------------------------------------------------------;; ----------------------------------------------------------------------;; Installation:;;;; o Place this file in a directory in your 'load-path and byte-compile;; it. You can surely ignore the warnings.;; o Put the following in your .emacs file:;; (GNU Emacs supports mic-paren only within a window-system but XEmacs;; supports mic-paren also without X);; (when (or (string-match "XEmacs\\|Lucid" emacs-version) window-system);; (require 'mic-paren) ; loading;; (paren-activate) ; activating;; ;;; set here any of the customizable variables of mic-paren, e.g.:;; ;;; ...;; );; o Restart your Emacs. mic-paren is now installed and activated!;; o To list the possible customizations enter `C-h f paren-activate' or;; go to the customization group `mic-paren-matching'.;; ----------------------------------------------------------------------;; Long Description:;;;; mic-paren.el is an extension and replacement to the packages paren.el;; and stig-paren.el for Emacs. When mic-paren is active (it is activated;; when loaded) Emacs normal parenthesis matching is deactivated. Instead;; parenthesis matching will be performed as soon as the cursor is;; positioned at a parenthesis. The matching parenthesis (or the entire;; expression between the parentheses) is highlighted until the cursor;; is moved away from the parenthesis. Features include:;; o Both forward and backward parenthesis matching (simultaneously if;; cursor is between two expressions).;; o Indication of mismatched parentheses.;; o Recognition of "escaped" (also often called "quoted") parentheses.;; o Option to match "escaped" parens too, especially in (La)TeX-mode;; (e.g. matches expressions like "\(foo bar\)" properly).;; o Offers two functions as replacement for forward-sexp and;; backward-sexp which handle properly quoted parens (s.a.). These new;; functions can automatically be bounded to the orgiginal binding of;; the standard forward-sexp and backward-sexp functions.;; o Option to activate matching of paired delimiter (i.e. characters with;; syntax '$'). This is useful for writing in LaTeX-mode for example.;; o Option to select in which situations (always, never, if match, if;; mismatch) the entire expression should be highlighted or only the;; matching parenthesis.;; o Message describing the match when the matching parenthesis is;; off-screen (vertical and/or horizontal). Message contains the;; linenumber. Option to select in which cases this message should be;; displayed.;; o Optional delayed highlighting (useful on slow systems),;; o Functions to activate/deactivate mic-paren.el is provided.;; o Numerous options to control the behaviour and appearance of;; mic-paren.el.;;;; mic-paren.el was originally developed and tested under Emacs 19.28 -;; 20.3. It should work on earlier and forthcoming Emacs versions. XEmacs;; compatibility has been provided by Steven L Baur <steve@xemacs.org>.;; Jan Dubois (jaduboi@ibm.net) provided help to get mic-paren to work in;; OS/2. Mic-paren versions >= v2.1 are only tested with recent Emacsen;; (FSF Emacs >= 20.3.1 and XEmacs >= 21.1) but should also work with;; earlier versions of (X)Emacs.;;;; This file can be obtained from "The Ohio Emacs Lisp State Archive";; http://www.cis.ohio-state.edu/emacs-lisp/.;; ----------------------------------------------------------------------;; Available customizable options:;; - `paren-priority';; - `paren-overlay-priority';; - `paren-sexp-mode';; - `paren-highlight-at-point';; - `paren-highlight-offscreen';; - `paren-display-message';; - `paren-message-linefeed-display';; - `paren-message-no-match';; - `paren-ding-unmatched';; - `paren-delay';; - `paren-dont-touch-blink';; - `paren-match-face';; - `paren-mismatch-face';; - `paren-no-match-paren';; - `paren-bind-modified-sexp-functions';; Available customizable faces:;; - `paren-face-match';; - `paren-face-mismatch';; - `paren-face-no-match';; Available commands:;; - `paren-activate';; - `paren-deactivate';; - `paren-toggle-matching-paired-delimiter';; - `paren-toggle-matching-quoted-paren';; - `paren-toggle-open-paren-context';; - `paren-forward-sexp';; - `paren-backward-sexp';; ----------------------------------------------------------------------;; IMPORTANT NOTES (important for people who have customized mic-paren;; from within elisp):;; - In version >= 3.3 the prefix "mic-" has been removed from the;; command-names 'mic-paren-forward-sexp' and 'mic-paren-backward-sexp'.;; Now all user-functions and -options begin with the prefix "paren-";; because this package should be a replacement of the;; other paren-packages like paren.el and stig-paren.el!;; - In version >= 3.2 the prefix "mic-" has been removed from the;; command-names 'mic-paren-toggle-matching-quoted-paren' and;; 'mic-paren-toggle-matching-paired-delimiter'.;; - In versions >= 3.1 mic-paren is NOT auto. activated after loading.;; - In versions >= 3.0 the variable 'paren-face' has been renamed to;; `paren-match-face'.;; ----------------------------------------------------------------------;; Versions:;; v3.3 + Now the priority of the paren-overlays can be customized;; (option `paren-overlay-priority'). For a description of the;; priority of an overlay see in the emacs-lisp-manual the node;; "Overlays". This option is mainly useful for experienced;; users which use many packages using overlays to perform their;; tasks.;; + Now you can determine what line-context will be displayed if;; the matching open paren is offscreen. In functional;; programming languages like lisp it is useful to display the;; following line in the echo-area if the opening matching paren;; has no preceding text in the same line.;; But in procedural languages like C++ or Java it is convenient;; to display the first previous non empty line in this case;; instead of the following line. Look at the new variable;; `paren-open-paren-context-backward' and the related toggling;; function `paren-toggle-open-paren-context' for a detailed;; description of this new feature.;; + In addition to the previous described new feature you can;; specify how a linefeed in the message (e.g. if the matching;; paren is offscreen) is displayed. This is mainly because the;; standard echo-area display of a linefeed (^J) is bad to read.;; Look at the option `paren-message-linefeed-display'.;; + Solved a little bug in the compatibility-code for Emacsen;; not supporting current customize-feature.;; + Removed the prefix "mic-" from the commands;; 'mic-paren-forward-sexp' and 'mic-paren-backward-sexp'. For;; an explanation look at comments for version v3.2.;;;; v3.2 + The prefix "mic-" has been removed from the commands;; 'mic-paren-toggle-matching-quoted-paren' and;; 'mic-paren-toggle-matching-paired-delimiter'. This is because;; of consistency. Now all user-variables, -faces and -commands;; begin with the prefix "paren-" and all internal functions and;; variables begin with the prefix "mic-paren-".;; + Now you can exactly specify in which situations the whole;; sexp should be highlighted (option `paren-sexp-mode'):;; Always, never, if match or if mismatch. Tested with Gnus;; Emacs >= 20.3.1 and XEmacs >= 21.1.;;;; v3.1 + From this version on mic-paren is not auto. loaded. To;; activate it you must call `paren-activate' (either in your;; .emacs or manually with M-x). Therefore the variable;; `paren-dont-activate-on-load' is obsolet and has been;; removed.;; + Now mic-paren works also in older Emacsen without the;; custom-feature. If the actual custom-library is provided;; mic-paren use them and is full customizable otherwise normal;; defvars are used for the options.;; + Fix of a bug displaying a message if the matching paren is;; horizontal out of view.;; + All new features are now tested with XEmacs >= 21.1.6;;;; v3.0 + Checking if matching paren is horizontally offscreen (in case;; of horizontal scrolling). In that case the message is;; displayed in the echo-area (anlogue to vertical offscreen).;; In case of horizontal offscreen closing parenthesis the;; displayed message is probably wider than the frame/window. So;; you can only read the whole message if you are using a;; package like mscroll.el (scrolling long messages) in GNU;; Emacs.;; + Now full customizable, means all user-options and -faces now;; can be set with the custom-feature of Emacs. On the other;; side this means this version of mic-paren only works with an;; Emacs which provides the custom-package!;; + In case of the matching paren is offscreen now the displayed;; message contains the linenumber of the matching paren too.;; This version is only tested with Gnu Emacs >= 20.4 and not with;; any XEmacs!;; Implemented by Klaus Berndl <berndl@sdm.de>;;;; v2.3 No additional feature but replacing 'char-bytes and;; 'char-before with 'mic-char-bytes and 'mic-char-before to;; prevent the global-namespace. Now the new features of v2.1;; and v2.2 are also tested with XEmacs!;;;; v2.2 Adding the new feature for matching paired delimiter. Not;; tested with XEmacs. Implemented by Klaus Berndl <berndl@sdm.de>;;;; v2.1 Adding the new feature for matching escaped parens too. Not;; tested with XEmacs. Implemented by Klaus Berndl <berndl@sdm.de>;;;; v2.0 Support for MULE and Emacs 20 multibyte characters added. Inspired;; by the suggestion and code of Saito Takaaki;; <takaaki@is.s.u-tokyo.ac.jp>;;;; v1.9 Avoids multiple messages/dings when point has not moved. Thus,;; mic-paren no longer overwrites messages in minibuffer. Inspired by;; the suggestion and code of Barzilay Eliyahu <eli@cs.bgu.ac.il>.;;;; v1.3.1 Some spelling corrected (from Vinicius Jose Latorre;; <vinicius@cpqd.br> and Steven L Baur <steve@xemacs.org>);;;; v1.3 Added code from Vinicius Jose Latorre <vinicius@cpqd.br> to;; highlight unmatched parentheses (useful in minibuffer);;;; v1.2.1 Fixed stuff to work with OS/2 emx-emacs;; - checks if x-display-colour-p is bound before calling it;; - changed how X/Lucid Emacs is detected;; Added automatic load of the timer-feature (+ variable to disable;; the loading);; TODO:;;;; + mic-paren-horizontal-pos-visible-p seems to have a very little bug;; (in 99.99% it should work, but maybe the limit-values in the;; comparisons differ from the correct value by 1 or 2; normally this;; doesn't matter!);; Suggestions for further releases:;;;; + [HARD] highlighting the parens between point is, means between the;; opening and the closing (Bernd Wolter Bernd.Wolter@mchm.siemens.de);;; Code(defvarmic-paren-version"3.3""Version string for mic-paren.");;; ======================================================================;; Compatibility stuff ;; BLOB to make custom stuff work even without customize(eval-and-compile(condition-case()(require'custom)(errornil))(unless(fboundp'defgroup)(defmacrodefgroup(&restrest)()))(unless(fboundp'defcustom)(defmacrodefcustom(symvalstr&restrest)`(defvar,sym,val,str)))(unless(fboundp'defface)(defmacrodefface(symvalstr&restrest)`(defvar,sym(make-face',sym),str))));;; ======================================================================;;; here begin the user options(defgroupmic-paren-matchingnil"Showing advanced (un)matching of parens and expressions.":prefix"paren-":group'paren-matching)(defcustomparen-priority'both"*Defines the behaviour of mic-paren when point is between aclosing and an opening parenthesis. This means what should be done in asituation like this: \(a b)\(c d) ^ point- 'close means highlight the parenthesis matching the close-parenthesis before the point \(highlight opening paren before 'a').- 'open means highlight the parenthesis matching the open-parenthesis after the point \(highlight closing paren after 'd').- 'both means highlight both parenthesis matching the parenthesis beside the point \(highlight opening before 'a' and closing after 'd').":type'(choice(const:tag"Match close"close)(const:tag"Match open"open)(const:tag"Match both"both)):group'mic-paren-matching)(defcustomparen-overlay-priority999"*Specify paren overlay priority \(Integer >= 0\). For a description of thepriority of an overlay see in the emacs-lisp manual the node Overlays.Normally you don't want to change the default-value!":set#'(lambda(symbolvalue)(setsymbol(if(<value0)(*-1value)value))):initialize'custom-initialize-default:type'integer:group'mic-paren-matching)(defcustomparen-sexp-modenil"*Defines in which situations the whole sexp should be highlighted.This means the whole s-expression between the matching parenthesis ishighlighted instead of only the matching/mismatching parenthesis.- t: Always highlight the whole s-expression.- nil: Never highlight the whole s-expression.- 'match: Highlight the whole s-expression only if the parens match.- 'mismatch: Highlight the whole s-expression only if the parens don't match.":type'(choice(const:tag"Never sexp-mode"nil)(const:tag"Always sexp-mode"t)(const:tag"If match"match)(const:tag"If mismatch"mismatch)):group'mic-paren-matching)(defcustomparen-highlight-at-pointt"*If non-nil and point is after a close parenthesis, both the closeand open parenthesis is highlighted. If nil, only the open parenthesis ishighlighted.":type'(choice(const:tag"Highlight both"t)(const:tag"Highlight open"nil)):group'mic-paren-matching)(defcustomparen-highlight-offscreennil"*If non-nil mic-paren will highlight text which is not visible in thecurrent buffer.This is useful if you regularly display the current buffer in multiplewindows or frames. For instance if you use follow-mode \(byandersl@csd.uu.se), however it may slow down your Emacs.\(This variable is ignored \(treated as non-nil) if you set paren-sexp-mode tonon-nil.)":type'boolean:group'mic-paren-matching)(defcustomparen-display-message'only"*Display message if matching parenthesis is off-screen.Possible settings are:- 'always: message is always displayed regardless if offscreen or not- 'only: message is only displayed when matching is offscreen- 'never: never a message is displayed.":type'(choice(const:tag"Display always"always)(const:tag"Display if offscreen"only)(const:tag"No Message display"never)):group'mic-paren-matching)(defcustomparen-message-linefeed-display" RET ""*How a linefeed in the matching paren context message is displayed.There are three predefined values:- Displays linefeeds with \" RET \" in the message.- Displays linefeeds with a SPACE in the message.- Displays linefeeds in the standard-form, means with \"^J\".But you can also specify any user-defined string for it.For further explanations about message displaying look at`paren-display-message'.":type'(choice(const:tag"Display with \"RET\"":value" RET ")(const:tag"Display with a SPACE":value" ")(const:tag"Standard":value"^J")(string:tag"User defined")):group'mic-paren-matching)(defcustomparen-message-no-matcht"*Display message if no matching parenthesis is found.":type'(choice(const:tag"Display message"t)(const:tag"No message"nil)):group'mic-paren-matching)(defcustomparen-ding-unmatchednil"*Non nil means make noise if the cursor is at an unmatchedparenthesis or no matching parenthesis is found.Even if nil, typing an unmatched parenthesis produces a ding.":type'boolean:group'mic-paren-matching)(defcustomparen-delaynil"*This variable controls when highlighting is done.The variable has different meaning in different versions of Emacs.In Emacs 19.29 and below: This variable is ignored.In Emacs 19.30: A value of nil will make highlighting happen immediately \(this may slow down your Emacs if running on a slow system). Any non-nil value will delay highlighting for the time specified by post-command-idle-delay.In Emacs 19.31 and above: A value of nil will make highlighting happen immediately \(this may slow down your Emacs if running on a slow system). If not nil, the value should be a number \(possible a floating point number if your Emacs support floating point numbers). The number is the delay in seconds before mic-paren performs highlighting.If you change this variable when mic-paren is active you have tore-activate \(with M-x paren-activate) mic-paren for the change to takeeffect.":type'(choice(number:tag"Delay time")(const:tag"No delay"nil)):group'mic-paren-matching)(defcustomparen-dont-touch-blinknil"*Non-nil means not to change the value of blink-matching-parenwhen mic-paren is activated of deactivated.If nil mic-paren turns of blinking when activated and turns on blinking whendeactivated.":type'boolean:group'mic-paren-matching)(defcustomparen-dont-load-timer(not(string-match"XEmacs\\|Lucid"emacs-version))"*If non-nil mic-paren will not try to load the timer-feature whenloaded.\(I have no idea why Emacs user ever want to set this to non-nil but I hatepackages which loads/activates stuff I don't want to use so I provide thisway to prevent the loading if someone doesn't want timers to be loaded.)":type'boolean:group'mic-paren-matching)(defcustomparen-bind-modified-sexp-functionst"*Automatic binding of the new sexp-functions to the old bindings.If non nil mic-paren checks at load-time the keybindings for the functions`forward-sexp' and `backward-sexp' and binds the modified sexp-functions`paren-forward-sexp' and `paren-backward-sexp' to exactly thesebindings if and only if matching quoted/escaped parens is turned on by`paren-toggle-matching-quoted-paren'. These new binding is done onlyfor the buffer local-key-map, therefore if you activate the quoted matchingonly in some modes from within a hook only in these buffers the new bindingis active and 'in all other not.If you deactivate the quoted matching feature by`paren-toggle-matching-quoted-paren' then `forward-sexp' and`backward-sexp' will be bound again to their original key-bindings!":type'boolean:group'mic-paren-matching);;; ------------------------------;;; Faces;;; ------------------------------(deffaceparen-face-match'((((classcolor))(:background"turquoise"))(t(:background"gray")))"Mic-paren mode face used for a matching paren.":group'faces:group'mic-paren-matching)(deffaceparen-face-mismatch'((((classcolor))(:foreground"white":background"purple"))(t(:reverse-videot)))"Mic-paren mode face used for a mismatching paren.":group'faces:group'mic-paren-matching)(deffaceparen-face-no-match'((((classcolor))(:foreground"black":background"yellow"))(t(:reverse-videot)))"Mic-paren mode face used for an unmatched paren.":group'faces:group'mic-paren-matching)(defcustomparen-match-face'paren-face-match"*Face to use for showing the matching parenthesis.":type'face:group'mic-paren-matching)(defcustomparen-mismatch-face'paren-face-mismatch"*Face to use when highlighting a mismatched parenthesis.":type'face:group'mic-paren-matching)(defcustomparen-no-match-face'paren-face-no-match"*Face to use when highlighting an unmatched parenthesis.":type'face:group'mic-paren-matching);;; End of User Options:;;; ======================================================================;;; Below there are only variables and options which either should be not;;; set directly but with toggle-functions or pure internal variables(defvarparen-match-quoted-parennil"*Non-nil causes to match properly quoted \(or escaped\) parens \(e.g. inTeX-files, e.g. \"\\\(x-3y + z = 7\\\)\"\). FSF-Emacs can not match quotedparens, so we must temporally deactivate the quoting until emacs has doneits sexp-parsing. Therefore emacs itself does not \(can not!\) take intoconsideration if either both matched parens are quoted or none. Butnevertheless we do this! Only symmetric balanced parens are matched: meanseither both matching parens must we quoted or none, otherwise they we willbe highlighted as mismatched.This package offers also two slightly modified versions of forward-sexp\(resp. backward-sexp\):`paren-forward-sexp'\(`paren-backward-sexp'\). This versions can alsojump to escaped/quoted parens.If this variable is not nil and `paren-bind-modified-sexp-functions' is setto non nil then `paren-toggle-matching-quoted-paren' will also togglethe original binding of `forward-sexp' \(resp. backward-sexp\) between theoriginal functions and the modified equivalents.Do NOT set this variable directly but use`paren-toggle-matching-quoted-paren' to activate/deactivate/toggle thisfeature!. The best method is to do this in a mode hook, e.g.:\(add-hook \'LaTeX-mode-hook \(function \(lambda \(\) \(paren-toggle-matching-quoted-paren 1\)\)\)\)")(make-variable-buffer-local'paren-match-quoted-paren)(defvarparen-match-paired-delimiternil"*If not nil then characters with syntax '$' \(means paired delimiter\)will be matched if possible (e.g. in LaTeX \"$...$\" is equal with\"\\(...\\)\"\) . Unlike to parens quoted/escaped paired delimiter willnever match.Do NOT set this variable directly but use`paren-toggle-matching-paired-delimiter' to activate/deactivate/togglethis feature!. The best method is to do this in a mode hook, e.g.:\(add-hook \'LaTeX-mode-hook \(function \(lambda \(\) \(paren-toggle-matching-paired-delimiter 1\)\)\)\)")(make-variable-buffer-local'paren-match-paired-delimiter)(defvarparen-open-paren-context-backwardnil"*Determines which context of the matching open paren will be displayedif the matching open paren is offscreen or `paren-display-message' is'always \(look at the documentation of `paren-display-message'\) and thematching open paren has no previous text in the same line.Meaning of the setting:- nil: Contents of the **next** not empty and not whitespace-line will be displayed. This value is useful for example in functional programming languages like \(emacs\)lisp.- not nil: Contents of the first **previous** not empty and not only whitespace-line will be displayed. This value is useful for example in procedural programming languages like C, C++, Java etc.Lets take a look at a short example:In languages like C++ we often have situations like if \(i > VALUE\) \{ // some code \}With a value non nil the displayed opening-brace context would be\"if \(i > VALUE\)^J\{\" but with nil it would be \"\{^J // some code\"which would be in C++ lesser useful as the non nil version.\(The ^J stands for a newline in the buffer\).Do NOT set this variable directly but use `paren-toggle-open-paren-context'to change the value of this option!. The best method is to do this in amode hook, e.g.:\(add-hook \'c-common-mode-hook \(function \(lambda \(\) \(paren-toggle-open-paren-context 1\)\)\)\)")(make-variable-buffer-local'paren-open-paren-context-backward)(defconstmic-paren-original-keybinding-of-sexp-functions(list(car(where-is-internal'forward-sexp))(car(where-is-internal'backward-sexp))));;; Compatibility.;;; Try to make mic-paren work in different Emacs flavours.;; XEmacs compatibility (mainly by Steven L Baur <steve@xemacs.org>)(eval-and-compile(if(string-match"\\(Lucid\\|XEmacs\\)"emacs-version)(progn(fset'mic-make-overlay'make-extent)(fset'mic-delete-overlay'delete-extent)(fset'mic-overlay-put'set-extent-property)(defunmic-cancel-timer(timer)(delete-itimertimer))(fset'mic-run-with-idle-timer'start-itimer))(fset'mic-make-overlay'make-overlay)(fset'mic-delete-overlay'delete-overlay)(fset'mic-overlay-put'overlay-put)(fset'mic-cancel-timer'cancel-timer)(fset'mic-run-with-idle-timer'run-with-idle-timer)));; MULE and Emacs 20 multibyte char compatibility.;; Implemented by defining dummys for functions which do not exist in vanilla;; Emacs.(if(fboundp'char-bytes)(fset'mic-char-bytes'char-bytes)(defunmic-char-bytes(ch)"Returns 1 for all input CH.Function defined by mic-paren to be compatible with multibyte Emacses."1))(if(fboundp'char-before)(fset'mic-char-before'char-before)(defunmic-char-before(pos)"Return character in current buffer preceding position POS.POS is an integer or a buffer pointer.If POS is out of range, the value is nil.Function defined by mic-paren to be compatible with multibyte Emacses."(char-after(1-pos))));;; ======================================================================;;; User Functions:;;;###autoload(defunparen-activate()"Activates mic-paren parenthesis highlighting.paren-activate deactivates the paren.el and stig-paren.el packages if they areactive !The following options are available via the customize-feature: `paren-priority' `paren-overlay-priority' `paren-sexp-mode' `paren-highlight-at-point' `paren-highlight-offscreen' `paren-display-message' `paren-message-linefeed-display' `paren-message-no-match' `paren-ding-unmatched' `paren-delay' `paren-dont-touch-blink' `paren-match-face' `paren-mismatch-face' `paren-no-match-face' `paren-bind-modified-sexp-functions'The following options are settable via toggling functions \(look at thedocumentation of these options for the names of these functions\): `paren-match-quoted-paren' `paren-match-paired-delimiter' `paren-open-paren-context-backward'"(interactive);; Deactivate mic-paren.el (To remove redundant hooks)(paren-deactivate);; Deactivate paren.el if loaded(if(boundp'post-command-idle-hook)(remove-hook'post-command-idle-hook'show-paren-command-hook))(remove-hook'post-command-hook'show-paren-command-hook)(and(boundp'show-paren-overlay)show-paren-overlay(mic-delete-overlayshow-paren-overlay))(and(boundp'show-paren-overlay-1)show-paren-overlay-1(mic-delete-overlayshow-paren-overlay-1));; Deactivate stig-paren.el if loaded(if(boundp'post-command-idle-hook)(remove-hook'post-command-idle-hook'stig-paren-command-hook))(remove-hook'post-command-hook'stig-paren-command-hook)(remove-hook'post-command-hook'stig-paren-safe-command-hook)(remove-hook'pre-command-hook'stig-paren-delete-overlay);; Deactivate Emacs standard parenthesis blinking(orparen-dont-touch-blink(setqblink-matching-parennil))(cond(;; If timers are available use them;; (Emacs 19.31 and above)(featurep'timer)(if(numberpparen-delay)(setqmic-paren-idle-timer(mic-run-with-idle-timerparen-delayt'mic-paren-command-idle-hook))(add-hook'post-command-hook'mic-paren-command-hook)));; If the idle hook exists assume it is functioning and use it;; (Emacs 19.30)((and(boundp'post-command-idle-hook)(boundp'post-command-idle-delay))(ifparen-delay(add-hook'post-command-idle-hook'mic-paren-command-idle-hook)(add-hook'post-command-hook'mic-paren-command-hook)));; Check if we (at least) have a post-comand-hook, and use it;; (Emacs 19.29 and below)((boundp'post-command-hook)(add-hook'post-command-hook'mic-paren-command-hook));; Not possible to install mic-paren hooks(t(error"Cannot activate mic-paren in this Emacs version"))));;;###autoload(defunparen-deactivate()"Deactivates mic-paren parenthesis highlighting"(interactive);; Deactivate (don't bother to check where/if mic-paren is acivte, just;; delete all possible hooks and timers)(if(boundp'post-command-idle-hook)(remove-hook'post-command-idle-hook'mic-paren-command-idle-hook))(ifmic-paren-idle-timer(mic-cancel-timermic-paren-idle-timer))(remove-hook'post-command-hook'mic-paren-command-hook);; Remove any old highlighs(mic-delete-overlaymic-paren-backw-overlay)(mic-delete-overlaymic-paren-point-overlay)(mic-delete-overlaymic-paren-forw-overlay);; Reactivate Emacs standard parenthesis blinking(orparen-dont-touch-blink(setqblink-matching-parent)));;;###autoload(defunparen-toggle-matching-paired-delimiter(arg)"Toggle matching paired delimiter, force on with positive arg. Use thisin mode-hooks to activate or deactivate paired delimiter matching."(interactive"P")(setqparen-match-paired-delimiter(if(numberparg)(>arg0)(notparen-match-paired-delimiter)))(message"Matching paired delimiter is %s"(ifparen-match-paired-delimiter"ON, you should be in (La)TeX-mode!""OFF")));;;###autoload(defunparen-toggle-matching-quoted-paren(arg)"Toggle matching quoted parens, force on with positive arg. Use this inmode-hooks to activate or deactivate quoted paren matching."(interactive"P")(setqparen-match-quoted-paren(if(numberparg)(>arg0)(notparen-match-quoted-paren)));; if matching quoted parens is active now bind the original binding of;; forward-sexp and backward-sexp to the modified;; versions paren-forward-sexp (resp. paren-backward-sexp);; if not bind it back to the original forward-sexp (resp. backward-sexp).(let((key-forward-sexp(carmic-paren-original-keybinding-of-sexp-functions))(key-backward-sexp(car(cdrmic-paren-original-keybinding-of-sexp-functions))))(if(andparen-bind-modified-sexp-functionskey-backward-sexpkey-forward-sexp)(ifparen-match-quoted-paren(progn(local-set-keykey-forward-sexp(quoteparen-forward-sexp))(local-set-keykey-backward-sexp(quoteparen-backward-sexp)))(global-set-keykey-forward-sexp(quoteforward-sexp))(global-set-keykey-backward-sexp(quotebackward-sexp)))))(message"Matching quoted parens is %s"(ifparen-match-quoted-paren"ON, you should be in (La)TeX-mode!""OFF")));;;###autoload(defunparen-toggle-open-paren-context(arg)"Toggle the determining of the context to display of the matchingopen-paren, force backward context with positive arg. Use this in mode-hooks.For a description of the meaning look at `paren-open-paren-context-backward'."(interactive"P")(setqparen-open-paren-context-backward(if(numberparg)(>arg0)(notparen-open-paren-context-backward))));;;###autoload(defunparen-forward-sexp(&optionalarg)"Acts like forward-sexp but can also matching quoted parens. Look at`paren-match-quoted-paren' for a detailed comment"(interactive"p")(orarg(setqarg1))(let*((uncharquote-diff(if(<arg0)21))(match-check-diff(if(<arg0)12))(charquote(mic-paren-uncharquote(-(point)uncharquote-diff)))match-posmismatch);; we must encapsulate this in condition-case so we regain control;; after error and we can undo our unquoting if any done before!(condition-case()(setqmatch-pos(scan-sexps(point)arg))(errornil))(mic-paren-recharquotecharquote)(if(notmatch-pos)(buffer-endarg)(setqmismatch(ifcharquote(not(mic-paren-is-following-char-quoted(-match-posmatch-check-diff)))(mic-paren-is-following-char-quoted(-match-posmatch-check-diff))))(if(notmismatch)(goto-charmatch-pos)(forward-sexparg)))));;;###autoload(defunparen-backward-sexp(&optionalarg)"Acts like backward-sexp but can also matching quoted parens. Look at`paren-match-quoted-paren' for a detailed comment"(interactive"p")(orarg(setqarg1))(paren-forward-sexp(-arg)));;; ======================================================================;;; Pure Internal variables:(defvarmic-paren-backw-overlay(mic-make-overlay(point-min)(point-min))"Overlay for the open-paren which matches the close-paren beforepoint. When in sexp-mode this is the overlay for the expression before point.")(defvarmic-paren-point-overlay(mic-make-overlay(point-min)(point-min))"Overlay for the close-paren before point.\(Not used when is sexp-mode.)")(defvarmic-paren-forw-overlay(mic-make-overlay(point-min)(point-min))"Overlay for the close-paren which matches the open-paren afterpoint. When in sexp-mode this is the overlay for the expression after point.")(defvarmic-paren-idle-timernil"Idle-timer. Used only in Emacs 19.31 and above \(and if paren-delay isnil)")(defvarmic-paren-previous-location[nilnilnil]"Records where point was the last time mic-paren performed some action.Format is [POINT BUFFER WINDOW]");;; ======================================================================;;; Internal function:(defunmic-paren-command-hook()(orexecuting-kbd-macro(input-pending-p);[This might cause trouble since the; function is unreliable](condition-caseparen-error(mic-paren-highlight)(error(if(not(window-minibuffer-p(selected-window)))(message"mic-paren catched error (please report): %s"paren-error))))))(defunmic-paren-command-idle-hook()(condition-caseparen-error(mic-paren-highlight)(error(if(not(window-minibuffer-p(selected-window)))(message"mic-paren catched error (please report): %s"paren-error)))));; helper macro to set a FACE and the value of `paren-overlay-priority';; to an OVERLAY.(defmacromic-paren-overlay-set(overlayface)`(progn(mic-overlay-put,overlay'face,face)(mic-overlay-put,overlay'priorityparen-overlay-priority)))(defunmic-paren-highlight()"The main-function of mic-paren. Does all highlighting, dinging, messages,cleaning-up.";; Remove any old highlighting(mic-delete-overlaymic-paren-forw-overlay)(mic-delete-overlaymic-paren-point-overlay)(mic-delete-overlaymic-paren-backw-overlay);; Handle backward highlighting (when after a close-paren or a paired;; delimiter):;; If (positioned after a close-paren, and;; not before an open-paren when priority=open, and;; (paren-match-quoted-paren is t or the close-paren is not escaped));; or;; (positioned after a paired delimiter, and;; not before a paired-delimiter when priority=open, and;; the paired-delimiter is not escaped));; then;; perform highlighting(if(or(and(eq(char-syntax(preceding-char))?\))(not(and(eq(char-syntax(following-char))?\()(eqparen-priority'open)))(orparen-match-quoted-paren(not(mic-paren-is-following-char-quoted(-(point)2)))))(andparen-match-paired-delimiter(eq(char-syntax(preceding-char))?\$)(not(and(eq(char-syntax(following-char))?\$)(eqparen-priority'open)))(not(mic-paren-is-following-char-quoted(-(point)2)))))(let(openmatched-parencharquote);; if we want to match quoted parens we must change the syntax of;; the escape or quote-char temporarily. This will be undone later.(setqcharquote(mic-paren-uncharquote(-(point)2)));; Find the position for the open-paren(save-excursion(save-restriction(ifblink-matching-paren-distance(narrow-to-region(max(point-min)(-(point)blink-matching-paren-distance))(point-max)))(condition-case()(setqopen(scan-sexps(point)-1))(errornil))));; we must call matching-paren because scan-sexps don't care about;; the kind of paren (e.g. matches '( and '}). matching-paren only;; returns the character displaying the matching paren in buffer's;; syntax-table (regardless of the buffer's current contents!).;; Below we compare the results of scan-sexps and matching-paren;; and if different we display a mismatch.(setqmatched-paren(matching-paren(preceding-char)));; matching-paren can only handle characters with syntax ) or ((if(eq(char-syntax(preceding-char))?\$)(setqmatched-paren(preceding-char)));; if we have changed the syntax of the escape or quote-char we;; must undo this and we can do this first now.(mic-paren-recharquotecharquote);; If match found;; highlight expression and/or print messages;; else;; highlight unmatched paren;; print no-match message(ifopen(let((mismatch(or(notmatched-paren)(/=matched-paren(char-afteropen))(ifcharquote(not(mic-paren-is-following-char-quoted(1-open)))(mic-paren-is-following-char-quoted(1-open)))));; check if match-pos is visible(visible(and(pos-visible-in-window-popen)(mic-paren-horizontal-pos-visible-popen))));; If highlight is appropriate;; highlight;; else;; remove any old highlight(if(orvisibleparen-highlight-offscreenparen-sexp-mode);; If sexp-mode;; highlight sexp;; else;; highlight the two parens(if(mic-paren-sexp-mode-pmismatch)(progn(setqmic-paren-backw-overlay(mic-make-overlayopen(point)))(ifmismatch(mic-paren-overlay-setmic-paren-backw-overlayparen-mismatch-face)(mic-paren-overlay-setmic-paren-backw-overlayparen-match-face)))(setqmic-paren-backw-overlay(mic-make-overlayopen(+open(mic-char-bytes(char-afteropen)))))(andparen-highlight-at-point(setqmic-paren-point-overlay(mic-make-overlay(-(point)(mic-char-bytes(preceding-char)))(point))))(ifmismatch(progn(mic-paren-overlay-setmic-paren-backw-overlayparen-mismatch-face)(andparen-highlight-at-point(mic-paren-overlay-setmic-paren-point-overlayparen-mismatch-face)))(mic-paren-overlay-setmic-paren-backw-overlayparen-match-face)(andparen-highlight-at-point(mic-paren-overlay-setmic-paren-point-overlayparen-match-face)))));; Print messages if match is offscreen(and(not(eqparen-display-message'never))(or(notvisible)(eqparen-display-message'always))(not(window-minibuffer-p(selected-window)))(mic-paren-is-new-location)(message"%s %s"(ifmismatch"MISMATCH:""Matches")(mic-paren-get-matching-open-textopen)));; Ding if mismatch(andmismatchparen-ding-unmatched(mic-paren-is-new-location)(ding)))(setqmic-paren-backw-overlay(mic-make-overlay(point)(-(point)(mic-char-bytes(preceding-char)))))(mic-paren-overlay-setmic-paren-backw-overlayparen-no-match-face)(andparen-message-no-match(not(window-minibuffer-p(selected-window)))(mic-paren-is-new-location)(message"No opening parenthesis found"))(andparen-message-no-matchparen-ding-unmatched(mic-paren-is-new-location)(ding)))));; Handle forward highlighting (when before an open-paren or a paired;; delimiter):;; If (positioned before an open-paren, and;; not after a close-paren when priority=close, and;; (paren-match-quoted-paren is t or the open-paren is not escaped));; or;; (positioned before a paired delimiter, and;; not after a paired-delimiter when priority=close, and;; the paired-delimiter is not escaped));; then;; perform highlighting(if(or(and(eq(char-syntax(following-char))?\()(not(and(eq(char-syntax(preceding-char))?\))(eqparen-priority'close)))(orparen-match-quoted-paren(not(mic-paren-is-following-char-quoted(1-(point))))))(andparen-match-paired-delimiter(eq(char-syntax(following-char))?\$)(not(and(eq(char-syntax(preceding-char))?\$)(eqparen-priority'close)))(not(mic-paren-is-following-char-quoted(1-(point))))))(let(closematched-parencharquote);; if we want to match quoted parens we must change the syntax of;; the escape or quote-char temporarily. This will be undone later.(setqcharquote(mic-paren-uncharquote(1-(point))));; Find the position for the close-paren(save-excursion(save-restriction(ifblink-matching-paren-distance(narrow-to-region(point-min)(min(point-max)(+(point)blink-matching-paren-distance))))(condition-case()(setqclose(scan-sexps(point)1))(errornil))));; for an explanation look above.(setqmatched-paren(matching-paren(following-char)))(if(eq(char-syntax(following-char))?\$)(setqmatched-paren(following-char)));; if we have changed the syntax of the escape or quote-char we;; must undo this and we can do this first now.(mic-paren-recharquotecharquote);; If match found;; highlight expression and/or print messages;; else;; highlight unmatched paren;; print no-match message(ifclose(let((mismatch(or(notmatched-paren)(/=matched-paren(mic-char-beforeclose))(ifcharquote(not(mic-paren-is-following-char-quoted(-close2)))(mic-paren-is-following-char-quoted(-close2)))));; check if match-pos is visible(visible(and(pos-visible-in-window-pclose)(mic-paren-horizontal-pos-visible-pclose))));; If highlight is appropriate;; highlight;; else;; remove any old highlight(if(orvisibleparen-highlight-offscreenparen-sexp-mode);; If sexp-mode;; highlight sexp;; else;; highlight the two parens(if(mic-paren-sexp-mode-pmismatch)(progn(setqmic-paren-forw-overlay(mic-make-overlay(point)close))(ifmismatch(mic-paren-overlay-setmic-paren-forw-overlayparen-mismatch-face)(mic-paren-overlay-setmic-paren-forw-overlayparen-match-face)))(setqmic-paren-forw-overlay(mic-make-overlay(-close(mic-char-bytes(mic-char-beforeclose)))close))(ifmismatch(mic-paren-overlay-setmic-paren-forw-overlayparen-mismatch-face)(mic-paren-overlay-setmic-paren-forw-overlayparen-match-face))));; Print messages if match is offscreen(and(not(eqparen-display-message'never))(or(notvisible)(eqparen-display-message'always))(not(window-minibuffer-p(selected-window)))(mic-paren-is-new-location)(message"%s %s"(ifmismatch"MISMATCH:""Matches")(mic-paren-get-matching-close-textclose)));; Ding if mismatch(andmismatch(mic-paren-is-new-location)paren-ding-unmatched(ding)))(setqmic-paren-forw-overlay(mic-make-overlay(point)(+(point)(mic-char-bytes(following-char)))))(mic-paren-overlay-setmic-paren-forw-overlayparen-no-match-face)(andparen-message-no-match(not(window-minibuffer-p(selected-window)))(mic-paren-is-new-location)(message"No closing parenthesis found"))(andparen-message-no-matchparen-ding-unmatched(mic-paren-is-new-location)(ding)))));; Store the points position in mic-paren-previous-location;; Later used by mic-paren-is-new-location(or(window-minibuffer-p(selected-window))(progn(asetmic-paren-previous-location0(point))(asetmic-paren-previous-location1(current-buffer))(asetmic-paren-previous-location2(selected-window)))));;; --------------------------------------------------(defunmic-paren-sexp-mode-p(mismatch)"Check if we must highlight the whole sexp and return t if we must"(cond((eqparen-sexp-modenil)nil)((eqparen-sexp-modet)t)((eqparen-sexp-mode'match)(notmismatch))((eqparen-sexp-mode'mismatch)mismatch)));;; --------------------------------------------------(defunmic-paren-horizontal-pos-visible-p(match-pos)"Returns non nil if the MATCH-POS is horizontal visible otherwise nil \(incase of horizontal scrolling)."(let((match-column(save-excursion(goto-charmatch-pos)(current-column))))(if(>(window-hscroll)0)(and(>=match-column(window-hscroll))(<match-column(+(window-hscroll)(window-width))))(<match-column(window-width)))))(defunmic-paren-get-matching-open-text(open)"Returns a string with the context around OPEN-paren.";; If there's stuff on this line preceding the paren, then display text from;; beginning of line to paren.;;;; If, however, the paren is at the beginning of a line (means only;; whitespace before the paren), then skip whitespace forward and display;; text from paren to end of the next line containing non-space text. But;; if `paren-open-paren-context-backward' is non nil then skip;; whitespaces backward and display text from beginning of previous line;; to paren.(let((str(save-excursion(goto-charopen)(if(save-excursion(skip-chars-backward" \t")(not(bolp)))(progn(beginning-of-line)(format"%s... [%d-]"(buffer-substring(point)(1+open))(count-lines(point-min)open)))(let(paren-context-string)(if(notparen-open-paren-context-backward)(progn(forward-char1)(skip-chars-forward"\n \t")(end-of-line)(setqparen-context-string(buffer-substringopen(point))))(skip-chars-backward"\n \t")(beginning-of-line)(setqparen-context-string(buffer-substring(point)(1+open))))(format"%s [%d]"paren-context-string(count-lines(point-min)open)))))))(while(string-match"[\n]"str)(setqstr(replace-matchparen-message-linefeed-displayniltstr)))str))(defunmic-paren-get-matching-close-text(close)"Returns a string with the context around CLOSE-paren.";; The whole line up until the close-paren with "..." appended if there are;; more text after the close-paren(let((str(save-excursion(goto-charclose)(forward-char-1)(skip-chars-backward"\n \t")(beginning-of-line)(format"%s%s [%d]"(buffer-substring(point)close)(progn(goto-charclose)(if(looking-at"[ \t]*$")"""..."))(count-lines(point-min)close)))))(while(string-match"[\n]"str)(setqstr(replace-matchparen-message-linefeed-displayniltstr)))str))(defunmic-paren-is-new-location()"Returns t if the points location is not the same as stored in`mic-paren-previous-location', nil otherwise.The variable `mic-paren-previous-location' is set by`mic-paren-highlight'."(not(and(eq(point)(arefmic-paren-previous-location0))(eq(current-buffer)(arefmic-paren-previous-location1))(eq(selected-window)(arefmic-paren-previous-location2)))))(defunmic-paren-is-following-char-quoted(pnt)"returns true if character at point PNT escapes or quotes the followingchar."(let((n0))(while(and(>=pnt(point-min))(or(eq(char-syntax(char-afterpnt))?\\)(eq(char-syntax(char-afterpnt))?/)))(setqn(1+n))(setqpnt(1-pnt)))(if(eq0(%n2))nilt)))(defunmic-paren-uncharquote(pnt)"if the syntax of character <c> at point PNT is escape or quote and if thecharacter is not escaped or quoted itself then its syntax will be modifiedto punctuation and multiple values \(<c> \"<syntax-of-c>\") will be returned;otherwise nil."(let(ccs)(if(<pnt(point-min))nil(setqc(char-afterpnt))(setqcs(char-syntaxc))(if(not(andparen-match-quoted-paren(mic-paren-is-following-char-quotedpnt)))nil(modify-syntax-entryc".")(listc(char-to-stringcs))))))(defunmic-paren-recharquote(charquote)"CHARQUOTE is a 2-element-list: car is a character <c> and its cadris a syntaxstring <s>. The syntax of character <c> will be set to syntax<s>. If CHARQUOTE is nil nothing will be done."(ifcharquote(modify-syntax-entry(carcharquote)(car(cdrcharquote)))));;; ======================================================================;;; Initialisation when loading:;;; Try to load the timer feature if its not already loaded(orparen-dont-load-timer(featurep'timer)(condition-case()(require'timer)(errornil)));;; no auto. loading;;;(or paren-dont-activate-on-load;;; (paren-activate));;;;;;;;; This is in case mic-paren.el is preloaded. [Does this work? /Mic];;;(add-hook 'window-setup-hook;;; (function (lambda ();;; (and window-system;;; (not paren-dont-activate-on-load);;; (paren-activate)))))(provide'mic-paren)(provide'paren);; mic-paren.el ends here