;;; statement.el --- Metalanguage for writing statement skeletons ;; Copyright (C) 1993 by Free Software Foundation, Inc. ;; Author: Daniel Pfeiffer ;; Keywords: shell programming ;; 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 metalanguage for writing structured statement 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. ;;; Modifications ;; Date Who, What & Why ;; 931112 ;; Modified indent to use 'mode-indent-level' instead of ;; 'tab-width' so that spaces instead of tabs would be ;; inserted. Allowed smaller "indents". ;; Added '%' feature to insert-statement skeleton so ;; an ELEMENT that was itself a DEFINITION could be ;; processed once. ;;; Code: (defvar statement-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 'statement-skeleton-transformation 'variable-interactive "aTransformation function: ") (defvar debug-statement-skeleton () "*If non-nil `define-statement-skeleton' will override previous definition.") ;;;###autoload (defmacro define-statement-skeleton (command documentation &rest definition) "Define a user-configurable COMMAND that enters a statement-skeleton. The command will have a raw prefix arg. DOCUMENTATION is that of the command, while the variable of the same name, which contains the definition, has a documentation to that effect. PROMPT and ELEMENT ... are as defined under insert-statement-skeleton." (require 'backquote) (`(progn (if debug-statement-skeleton (setq (, command) (, definition))) (defvar (, command) '(, definition) (, (concat "*Definition for the " (symbol-name command) " command. See function insert-statement-skeleton for meaning.")) ) ;; Don't use last-command to guarantee command does the same thing, ;; whatever other name it is given. (defun (, command) (&optional arg) (, documentation) (interactive "*P") (insert-statement-skeleton (, command)))))) ;;;###autoload (defun insert-statement-skeleton (definition) "Insert the complex statement-skeleton DEFINITION describes very concisely. DEFINITION is made up as (PROMPT ELEMENT ...). Prompt may be nil if not needed. If element is a string or a character it gets inserted (see also `statement-skeleton-transformation'). Other possibilities are: \n go to next line and align cursor > indent (more) according to major mode < undent mode-indent-level spaces but not beyond start of line _ cursor after termination arg prefix ARG of calling command if present and non-nil str first time: read a string prompting with PROMPT and insert it then: insert previously read string once more & skip next ELEMENT if previous didn't move point | skip next ELEMENT if previous moved point nil skipped % prompt only once if ELEMENT is itself a DEFINITION ELEMENT may itself be DEFINITION with a PROMPT. The user is prompted repeatedly for different values of str. The DEFINITION is processed as often as the user enters a non-empty string. If only one prompt is desired, the first ELEMENT after the PROMPT must be '%'. Other lisp-expressions are evaluated and the value treated as above." (let ((literal t) (abbrev-mode nil) (arg (and (boundp 'arg) arg (int-to-string (prefix-numeric-value arg)))) (str (list 'setq 'str (list 'read-string (car definition)))) modified opoint point) (insert-statement-internal-list definition) (or (eolp) (newline) (indent-relative t)) (if point (goto-char point)) str)) (defun insert-statement-internal-list (definition) (while (setq modified (eq opoint (point)) opoint (point) definition (cdr definition)) (insert-statement-internal-1 (car definition)))) (defun insert-statement-internal-1 (element) (cond ( (char-or-string-p element) (insert (or (and literal statement-skeleton-transformation (funcall statement-skeleton-transformation element)) element)) ) ( (eq element '\n) ; actually (eq '\n 'n) (newline) (indent-relative t) ) ( (eq element '>) (indent-according-to-mode) ) ( (eq element '<) (backward-delete-char-untabify (min mode-indent-level (current-column))) ) ( (eq element '_) (setq point (point)) ) ( (eq element '&) (if modified (setq definition (cdr definition))) ) ( (eq element '|) (or modified (setq definition (cdr definition))) ) ( (if (consp element) (stringp (car element))) (let (str) (if (eq (car (cdr element)) '%) (if (string< "" (setq str (read-string (car element)))) (insert-statement-internal-list (cdr element))) (while (string< "" (setq str (read-string (car element)))) (insert-statement-internal-list element)))) ) ( (null element) ) ( (let (literal) (insert-statement-internal-1 (eval element))) ) ) )