X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5d80cc9cbc2ffd18c4fc5ca2c9c04e76ae7f8c30..c66cd0ff658dfcba849176d58a405c69e9672e80:/lisp/emacs-lisp/cl-indent.el diff --git a/lisp/emacs-lisp/cl-indent.el b/lisp/emacs-lisp/cl-indent.el index 295a85b7ae..d52c487917 100644 --- a/lisp/emacs-lisp/cl-indent.el +++ b/lisp/emacs-lisp/cl-indent.el @@ -1,6 +1,7 @@ ;;; cl-indent.el --- enhanced lisp-indent mode -;; Copyright (C) 1987 Free Software Foundation, Inc. +;; Copyright (C) 1987, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, +;; 2008, 2009 Free Software Foundation, Inc. ;; Author: Richard Mlynarik ;; Created: July 1987 @@ -9,10 +10,10 @@ ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; 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. +;; the Free Software Foundation, either version 3 of the License, 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 @@ -20,9 +21,7 @@ ;; 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. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -49,25 +48,25 @@ ;;; Code: (defgroup lisp-indent nil - "Indentation in Lisp" + "Indentation in Lisp." :group 'lisp) (defcustom lisp-indent-maximum-backtracking 3 - "*Maximum depth to backtrack out from a sublist for structured indentation. -If this variable is 0, no backtracking will occur and forms such as flet + "Maximum depth to backtrack out from a sublist for structured indentation. +If this variable is 0, no backtracking will occur and forms such as `flet' may not be correctly indented." :type 'integer :group 'lisp-indent) (defcustom lisp-tag-indentation 1 - "*Indentation of tags relative to containing list. + "Indentation of tags relative to containing list. This variable is used by the function `lisp-indent-tagbody'." :type 'integer :group 'lisp-indent) (defcustom lisp-tag-body-indentation 3 - "*Indentation of non-tagged lines relative to containing list. + "Indentation of non-tagged lines relative to containing list. This variable is used by the function `lisp-indent-tagbody' to indent normal lines (lines without tags). The indentation is relative to the indentation of the parenthesis enclosing @@ -78,12 +77,140 @@ by `lisp-body-indent'." :type 'integer :group 'lisp-indent) +(defcustom lisp-backquote-indentation t + "Whether or not to indent backquoted lists as code. +If nil, indent backquoted lists as data, i.e., like quoted lists." + :type 'boolean + :group 'lisp-indent) + + +(defcustom lisp-loop-keyword-indentation 3 + "Indentation of loop keywords in extended loop forms." + :type 'integer + :group 'lisp-indent) + + +(defcustom lisp-loop-forms-indentation 5 + "Indentation of forms in extended loop forms." + :type 'integer + :group 'lisp-indent) + + +(defcustom lisp-simple-loop-indentation 3 + "Indentation of forms in simple loop forms." + :type 'integer + :group 'lisp-indent) + -(defvar lisp-indent-error-function) -(defvar lisp-indent-defun-method '(4 &lambda &body)) +(defvar lisp-indent-defun-method '(4 &lambda &body) + "Indentation for function with `common-lisp-indent-function' property `defun'.") + + +(defun extended-loop-p (loop-start) + "True if an extended loop form starts at LOOP-START." + (condition-case () + (save-excursion + (goto-char loop-start) + (forward-char 1) + (forward-sexp 2) + (backward-sexp 1) + (looking-at "\\sw")) + (error t))) + + +(defun common-lisp-loop-part-indentation (indent-point state) + "Compute the indentation of loop form constituents." + (let* ((loop-indentation (save-excursion + (goto-char (elt state 1)) + (current-column)))) + (goto-char indent-point) + (beginning-of-line) + (cond ((not (extended-loop-p (elt state 1))) + (+ loop-indentation lisp-simple-loop-indentation)) + ((looking-at "^\\s-*\\(:?\\sw+\\|;\\)") + (+ loop-indentation lisp-loop-keyword-indentation)) + (t + (+ loop-indentation lisp-loop-forms-indentation))))) + ;;;###autoload (defun common-lisp-indent-function (indent-point state) + "Function to indent the arguments of a Lisp function call. +This is suitable for use as the value of the variable +`lisp-indent-function'. INDENT-POINT is the point at which the +indentation function is called, and STATE is the +`parse-partial-sexp' state at that position. Browse the +`lisp-indent' customize group for options affecting the behavior +of this function. + +If the indentation point is in a call to a Lisp function, that +function's common-lisp-indent-function property specifies how +this function should indent it. Possible values for this +property are: + +* defun, meaning indent according to `lisp-indent-defun-method'; + i.e., like (4 &lambda &body), as explained below. + +* any other symbol, meaning a function to call. The function should + take the arguments: PATH STATE INDENT-POINT SEXP-COLUMN NORMAL-INDENT. + PATH is a list of integers describing the position of point in terms of + list-structure with respect to the containing lists. For example, in + ((a b c (d foo) f) g), foo has a path of (0 3 1). In other words, + to reach foo take the 0th element of the outermost list, then + the 3rd element of the next list, and finally the 1st element. + STATE and INDENT-POINT are as in the arguments to + `common-lisp-indent-function'. SEXP-COLUMN is the column of + the open parenthesis of the innermost containing list. + NORMAL-INDENT is the column the indentation point was + originally in. This function should behave like `lisp-indent-259'. + +* an integer N, meaning indent the first N arguments like + function arguments, and any further arguments like a body. + This is equivalent to (4 4 ... &body). + +* a list. The list element in position M specifies how to indent the Mth + function argument. If there are fewer elements than function arguments, + the last list element applies to all remaining arguments. The accepted + list elements are: + + * nil, meaning the default indentation. + + * an integer, specifying an explicit indentation. + + * &lambda. Indent the argument (which may be a list) by 4. + + * &rest. When used, this must be the penultimate element. The + element after this one applies to all remaining arguments. + + * &body. This is equivalent to &rest lisp-body-indent, i.e., indent + all remaining elements by `lisp-body-indent'. + + * &whole. This must be followed by nil, an integer, or a + function symbol. This indentation is applied to the + associated argument, and as a base indent for all remaining + arguments. For example, an integer P means indent this + argument by P, and all remaining arguments by P, plus the + value specified by their associated list element. + + * a symbol. A function to call, with the 6 arguments specified above. + + * a list, with elements as described above. This applies when the + associated function argument is itself a list. Each element of the list + specifies how to indent the associated argument. + +For example, the function `case' has an indent property +\(4 &rest (&whole 2 &rest 1)), meaning: + * indent the first argument by 4. + * arguments after the first should be lists, and there may be any number + of them. The first list element has an offset of 2, all the rest + have an offset of 2+1=3." + (if (save-excursion (goto-char (elt state 1)) + (looking-at "([Ll][Oo][Oo][Pp]")) + (common-lisp-loop-part-indentation indent-point state) + (common-lisp-indent-function-1 indent-point state))) + + +(defun common-lisp-indent-function-1 (indent-point state) (let ((normal-indent (current-column))) ;; Walk up list levels until we see something ;; which does special things with subforms. @@ -91,10 +218,14 @@ by `lisp-body-indent'." ;; Path describes the position of point in terms of ;; list-structure with respect to containing lists. ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)' + ;; (Surely (0 3 1)?). (path ()) ;; set non-nil when somebody works out the indentation to use calculated - (last-point indent-point) + ;; If non-nil, this is an indentation to use + ;; if nothing else specifies it more firmly. + tentative-calculated + (last-point indent-point) ;; the position of the open-paren of the innermost containing list (containing-form-start (elt state 1)) ;; the column of the above @@ -102,6 +233,7 @@ by `lisp-body-indent'." ;; Move to start of innermost containing list (goto-char containing-form-start) (setq sexp-column (current-column)) + ;; Look over successively less-deep containing forms (while (and (not calculated) (< depth lisp-indent-maximum-backtracking)) @@ -109,7 +241,7 @@ by `lisp-body-indent'." (forward-char 1) (parse-partial-sexp (point) indent-point 1 t) ;; Move to the car of the relevant containing form - (let (tem function method) + (let (tem function method tentative-defun) (if (not (looking-at "\\sw\\|\\s_")) ;; This form doesn't seem to start with a symbol (setq function nil method nil) @@ -149,18 +281,24 @@ by `lisp-body-indent'." (cond ((null function)) ((null method) (when (null (cdr path)) - ;; (package prefix was stripped off above) - (setq method (cond ((string-match "\\`def" - function) - lisp-indent-defun-method) - ((string-match "\\`\\(with\\|do\\)-" - function) - '(&lambda &body)))))) + ;; (package prefix was stripped off above) + (cond ((string-match "\\`def" + function) + (setq tentative-defun t)) + ((string-match + (eval-when-compile + (concat "\\`\\(" + (regexp-opt '("with" "without" "do")) + "\\)-")) + function) + (setq method '(&lambda &body)))))) ;; backwards compatibility. Bletch. ((eq method 'defun) (setq method lisp-indent-defun-method))) - (cond ((and (memq (char-after (1- containing-sexp)) '(?\' ?\`)) + (cond ((and (or (eq (char-after (1- containing-sexp)) ?\') + (and (not lisp-backquote-indentation) + (eq (char-after (1- containing-sexp)) ?\`))) (not (eq (char-after (- containing-sexp 2)) ?\#))) ;; No indentation for "'(...)" elements (setq calculated (1+ sexp-column))) @@ -172,7 +310,26 @@ by `lisp-body-indent'." ((eq (char-after (1- containing-sexp)) ?\#) ;; "#(...)" (setq calculated (1+ sexp-column))) - ((null method)) + ((null method) + ;; If this looks like a call to a `def...' form, + ;; think about indenting it as one, but do it + ;; tentatively for cases like + ;; (flet ((defunp () + ;; nil))) + ;; Set both normal-indent and tentative-calculated. + ;; The latter ensures this value gets used + ;; if there are no relevant containing constructs. + ;; The former ensures this value gets used + ;; if there is a relevant containing construct + ;; but we are nested within the structure levels + ;; that it specifies indentation for. + (if tentative-defun + (setq tentative-calculated + (common-lisp-indent-call-method + function lisp-indent-defun-method + path state indent-point + sexp-column normal-indent) + normal-indent tentative-calculated))) ((integerp method) ;; convenient top-level hack. ;; (also compatible with lisp-indent-function) @@ -191,25 +348,33 @@ by `lisp-body-indent'." (t ;; other body form normal-indent)))) - ((symbolp method) - (let ((lisp-indent-error-function function)) - (setq calculated (funcall method - path state indent-point - sexp-column normal-indent)))) - (t - (let ((lisp-indent-error-function function)) - (setq calculated (lisp-indent-259 - method path state indent-point - sexp-column normal-indent)))))) + (t + (setq calculated + (common-lisp-indent-call-method + function method path state indent-point + sexp-column normal-indent))))) (goto-char containing-sexp) (setq last-point containing-sexp) (unless calculated - (condition-case () - (progn (backward-up-list 1) - (setq depth (1+ depth))) - (error (setq depth lisp-indent-maximum-backtracking)))))) - calculated))) - + (condition-case () + (progn (backward-up-list 1) + (setq depth (1+ depth))) + (error (setq depth lisp-indent-maximum-backtracking)))))) + (or calculated tentative-calculated)))) + + +(defun common-lisp-indent-call-method (function method path state indent-point + sexp-column normal-indent) + (let ((lisp-indent-error-function function)) + (if (symbolp method) + (funcall method + path state indent-point + sexp-column normal-indent) + (lisp-indent-259 method path state indent-point + sexp-column normal-indent)))) + +;; Dynamically bound in common-lisp-indent-call-method. +(defvar lisp-indent-error-function) (defun lisp-indent-report-bad-format (m) (error "%s has a badly-formed %s property: %s" @@ -279,14 +444,16 @@ by `lisp-body-indent'." ;; Too few elements in pattern. (throw 'exit normal-indent))) ((eq tem 'nil) - (throw 'exit (list normal-indent containing-form-start))) - ((eq tem '&lambda) - (throw 'exit - (cond ((null p) - (list (+ sexp-column 4) containing-form-start)) - ((null (cdr p)) - (+ sexp-column 1)) - (t normal-indent)))) + (throw 'exit (if (consp normal-indent) + normal-indent + (list normal-indent containing-form-start)))) + ((eq tem '&lambda) + (throw 'exit + (cond ((null p) + (list (+ sexp-column 4) containing-form-start)) + ((null (cdr p)) + (+ sexp-column 1)) + (t normal-indent)))) ((integerp tem) (throw 'exit (if (null p) ;not in subforms @@ -355,6 +522,22 @@ by `lisp-body-indent'." (&whole nil &rest 1)) path state indent-point sexp-column normal-indent))) + +(defun lisp-indent-defmethod (path state indent-point sexp-column + normal-indent) + "Indentation function defmethod." + (lisp-indent-259 (if (and (>= (car path) 3) + (null (cdr path)) + (save-excursion (goto-char (elt state 1)) + (forward-char 1) + (forward-sexp 3) + (backward-sexp) + (looking-at ":\\|\\sw+"))) + '(4 4 (&whole 4 &rest 4) &body) + (get 'defun 'common-lisp-indent-function)) + path state indent-point sexp-column normal-indent)) + + (defun lisp-indent-function-lambda-hack (path state indent-point sexp-column normal-indent) ;; indent (function (lambda () )) kludgily. @@ -373,28 +556,33 @@ by `lisp-body-indent'." (+ sexp-column lisp-body-indent))) (error (+ sexp-column lisp-body-indent))))) + (let ((l '((block 1) (case (4 &rest (&whole 2 &rest 1))) - (ccase . case) (ecase . case) - (condition-case ((1 4) (&whole 2 ((0 1) (1 3) (2 &body))))) - (typecase . case) (etypecase . case) (ctypecase . case) + (ccase . case) + (ecase . case) + (typecase . case) + (etypecase . case) + (ctypecase . case) (catch 1) (cond (&rest (&whole 2 &rest 1))) (defvar (4 2 2)) - (defclass ((&whole 4 &rest (&whole 2 &rest 1)) - &rest (&whole 2 &rest 1))) + (defclass (6 4 (&whole 2 &rest 1) (&whole 2 &rest 1))) (defconstant . defvar) (defcustom (4 2 2 2)) (defparameter . defvar) - (define-modify-macro - (4 &body)) + (defconst . defcustom) + (define-condition . defclass) + (define-modify-macro (4 &lambda &body)) (defsetf (4 &lambda 4 &body)) (defun (4 &lambda &body)) (define-setf-method . defun) (define-setf-expander . defun) - (defmacro . defun) (defsubst . defun) (deftype . defun) - (defmethod (4 4 (&whole 4 &rest 1) &body)) + (defmacro . defun) + (defsubst . defun) + (deftype . defun) + (defmethod lisp-indent-defmethod) (defpackage (4 2)) (defstruct ((&whole 4 &rest (&whole 2 &rest 1)) &rest (&whole 2 &rest 1))) @@ -408,6 +596,8 @@ by `lisp-body-indent'." (flet ((&whole 4 &rest (&whole 1 &lambda &body)) &body)) (labels . flet) (macrolet . flet) + (generic-flet . flet) + (generic-labels . flet) (handler-case (4 &rest (&whole 2 &lambda &body))) (restart-case . handler-case) ;; `else-body' style @@ -418,13 +608,13 @@ by `lisp-body-indent'." (let ((&whole 4 &rest (&whole 1 1 2)) &body)) (let* . let) (compiler-let . let) ;barf - (handler-bind . let) (restart-bind . let) + (handler-bind . let) + (restart-bind . let) (locally 1) - ;(loop ...) - (multiple-value-bind - ((&whole 6 &rest 1) 4 &body)) - (multiple-value-call - (4 &body)) + ;(loop lisp-indent-loop) + (:method (&lambda &body)) ; in `defgeneric' + (multiple-value-bind ((&whole 6 &rest 1) 4 &body)) + (multiple-value-call (4 &body)) (multiple-value-prog1 1) (multiple-value-setq (4 2)) (multiple-value-setf . multiple-value-setq) @@ -439,20 +629,22 @@ by `lisp-body-indent'." (progv (4 4 &body)) (return 0) (return-from (nil &body)) - (symbol-macrolet . multiple-value-bind) + (symbol-macrolet . let) (tagbody lisp-indent-tagbody) (throw 1) (unless 1) (unwind-protect (5 &body)) (when 1) + (with-accessors . multiple-value-bind) + (with-condition-restarts . multiple-value-bind) (with-output-to-string (4 2)) + (with-slots . multiple-value-bind) (with-standard-io-syntax (2))))) - (while l - (put (caar l) 'common-lisp-indent-function - (if (symbolp (cdar l)) - (get (cdar l) 'common-lisp-indent-function) - (car (cdar l)))) - (setq l (cdr l)))) + (dolist (el l) + (put (car el) 'common-lisp-indent-function + (if (symbolp (cdr el)) + (get (cdr el) 'common-lisp-indent-function) + (car (cdr el)))))) ;(defun foo (x) @@ -492,8 +684,11 @@ by `lisp-body-indent'." ;(put 'with-restart 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body))) ;(put 'restart-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (* 1))))) -;(put 'define-condition 'common-lisp-indent-function '((1 6) (2 6 ((* 1))) (3 4 ((* 1))) (4 &body))) +;(put 'define-condition 'common-lisp-indent-function '((1 6) (2 6 ((&whole 1))) (3 4 ((&whole 1))) (4 &body))) ;(put 'with-condition-handler 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body))) ;(put 'condition-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (1 3) (2 &body))))) +;(put 'defclass 'common-lisp-indent-function '((&whole 2 &rest (&whole 2 &rest 1) &rest (&whole 2 &rest 1))) +;(put 'defgeneric 'common-lisp-indent-function 'defun) +;; arch-tag: 7914d50f-92ec-4476-93fc-0f043a380e03 ;;; cl-indent.el ends here