]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/cl-indent.el
Remove leading "*" from defcustom docs.
[gnu-emacs] / lisp / emacs-lisp / cl-indent.el
index 294b7b7f5d2150a7a94d26842fb302a3caae7c37..d52c487917b84e6d0d357cbf123eedfa816457e9 100644 (file)
@@ -1,6 +1,7 @@
 ;;; cl-indent.el --- enhanced lisp-indent mode
 
-;; Copyright (C) 1987, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1987, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+;;   2008, 2009 Free Software Foundation, Inc.
 
 ;; Author: Richard Mlynarik <mly@eddie.mit.edu>
 ;; Created: July 1987
 
 ;; 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 <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;;; 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)
+
 \f
-(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,16 +522,17 @@ 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 (>= (first path) 3)
-                            (null (rest path))
+  (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 ":")))
+                                           (looking-at ":\\|\\sw+")))
                       '(4 4 (&whole 4 &rest 4) &body)
                     (get 'defun 'common-lisp-indent-function))
                   path state indent-point sexp-column normal-indent))
@@ -388,11 +556,15 @@ by `lisp-body-indent'."
               (+ sexp-column lisp-body-indent)))
        (error (+ sexp-column lisp-body-indent)))))
 
+
 \f
 (let ((l '((block 1)
            (case        (4 &rest (&whole 2 &rest 1)))
-           (ccase . case) (ecase . case)
-           (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))
@@ -407,7 +579,9 @@ by `lisp-body-indent'."
            (defun       (4 &lambda &body))
            (define-setf-method . defun)
            (define-setf-expander . defun)
-           (defmacro . defun) (defsubst . defun) (deftype . defun)
+           (defmacro . defun)
+           (defsubst . defun)
+           (deftype . defun)
           (defmethod   lisp-indent-defmethod)
            (defpackage  (4 2))
            (defstruct   ((&whole 4 &rest (&whole 2 &rest 1))
@@ -422,7 +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)
+           (generic-flet . flet)
+           (generic-labels . flet)
            (handler-case (4 &rest (&whole 2 &lambda &body)))
            (restart-case . handler-case)
            ;; `else-body' style
@@ -433,9 +608,10 @@ 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 ...)
+           ;(loop         lisp-indent-loop)
            (:method (&lambda &body)) ; in `defgeneric'
            (multiple-value-bind ((&whole 6 &rest 1) 4 &body))
            (multiple-value-call (4 &body))
@@ -453,7 +629,7 @@ 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)
@@ -514,4 +690,5 @@ by `lisp-body-indent'."
 ;(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