diff lisp/packages/blink-paren.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/packages/blink-paren.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,180 @@
+;;; blink-paren.el --- blink the matching paren, just like Zmacs
+;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+
+;; Author: devin@lucid.com.
+;; Keywords: faces
+
+;; This file is part of XEmacs.
+
+;; XEmacs 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.
+
+;; XEmacs 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 XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Synched up with: Not in FSF.
+
+(defvar blink-paren-timeout 0.2
+  "*If the cursor is on a parenthesis, the matching parenthesis will blink.
+This variable controls how long each phase of the blink lasts in seconds.
+This should be a fractional part of a second (a float.)")
+
+(defvar highlight-paren-expression nil
+  "*If true, highlight the whole expression of the paren under the cursor
+instead of blinking (or highlighting) the matching paren.  This will highlight
+the expression using the `highlight-expression' face.")
+
+;;; The blinking paren alternates between the faces blink-paren-on and
+;;; blink-paren-off.  The default is for -on to look just like default
+;;; text, and -off to be invisible.  You can change this so that, for
+;;; example, the blinking paren fluctuates between bold and italic...
+;;;
+;;; You can make the matching paren merely be highlighted (and not blink)
+;;; by setting the blink-paren-on and blink-paren-off faces to have the same
+;;; attributes; if you do this, then emacs will not consume as much CPU.
+;;;
+;;; If highlight-paren-expression is true, then the whole sexp between the
+;;; parens will be displayed in the `highlight-expression' face instead.
+
+(make-face 'blink-paren-on)
+(make-face 'blink-paren-off)
+(make-face 'highlight-expression)
+
+;; extent used to change the face of the matching paren
+(defvar blink-paren-extent nil)
+
+;; timeout to blink the face
+(defvar blink-paren-timeout-id nil)
+
+;; find if we should look foward or backward to find the matching paren
+(defun blink-paren-sexp-dir ()
+  (cond ((and (< (point) (point-max))
+	      (eq (char-syntax (char-after (point))) ?\())
+	 1)
+	((and (> (point) (point-min))
+	      (eq (char-syntax (char-after (- (point) 1))) ?\)))
+	 -1)
+	(t ())))
+
+;; make an extent on the matching paren if any.  return it.
+(defun blink-paren-make-extent ()
+  (let ((dir (blink-paren-sexp-dir)))
+    (and dir
+	 (condition-case ()
+	     (let* ((parse-sexp-ignore-comments t)
+		    (other-pos (let ((pmin (point-min))
+				     (pmax (point-max))
+				     (point (point)))
+				 (unwind-protect
+				     (progn
+				       (narrow-to-region
+					(max pmin (- point blink-matching-paren-distance))
+					(min pmax (+ point blink-matching-paren-distance)))
+				       (forward-sexp dir) (point))
+				   (narrow-to-region pmin pmax)
+				   (goto-char point))))
+		    (extent (if (= dir 1)
+				(make-extent (if highlight-paren-expression
+						 (point)
+					       (- other-pos 1))
+					     other-pos)
+			      (make-extent other-pos
+					   (if highlight-paren-expression
+					       (point)
+					     (+ other-pos 1))))))
+	       (set-extent-face extent (if highlight-paren-expression
+					   'highlight-expression
+					 'blink-paren-on))
+	       extent)
+	   (error nil)))))
+
+;; callback for the timeout
+;; swap the face of the extent on the matching paren
+(defun blink-paren-timeout (arg)
+  ;; The extent could have been deleted for some reason and not point to a
+  ;; buffer anymore.  So catch any error to remove the timeout.
+  (condition-case ()
+      (set-extent-face blink-paren-extent 
+		       (if (eq (extent-face blink-paren-extent)
+			       'blink-paren-on)
+			   'blink-paren-off
+			 'blink-paren-on))
+    (error (blink-paren-pre-command))))
+
+;; called after each command is executed in the post-command-hook
+;; add the extent and the time-out if we are on a paren.
+(defun blink-paren-post-command ()
+  (blink-paren-pre-command)
+  (if (and (setq blink-paren-extent (blink-paren-make-extent))
+	   (not highlight-paren-expression)
+	   (not (and (face-equal 'blink-paren-on 'blink-paren-off)
+		     (progn
+		       (set-extent-face blink-paren-extent 'blink-paren-on)
+		       t)))
+	   (or (floatp blink-paren-timeout)
+	       (integerp blink-paren-timeout)))
+      (setq blink-paren-timeout-id
+	    (add-timeout blink-paren-timeout 'blink-paren-timeout ()
+			 blink-paren-timeout))))
+
+;; called before a new command is executed in the pre-command-hook
+;; cleanup by removing the extent and the time-out
+(defun blink-paren-pre-command ()
+  (condition-case c  ; don't ever signal an error in pre-command-hook!
+      (let ((inhibit-quit t))
+	(if blink-paren-timeout-id
+	    (disable-timeout (prog1 blink-paren-timeout-id
+			       (setq blink-paren-timeout-id nil))))
+	(if blink-paren-extent
+	    (delete-extent (prog1 blink-paren-extent
+			     (setq blink-paren-extent nil)))))
+    (error
+     (message "blink paren error! %s" c))))
+
+
+(defun blink-paren (&optional arg)
+  "Toggles paren blinking on and off.
+With a positive argument, turns it on.
+With a non-positive argument, turns it off."
+  (interactive "P")
+  (let* ((was-on (not (not (memq 'blink-paren-pre-command pre-command-hook))))
+	 (on-p (if (null arg)
+		   (not was-on)
+		(> (prefix-numeric-value arg) 0))))
+    (cond (on-p
+
+	   ;; in case blink paren was dumped, this needs to be setup
+	   (or (face-differs-from-default-p 'blink-paren-off)
+	       (progn
+		 (set-face-background 'blink-paren-off (face-background 'default))
+		 (set-face-foreground 'blink-paren-off (face-background 'default))))
+
+	   (or (face-differs-from-default-p 'highlight-expression)
+	       (set-face-underline-p 'highlight-expression t))
+	   
+	   (add-hook 'pre-command-hook 'blink-paren-pre-command)
+	   (add-hook 'post-command-hook 'blink-paren-post-command)
+	   (setq blink-matching-paren nil))
+	  (t
+	   (remove-hook 'pre-command-hook 'blink-paren-pre-command)
+	   (remove-hook 'post-command-hook 'blink-paren-post-command)
+	   (and blink-paren-extent (detach-extent blink-paren-extent))
+	   (setq blink-matching-paren t)))
+    on-p))
+
+(defun blink-paren-init ()
+  "obsolete - use `blink-paren' instead."
+  (interactive)
+  (blink-paren 1))
+
+(provide 'blink-paren)
+
+(blink-paren 1)