diff lisp/utils/skeleton.el @ 2:ac2d302a0011 r19-15b2

Import from CVS: tag r19-15b2
author cvs
date Mon, 13 Aug 2007 08:46:35 +0200
parents 376386a54a3c
children 859a2309aef8
line wrap: on
line diff
--- a/lisp/utils/skeleton.el	Mon Aug 13 08:45:53 2007 +0200
+++ b/lisp/utils/skeleton.el	Mon Aug 13 08:46:35 2007 +0200
@@ -5,23 +5,24 @@
 ;; Maintainer: FSF
 ;; Keywords: extensions, abbrev, languages, tools
 
-;; This file is part of GNU Emacs.
+;; This file is part of XEmacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
+;; 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.
 
-;; GNU Emacs 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.
+;; 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 GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
 
-;;; Synched up with: FSF 19.30.
+;;; Synched up with: FSF 19.34.
 
 ;;; Commentary:
 
@@ -49,6 +50,16 @@
      "aTransformation function: ")
 
 
+(defvar skeleton-autowrap t
+  "Controls wrapping behaviour of functions created with `define-skeleton'.
+When the region is visible (due to `transient-mark-mode' or marking a region
+with the mouse) and this is non-`nil' and the function was called without an
+explicit ARG, then the ARG defaults to -1, i.e. wrapping around the visible
+region.
+
+We will probably delete this variable in a future Emacs version
+unless we get a substantial number of complaints about the auto-wrap
+feature.")
 
 (defvar skeleton-end-hook
   (lambda ()
@@ -60,7 +71,7 @@
 
 ;;;###autoload
 (defvar skeleton-filter 'identity
-  "Function for transforming a skeleton-proxy's aliases' variable value.")
+  "Function for transforming a skeleton proxy's aliases' variable value.")
 
 (defvar skeleton-untabify t
   "When non-`nil' untabifies when deleting backwards with element -ARG.")
@@ -83,9 +94,10 @@
   "*Replacement for %s in prompts of recursive subskeletons.")
 
 
-(defvar skeleton-abbrev-cleanup nil)
+(defvar skeleton-abbrev-cleanup nil
+  "Variable used to delete the character that led to abbrev expansion.")
 
-
+;; XEmacs -- won't byte compile without the wrapper
 (eval-and-compile
   (defvar skeleton-debug nil
     "*If non-nil `define-skeleton' will override previous definition."))
@@ -105,10 +117,61 @@
   (if skeleton-debug
       (set command skeleton))
   `(progn
-     (defvar ,command ',skeleton ,documentation)
-     (defalias ',command 'skeleton-proxy)))
+     (defun ,command (&optional str arg)
+       ,(concat documentation
+		(if (string-match "\n\\>" documentation)
+		    "" "\n")
+		"\n"
+		"This is a skeleton command (see `skeleton-insert').
+Normally the skeleton text is inserted at point, with nothing \"inside\".
+If there is a highlighted region, the skeleton text is wrapped
+around the region text.
+
+A prefix argument ARG says to wrap the skeleton around the next ARG words.
+A prefix argument of zero says to wrap around zero words---that is, nothing.
+This is a way of overiding the use of a highlighted region.")
+       (interactive "*P\nP")
+       (skeleton-proxy-new ',skeleton str arg))))
 
-
+;;;###autoload
+(defun skeleton-proxy-new (skeleton &optional str arg)
+  "Insert skeleton defined by variable of same name (see `skeleton-insert').
+Prefix ARG allows wrapping around words or regions (see `skeleton-insert').
+If no ARG was given, but the region is visible, ARG defaults to -1 depending
+on `skeleton-autowrap'.  An ARG of  M-0  will prevent this just for once.
+This command can also be an abbrev expansion (3rd and 4th columns in
+\\[edit-abbrevs]  buffer: \"\"  command-name).
+ 
+When called as a function, optional first argument STR may also be a string
+which will be the value of `str' whereas the skeleton's interactor is then
+ignored."
+  (interactive "*P\nP")
+  (setq skeleton (funcall skeleton-filter skeleton))
+  (if (not skeleton)
+      (if (memq this-command '(self-insert-command
+			       skeleton-pair-insert-maybe
+			       expand-abbrev))
+	  (setq buffer-undo-list (primitive-undo 1 buffer-undo-list)))
+    (skeleton-insert skeleton
+		     (if (setq skeleton-abbrev-cleanup
+			       (or (eq this-command 'self-insert-command)
+				   (eq this-command
+				       'skeleton-pair-insert-maybe)))
+			 ()
+		       ;; Pretend  C-x a e  passed its prefix arg to us
+		       (if (or arg current-prefix-arg)
+			   (prefix-numeric-value (or arg
+						     current-prefix-arg))
+			 (and skeleton-autowrap
+			      (or (eq last-command 'mouse-drag-region)
+				  (and (boundp 'transient-mark-mode)
+				       transient-mark-mode mark-active))
+			      -1)))
+		     (if (stringp str)
+			 str))
+    (and skeleton-abbrev-cleanup
+	 (setq skeleton-abbrev-cleanup (point))
+	 (add-hook 'post-command-hook 'skeleton-abbrev-cleanup nil t))))
 
 ;; This command isn't meant to be called, only it's aliases with meaningful
 ;; names are.
@@ -116,6 +179,8 @@
 (defun skeleton-proxy (&optional str arg)
   "Insert skeleton defined by variable of same name (see `skeleton-insert').
 Prefix ARG allows wrapping around words or regions (see `skeleton-insert').
+If no ARG was given, but the region is visible, ARG defaults to -1 depending
+on `skeleton-autowrap'.  An ARG of  M-0  will prevent this just for once.
 This command can also be an abbrev expansion (3rd and 4th columns in
 \\[edit-abbrevs]  buffer: \"\"  command-name).
 
@@ -124,7 +189,7 @@
 ignored."
   (interactive "*P\nP")
   (let ((function (nth 1 (backtrace-frame 1))))
-    (if (eq function 'nth)		; uncompiled lisp function
+    (if (eq function 'nth)		; uncompiled Lisp function
 	(setq function (nth 1 (backtrace-frame 5)))
       (if (eq function 'byte-code)	; tracing byte-compiled function
 	  (setq function (nth 1 (backtrace-frame 2)))))
@@ -142,13 +207,17 @@
 			 ;; Pretend  C-x a e  passed its prefix arg to us
 			 (if (or arg current-prefix-arg)
 			     (prefix-numeric-value (or arg
-						       current-prefix-arg))))
+						       current-prefix-arg))
+			   (and skeleton-autowrap
+				(or (eq last-command 'mouse-drag-region)
+				    (and (boundp 'transient-mark-mode)
+					 transient-mark-mode mark-active))
+				-1)))
 		       (if (stringp str)
 			   str))
-      (if skeleton-abbrev-cleanup
-	  (setq deferred-action-list t
-		deferred-action-function 'skeleton-abbrev-cleanup
-		skeleton-abbrev-cleanup (point))))))
+      (and skeleton-abbrev-cleanup
+	   (setq skeleton-abbrev-cleanup (point))
+	   (add-hook 'post-command-hook 'skeleton-abbrev-cleanup nil t)))))
 
 
 (defun skeleton-abbrev-cleanup (&rest list)
@@ -156,10 +225,8 @@
   (if (integerp skeleton-abbrev-cleanup)
       (progn
 	(delete-region skeleton-abbrev-cleanup (point))
-	(setq deferred-action-list ()
-	      deferred-action-function nil
-	      skeleton-abbrev-cleanup nil))))
-
+	(setq skeleton-abbrev-cleanup nil)
+	(remove-hook 'post-command-hook 'skeleton-abbrev-cleanup t))))
 
 ;;;###autoload
 (defun skeleton-insert (skeleton &optional skeleton-regions str)
@@ -201,9 +268,9 @@
 formatted with `skeleton-subprompt'.  Such an INTERACTOR may also a list of
 strings with the subskeleton being repeated once for each string.
 
-Quoted lisp-expressions are evaluated evaluated for their side-effect.
-Other lisp-expressions are evaluated and the value treated as above.
-Note that expressions may not return `t' since this impplies an
+Quoted Lisp expressions are evaluated evaluated for their side-effect.
+Other Lisp expressions are evaluated and the value treated as above.
+Note that expressions may not return `t' since this implies an
 endless loop.  Modes can define other symbols by locally setting them
 to any valid skeleton element.  The following local variables are
 available:
@@ -212,7 +279,7 @@
 		then: insert previously read string once more
 	help	help-form during interaction with the user or `nil'
 	input	initial input (string or cons with index) while reading str
-	v1, v2	local variables for memorising anything you want
+	v1, v2	local variables for memorizing anything you want
 
 When done with skeleton, but before going back to `_'-point call
 `skeleton-end-hook' if that is non-`nil'."
@@ -382,20 +449,19 @@
 
 
 ;; Maybe belongs into simple.el or elsewhere
-
+;###autoload
 (define-skeleton local-variables-section
   "Insert a local variables section.  Use current comment syntax if any."
-  ()
-  '(save-excursion
-     (if (re-search-forward page-delimiter nil t)
-	 (error "Not on last page.")))
-  comment-start "Local Variables:" comment-end \n
-  comment-start "mode: "
   (completing-read "Mode: " obarray
 		   (lambda (symbol)
 		     (if (commandp symbol)
 			 (string-match "-mode$" (symbol-name symbol))))
 		   t)
+  '(save-excursion
+     (if (re-search-forward page-delimiter nil t)
+	 (error "Not on last page.")))
+  comment-start "Local Variables:" comment-end \n
+  comment-start "mode: " str
   & -5 | '(kill-line 0) & -1 | comment-end \n
   ( (completing-read (format "Variable, %s: " skeleton-subprompt)
 		     obarray
@@ -406,9 +472,9 @@
     comment-start str ": "
     (read-from-minibuffer "Expression: " nil read-expression-map nil
 			  'read-expression-history) | _
-    comment-end \n)
+			  comment-end \n)
   resume:
-  comment-start "End:" comment-end)
+  comment-start "End:" comment-end \n)
 
 ;; Variables and command for automatically inserting pairs like () or "".
 
