(occur-read-primary-args): Pass default to read-from-minibuffer.
[bpt/emacs.git] / lisp / skeleton.el
dissimilarity index 63%
index 7ee3c8f..e843ef9 100644 (file)
-;;; skeleton.el --- Lisp language extension for writing statement skeletons
-;; Copyright (C) 1993, 1994, 1995 by Free Software Foundation, Inc.
-
-;; Author: Daniel.Pfeiffer@Informatik.START.dbp.de, fax (+49 69) 7588-2389
-;; Maintainer: FSF
-;; Keywords: extensions, abbrev, languages, tools
-
-;; This file is part of GNU Emacs.
-
-;; 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
-;; 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.
-
-;; 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.
-
-;;; Commentary:
-
-;; A very concise language extension for writing structured statement
-;; skeleton insertion commands for programming language modes.  This
-;; originated in shell-script mode and was applied to ada-mode's
-;; commands which shrunk to one third.  And these commands are now
-;; user configurable.
-
-;;; Code:
-
-;; page 1:     statement skeleton language definition & interpreter
-;; page 2:     paired insertion
-;; page 3:     mirror-mode, an example for setting up paired insertion
-
-
-(defvar skeleton-transformation nil
-  "*If non-nil, function applied to literal strings before they are inserted.
-It should take strings and characters and return them transformed, or nil
-which means no transformation.
-Typical examples might be `upcase' or `capitalize'.")
-
-; this should be a fourth argument to defvar
-(put 'skeleton-transformation 'variable-interactive
-     "aTransformation function: ")
-
-
-
-;;;###autoload
-(defvar skeleton-filter 'identity
-  "Function for transforming a skeleton-proxy's aliases' variable value.")
-
-
-(defvar skeleton-untabify t
-  "When non-`nil' untabifies when deleting backwards with element -ARG.")
-
-
-(defvar skeleton-further-elements ()
-  "A buffer-local varlist (see `let') of mode specific skeleton elements.
-These variables are bound while interpreting a skeleton.  Their value may
-in turn be any valid skeleton element if they are themselves to be used as
-skeleton elements.")
-(make-variable-buffer-local 'skeleton-further-elements)
-
-
-(defvar skeleton-subprompt
-  (substitute-command-keys
-   "RET, \\<minibuffer-local-map>\\[abort-recursive-edit] or \\[help-command]")
-  "*Replacement for %s in prompts of recursive subskeletons.")
-
-
-(defvar skeleton-abbrev-cleanup nil)
-
-
-(defvar skeleton-debug nil
-  "*If non-nil `define-skeleton' will override previous definition.")
-
-
-;;;###autoload
-(defmacro define-skeleton (command documentation &rest skeleton)
-  "Define a user-configurable COMMAND that enters a statement skeleton.
-DOCUMENTATION is that of the command, while the variable of the same name,
-which contains the skeleton, has a documentation to that effect.
-INTERACTOR and ELEMENT ... are as defined under `skeleton-insert'."
-  (if skeleton-debug
-      (set command skeleton))
-  (require 'backquote)
-  (`(progn
-      (defvar (, command) '(, skeleton)
-       (, documentation))
-      (defalias '(, command) 'skeleton-proxy))))
-
-
-
-;; This command isn't meant to be called, only it's aliases with meaningful
-;; names are.
-;;;###autoload
-(defun skeleton-proxy (&optional arg)
-  "Insert a skeleton defined by variable of same name (see `skeleton-insert').
-Prefix ARG allows wrapping around words or regions (see `skeleton-insert').
-This command can also be an abbrev expansion (3rd and 4th columns in
-\\[edit-abbrevs]  buffer: \"\"  command-name)."
-  (interactive "*P")
-  (let ((function (nth 1 (backtrace-frame 1))))
-    (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)))))
-    (if (not (setq function (funcall skeleton-filter (symbol-value function))))
-       (if (or (eq this-command 'self-insert-command)
-               (eq this-command 'skeleton-pair-insert-maybe)
-               (eq this-command 'expand-abbrev))
-           (setq buffer-undo-list
-                 (primitive-undo 1 buffer-undo-list)))
-      (skeleton-insert function
-                      nil
-                      (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 the prefix arg to us
-                        (if (or arg current-prefix-arg)
-                            (prefix-numeric-value (or arg
-                                                      current-prefix-arg)))))
-      (if skeleton-abbrev-cleanup
-         (setq deferred-action-list t
-               deferred-action-function 'skeleton-abbrev-cleanup
-               skeleton-abbrev-cleanup (point))))))
-
-
-(defun skeleton-abbrev-cleanup (&rest list)
-  "Value for `post-command-hook' to remove char that expanded abbrev."
-  (if (integerp skeleton-abbrev-cleanup)
-      (progn
-       (delete-region skeleton-abbrev-cleanup (point))
-       (setq deferred-action-list ()
-             deferred-action-function nil
-             skeleton-abbrev-cleanup nil))))
-
-
-;;;###autoload
-(defun skeleton-insert (skeleton &optional no-newline regions)
-  "Insert the complex statement skeleton SKELETON describes very concisely.
-If optional NO-NEWLINE is nil the skeleton will end on a line of its own.
-
-With optional third REGIONS wrap first interesting point (`_') in skeleton
-around next REGIONS words, if REGIONS is positive.  If REGIONS is negative,
-wrap REGIONS preceding interregions into first REGIONS interesting positions
-\(successive `_'s) in skeleton.  An interregion is the stretch of text between
-two contiguous marked points.  If you marked A B C [] (where [] is the cursor)
-in alphabetical order, the 3 interregions are simply the last 3 regions.  But
-if you marked B A [] C, the interregions are B-A, A-[], []-C.
-
-SKELETON is made up as (INTERACTOR ELEMENT ...).  INTERACTOR may be nil if
-not needed, a prompt-string or an expression for complex read functions.
-
-If ELEMENT is a string or a character it gets inserted (see also
-`skeleton-transformation').  Other possibilities are:
-
-       \\n     go to next line and align cursor
-       _       interesting point, interregion here, point after termination
-       >       indent line (or interregion if > _) according to major mode
-       &       do next ELEMENT if previous moved point
-       |       do next ELEMENT if previous didn't move point
-       -num    delete num preceding characters (see `skeleton-untabify')
-       resume: skipped, continue here if quit is signaled
-       nil     skipped
-
-Further elements can be defined via `skeleton-further-elements'.  ELEMENT may
-itself be a SKELETON with an INTERACTOR.  The user is prompted repeatedly for
-different inputs.  The SKELETON is processed as often as the user enters a
-non-empty string.  \\[keyboard-quit] terminates skeleton insertion, but
-continues after `resume:' and positions at `_' if any.  If INTERACTOR in such
-a subskeleton is a prompt-string which contains a \".. %s ..\" it is
-formatted with `skeleton-subprompt'.
-
-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
-endless loop.  Modes can define other symbols by locally setting them
-to any valid skeleton element.  The following local variables are
-available:
-
-       str     first time: read a string according to INTERACTOR
-               then: insert previously read string once more
-       help    help-form during interaction with the user or `nil'
-       quit    non-nil after resume: section is entered by keyboard quit
-       v1, v2  local variables for memorising anything you want"
-  (and regions
-       (setq regions
-            (if (> regions 0)
-                (list (point-marker)
-                      (save-excursion (forward-word regions) (point-marker)))
-              (setq regions (- regions))
-              ;; copy regions - 1 elements from `mark-ring'
-              (let ((l1 (cons (mark-marker) mark-ring))
-                    (l2 (list (point-marker))))
-                (while (and l1 (> regions 0))
-                  (setq l2 (cons (car l1) l2)
-                        regions (1- regions)
-                        l1 (cdr l1)))
-                (sort l2 '<))))
-       (goto-char (car regions))
-       (setq regions (cdr regions)))
-  (let (modified point resume: help quit v1 v2)
-    (or no-newline
-       (eolp)
-       ;;(save-excursion
-       ;;  (indent-to (prog1
-       ;;               (current-indentation)
-       ;;             (newline))))
-       (goto-char (prog1 (point)
-                    (indent-to (prog1
-                                   (current-indentation)
-                                 (newline))))))
-    (unwind-protect
-       (eval (list 'let skeleton-further-elements
-                   '(skeleton-internal-list skeleton (car skeleton))))
-      (if point
-         (goto-char point)))))
-
-
-
-(defun skeleton-read (str &optional initial-input recursive)
-  "Function for reading a string from the minibuffer in skeletons.
-PROMPT may contain a `%s' which will be replaced by `skeleton-subprompt'.
-If non-`nil' second arg INITIAL-INPUT is a string to insert before reading.
-While reading, the value of `minibuffer-help-form' is variable `help' if that is
-non-`nil' or a default string if optional ITERATIVE is non-`nil'."
-
-  (or no-newline
-      (eolp)
-      (goto-char (prog1 (point)
-                  (indent-to (prog1
-                                 (current-indentation)
-                               (newline))))))
-  (let ((minibuffer-help-form (or help (if recursive "\
-As long as you provide input you will insert another subskeleton.
-
-If you enter the empty string, the loop inserting subskeletons is
-left, and the current one is removed as far as it has been entered.
-
-If you quit, the current subskeleton is removed as far as it has been
-entered.  No more of the skeleton will be inserted, except maybe for a
-syntactically necessary termination."
-                                        "
-You are inserting a skeleton.  Standard text gets inserted into the buffer
-automatically, and you are prompted to fill in the variable parts."))))
-    (setq str (if (stringp str)
-                 (read-string (format str skeleton-subprompt) initial-input)
-               (eval str))))
-  (if (or (null str) (string= str ""))
-      (signal 'quit t)
-    str))
-
-
-(defun skeleton-internal-list (skeleton &optional str recursive)
-  (let* ((start (save-excursion (beginning-of-line) (point)))
-        (column (current-column))
-        (line (buffer-substring start
-                                (save-excursion (end-of-line) (point))))
-        opoint)
-    (condition-case quit
-       (progn
-         '(setq str (list 'setq 'str
-                         (if recursive
-                             (list 'skeleton-read (list 'quote str))
-                           (list (if (stringp str)
-                                     'read-string
-                                   'eval)
-                                 str))))
-         (setq str (list 'setq 'str
-                         (list 'skeleton-read
-                               (list 'quote str nil recursive))))
-         (while (setq modified (eq opoint (point))
-                      opoint (point)
-                      skeleton (cdr skeleton))
-           (skeleton-internal-1 (car skeleton)))
-         ;; maybe continue loop
-         recursive)
-      (quit ;; remove the subskeleton as far as it has been shown
-       (if (eq (cdr quit) 'recursive)
-          ()
-        ;; the subskeleton shouldn't have deleted outside current line
-        (end-of-line)
-        (delete-region start (point))
-        (insert line)
-        (move-to-column column))
-       (if (eq (cdr quit) t)
-          ;; empty string entered
-          nil
-        (while (if skeleton
-                   (not (eq (car (setq skeleton (cdr skeleton)))
-                            'resume:))))
-        (if skeleton
-            (skeleton-internal-list skeleton)
-          ;; propagate signal we can't handle
-          (if recursive (signal 'quit 'recursive)))
-        (signal 'quit nil))))))
-
-
-(defun skeleton-internal-1 (element &optional literal)
-  (cond ((and (integerp element)       ; -num
-             (< element 0))
-        (if skeleton-untabify
-            (backward-delete-char-untabify (- element))
-          (delete-backward-char (- element))))
-       ((char-or-string-p element)
-        (insert-before-markers (if (and skeleton-transformation
-                                        (not literal))
-                                   (funcall skeleton-transformation element)
-                                 element)))
-       ((eq element '\n)               ; actually (eq '\n 'n)
-        (newline)
-        (indent-relative t))
-       ((eq element '>)
-        (if (and regions
-                 (eq (nth 1 skeleton) '_))
-            (indent-region (point) (car regions) nil)
-          (indent-for-tab-command)))
-       ((eq element '_)
-        (if regions
-            (progn
-              (goto-char (car regions))
-              (setq regions (cdr regions)))
-          (or point
-              (setq point (point)))))
-       ((eq element '&)
-        (if modified
-            (setq skeleton (cdr skeleton))))
-       ((eq element '|)
-        (or modified
-            (setq skeleton (cdr skeleton))))
-       ((if (consp element)
-            (or (stringp (car element))
-                (consp (car element))))
-        (while (skeleton-internal-list element (car element) t)))
-       ((if (consp element)
-            (eq 'quote (car element)))
-        (eval (nth 1 element)))
-       ((null element))
-       ((skeleton-internal-1 (eval element) t))))
-
-;; Maybe belongs into simple.el or elsewhere
-
-(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)
-  & -5 | '(kill-line 0) & -1 | comment-end \n
-  ( (completing-read (format "Variable, %s: " skeleton-subprompt)
-                    obarray
-                    (lambda (symbol)
-                      (or (eq symbol 'eval)
-                          (user-variable-p symbol)))
-                    t)
-    comment-start str ": "
-    (read-from-minibuffer "Expression: " nil read-expression-map nil
-                         'read-expression-history) | _
-    comment-end \n)
-  resume:
-  comment-start "End:" comment-end)
-\f
-;; Variables and command for automatically inserting pairs like () or "".
-
-(defvar skeleton-pair nil
-  "*If this is nil pairing is turned off, no matter what else is set.
-Otherwise modes with `skeleton-pair-insert-maybe' on some keys
-will attempt to insert pairs of matching characters.")
-
-
-(defvar skeleton-pair-on-word nil
-  "*If this is nil, paired insertion is inhibited before or inside a word.")
-
-
-(defvar skeleton-pair-filter (lambda ())
-  "Attempt paired insertion if this function returns nil, before inserting.
-This allows for context-sensitive checking whether pairing is appropriate.")
-
-
-(defvar skeleton-pair-alist ()
-  "An override alist of pairing partners matched against `last-command-char'.
-Each alist element, which looks like (ELEMENT ...), is passed to
-`skeleton-insert' with no interactor.  Variable `str' does nothing.
-
-Elements might be (?` ?` _ \"''\"), (?\\( ?  _ \" )\") or (?{ \\n > _ \\n ?} >).")
-
-
-;;;###autoload
-(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
-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
-         (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, and car means no interactor
-         (skeleton-insert arg t)
-       (save-excursion
-         (insert (or (cdr (assq (preceding-char)
-                                '((?( . ?))
-                                  (?[ . ?])
-                                  (?{ . ?})
-                                  (?< . ?>)
-                                  (?` . ?'))))
-                     last-command-char)))))))
-
-\f
-;;; ;; 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))
-
-;; skeleton.el ends here
+;;; skeleton.el --- Lisp language extension for writing statement skeletons
+
+;; Copyright (C) 1993, 1994, 1995, 1996, 2003 by Free Software Foundation, Inc.
+
+;; Author: Daniel Pfeiffer <occitan@esperanto.org>
+;; Maintainer: FSF
+;; Keywords: extensions, abbrev, languages, tools
+
+;; This file is part of GNU Emacs.
+
+;; 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
+;; 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.
+
+;; 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:
+
+;; A very concise language extension for writing structured statement
+;; skeleton insertion commands for programming language modes.  This
+;; originated in shell-script mode and was applied to ada-mode's
+;; commands which shrunk to one third.  And these commands are now
+;; user configurable.
+
+;;; Code:
+
+;; page 1:     statement skeleton language definition & interpreter
+;; page 2:     paired insertion
+;; page 3:     mirror-mode, an example for setting up paired insertion
+
+
+(defvar skeleton-transformation 'identity
+  "*If non-nil, function applied to literal strings before they are inserted.
+It should take strings and characters and return them transformed, or nil
+which means no transformation.
+Typical examples might be `upcase' or `capitalize'.")
+
+; this should be a fourth argument to defvar
+(put 'skeleton-transformation 'variable-interactive
+     "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-newline t
+  "If non-nil, make sure that the skeleton inserted ends with a newline.
+This just influences the way the default `skeleton-end-hook' behaves.")
+
+(defvar skeleton-end-hook
+  (lambda ()
+    (or (eolp) (not skeleton-end-newline) (newline-and-indent)))
+  "Hook called at end of skeleton but before going to point of interest.
+By default this moves out anything following to next line,
+  unless `skeleton-end-newline' is set to nil.
+The variables `v1' and `v2' are still set when calling this.")
+
+
+;;;###autoload
+(defvar skeleton-filter 'identity
+  "Function for transforming a skeleton proxy's aliases' variable value.")
+
+(defvar skeleton-untabify t
+  "When non-nil untabifies when deleting backwards with element -ARG.")
+
+(defvar skeleton-newline-indent-rigidly nil
+  "When non-nil, indent rigidly under current line for element `\\n'.
+Else use mode's `indent-line-function'.")
+
+(defvar skeleton-further-elements ()
+  "A buffer-local varlist (see `let') of mode specific skeleton elements.
+These variables are bound while interpreting a skeleton.  Their value may
+in turn be any valid skeleton element if they are themselves to be used as
+skeleton elements.")
+(make-variable-buffer-local 'skeleton-further-elements)
+
+
+(defvar skeleton-subprompt
+  (substitute-command-keys
+   "RET, \\<minibuffer-local-map>\\[abort-recursive-edit] or \\[help-command]")
+  "*Replacement for %s in prompts of recursive subskeletons.")
+
+
+(defvar skeleton-debug nil
+  "*If non-nil `define-skeleton' will override previous definition.")
+
+(defvar skeleton-positions nil
+  "List of positions marked with @, after skeleton insertion.
+The list describes the most recent skeleton insertion, and its elements
+are integer buffer positions in the reverse order of the insertion order.")
+
+;; reduce the number of compiler warnings
+(defvar skeleton)
+(defvar skeleton-modified)
+(defvar skeleton-point)
+(defvar skeleton-regions)
+
+(def-edebug-spec skeleton-edebug-spec
+  ([&or null stringp (stringp &rest stringp) [[&not atom] def-form]]
+   &rest &or "n" "_" "-" ">" "@" "&" "!" "resume:"
+   ("quote" def-form) skeleton-edebug-spec def-form))
+;;;###autoload
+(defmacro define-skeleton (command documentation &rest skeleton)
+  "Define a user-configurable COMMAND that enters a statement skeleton.
+DOCUMENTATION is that of the command.
+SKELETON is as defined under `skeleton-insert'."
+  (declare (debug (&define name stringp skeleton-edebug-spec)))
+  (if skeleton-debug
+      (set command skeleton))
+  `(progn
+     ;; Tell self-insert-command that this function, if called by an
+     ;; abbrev, should cause the self-insert to be skipped.
+     (put ',command 'no-self-insert t)
+     (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 -1 says to wrap around region, even if not highlighted.
+A prefix argument of zero says to wrap around zero words---that is, nothing.
+This is a way of overriding 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.
+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).
+
+Optional first argument STR may also be a string which will be the value
+of `str' whereas the skeleton's interactor is then ignored."
+  (skeleton-insert (funcall skeleton-filter skeleton)
+                  ;; 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 transient-mark-mode mark-active))
+                         ;; Deactivate the mark, in case one of the
+                         ;; elements of the skeleton is sensitive
+                         ;; to such situations (e.g. it is itself a
+                         ;; skeleton).
+                         (progn (deactivate-mark)
+                                -1)))
+                  (if (stringp str)
+                      str))
+  ;; Return non-nil to tell expand-abbrev that expansion has happened.
+  ;; Otherwise the no-self-insert is ignored.
+  t)
+
+;;;###autoload
+(defun skeleton-insert (skeleton &optional regions str)
+  "Insert the complex statement skeleton SKELETON describes very concisely.
+
+With optional second argument REGIONS, wrap first interesting point
+\(`_') in skeleton around next REGIONS words, if REGIONS is positive.
+If REGIONS is negative, wrap REGIONS preceding interregions into first
+REGIONS interesting positions \(successive `_'s) in skeleton.
+
+An interregion is the stretch of text between two contiguous marked
+points.  If you marked A B C [] (where [] is the cursor) in
+alphabetical order, the 3 interregions are simply the last 3 regions.
+But if you marked B A [] C, the interregions are B-A, A-[], []-C.
+
+The optional third argument STR, if specified, is the value for the
+variable `str' within the skeleton.  When this is non-nil, the
+interactor gets ignored, and this should be a valid skeleton element.
+
+SKELETON is made up as (INTERACTOR ELEMENT ...).  INTERACTOR may be nil if
+not needed, a prompt-string or an expression for complex read functions.
+
+If ELEMENT is a string or a character it gets inserted (see also
+`skeleton-transformation').  Other possibilities are:
+
+       \\n     go to next line and indent according to mode
+       _       interesting point, interregion here
+       -       interesting point, no interregion interaction, overrides
+               interesting point set by _
+       >       indent line (or interregion if > _) according to major mode
+       @       add position to `skeleton-positions'
+       &       do next ELEMENT iff previous moved point
+       |       do next ELEMENT iff previous didn't move point
+       -num    delete num preceding characters (see `skeleton-untabify')
+       resume: skipped, continue here if quit is signaled
+       nil     skipped
+
+After termination, point will be positioned at the last occurrence of -
+or at the first occurrence of _ or at the end of the inserted text.
+
+Further elements can be defined via `skeleton-further-elements'.  ELEMENT may
+itself be a SKELETON with an INTERACTOR.  The user is prompted repeatedly for
+different inputs.  The SKELETON is processed as often as the user enters a
+non-empty string.  \\[keyboard-quit] terminates skeleton insertion, but
+continues after `resume:' and positions at `_' if any.  If INTERACTOR in such
+a subskeleton is a prompt-string which contains a \".. %s ..\" it is
+formatted with `skeleton-subprompt'.  Such an INTERACTOR may also be a list of
+strings with the subskeleton being repeated once for each string.
+
+Quoted Lisp expressions are evaluated for their side-effects.
+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:
+
+       str     first time: read a string according to INTERACTOR
+               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 memorizing anything you want
+
+When done with skeleton, but before going back to `_'-point call
+`skeleton-end-hook' if that is non-nil."
+  (let ((skeleton-regions regions))
+    (and skeleton-regions
+        (setq skeleton-regions
+              (if (> skeleton-regions 0)
+                  (list (copy-marker (point) t)
+                        (save-excursion (forward-word skeleton-regions)
+                                        (point-marker)))
+                (setq skeleton-regions (- skeleton-regions))
+                ;; copy skeleton-regions - 1 elements from `mark-ring'
+                (let ((l1 (cons (mark-marker) mark-ring))
+                      (l2 (list (copy-marker (point) t))))
+                  (while (and l1 (> skeleton-regions 0))
+                    (push (copy-marker (pop l1) t) l2)
+                    (setq skeleton-regions (1- skeleton-regions)))
+                  (sort l2 '<))))
+        (goto-char (car skeleton-regions))
+        (setq skeleton-regions (cdr skeleton-regions)))
+    (let ((beg (point))
+         skeleton-modified skeleton-point resume: help input v1 v2)
+      (setq skeleton-positions nil)
+      (unwind-protect
+         (eval `(let ,skeleton-further-elements
+                  (skeleton-internal-list skeleton str)))
+       (run-hooks 'skeleton-end-hook)
+       (sit-for 0)
+       (or (pos-visible-in-window-p beg)
+           (progn
+             (goto-char beg)
+             (recenter 0)))
+       (if skeleton-point
+           (goto-char skeleton-point))))))
+
+(defun skeleton-read (prompt &optional initial-input recursive)
+  "Function for reading a string from the minibuffer within skeletons.
+
+PROMPT must be a string or a form that evaluates to a string.
+It may contain a `%s' which will be replaced by `skeleton-subprompt'.
+If non-nil second arg INITIAL-INPUT or variable `input' is a string or
+cons with index to insert before reading.  If third arg RECURSIVE is non-nil
+i.e. we are handling the iterator of a subskeleton, returns empty string if
+user didn't modify input.
+While reading, the value of `minibuffer-help-form' is variable `help' if that
+is non-nil or a default string."
+  (let ((minibuffer-help-form (or (if (boundp 'help) (symbol-value 'help))
+                                 (if recursive "\
+As long as you provide input you will insert another subskeleton.
+
+If you enter the empty string, the loop inserting subskeletons is
+left, and the current one is removed as far as it has been entered.
+
+If you quit, the current subskeleton is removed as far as it has been
+entered.  No more of the skeleton will be inserted, except maybe for a
+syntactically necessary termination."
+                                   "\
+You are inserting a skeleton.  Standard text gets inserted into the buffer
+automatically, and you are prompted to fill in the variable parts.")))
+       (eolp (eolp)))
+    ;; since Emacs doesn't show main window's cursor, do something noticeable
+    (or eolp
+       (open-line 1))
+    (unwind-protect
+       (setq prompt (if (stringp prompt)
+                        (read-string (format prompt skeleton-subprompt)
+                                     (setq initial-input
+                                           (or initial-input
+                                               (symbol-value 'input))))
+                      (eval prompt)))
+      (or eolp
+         (delete-char 1))))
+  (if (and recursive
+          (or (null prompt)
+              (string= prompt "")
+              (equal prompt initial-input)
+              (equal prompt (car-safe initial-input))))
+      (signal 'quit t)
+    prompt))
+
+(defun skeleton-internal-list (skeleton &optional str recursive)
+  (let* ((start (save-excursion (beginning-of-line) (point)))
+        (column (current-column))
+        (line (buffer-substring start (line-end-position)))
+        opoint)
+    (or str
+       (setq str `(setq str (skeleton-read ',(car skeleton) nil ,recursive))))
+    (when (and (eq (cadr skeleton) '\n) (not recursive)
+              (save-excursion (skip-chars-backward " \t") (bolp)))
+      (setq skeleton (cons nil (cons '> (cddr skeleton)))))
+    (while (setq skeleton-modified (eq opoint (point))
+                opoint (point)
+                skeleton (cdr skeleton))
+      (condition-case quit
+         (skeleton-internal-1 (car skeleton) nil recursive)
+       (quit
+        (if (eq (cdr quit) 'recursive)
+            (setq recursive 'quit
+                  skeleton (memq 'resume: skeleton))
+          ;; Remove the subskeleton as far as it has been shown
+          ;; the subskeleton shouldn't have deleted outside current line.
+          (end-of-line)
+          (delete-region start (point))
+          (insert line)
+          (move-to-column column)
+          (if (cdr quit)
+              (setq skeleton ()
+                    recursive nil)
+            (signal 'quit 'recursive)))))))
+  ;; maybe continue loop or go on to next outer resume: section
+  (if (eq recursive 'quit)
+      (signal 'quit 'recursive)
+    recursive))
+
+(defun skeleton-internal-1 (element &optional literal recursive)
+  (cond
+   ((char-or-string-p element)
+    (if (and (integerp element)                ; -num
+            (< element 0))
+       (if skeleton-untabify
+           (backward-delete-char-untabify (- element))
+         (delete-backward-char (- element)))
+      (insert (if (not literal)
+                 (funcall skeleton-transformation element)
+               element))))
+   ((or (eq element '\n)                       ; actually (eq '\n 'n)
+       ;; The sequence `> \n' is handled specially so as to indent the first
+       ;; line after inserting the newline (to get the proper indentation).
+       (and (eq element '>) (eq (nth 1 skeleton) '\n) (pop skeleton)))
+    (let ((pos (if (eq element '>) (point))))
+      (cond
+       ((and skeleton-regions (eq (nth 1 skeleton) '_))
+       (or (eolp) (newline))
+       (if pos (save-excursion (goto-char pos) (indent-according-to-mode)))
+       (indent-region (line-beginning-position)
+                      (car skeleton-regions) nil))
+       ;; \n as last element only inserts \n if not at eol.
+       ((and (null (cdr skeleton)) (not recursive) (eolp))
+       (if pos (indent-according-to-mode)))
+       (skeleton-newline-indent-rigidly
+       (let ((pt (point)))
+         (newline)
+         (indent-to (save-excursion
+                      (goto-char pt)
+                      (if pos (indent-according-to-mode))
+                      (current-indentation)))))
+       (t (if pos (reindent-then-newline-and-indent)
+           (newline)
+           (indent-according-to-mode))))))
+   ((eq element '>)
+    (if (and skeleton-regions (eq (nth 1 skeleton) '_))
+       (indent-region (line-beginning-position)
+                      (car skeleton-regions) nil)
+      (indent-according-to-mode)))
+   ((eq element '_)
+    (if skeleton-regions
+       (progn
+         (goto-char (pop skeleton-regions))
+         (and (<= (current-column) (current-indentation))
+              (eq (nth 1 skeleton) '\n)
+              (end-of-line 0)))
+      (or skeleton-point
+         (setq skeleton-point (point)))))
+   ((eq element '-)
+    (setq skeleton-point (point)))
+   ((eq element '&)
+    (when skeleton-modified (pop skeleton)))
+   ((eq element '|)
+    (unless skeleton-modified (pop skeleton)))
+   ((eq element '@)
+    (push (point) skeleton-positions))
+   ((eq 'quote (car-safe element))
+    (eval (nth 1 element)))
+   ((and (consp element)
+        (or (stringp (car element)) (listp (car element))))
+    ;; Don't forget: `symbolp' is also true for nil.
+    (if (symbolp (car-safe (car element)))
+       (while (and (skeleton-internal-list element nil t)
+                   ;; If the interactor is nil, don't infinite loop.
+                   (car element)))
+      (setq literal (car element))
+      (while literal
+       (skeleton-internal-list element (car literal))
+       (setq literal (cdr literal)))))
+   ((null element))
+   (t (skeleton-internal-1 (eval element) t recursive))))
+\f
+;; Maybe belongs into simple.el or elsewhere
+;; ;;;###autoload
+;; (define-skeleton local-variables-section
+;;  "Insert a local variables section.  Use current comment syntax if any."
+;;  (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
+;;                  (lambda (symbol)
+;;                    (or (eq symbol 'eval)
+;;                        (user-variable-p symbol)))
+;;                  t)
+;;    comment-start str ": "
+;;    (read-from-minibuffer "Expression: " nil read-expression-map nil
+;;                       'read-expression-history) | _
+;;    comment-end \n)
+;;  resume:
+;;  comment-start "End:" comment-end \n)
+\f
+;; Variables and command for automatically inserting pairs like () or "".
+
+(defvar skeleton-pair nil
+  "*If this is nil pairing is turned off, no matter what else is set.
+Otherwise modes with `skeleton-pair-insert-maybe' on some keys
+will attempt to insert pairs of matching characters.")
+
+
+(defvar skeleton-pair-on-word nil
+  "*If this is nil, paired insertion is inhibited before or inside a word.")
+
+
+(defvar skeleton-pair-filter (lambda () nil)
+  "Attempt paired insertion if this function returns nil, before inserting.
+This allows for context-sensitive checking whether pairing is appropriate.")
+
+
+(defvar skeleton-pair-alist ()
+  "An override alist of pairing partners matched against `last-command-char'.
+Each alist element, which looks like (ELEMENT ...), is passed to
+`skeleton-insert' with no interactor.  Variable `str' does nothing.
+
+Elements might be (?` ?` _ \"''\"), (?\\( ?  _ \" )\") or (?{ \\n > _ \\n ?} >).")
+
+(defvar skeleton-pair-default-alist '((?( _ ?)) (?\))
+                                     (?[ _ ?]) (?\])
+                                     (?{ _ ?}) (?\})
+                                     (?< _ ?>) (?\>)
+                                     (?« _ ?») (?\»)
+                                     (?` _ ?')))
+
+;;;###autoload
+(defun skeleton-pair-insert-maybe (arg)
+  "Insert the character you type ARG times.
+
+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.
+Pairing is also prohibited if we are right after a quoting character
+such as backslash.
+
+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 (not skeleton-pair))
+      (self-insert-command (prefix-numeric-value arg))
+    (let* ((mark (and skeleton-autowrap
+                     (or (eq last-command 'mouse-drag-region)
+                         (and transient-mark-mode mark-active))))
+          (skeleton-end-hook)
+          (char last-command-char)
+          (skeleton (or (assq char skeleton-pair-alist)
+                        (assq char skeleton-pair-default-alist)
+                        `(,char _ ,char))))
+      (if (or (memq (char-syntax (preceding-char)) '(?\\ ?/))
+             (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))
+       (skeleton-insert (cons nil skeleton) (if mark -1))))))
+
+\f
+;; 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)
+
+;;; arch-tag: ccad7bd5-eb5d-40de-9ded-900197215c3e
+;;; skeleton.el ends here