;;; skeleton.el --- Lisp language extension for writing statement skeletons -*- coding: utf-8 -*-
-;; Copyright (C) 1993-1996, 2001-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1996, 2001-2014 Free Software Foundation, Inc.
;; Author: Daniel Pfeiffer <occitan@esperanto.org>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
;; Keywords: extensions, abbrev, languages, tools
;; This file is part of GNU Emacs.
;;; Code:
+(eval-when-compile (require 'cl-lib))
+
;; page 1: statement skeleton language definition & interpreter
;; page 2: paired insertion
;; page 3: mirror-mode, an example for setting up paired insertion
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.")
+region.")
+(make-obsolete-variable 'skeleton-autowrap nil "24.5")
(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)))
+(defvar skeleton-end-hook nil
"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.")
"Function for transforming a skeleton proxy's aliases' variable value.")
(defvaralias 'skeleton-filter 'skeleton-filter-function)
-(defvar skeleton-untabify t
+(defvar skeleton-untabify nil ; bug#12223
"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 ()
+(defvar-local 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
"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)))
+ (declare (doc-string 2) (debug (&define name stringp skeleton-edebug-spec)))
(if skeleton-debug
(set command skeleton))
`(progn
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.
+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
If ELEMENT is a string or a character it gets inserted (see also
`skeleton-transformation-function'). Other possibilities are:
- \\n go to next line and indent according to mode
+ \\n go to next line and indent according to mode, unless
+ this is the first/last element of a skeleton and point
+ is at bol/eol
_ interesting point, interregion here
- interesting point, no interregion interaction, overrides
interesting point set by _
@ add position to `skeleton-positions'
& do next ELEMENT if previous moved point
| do next ELEMENT if previous didn't move point
- -num delete num preceding characters (see `skeleton-untabify')
+ -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.
+Note that \\n as the last element of the skeleton only inserts a
+newline if not at eol. If you want to unconditionally insert a newline
+at the end of the skeleton, use \"\\n\" instead. Likewise with \\n
+as the first element when at bol.
+
+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.
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)))
+ (cl-progv
+ (mapcar #'car skeleton-further-elements)
+ (mapcar (lambda (x) (eval (cadr x))) skeleton-further-elements)
+ (skeleton-internal-list skeleton str))
+ (or (eolp) (not skeleton-end-newline) (newline-and-indent))
(run-hooks 'skeleton-end-hook)
(sit-for 0)
(or (pos-visible-in-window-p beg)
(signal 'quit 'recursive)
recursive))
-(defun skeleton-newline ()
- (if (or (eq (point) skeleton-point)
- (eq (point) (car skeleton-positions)))
- ;; If point is recorded, avoid `newline' since it may do things like
- ;; strip trailing spaces, and since recorded points are commonly placed
- ;; right after a trailing space, calling `newline' can destroy the
- ;; position and renders the recorded position incorrect.
- (insert "\n")
- (newline)))
(defun skeleton-internal-1 (element &optional literal recursive)
(cond
(let ((pos (if (eq element '>) (point))))
(cond
((and skeleton-regions (eq (nth 1 skeleton-il) '_))
- (or (eolp) (newline))
+ (or (eolp) (insert "\n"))
(if pos (save-excursion (goto-char pos) (indent-according-to-mode)))
(indent-region (line-beginning-position)
(car skeleton-regions) nil))
(if pos (indent-according-to-mode)))
(skeleton-newline-indent-rigidly
(let ((pt (point)))
- (skeleton-newline)
+ (insert "\n")
(indent-to (save-excursion
(goto-char pt)
(if pos (indent-according-to-mode))
(current-indentation)))))
(t (if pos (reindent-then-newline-and-indent)
- (skeleton-newline)
+ (insert "\n")
(indent-according-to-mode))))))
((eq element '>)
(if (and skeleton-regions (eq (nth 1 skeleton-il) '_))
(let* ((mark (and skeleton-autowrap
(or (eq last-command 'mouse-drag-region)
(and transient-mark-mode mark-active))))
- (skeleton-end-hook)
(char last-command-event)
(skeleton (or (assq char skeleton-pair-alist)
(assq char skeleton-pair-default-alist)
(if (not skeleton-pair-on-word) (looking-at "\\w"))
(funcall skeleton-pair-filter-function))))
(self-insert-command (prefix-numeric-value arg))
- (skeleton-insert (cons nil skeleton) (if mark -1))))))
+ ;; Newlines not desirable for inserting pairs. See bug#16138.
+ (let ((skeleton-end-newline nil))
+ (skeleton-insert (cons nil skeleton) (if mark -1)))))))
\f
;; A more serious example can be found in sh-script.el