@@ -439,80 +505,83 @@
 (defun skeleton-pair-insert-maybe (arg)
   "Insert the character you type ARG times.
 
-With no ARG, if `skeleton-pair' is non-nil, and if
-`skeleton-pair-on-word' is non-nil or we are not before or inside a
+With no ARG, if `skeleton-pair' is non-nil, pairing can occur.  If the region
+is visible the pair is wrapped around it depending on `skeleton-autowrap'.
+Else, if `skeleton-pair-on-word' is non-nil or we are not before or inside a
 word, and if `skeleton-pair-filter' returns nil, pairing is performed.
 
 If a match is found in `skeleton-pair-alist', that is inserted, else
 the defaults are used.  These are (), [], {}, <> and `' for the
 symmetrical ones, and the same character twice for the others."
   (interactive "*P")
-  (if (or arg
-	  overwrite-mode
-	  (not skeleton-pair)
-	  (if (not skeleton-pair-on-word) (looking-at "\\w"))
-	  (funcall skeleton-pair-filter))
-      (self-insert-command (prefix-numeric-value arg))
-    (self-insert-command 1)
-    (if skeleton-abbrev-cleanup
-	()
-      ;; (preceding-char) is stripped of any Meta-stuff in last-command-char
-      (if (setq arg (assq (preceding-char) skeleton-pair-alist))
-	  ;; typed char is inserted (car is no real interactor)
-	  (let (skeleton-end-hook)
-	    (skeleton-insert arg))
-	(save-excursion
-	  (insert (or (cdr (assq (preceding-char)
-				 '((?( . ?))
-				   (?[ . ?])
-				   (?{ . ?})
-				   (?< . ?>)
-				   (?` . ?'))))
-		      last-command-char)))))))
+  (let ((mark (and skeleton-autowrap
+		   (or (eq last-command 'mouse-drag-region)
+		       (and (boundp 'transient-mark-mode)
+			    transient-mark-mode mark-active))))
+	(skeleton-end-hook))
+    (if (or arg
+	    (not skeleton-pair)
+	    (and (not mark)
+		 (or overwrite-mode
+		     (if (not skeleton-pair-on-word) (looking-at "\\w"))
+		     (funcall skeleton-pair-filter))))
+	(self-insert-command (prefix-numeric-value arg))
+      (setq last-command-char (logand last-command-char 255))
+      (or skeleton-abbrev-cleanup
+	  (skeleton-insert
+	   (cons nil (or (assq last-command-char skeleton-pair-alist)
+			 (assq last-command-char '((?( _ ?))
+						   (?[ _ ?])
+						   (?{ _ ?})
+						   (?< _ ?>)
+						   (?` _ ?')))
+			 `(,last-command-char _ ,last-command-char)))
+	   (if mark -1))))))
 
 
-;;; ;; A more serious example can be found in sh-script.el
-;;; ;; The quote before (defun prevents this from being byte-compiled.
-;;;(defun mirror-mode ()
-;;;  "This major mode is an amusing little example of paired insertion.
-;;;All printable characters do a paired self insert, while the other commands
-;;;work normally."
-;;;  (interactive)
-;;;  (kill-all-local-variables)
-;;;  (make-local-variable 'pair)
-;;;  (make-local-variable 'pair-on-word)
-;;;  (make-local-variable 'pair-filter)
-;;;  (make-local-variable 'pair-alist)
-;;;  (setq major-mode 'mirror-mode
-;;;	mode-name "Mirror"
-;;;	pair-on-word t
-;;;	;; in the middle column insert one or none if odd window-width
-;;;	pair-filter (lambda ()
-;;;		      (if (>= (current-column)
-;;;			      (/ (window-width) 2))
-;;;			  ;; insert both on next line
-;;;			  (next-line 1)
-;;;			;; insert one or both?
-;;;			(= (* 2 (1+ (current-column)))
-;;;			   (window-width))))
-;;;	;; mirror these the other way round as well
-;;;	pair-alist '((?) _ ?()
-;;;		     (?] _ ?[)
-;;;		     (?} _ ?{)
-;;;		     (?> _ ?<)
-;;;		     (?/ _ ?\\)
-;;;		     (?\\ _ ?/)
-;;;		     (?` ?` _ "''")
-;;;		     (?' ?' _ "``"))
-;;;	;; in this mode we exceptionally ignore the user, else it's no fun
-;;;	pair t)
-;;;  (let ((map (make-keymap))
-;;;	(i ? ))
-;;;    (use-local-map map)
-;;;    (setq map (car (cdr map)))
-;;;    (while (< i ?\^?)
-;;;      (aset map i 'skeleton-pair-insert-maybe)
-;;;      (setq i (1+ i))))
-;;;  (run-hooks 'mirror-mode-hook))
+;; A more serious example can be found in sh-script.el
+;;; (defun mirror-mode ()
+;;  "This major mode is an amusing little example of paired insertion.
+;;All printable characters do a paired self insert, while the other commands
+;;work normally."
+;;  (interactive)
+;;  (kill-all-local-variables)
+;;  (make-local-variable 'skeleton-pair)
+;;  (make-local-variable 'skeleton-pair-on-word)
+;;  (make-local-variable 'skeleton-pair-filter)
+;;  (make-local-variable 'skeleton-pair-alist)
+;;  (setq major-mode 'mirror-mode
+;;	mode-name "Mirror"
+;;	skeleton-pair-on-word t
+;;	;; in the middle column insert one or none if odd window-width
+;;	skeleton-pair-filter (lambda ()
+;;			       (if (>= (current-column)
+;;				       (/ (window-width) 2))
+;;				   ;; insert both on next line
+;;				   (next-line 1)
+;;				 ;; insert one or both?
+;;				 (= (* 2 (1+ (current-column)))
+;;				    (window-width))))
+;;	;; mirror these the other way round as well
+;;	skeleton-pair-alist '((?) _ ?()
+;;			      (?] _ ?[)
+;;			      (?} _ ?{)
+;;			      (?> _ ?<)
+;;			      (?/ _ ?\\)
+;;			      (?\\ _ ?/)
+;;			      (?` ?` _ "''")
+;;			      (?' ?' _ "``"))
+;;	;; in this mode we exceptionally ignore the user, else it's no fun
+;;	skeleton-pair t)
+;;  (let ((map (make-vector 256 'skeleton-pair-insert-maybe))
+;;	(i 0))
+;;    (use-local-map `(keymap ,map))
+;;    (while (< i ? )
+;;      (aset map i nil)
+;;      (aset map (+ i 128) nil)
+;;      (setq i (1+ i))))
+;;  (run-hooks 'mirror-mode-hook))
+
+(provide 'skeleton)
 
 ;; skeleton.el ends here