Many trivial doc fixes.
[bpt/emacs.git] / lisp / emacs-lisp / cl-indent.el
CommitLineData
c0274f38
ER
1;;; cl-indent.el --- enhanced lisp-indent mode
2
6f26dfa5 3;; Copyright (C) 1987, 2000, 2001 Free Software Foundation, Inc.
e41b2db1 4
a7acbbe4 5;; Author: Richard Mlynarik <mly@eddie.mit.edu>
e41b2db1 6;; Created: July 1987
e5167999 7;; Maintainer: FSF
fd7fa35a 8;; Keywords: lisp, tools
e5167999 9
745bc783
JB
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
e5167999 14;; the Free Software Foundation; either version 2, or (at your option)
745bc783
JB
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
745bc783 26
e5167999
ER
27;;; Commentary:
28
e41b2db1
ER
29;; This package supplies a single entry point, common-lisp-indent-function,
30;; which performs indentation in the preferred style for Common Lisp code.
31;; To enable it:
32;;
33;; (setq lisp-indent-function 'common-lisp-indent-function)
34
745bc783
JB
35;;>> TODO
36;; :foo
37;; bar
38;; :baz
39;; zap
40;; &key (like &body)??
41
42;; &rest 1 in lambda-lists doesn't work
43;; -- really want (foo bar
44;; baz)
45;; not (foo bar
46;; baz)
47;; Need something better than &rest for such cases
48
e5167999 49;;; Code:
745bc783 50
fcad5199
RS
51(defgroup lisp-indent nil
52 "Indentation in Lisp"
53 :group 'lisp)
54
55
56(defcustom lisp-indent-maximum-backtracking 3
745bc783
JB
57 "*Maximum depth to backtrack out from a sublist for structured indentation.
58If this variable is 0, no backtracking will occur and forms such as flet
fcad5199
RS
59may not be correctly indented."
60 :type 'integer
61 :group 'lisp-indent)
745bc783 62
fcad5199 63(defcustom lisp-tag-indentation 1
745bc783 64 "*Indentation of tags relative to containing list.
fcad5199
RS
65This variable is used by the function `lisp-indent-tagbody'."
66 :type 'integer
67 :group 'lisp-indent)
745bc783 68
fcad5199 69(defcustom lisp-tag-body-indentation 3
745bc783
JB
70 "*Indentation of non-tagged lines relative to containing list.
71This variable is used by the function `lisp-indent-tagbody' to indent normal
72lines (lines without tags).
73The indentation is relative to the indentation of the parenthesis enclosing
74the special form. If the value is t, the body of tags will be indented
75as a block at the same indentation as the first s-expression following
76the tag. In this case, any forms before the first tag are indented
fcad5199
RS
77by `lisp-body-indent'."
78 :type 'integer
79 :group 'lisp-indent)
745bc783
JB
80
81\f
bf92b5a4 82(defvar lisp-indent-error-function)
bbf1ae49 83(defvar lisp-indent-defun-method '(4 &lambda &body))
bf92b5a4 84
745bc783
JB
85;;;###autoload
86(defun common-lisp-indent-function (indent-point state)
87 (let ((normal-indent (current-column)))
88 ;; Walk up list levels until we see something
89 ;; which does special things with subforms.
90 (let ((depth 0)
91 ;; Path describes the position of point in terms of
eb8c3be9 92 ;; list-structure with respect to containing lists.
745bc783
JB
93 ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)'
94 (path ())
95 ;; set non-nil when somebody works out the indentation to use
96 calculated
97 (last-point indent-point)
98 ;; the position of the open-paren of the innermost containing list
99 (containing-form-start (elt state 1))
100 ;; the column of the above
101 sexp-column)
102 ;; Move to start of innermost containing list
103 (goto-char containing-form-start)
104 (setq sexp-column (current-column))
105 ;; Look over successively less-deep containing forms
106 (while (and (not calculated)
107 (< depth lisp-indent-maximum-backtracking))
108 (let ((containing-sexp (point)))
109 (forward-char 1)
110 (parse-partial-sexp (point) indent-point 1 t)
111 ;; Move to the car of the relevant containing form
112 (let (tem function method)
113 (if (not (looking-at "\\sw\\|\\s_"))
114 ;; This form doesn't seem to start with a symbol
115 (setq function nil method nil)
116 (setq tem (point))
117 (forward-sexp 1)
bbf1ae49
RS
118 (setq function (downcase (buffer-substring-no-properties
119 tem (point))))
745bc783
JB
120 (goto-char tem)
121 (setq tem (intern-soft function)
122 method (get tem 'common-lisp-indent-function))
123 (cond ((and (null method)
124 (string-match ":[^:]+" function))
125 ;; The pleblisp package feature
126 (setq function (substring function
127 (1+ (match-beginning 0)))
128 method (get (intern-soft function)
129 'common-lisp-indent-function)))
130 ((and (null method))
131 ;; backwards compatibility
132 (setq method (get tem 'lisp-indent-function)))))
133 (let ((n 0))
134 ;; How far into the containing form is the current form?
135 (if (< (point) indent-point)
136 (while (condition-case ()
137 (progn
138 (forward-sexp 1)
139 (if (>= (point) indent-point)
140 nil
141 (parse-partial-sexp (point)
142 indent-point 1 t)
143 (setq n (1+ n))
144 t))
145 (error nil))))
146 (setq path (cons n path)))
147
148 ;; backwards compatibility.
149 (cond ((null function))
150 ((null method)
bbf1ae49 151 (when (null (cdr path))
745bc783
JB
152 ;; (package prefix was stripped off above)
153 (setq method (cond ((string-match "\\`def"
154 function)
bbf1ae49 155 lisp-indent-defun-method)
745bc783
JB
156 ((string-match "\\`\\(with\\|do\\)-"
157 function)
bbf1ae49 158 '(&lambda &body))))))
745bc783
JB
159 ;; backwards compatibility. Bletch.
160 ((eq method 'defun)
bbf1ae49 161 (setq method lisp-indent-defun-method)))
745bc783
JB
162
163 (cond ((and (memq (char-after (1- containing-sexp)) '(?\' ?\`))
893d4ef0 164 (not (eq (char-after (- containing-sexp 2)) ?\#)))
745bc783
JB
165 ;; No indentation for "'(...)" elements
166 (setq calculated (1+ sexp-column)))
5d80cc9c
SS
167 ((or (eq (char-after (1- containing-sexp)) ?\,)
168 (and (eq (char-after (1- containing-sexp)) ?\@)
169 (eq (char-after (- containing-sexp 2)) ?\,)))
170 ;; ",(...)" or ",@(...)"
171 (setq calculated normal-indent))
893d4ef0 172 ((eq (char-after (1- containing-sexp)) ?\#)
745bc783
JB
173 ;; "#(...)"
174 (setq calculated (1+ sexp-column)))
175 ((null method))
176 ((integerp method)
177 ;; convenient top-level hack.
178 ;; (also compatible with lisp-indent-function)
179 ;; The number specifies how many `distinguished'
180 ;; forms there are before the body starts
181 ;; Equivalent to (4 4 ... &body)
182 (setq calculated (cond ((cdr path)
183 normal-indent)
184 ((<= (car path) method)
185 ;; `distinguished' form
186 (list (+ sexp-column 4)
187 containing-form-start))
188 ((= (car path) (1+ method))
189 ;; first body form.
190 (+ sexp-column lisp-body-indent))
191 (t
192 ;; other body form
193 normal-indent))))
194 ((symbolp method)
5d80cc9c
SS
195 (let ((lisp-indent-error-function function))
196 (setq calculated (funcall method
197 path state indent-point
198 sexp-column normal-indent))))
745bc783 199 (t
5d80cc9c
SS
200 (let ((lisp-indent-error-function function))
201 (setq calculated (lisp-indent-259
202 method path state indent-point
203 sexp-column normal-indent))))))
745bc783
JB
204 (goto-char containing-sexp)
205 (setq last-point containing-sexp)
bbf1ae49 206 (unless calculated
745bc783
JB
207 (condition-case ()
208 (progn (backward-up-list 1)
209 (setq depth (1+ depth)))
210 (error (setq depth lisp-indent-maximum-backtracking))))))
211 calculated)))
212
213
214(defun lisp-indent-report-bad-format (m)
215 (error "%s has a badly-formed %s property: %s"
216 ;; Love those free variable references!!
bf92b5a4 217 lisp-indent-error-function 'common-lisp-indent-function m))
745bc783
JB
218
219;; Blame the crufty control structure on dynamic scoping
220;; -- not on me!
221(defun lisp-indent-259 (method path state indent-point
222 sexp-column normal-indent)
223 (catch 'exit
224 (let ((p path)
225 (containing-form-start (elt state 1))
226 n tem tail)
227 ;; Isn't tail-recursion wonderful?
228 (while p
229 ;; This while loop is for destructuring.
230 ;; p is set to (cdr p) each iteration.
231 (if (not (consp method)) (lisp-indent-report-bad-format method))
232 (setq n (1- (car p))
233 p (cdr p)
234 tail nil)
235 (while n
236 ;; This while loop is for advancing along a method
237 ;; until the relevant (possibly &rest/&body) pattern
238 ;; is reached.
239 ;; n is set to (1- n) and method to (cdr method)
240 ;; each iteration.
241 (setq tem (car method))
242
243 (or (eq tem 'nil) ;default indentation
5d80cc9c 244 (eq tem '&lambda) ;lambda list
745bc783
JB
245 (and (eq tem '&body) (null (cdr method)))
246 (and (eq tem '&rest)
5d80cc9c
SS
247 (consp (cdr method))
248 (null (cddr method)))
745bc783
JB
249 (integerp tem) ;explicit indentation specified
250 (and (consp tem) ;destructuring
251 (eq (car tem) '&whole)
5d80cc9c
SS
252 (or (symbolp (cadr tem))
253 (integerp (cadr tem))))
745bc783
JB
254 (and (symbolp tem) ;a function to call to do the work.
255 (null (cdr method)))
256 (lisp-indent-report-bad-format method))
257
258 (cond ((and tail (not (consp tem)))
259 ;; indent tail of &rest in same way as first elt of rest
260 (throw 'exit normal-indent))
261 ((eq tem '&body)
262 ;; &body means (&rest <lisp-body-indent>)
263 (throw 'exit
264 (if (and (= n 0) ;first body form
265 (null p)) ;not in subforms
266 (+ sexp-column
267 lisp-body-indent)
268 normal-indent)))
269 ((eq tem '&rest)
270 ;; this pattern holds for all remaining forms
271 (setq tail (> n 0)
272 n 0
273 method (cdr method)))
274 ((> n 0)
275 ;; try next element of pattern
276 (setq n (1- n)
277 method (cdr method))
278 (if (< n 0)
279 ;; Too few elements in pattern.
280 (throw 'exit normal-indent)))
281 ((eq tem 'nil)
282 (throw 'exit (list normal-indent containing-form-start)))
bbf1ae49
RS
283 ((eq tem '&lambda)
284 (throw 'exit
285 (cond ((null p)
286 (list (+ sexp-column 4) containing-form-start))
287 ((null (cdr p))
288 (+ sexp-column 1))
289 (t normal-indent))))
745bc783
JB
290 ((integerp tem)
291 (throw 'exit
292 (if (null p) ;not in subforms
293 (list (+ sexp-column tem) containing-form-start)
294 normal-indent)))
295 ((symbolp tem) ;a function to call
296 (throw 'exit
297 (funcall tem path state indent-point
298 sexp-column normal-indent)))
299 (t
300 ;; must be a destructing frob
301 (if (not (null p))
302 ;; descend
bbf1ae49 303 (setq method (cddr tem)
745bc783 304 n nil)
bbf1ae49 305 (setq tem (cadr tem))
745bc783
JB
306 (throw 'exit
307 (cond (tail
308 normal-indent)
309 ((eq tem 'nil)
310 (list normal-indent
311 containing-form-start))
312 ((integerp tem)
313 (list (+ sexp-column tem)
314 containing-form-start))
315 (t
316 (funcall tem path state indent-point
317 sexp-column normal-indent))))))))))))
318\f
319(defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent)
320 (if (not (null (cdr path)))
321 normal-indent
322 (save-excursion
323 (goto-char indent-point)
324 (beginning-of-line)
325 (skip-chars-forward " \t")
326 (list (cond ((looking-at "\\sw\\|\\s_")
327 ;; a tagbody tag
328 (+ sexp-column lisp-tag-indentation))
329 ((integerp lisp-tag-body-indentation)
330 (+ sexp-column lisp-tag-body-indentation))
331 ((eq lisp-tag-body-indentation 't)
332 (condition-case ()
333 (progn (backward-sexp 1) (current-column))
334 (error (1+ sexp-column))))
335 (t (+ sexp-column lisp-body-indent)))
336; (cond ((integerp lisp-tag-body-indentation)
337; (+ sexp-column lisp-tag-body-indentation))
338; ((eq lisp-tag-body-indentation 't)
339; normal-indent)
340; (t
341; (+ sexp-column lisp-body-indent)))
342 (elt state 1)
343 ))))
344
345(defun lisp-indent-do (path state indent-point sexp-column normal-indent)
346 (if (>= (car path) 3)
347 (let ((lisp-tag-body-indentation lisp-body-indent))
348 (funcall (function lisp-indent-tagbody)
5d80cc9c 349 path state indent-point sexp-column normal-indent))
745bc783 350 (funcall (function lisp-indent-259)
5d80cc9c
SS
351 '((&whole nil &rest
352 ;; the following causes weird indentation
353 ;;(&whole 1 1 2 nil)
354 )
355 (&whole nil &rest 1))
356 path state indent-point sexp-column normal-indent)))
745bc783 357
ec69d5ec
GM
358(defun lisp-indent-defmethod (path state indent-point sexp-column
359 normal-indent)
360 "Indentation function defmethod."
361 (lisp-indent-259 (if (save-excursion (goto-char (elt state 1))
362 (forward-char 1)
363 (forward-sexp 2)
364 (looking-at "\\s-+:"))
365 '(4 4 (&whole 4 &rest 4) &body)
366 (get 'defun 'common-lisp-indent-function))
367 path state indent-point sexp-column normal-indent))
368
369
745bc783
JB
370(defun lisp-indent-function-lambda-hack (path state indent-point
371 sexp-column normal-indent)
372 ;; indent (function (lambda () <newline> <body-forms>)) kludgily.
373 (if (or (cdr path) ; wtf?
374 (> (car path) 3))
375 ;; line up under previous body form
376 normal-indent
377 ;; line up under function rather than under lambda in order to
378 ;; conserve horizontal space. (Which is what #' is for.)
379 (condition-case ()
380 (save-excursion
381 (backward-up-list 2)
382 (forward-char 1)
383 (if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
384 (+ lisp-body-indent -1 (current-column))
385 (+ sexp-column lisp-body-indent)))
386 (error (+ sexp-column lisp-body-indent)))))
387
388\f
389(let ((l '((block 1)
5d80cc9c
SS
390 (case (4 &rest (&whole 2 &rest 1)))
391 (ccase . case) (ecase . case)
5d80cc9c
SS
392 (typecase . case) (etypecase . case) (ctypecase . case)
393 (catch 1)
394 (cond (&rest (&whole 2 &rest 1)))
395 (defvar (4 2 2))
5e9e032a 396 (defclass (6 4 (&whole 2 &rest 1) (&whole 2 &rest 1)))
5d80cc9c 397 (defconstant . defvar)
2ac6f2c8 398 (defcustom (4 2 2 2))
5d80cc9c 399 (defparameter . defvar)
5e9e032a
SS
400 (defconst . defcustom)
401 (define-condition . defclass)
402 (define-modify-macro (4 &body))
5d80cc9c
SS
403 (defsetf (4 &lambda 4 &body))
404 (defun (4 &lambda &body))
405 (define-setf-method . defun)
406 (define-setf-expander . defun)
407 (defmacro . defun) (defsubst . defun) (deftype . defun)
ec69d5ec 408 (defmethod lisp-indent-defmethod)
5d80cc9c
SS
409 (defpackage (4 2))
410 (defstruct ((&whole 4 &rest (&whole 2 &rest 1))
411 &rest (&whole 2 &rest 1)))
412 (destructuring-bind
413 ((&whole 6 &rest 1) 4 &body))
414 (do lisp-indent-do)
415 (do* . do)
416 (dolist ((&whole 4 2 1) &body))
417 (dotimes . dolist)
418 (eval-when 1)
419 (flet ((&whole 4 &rest (&whole 1 &lambda &body)) &body))
420 (labels . flet)
421 (macrolet . flet)
bbf1ae49 422 (handler-case (4 &rest (&whole 2 &lambda &body)))
09a4d958 423 (restart-case . handler-case)
5d80cc9c
SS
424 ;; `else-body' style
425 (if (nil nil &body))
426 ;; single-else style (then and else equally indented)
427 (if (&rest nil))
428 (lambda (&lambda &rest lisp-indent-function-lambda-hack))
429 (let ((&whole 4 &rest (&whole 1 1 2)) &body))
430 (let* . let)
431 (compiler-let . let) ;barf
09a4d958 432 (handler-bind . let) (restart-bind . let)
5d80cc9c
SS
433 (locally 1)
434 ;(loop ...)
2180ea97 435 (:method (&lambda &body)) ; in `defgeneric'
5e9e032a
SS
436 (multiple-value-bind ((&whole 6 &rest 1) 4 &body))
437 (multiple-value-call (4 &body))
5d80cc9c
SS
438 (multiple-value-prog1 1)
439 (multiple-value-setq (4 2))
440 (multiple-value-setf . multiple-value-setq)
7dd21017 441 (pprint-logical-block (4 2))
5d80cc9c
SS
442 (print-unreadable-object ((&whole 4 1 &rest 1) &body))
443 ;; Combines the worst features of BLOCK, LET and TAGBODY
444 (prog (&lambda &rest lisp-indent-tagbody))
445 (prog* . prog)
446 (prog1 1)
447 (prog2 2)
448 (progn 0)
449 (progv (4 4 &body))
450 (return 0)
451 (return-from (nil &body))
452 (symbol-macrolet . multiple-value-bind)
453 (tagbody lisp-indent-tagbody)
454 (throw 1)
455 (unless 1)
456 (unwind-protect (5 &body))
f0d527fc 457 (when 1)
44c705d4 458 (with-output-to-string (4 2))
5e9e032a 459 (with-slots . multiple-value-bind)
f0d527fc 460 (with-standard-io-syntax (2)))))
745bc783 461 (while l
bbf1ae49 462 (put (caar l) 'common-lisp-indent-function
5d80cc9c
SS
463 (if (symbolp (cdar l))
464 (get (cdar l) 'common-lisp-indent-function)
465 (car (cdar l))))
745bc783
JB
466 (setq l (cdr l))))
467
468\f
469;(defun foo (x)
470; (tagbody
471; foo
472; (bar)
473; baz
474; (when (losing)
475; (with-big-loser
476; (yow)
477; ((lambda ()
478; foo)
479; big)))
480; (flet ((foo (bar baz zap)
481; (zip))
482; (zot ()
483; quux))
484; (do ()
485; ((lose)
486; (foo 1))
487; (quux)
488; foo
489; (lose))
490; (cond ((x)
491; (win 1 2
492; (foo)))
493; (t
494; (lose
495; 3))))))
5d80cc9c 496
745bc783
JB
497
498;(put 'while 'common-lisp-indent-function 1)
499;(put 'defwrapper'common-lisp-indent-function ...)
500;(put 'def 'common-lisp-indent-function ...)
501;(put 'defflavor 'common-lisp-indent-function ...)
502;(put 'defsubst 'common-lisp-indent-function ...)
503
504;(put 'with-restart 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
505;(put 'restart-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (* 1)))))
968880c4 506;(put 'define-condition 'common-lisp-indent-function '((1 6) (2 6 ((&whole 1))) (3 4 ((&whole 1))) (4 &body)))
745bc783
JB
507;(put 'with-condition-handler 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
508;(put 'condition-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (1 3) (2 &body)))))
968880c4
DL
509;(put 'defclass 'common-lisp-indent-function '((&whole 2 &rest (&whole 2 &rest 1) &rest (&whole 2 &rest 1)))
510;(put 'defgeneric 'common-lisp-indent-function 'defun)
745bc783 511
c0274f38 512;;; cl-indent.el ends here