(insert-directory): When WILDCARD is nil, expand ~ if necessary.
[bpt/emacs.git] / lisp / emacs-lisp / cl-indent.el
CommitLineData
c0274f38
ER
1;;; cl-indent.el --- enhanced lisp-indent mode
2
9750e079 3;; Copyright (C) 1987 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
82;;;###autoload
83(defun common-lisp-indent-function (indent-point state)
84 (let ((normal-indent (current-column)))
85 ;; Walk up list levels until we see something
86 ;; which does special things with subforms.
87 (let ((depth 0)
88 ;; Path describes the position of point in terms of
eb8c3be9 89 ;; list-structure with respect to containing lists.
745bc783
JB
90 ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)'
91 (path ())
92 ;; set non-nil when somebody works out the indentation to use
93 calculated
94 (last-point indent-point)
95 ;; the position of the open-paren of the innermost containing list
96 (containing-form-start (elt state 1))
97 ;; the column of the above
98 sexp-column)
99 ;; Move to start of innermost containing list
100 (goto-char containing-form-start)
101 (setq sexp-column (current-column))
102 ;; Look over successively less-deep containing forms
103 (while (and (not calculated)
104 (< depth lisp-indent-maximum-backtracking))
105 (let ((containing-sexp (point)))
106 (forward-char 1)
107 (parse-partial-sexp (point) indent-point 1 t)
108 ;; Move to the car of the relevant containing form
109 (let (tem function method)
110 (if (not (looking-at "\\sw\\|\\s_"))
111 ;; This form doesn't seem to start with a symbol
112 (setq function nil method nil)
113 (setq tem (point))
114 (forward-sexp 1)
115 (setq function (downcase (buffer-substring tem (point))))
116 (goto-char tem)
117 (setq tem (intern-soft function)
118 method (get tem 'common-lisp-indent-function))
119 (cond ((and (null method)
120 (string-match ":[^:]+" function))
121 ;; The pleblisp package feature
122 (setq function (substring function
123 (1+ (match-beginning 0)))
124 method (get (intern-soft function)
125 'common-lisp-indent-function)))
126 ((and (null method))
127 ;; backwards compatibility
128 (setq method (get tem 'lisp-indent-function)))))
129 (let ((n 0))
130 ;; How far into the containing form is the current form?
131 (if (< (point) indent-point)
132 (while (condition-case ()
133 (progn
134 (forward-sexp 1)
135 (if (>= (point) indent-point)
136 nil
137 (parse-partial-sexp (point)
138 indent-point 1 t)
139 (setq n (1+ n))
140 t))
141 (error nil))))
142 (setq path (cons n path)))
143
144 ;; backwards compatibility.
145 (cond ((null function))
146 ((null method)
147 (if (null (cdr path))
148 ;; (package prefix was stripped off above)
149 (setq method (cond ((string-match "\\`def"
150 function)
151 '(4 (&whole 4 &rest 1) &body))
152 ((string-match "\\`\\(with\\|do\\)-"
153 function)
154 '(4 &body))))))
155 ;; backwards compatibility. Bletch.
156 ((eq method 'defun)
157 (setq method '(4 (&whole 4 &rest 1) &body))))
158
159 (cond ((and (memq (char-after (1- containing-sexp)) '(?\' ?\`))
160 (not (eql (char-after (- containing-sexp 2)) ?\#)))
161 ;; No indentation for "'(...)" elements
162 (setq calculated (1+ sexp-column)))
163 ((or (eql (char-after (1- containing-sexp)) ?\,)
164 (and (eql (char-after (1- containing-sexp)) ?\@)
165 (eql (char-after (- containing-sexp 2)) ?\,)))
166 ;; ",(...)" or ",@(...)"
167 (setq calculated normal-indent))
168 ((eql (char-after (1- containing-sexp)) ?\#)
169 ;; "#(...)"
170 (setq calculated (1+ sexp-column)))
171 ((null method))
172 ((integerp method)
173 ;; convenient top-level hack.
174 ;; (also compatible with lisp-indent-function)
175 ;; The number specifies how many `distinguished'
176 ;; forms there are before the body starts
177 ;; Equivalent to (4 4 ... &body)
178 (setq calculated (cond ((cdr path)
179 normal-indent)
180 ((<= (car path) method)
181 ;; `distinguished' form
182 (list (+ sexp-column 4)
183 containing-form-start))
184 ((= (car path) (1+ method))
185 ;; first body form.
186 (+ sexp-column lisp-body-indent))
187 (t
188 ;; other body form
189 normal-indent))))
190 ((symbolp method)
191 (setq calculated (funcall method
192 path state indent-point
193 sexp-column normal-indent)))
194 (t
195 (setq calculated (lisp-indent-259
196 method path state indent-point
197 sexp-column normal-indent)))))
198 (goto-char containing-sexp)
199 (setq last-point containing-sexp)
200 (if (not calculated)
201 (condition-case ()
202 (progn (backward-up-list 1)
203 (setq depth (1+ depth)))
204 (error (setq depth lisp-indent-maximum-backtracking))))))
205 calculated)))
206
207
208(defun lisp-indent-report-bad-format (m)
209 (error "%s has a badly-formed %s property: %s"
210 ;; Love those free variable references!!
211 function 'common-lisp-indent-function m))
212
213;; Blame the crufty control structure on dynamic scoping
214;; -- not on me!
215(defun lisp-indent-259 (method path state indent-point
216 sexp-column normal-indent)
217 (catch 'exit
218 (let ((p path)
219 (containing-form-start (elt state 1))
220 n tem tail)
221 ;; Isn't tail-recursion wonderful?
222 (while p
223 ;; This while loop is for destructuring.
224 ;; p is set to (cdr p) each iteration.
225 (if (not (consp method)) (lisp-indent-report-bad-format method))
226 (setq n (1- (car p))
227 p (cdr p)
228 tail nil)
229 (while n
230 ;; This while loop is for advancing along a method
231 ;; until the relevant (possibly &rest/&body) pattern
232 ;; is reached.
233 ;; n is set to (1- n) and method to (cdr method)
234 ;; each iteration.
235 (setq tem (car method))
236
237 (or (eq tem 'nil) ;default indentation
238; (eq tem '&lambda) ;abbrev for (&whole 4 (&rest 1))
239 (and (eq tem '&body) (null (cdr method)))
240 (and (eq tem '&rest)
241 (consp (cdr method)) (null (cdr (cdr method))))
242 (integerp tem) ;explicit indentation specified
243 (and (consp tem) ;destructuring
244 (eq (car tem) '&whole)
245 (or (symbolp (car (cdr tem)))
246 (integerp (car (cdr tem)))))
247 (and (symbolp tem) ;a function to call to do the work.
248 (null (cdr method)))
249 (lisp-indent-report-bad-format method))
250
251 (cond ((and tail (not (consp tem)))
252 ;; indent tail of &rest in same way as first elt of rest
253 (throw 'exit normal-indent))
254 ((eq tem '&body)
255 ;; &body means (&rest <lisp-body-indent>)
256 (throw 'exit
257 (if (and (= n 0) ;first body form
258 (null p)) ;not in subforms
259 (+ sexp-column
260 lisp-body-indent)
261 normal-indent)))
262 ((eq tem '&rest)
263 ;; this pattern holds for all remaining forms
264 (setq tail (> n 0)
265 n 0
266 method (cdr method)))
267 ((> n 0)
268 ;; try next element of pattern
269 (setq n (1- n)
270 method (cdr method))
271 (if (< n 0)
272 ;; Too few elements in pattern.
273 (throw 'exit normal-indent)))
274 ((eq tem 'nil)
275 (throw 'exit (list normal-indent containing-form-start)))
276; ((eq tem '&lambda)
277; ;; abbrev for (&whole 4 &rest 1)
278; (throw 'exit
279; (cond ((null p)
280; (list (+ sexp-column 4) containing-form-start))
281; ((null (cdr p))
282; (+ sexp-column 1))
283; (t normal-indent))))
284 ((integerp tem)
285 (throw 'exit
286 (if (null p) ;not in subforms
287 (list (+ sexp-column tem) containing-form-start)
288 normal-indent)))
289 ((symbolp tem) ;a function to call
290 (throw 'exit
291 (funcall tem path state indent-point
292 sexp-column normal-indent)))
293 (t
294 ;; must be a destructing frob
295 (if (not (null p))
296 ;; descend
297 (setq method (cdr (cdr tem))
298 n nil)
299 (setq tem (car (cdr tem)))
300 (throw 'exit
301 (cond (tail
302 normal-indent)
303 ((eq tem 'nil)
304 (list normal-indent
305 containing-form-start))
306 ((integerp tem)
307 (list (+ sexp-column tem)
308 containing-form-start))
309 (t
310 (funcall tem path state indent-point
311 sexp-column normal-indent))))))))))))
312\f
313(defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent)
314 (if (not (null (cdr path)))
315 normal-indent
316 (save-excursion
317 (goto-char indent-point)
318 (beginning-of-line)
319 (skip-chars-forward " \t")
320 (list (cond ((looking-at "\\sw\\|\\s_")
321 ;; a tagbody tag
322 (+ sexp-column lisp-tag-indentation))
323 ((integerp lisp-tag-body-indentation)
324 (+ sexp-column lisp-tag-body-indentation))
325 ((eq lisp-tag-body-indentation 't)
326 (condition-case ()
327 (progn (backward-sexp 1) (current-column))
328 (error (1+ sexp-column))))
329 (t (+ sexp-column lisp-body-indent)))
330; (cond ((integerp lisp-tag-body-indentation)
331; (+ sexp-column lisp-tag-body-indentation))
332; ((eq lisp-tag-body-indentation 't)
333; normal-indent)
334; (t
335; (+ sexp-column lisp-body-indent)))
336 (elt state 1)
337 ))))
338
339(defun lisp-indent-do (path state indent-point sexp-column normal-indent)
340 (if (>= (car path) 3)
341 (let ((lisp-tag-body-indentation lisp-body-indent))
342 (funcall (function lisp-indent-tagbody)
343 path state indent-point sexp-column normal-indent))
344 (funcall (function lisp-indent-259)
345 '((&whole nil &rest
eb8c3be9 346 ;; the following causes weird indentation
745bc783
JB
347 ;;(&whole 1 1 2 nil)
348 )
349 (&whole nil &rest 1))
350 path state indent-point sexp-column normal-indent)))
351
352(defun lisp-indent-function-lambda-hack (path state indent-point
353 sexp-column normal-indent)
354 ;; indent (function (lambda () <newline> <body-forms>)) kludgily.
355 (if (or (cdr path) ; wtf?
356 (> (car path) 3))
357 ;; line up under previous body form
358 normal-indent
359 ;; line up under function rather than under lambda in order to
360 ;; conserve horizontal space. (Which is what #' is for.)
361 (condition-case ()
362 (save-excursion
363 (backward-up-list 2)
364 (forward-char 1)
365 (if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
366 (+ lisp-body-indent -1 (current-column))
367 (+ sexp-column lisp-body-indent)))
368 (error (+ sexp-column lisp-body-indent)))))
369
370\f
371(let ((l '((block 1)
372 (catch 1)
a63f3864
KH
373 (case (4 &rest (&whole 2 &rest 1)))
374 (ccase . case) (ecase . case)
375 (typecase . case) (etypecase . case) (ctypecase . case)
376 (catch 1)
377 (cond (&rest (&whole 2 &rest 1)))
378 (block 1)
379 (defvar (4 2 2))
7bd1de91
RS
380 (defconstant . defvar)
381 (defparameter . defvar)
a63f3864 382 (define-modify-macro
745bc783 383 (4 &body))
a63f3864
KH
384 (define-setf-method
385 (4 (&whole 4 &rest 1) &body))
386 (defsetf (4 (&whole 4 &rest 1) 4 &body))
387 (defun (4 (&whole 4 &rest 1) &body))
388 (defmacro . defun) (deftype . defun)
8acc018f 389 (defpackage (4 2))
a63f3864
KH
390 (defstruct ((&whole 4 &rest (&whole 2 &rest 1))
391 &rest (&whole 2 &rest 1)))
392 (destructuring-bind
393 ((&whole 6 &rest 1) 4 &body))
394 (do lisp-indent-do)
395 (do* . do)
396 (dolist ((&whole 4 2 1) &body))
397 (dotimes . dolist)
398 (eval-when 1)
399 (flet ((&whole 4 &rest (&whole 1 (&whole 4 &rest 1) &body))
400 &body))
401 (labels . flet)
402 (macrolet . flet)
403 ;; `else-body' style
404 (if (nil nil &body))
405 ;; single-else style (then and else equally indented)
406 (if (&rest nil))
7bd1de91 407 ;; (lambda ((&whole 4 &rest 1) &body))
a63f3864
KH
408 (lambda ((&whole 4 &rest 1)
409 &rest lisp-indent-function-lambda-hack))
410 (let ((&whole 4 &rest (&whole 1 1 2)) &body))
411 (let* . let)
412 (compiler-let . let) ;barf
413 (locally 1)
414 ;(loop ...)
7bd1de91
RS
415 (multiple-value-bind
416 ((&whole 6 &rest 1) 4 &body))
417 (multiple-value-call
418 (4 &body))
a63f3864 419 (multiple-value-prog1 1)
7bd1de91
RS
420 (multiple-value-setq
421 (4 2))
a63f3864
KH
422 (multiple-value-setf . multiple-value-setq)
423 ;; Combines the worst features of BLOCK, LET and TAGBODY
424 (prog ((&whole 4 &rest 1) &rest lisp-indent-tagbody))
425 (prog* . prog)
426 (prog1 1)
427 (prog2 2)
428 (progn 0)
429 (progv (4 4 &body))
430 (return 0)
431 (return-from (nil &body))
432 (tagbody lisp-indent-tagbody)
433 (throw 1)
434 (unless 1)
435 (unwind-protect (5 &body))
436 (when 1))))
745bc783
JB
437 (while l
438 (put (car (car l)) 'common-lisp-indent-function
a63f3864
KH
439 (if (symbolp (cdr (car l)))
440 (get (cdr (car l)) 'common-lisp-indent-function)
441 (car (cdr (car l)))))
745bc783
JB
442 (setq l (cdr l))))
443
444\f
445;(defun foo (x)
446; (tagbody
447; foo
448; (bar)
449; baz
450; (when (losing)
451; (with-big-loser
452; (yow)
453; ((lambda ()
454; foo)
455; big)))
456; (flet ((foo (bar baz zap)
457; (zip))
458; (zot ()
459; quux))
460; (do ()
461; ((lose)
462; (foo 1))
463; (quux)
464; foo
465; (lose))
466; (cond ((x)
467; (win 1 2
468; (foo)))
469; (t
470; (lose
471; 3))))))
472
473
474;(put 'while 'common-lisp-indent-function 1)
475;(put 'defwrapper'common-lisp-indent-function ...)
476;(put 'def 'common-lisp-indent-function ...)
477;(put 'defflavor 'common-lisp-indent-function ...)
478;(put 'defsubst 'common-lisp-indent-function ...)
479
480;(put 'with-restart 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
481;(put 'restart-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (* 1)))))
482;(put 'define-condition 'common-lisp-indent-function '((1 6) (2 6 ((* 1))) (3 4 ((* 1))) (4 &body)))
483;(put 'with-condition-handler 'common-lisp-indent-function '((1 4 ((* 1))) (2 &body)))
484;(put 'condition-case 'common-lisp-indent-function '((1 4) (* 2 ((0 1) (1 3) (2 &body)))))
485
c0274f38 486;;; cl-indent.el ends here