6b40051193e9ff44f241059dc7e919c8d03ea501
[bpt/emacs.git] / lisp / emacs-lisp / cl-indent.el
1 ;;; cl-indent.el --- enhanced lisp-indent mode
2
3 ;; Copyright (C) 1987, 2000, 2001, 2002 Free Software Foundation, Inc.
4
5 ;; Author: Richard Mlynarik <mly@eddie.mit.edu>
6 ;; Created: July 1987
7 ;; Maintainer: FSF
8 ;; Keywords: lisp, tools
9
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
14 ;; the Free Software Foundation; either version 2, or (at your option)
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
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.
26
27 ;;; Commentary:
28
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
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
49 ;;; Code:
50
51 (defgroup lisp-indent nil
52 "Indentation in Lisp"
53 :group 'lisp)
54
55
56 (defcustom lisp-indent-maximum-backtracking 3
57 "*Maximum depth to backtrack out from a sublist for structured indentation.
58 If this variable is 0, no backtracking will occur and forms such as flet
59 may not be correctly indented."
60 :type 'integer
61 :group 'lisp-indent)
62
63 (defcustom lisp-tag-indentation 1
64 "*Indentation of tags relative to containing list.
65 This variable is used by the function `lisp-indent-tagbody'."
66 :type 'integer
67 :group 'lisp-indent)
68
69 (defcustom lisp-tag-body-indentation 3
70 "*Indentation of non-tagged lines relative to containing list.
71 This variable is used by the function `lisp-indent-tagbody' to indent normal
72 lines (lines without tags).
73 The indentation is relative to the indentation of the parenthesis enclosing
74 the special form. If the value is t, the body of tags will be indented
75 as a block at the same indentation as the first s-expression following
76 the tag. In this case, any forms before the first tag are indented
77 by `lisp-body-indent'."
78 :type 'integer
79 :group 'lisp-indent)
80
81 (defcustom lisp-backquote-indentation t
82 "*Whether or not to indent backquoted lists as code.
83 If nil, indent backquoted lists as data, i.e., like quoted lists."
84 :type 'boolean
85 :group 'lisp-indent)
86
87
88 (defcustom lisp-loop-keyword-indentation 3
89 "*Indentation of loop keywords in extended loop forms."
90 :type 'integer
91 :group 'lisp-indent)
92
93
94 (defcustom lisp-loop-forms-indentation 5
95 "*Indentation of forms in extended loop forms."
96 :type 'integer
97 :group 'lisp-indent)
98
99
100 (defcustom lisp-simple-loop-indentation 3
101 "*Indentation of forms in simple loop forms."
102 :type 'integer
103 :group 'lisp-indent)
104
105 \f
106 (defvar lisp-indent-error-function)
107 (defvar lisp-indent-defun-method '(4 &lambda &body))
108
109
110 (defun extended-loop-p (loop-start)
111 "True if an extended loop form starta at LOOP-START."
112 (condition-case ()
113 (save-excursion
114 (goto-char loop-start)
115 (forward-char 1)
116 (forward-sexp 2)
117 (backward-sexp 1)
118 (looking-at "\\sw"))
119 (error t)))
120
121
122 (defun common-lisp-loop-part-indentation (indent-point state)
123 "Compute the indentation of loop form constituents."
124 (let* ((loop-indentation (save-excursion
125 (goto-char (elt state 1))
126 (current-column))))
127 (goto-char indent-point)
128 (beginning-of-line)
129 (cond ((not (extended-loop-p (elt state 1)))
130 lisp-simple-loop-indentation)
131 ((looking-at "^\\s-*\\(:?\\sw+\\|;\\)")
132 (+ loop-indentation lisp-loop-keyword-indentation))
133 (t
134 (+ loop-indentation lisp-loop-forms-indentation)))))
135
136
137 ;;;###autoload
138 (defun common-lisp-indent-function (indent-point state)
139 (if (save-excursion (goto-char (elt state 1))
140 (looking-at "([Ll][Oo][Oo][Pp]"))
141 (common-lisp-loop-part-indentation indent-point state)
142 (common-lisp-indent-function-1 indent-point state)))
143
144
145 (defun common-lisp-indent-function-1 (indent-point state)
146 (let ((normal-indent (current-column)))
147 ;; Walk up list levels until we see something
148 ;; which does special things with subforms.
149 (let ((depth 0)
150 ;; Path describes the position of point in terms of
151 ;; list-structure with respect to containing lists.
152 ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)'
153 (path ())
154 ;; set non-nil when somebody works out the indentation to use
155 calculated
156 (last-point indent-point)
157 ;; the position of the open-paren of the innermost containing list
158 (containing-form-start (elt state 1))
159 ;; the column of the above
160 sexp-column)
161 ;; Move to start of innermost containing list
162 (goto-char containing-form-start)
163 (setq sexp-column (current-column))
164
165 ;; Look over successively less-deep containing forms
166 (while (and (not calculated)
167 (< depth lisp-indent-maximum-backtracking))
168 (let ((containing-sexp (point)))
169 (forward-char 1)
170 (parse-partial-sexp (point) indent-point 1 t)
171 ;; Move to the car of the relevant containing form
172 (let (tem function method)
173 (if (not (looking-at "\\sw\\|\\s_"))
174 ;; This form doesn't seem to start with a symbol
175 (setq function nil method nil)
176 (setq tem (point))
177 (forward-sexp 1)
178 (setq function (downcase (buffer-substring-no-properties
179 tem (point))))
180 (goto-char tem)
181 (setq tem (intern-soft function)
182 method (get tem 'common-lisp-indent-function))
183 (cond ((and (null method)
184 (string-match ":[^:]+" function))
185 ;; The pleblisp package feature
186 (setq function (substring function
187 (1+ (match-beginning 0)))
188 method (get (intern-soft function)
189 'common-lisp-indent-function)))
190 ((and (null method))
191 ;; backwards compatibility
192 (setq method (get tem 'lisp-indent-function)))))
193 (let ((n 0))
194 ;; How far into the containing form is the current form?
195 (if (< (point) indent-point)
196 (while (condition-case ()
197 (progn
198 (forward-sexp 1)
199 (if (>= (point) indent-point)
200 nil
201 (parse-partial-sexp (point)
202 indent-point 1 t)
203 (setq n (1+ n))
204 t))
205 (error nil))))
206 (setq path (cons n path)))
207
208 ;; backwards compatibility.
209 (cond ((null function))
210 ((null method)
211 (when (null (cdr path))
212 ;; (package prefix was stripped off above)
213 (setq method (cond ((string-match "\\`def"
214 function)
215 lisp-indent-defun-method)
216 ((string-match "\\`\\(with\\|do\\)-"
217 function)
218 '(&lambda &body))))))
219 ;; backwards compatibility. Bletch.
220 ((eq method 'defun)
221 (setq method lisp-indent-defun-method)))
222
223 (cond ((and (or (eq (char-after (1- containing-sexp)) ?\')
224 (and (not lisp-backquote-indentation)
225 (eq (char-after (1- containing-sexp)) ?\`)))
226 (not (eq (char-after (- containing-sexp 2)) ?\#)))
227 ;; No indentation for "'(...)" elements
228 (setq calculated (1+ sexp-column)))
229 ((or (eq (char-after (1- containing-sexp)) ?\,)
230 (and (eq (char-after (1- containing-sexp)) ?\@)
231 (eq (char-after (- containing-sexp 2)) ?\,)))
232 ;; ",(...)" or ",@(...)"
233 (setq calculated normal-indent))
234 ((eq (char-after (1- containing-sexp)) ?\#)
235 ;; "#(...)"
236 (setq calculated (1+ sexp-column)))
237 ((null method))
238 ((integerp method)
239 ;; convenient top-level hack.
240 ;; (also compatible with lisp-indent-function)
241 ;; The number specifies how many `distinguished'
242 ;; forms there are before the body starts
243 ;; Equivalent to (4 4 ... &body)
244 (setq calculated (cond ((cdr path)
245 normal-indent)
246 ((<= (car path) method)
247 ;; `distinguished' form
248 (list (+ sexp-column 4)
249 containing-form-start))
250 ((= (car path) (1+ method))
251 ;; first body form.
252 (+ sexp-column lisp-body-indent))
253 (t
254 ;; other body form
255 normal-indent))))
256 ((symbolp method)
257 (let ((lisp-indent-error-function function))
258 (setq calculated (funcall method
259 path state indent-point
260 sexp-column normal-indent))))
261 (t
262 (let ((lisp-indent-error-function function))
263 (setq calculated (lisp-indent-259
264 method path state indent-point
265 sexp-column normal-indent))))))
266 (goto-char containing-sexp)
267 (setq last-point containing-sexp)
268 (unless calculated
269 (condition-case ()
270 (progn (backward-up-list 1)
271 (setq depth (1+ depth)))
272 (error (setq depth lisp-indent-maximum-backtracking))))))
273 calculated)))
274
275
276 (defun lisp-indent-report-bad-format (m)
277 (error "%s has a badly-formed %s property: %s"
278 ;; Love those free variable references!!
279 lisp-indent-error-function 'common-lisp-indent-function m))
280
281 ;; Blame the crufty control structure on dynamic scoping
282 ;; -- not on me!
283 (defun lisp-indent-259 (method path state indent-point
284 sexp-column normal-indent)
285 (catch 'exit
286 (let ((p path)
287 (containing-form-start (elt state 1))
288 n tem tail)
289 ;; Isn't tail-recursion wonderful?
290 (while p
291 ;; This while loop is for destructuring.
292 ;; p is set to (cdr p) each iteration.
293 (if (not (consp method)) (lisp-indent-report-bad-format method))
294 (setq n (1- (car p))
295 p (cdr p)
296 tail nil)
297 (while n
298 ;; This while loop is for advancing along a method
299 ;; until the relevant (possibly &rest/&body) pattern
300 ;; is reached.
301 ;; n is set to (1- n) and method to (cdr method)
302 ;; each iteration.
303 (setq tem (car method))
304
305 (or (eq tem 'nil) ;default indentation
306 (eq tem '&lambda) ;lambda list
307 (and (eq tem '&body) (null (cdr method)))
308 (and (eq tem '&rest)
309 (consp (cdr method))
310 (null (cddr method)))
311 (integerp tem) ;explicit indentation specified
312 (and (consp tem) ;destructuring
313 (eq (car tem) '&whole)
314 (or (symbolp (cadr tem))
315 (integerp (cadr tem))))
316 (and (symbolp tem) ;a function to call to do the work.
317 (null (cdr method)))
318 (lisp-indent-report-bad-format method))
319
320 (cond ((and tail (not (consp tem)))
321 ;; indent tail of &rest in same way as first elt of rest
322 (throw 'exit normal-indent))
323 ((eq tem '&body)
324 ;; &body means (&rest <lisp-body-indent>)
325 (throw 'exit
326 (if (and (= n 0) ;first body form
327 (null p)) ;not in subforms
328 (+ sexp-column
329 lisp-body-indent)
330 normal-indent)))
331 ((eq tem '&rest)
332 ;; this pattern holds for all remaining forms
333 (setq tail (> n 0)
334 n 0
335 method (cdr method)))
336 ((> n 0)
337 ;; try next element of pattern
338 (setq n (1- n)
339 method (cdr method))
340 (if (< n 0)
341 ;; Too few elements in pattern.
342 (throw 'exit normal-indent)))
343 ((eq tem 'nil)
344 (throw 'exit (list normal-indent containing-form-start)))
345 ((eq tem '&lambda)
346 (throw 'exit
347 (cond ((null p)
348 (list (+ sexp-column 4) containing-form-start))
349 ((null (cdr p))
350 (+ sexp-column 1))
351 (t normal-indent))))
352 ((integerp tem)
353 (throw 'exit
354 (if (null p) ;not in subforms
355 (list (+ sexp-column tem) containing-form-start)
356 normal-indent)))
357 ((symbolp tem) ;a function to call
358 (throw 'exit
359 (funcall tem path state indent-point
360 sexp-column normal-indent)))
361 (t
362 ;; must be a destructing frob
363 (if (not (null p))
364 ;; descend
365 (setq method (cddr tem)
366 n nil)
367 (setq tem (cadr tem))
368 (throw 'exit
369 (cond (tail
370 normal-indent)
371 ((eq tem 'nil)
372 (list normal-indent
373 containing-form-start))
374 ((integerp tem)
375 (list (+ sexp-column tem)
376 containing-form-start))
377 (t
378 (funcall tem path state indent-point
379 sexp-column normal-indent))))))))))))
380 \f
381 (defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent)
382 (if (not (null (cdr path)))
383 normal-indent
384 (save-excursion
385 (goto-char indent-point)
386 (beginning-of-line)
387 (skip-chars-forward " \t")
388 (list (cond ((looking-at "\\sw\\|\\s_")
389 ;; a tagbody tag
390 (+ sexp-column lisp-tag-indentation))
391 ((integerp lisp-tag-body-indentation)
392 (+ sexp-column lisp-tag-body-indentation))
393 ((eq lisp-tag-body-indentation 't)
394 (condition-case ()
395 (progn (backward-sexp 1) (current-column))
396 (error (1+ sexp-column))))
397 (t (+ sexp-column lisp-body-indent)))
398 ; (cond ((integerp lisp-tag-body-indentation)
399 ; (+ sexp-column lisp-tag-body-indentation))
400 ; ((eq lisp-tag-body-indentation 't)
401 ; normal-indent)
402 ; (t
403 ; (+ sexp-column lisp-body-indent)))
404 (elt state 1)
405 ))))
406
407 (defun lisp-indent-do (path state indent-point sexp-column normal-indent)
408 (if (>= (car path) 3)
409 (let ((lisp-tag-body-indentation lisp-body-indent))
410 (funcall (function lisp-indent-tagbody)
411 path state indent-point sexp-column normal-indent))
412 (funcall (function lisp-indent-259)
413 '((&whole nil &rest
414 ;; the following causes weird indentation
415 ;;(&whole 1 1 2 nil)
416 )
417 (&whole nil &rest 1))
418 path state indent-point sexp-column normal-indent)))
419
420
421 (defun lisp-indent-defmethod (path state indent-point sexp-column
422 normal-indent)
423 "Indentation function defmethod."
424 (lisp-indent-259 (if (and (>= (car path) 3)
425 (null (cdr path))
426 (save-excursion (goto-char (elt state 1))
427 (forward-char 1)
428 (forward-sexp 3)
429 (backward-sexp)
430 (looking-at ":")))
431 '(4 4 (&whole 4 &rest 4) &body)
432 (get 'defun 'common-lisp-indent-function))
433 path state indent-point sexp-column normal-indent))
434
435
436 (defun lisp-indent-function-lambda-hack (path state indent-point
437 sexp-column normal-indent)
438 ;; indent (function (lambda () <newline> <body-forms>)) kludgily.
439 (if (or (cdr path) ; wtf?
440 (> (car path) 3))
441 ;; line up under previous body form
442 normal-indent
443 ;; line up under function rather than under lambda in order to
444 ;; conserve horizontal space. (Which is what #' is for.)
445 (condition-case ()
446 (save-excursion
447 (backward-up-list 2)
448 (forward-char 1)
449 (if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
450 (+ lisp-body-indent -1 (current-column))
451 (+ sexp-column lisp-body-indent)))
452 (error (+ sexp-column lisp-body-indent)))))
453
454
455 \f
456 (let ((l '((block 1)
457 (case (4 &rest (&whole 2 &rest 1)))
458 (ccase . case) (ecase . case)
459 (typecase . case) (etypecase . case) (ctypecase . case)
460 (catch 1)
461 (cond (&rest (&whole 2 &rest 1)))
462 (defvar (4 2 2))
463 (defclass (6 4 (&whole 2 &rest 1) (&whole 2 &rest 1)))
464 (defconstant . defvar)
465 (defcustom (4 2 2 2))
466 (defparameter . defvar)
467 (defconst . defcustom)
468 (define-condition . defclass)
469 (define-modify-macro (4 &lambda &body))
470 (defsetf (4 &lambda 4 &body))
471 (defun (4 &lambda &body))
472 (define-setf-method . defun)
473 (define-setf-expander . defun)
474 (defmacro . defun) (defsubst . defun) (deftype . defun)
475 (defmethod lisp-indent-defmethod)
476 (defpackage (4 2))
477 (defstruct ((&whole 4 &rest (&whole 2 &rest 1))
478 &rest (&whole 2 &rest 1)))
479 (destructuring-bind
480 ((&whole 6 &rest 1) 4 &body))
481 (do lisp-indent-do)
482 (do* . do)
483 (dolist ((&whole 4 2 1) &body))
484 (dotimes . dolist)
485 (eval-when 1)
486 (flet ((&whole 4 &rest (&whole 1 &lambda &body)) &body))
487 (labels . flet)
488 (macrolet . flet)
489 (generic-flet . flet) (generic-labels . flet)
490 (handler-case (4 &rest (&whole 2 &lambda &body)))
491 (restart-case . handler-case)
492 ;; `else-body' style
493 (if (nil nil &body))
494 ;; single-else style (then and else equally indented)
495 (if (&rest nil))
496 (lambda (&lambda &rest lisp-indent-function-lambda-hack))
497 (let ((&whole 4 &rest (&whole 1 1 2)) &body))
498 (let* . let)
499 (compiler-let . let) ;barf
500 (handler-bind . let) (restart-bind . let)
501 (locally 1)
502 ;(loop lisp-indent-loop)
503 (:method (&lambda &body)) ; in `defgeneric'
504 (multiple-value-bind ((&whole 6 &rest 1) 4 &body))
505 (multiple-value-call (4 &body))
506 (multiple-value-prog1 1)
507 (multiple-value-setq (4 2))
508 (multiple-value-setf . multiple-value-setq)
509 (pprint-logical-block (4 2))
510 (print-unreadable-object ((&whole 4 1 &rest 1) &body))
511 ;; Combines the worst features of BLOCK, LET and TAGBODY
512 (prog (&lambda &rest lisp-indent-tagbody))
513 (prog* . prog)
514 (prog1 1)
515 (prog2 2)
516 (progn 0)
517 (progv (4 4 &body))
518 (return 0)
519 (return-from (nil &body))
520 (symbol-macrolet . multiple-value-bind)
521 (tagbody lisp-indent-tagbody)
522 (throw 1)
523 (unless 1)
524 (unwind-protect (5 &body))
525 (when 1)
526 (with-accessors . multiple-value-bind)
527 (with-condition-restarts . multiple-value-bind)
528 (with-output-to-string (4 2))
529 (with-slots . multiple-value-bind)
530 (with-standard-io-syntax (2)))))
531 (dolist (el l)
532 (put (car el) 'common-lisp-indent-function
533 (if (symbolp (cdr el))
534 (get (cdr el) 'common-lisp-indent-function)
535 (car (cdr el))))))
536
537 \f
538 ;(defun foo (x)
539 ; (tagbody
540 ; foo
541 ; (bar)
542 ; baz
543 ; (when (losing)
544 ; (with-big-loser
545 ; (yow)
546 ; ((lambda ()
547 ; foo)
548 ; big)))
549 ; (flet ((foo (bar baz zap)
550 ; (zip))
551 ; (zot ()
552 ; quux))
553 ; (do ()
554 ; ((lose)
555 ; (foo 1))
556 ; (quux)
557 ; foo
558 ; (lose))
559 ; (cond ((x)
560 ; (win 1 2
561 ; (foo)))
562 ; (t
563 ; (lose
564 ; 3))))))
565
566
567 ;(put 'while 'common-lisp-indent-function 1)
568 ;(put 'defwrapper'common-lisp-indent-function ...)
569 ;(put 'def 'common-lisp-indent-function ...)
570 ;(put 'defflavor 'common-lisp-indent-function ...)
571 ;(put 'defsubst 'common-lisp-indent-function ...)
572
573 ;(put 'with-restart 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
574 ;(put 'restart-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (* 1)))))
575 ;(put 'define-condition 'common-lisp-indent-function '((1 6) (2 6 ((&whole 1))) (3 4 ((&whole 1))) (4 &body)))
576 ;(put 'with-condition-handler 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
577 ;(put 'condition-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (1 3) (2 &body)))))
578 ;(put 'defclass 'common-lisp-indent-function '((&whole 2 &rest (&whole 2 &rest 1) &rest (&whole 2 &rest 1)))
579 ;(put 'defgeneric 'common-lisp-indent-function 'defun)
580
581 ;;; cl-indent.el ends here