|
|
1.1 root 1: ;; Lisp mode, and its idiosyncratic commands.
2: ;; Copyright (C) 1987 Free Software Foundation, Inc.
3: ;; Written by Richard Mlynarik July 1987
4:
5: ;; This file is part of GNU Emacs.
6:
7: ;; GNU Emacs is distributed in the hope that it will be useful,
8: ;; but WITHOUT ANY WARRANTY. No author or distributor
9: ;; accepts responsibility to anyone for the consequences of using it
10: ;; or for whether it serves any particular purpose or works at all,
11: ;; unless he says so in writing. Refer to the GNU Emacs General Public
12: ;; License for full details.
13:
14: ;; Everyone is granted permission to copy, modify and redistribute
15: ;; GNU Emacs, but only under the conditions described in the
16: ;; GNU Emacs General Public License. A copy of this license is
17: ;; supposed to have been given to you along with GNU Emacs so you
18: ;; can know your rights and responsibilities. It should be in a
19: ;; file named COPYING. Among other things, the copyright notice
20: ;; and this notice must be preserved on all copies.
21:
22: ;;>> TODO
23: ;; :foo
24: ;; bar
25: ;; :baz
26: ;; zap
27: ;; &key (like &body)??
28:
29: ;; &rest 1 in lambda-lists doesn't work
30: ;; -- really want (foo bar
31: ;; baz)
32: ;; not (foo bar
33: ;; baz)
34: ;; Need something better than &rest for such cases
35:
36:
37: ;;; Hairy lisp indentation.
38:
39: (defvar lisp-indent-maximum-backtracking 3
40: "*Maximum depth to backtrack out from a sublist for structured indentation.
41: If this variable is 0, no backtracking will occur and forms such as flet
42: may not be correctly indented.")
43:
44: (defvar lisp-tag-indentation 1
45: "*Indentation of tags relative to containing list.
46: This variable is used by the function lisp-indent-tagbody.")
47:
48: (defvar lisp-tag-body-indentation 3
49: "*Indentation of non-tagged lines relative to containing list.
50: This variable is used by the function lisp-indent-tagbody to indent normal
51: lines (lines without tags).
52: The indentation is relative to the indentation of the parenthesis enclosing
53: he special form. If the value is t, the body of tags will be indented
54: as a block at the same indentation as the first s-expression following
55: the tag. In this case, any forms before the first tag are indented
56: by lisp-body-indent.")
57:
58:
59: (defun common-lisp-indent-hook (indent-point state)
60: (let ((normal-indent (current-column)))
61: ;; Walk up list levels until we see something
62: ;; which does special things with subforms.
63: (let ((depth 0)
64: ;; Path describes the position of point in terms of
65: ;; list-structure with respect to contining lists.
66: ;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)'
67: (path ())
68: ;; set non-nil when somebody works out the indentation to use
69: calculated
70: (last-point indent-point)
71: ;; the position of the open-paren of the innermost containing list
72: (containing-form-start (elt state 1))
73: ;; the column of the above
74: sexp-column)
75: ;; Move to start of innermost containing list
76: (goto-char containing-form-start)
77: (setq sexp-column (current-column))
78: ;; Look over successively less-deep containing forms
79: (while (and (not calculated)
80: (< depth lisp-indent-maximum-backtracking))
81: (let ((containing-sexp (point)))
82: (forward-char 1)
83: (parse-partial-sexp (point) indent-point 1 t)
84: ;; Move to the car of the relevant containing form
85: (let (tem function method)
86: (if (not (looking-at "\\sw\\|\\s_"))
87: ;; This form doesn't seem to start with a symbol
88: (setq function nil method nil)
89: (setq tem (point))
90: (forward-sexp 1)
91: (setq function (downcase (buffer-substring tem (point))))
92: (goto-char tem)
93: (setq tem (intern-soft function)
94: method (get tem 'common-lisp-indent-hook))
95: (cond ((and (null method)
96: (string-match ":[^:]+" function))
97: ;; The pleblisp package feature
98: (setq function (substring function
99: (1+ (match-beginning 0)))
100: method (get (intern-soft function)
101: 'common-lisp-indent-hook)))
102: ((and (null method))
103: ;; backwards compatibility
104: (setq method (get tem 'lisp-indent-hook)))))
105: (let ((n 0))
106: ;; How far into the containing form is the current form?
107: (if (< (point) indent-point)
108: (while (condition-case ()
109: (progn
110: (forward-sexp 1)
111: (if (>= (point) indent-point)
112: nil
113: (parse-partial-sexp (point)
114: indent-point 1 t)
115: (setq n (1+ n))
116: t))
117: (error nil))))
118: (setq path (cons n path)))
119:
120: ;; backwards compatibility.
121: (cond ((null function))
122: ((null method)
123: (if (null (cdr path))
124: ;; (package prefix was stripped off above)
125: (setq method (cond ((string-match "\\`def"
126: function)
127: '(4 (&whole 4 &rest 1) &body))
128: ((string-match "\\`\\(with\\|do\\)-"
129: function)
130: '(4 &body))))))
131: ;; backwards compatibility. Bletch.
132: ((eq method 'defun)
133: (setq method '(4 (&whole 4 &rest 1) &body))))
134:
135: (cond ((and (memq (char-after (1- containing-sexp)) '(?\' ?\`))
136: (not (eql (char-after (- containing-sexp 2)) ?\#)))
137: ;; No indentation for "'(...)" elements
138: (setq calculated (1+ sexp-column)))
139: ((eql (char-after (1- containing-sexp)) ?\#)
140: ;; "#(...)"
141: (setq calculated (1+ sexp-column)))
142: ((null method))
143: ((integerp method)
144: ;; convenient top-level hack.
145: ;; (also compatible with lisp-indent-hook)
146: ;; The number specifies how many `distinguished'
147: ;; forms there are before the body starts
148: ;; Equivalent to (4 4 ... &body)
149: (setq calculated (cond ((cdr path)
150: normal-indent)
151: ((<= (car path) method)
152: ;; `distinguished' form
153: (list (+ sexp-column 4)
154: containing-form-start))
155: ((= (car path) (1+ method))
156: ;; first body form.
157: (+ sexp-column lisp-body-indent))
158: (t
159: ;; other body form
160: normal-indent))))
161: ((symbolp method)
162: (setq calculated (funcall method
163: path state indent-point
164: sexp-column normal-indent)))
165: (t
166: (setq calculated (lisp-indent-259
167: method path state indent-point
168: sexp-column normal-indent)))))
169: (goto-char containing-sexp)
170: (setq last-point containing-sexp)
171: (if (not calculated)
172: (condition-case ()
173: (progn (backward-up-list 1)
174: (setq depth (1+ depth)))
175: (error (setq depth lisp-indent-maximum-backtracking))))))
176: calculated)))
177:
178:
179: (defun lisp-indent-report-bad-format (m)
180: (error "%s has a badly-formed %s property: %s"
181: ;; Love them free variable references!!
182: function 'common-lisp-indent-hook m))
183:
184: ;; Blame the crufty control structure on dynamic scoping
185: ;; -- not on me!
186: (defun lisp-indent-259 (method path state indent-point
187: sexp-column normal-indent)
188: (catch 'exit
189: (let ((p path)
190: (containing-form-start (elt state 1))
191: n tem tail)
192: ;; Isn't tail-recursion wonderful?
193: (while p
194: ;; This while loop is for destructuring.
195: ;; p is set to (cdr p) each iteration.
196: (if (not (consp method)) (lisp-indent-report-bad-format method))
197: (setq n (1- (car p))
198: p (cdr p)
199: tail nil)
200: (while n
201: ;; This while loop is for advancing along a method
202: ;; until the relevant (possibly &rest/&body) pattern
203: ;; is reached.
204: ;; n is set to (1- n) and method to (cdr method)
205: ;; each iteration.
206: ; (message "trying %s for %s %s" method p function) (sit-for 1)
207: (setq tem (car method))
208:
209: (or (eq tem 'nil) ;default indentation
210: ; (eq tem '&lambda) ;abbrev for (&whole 4 (&rest 1))
211: (and (eq tem '&body) (null (cdr method)))
212: (and (eq tem '&rest)
213: (consp (cdr method)) (null (cdr (cdr method))))
214: (integerp tem) ;explicit indentation specified
215: (and (consp tem) ;destructuring
216: (eq (car tem) '&whole)
217: (or (symbolp (car (cdr tem)))
218: (integerp (car (cdr tem)))))
219: (and (symbolp tem) ;a function to call to do the work.
220: (null (cdr method)))
221: (lisp-indent-report-bad-format method))
222:
223: (cond ((and tail (not (consp tem)))
224: ;; indent tail of &rest in same way as first elt of rest
225: (throw 'exit normal-indent))
226: ((eq tem '&body)
227: ;; &body means (&rest <lisp-body-indent>)
228: (throw 'exit
229: (if (and (= n 0) ;first body form
230: (null p)) ;not in subforms
231: (+ sexp-column
232: lisp-body-indent)
233: normal-indent)))
234: ((eq tem '&rest)
235: ;; this pattern holds for all remaining forms
236: (setq tail (> n 0)
237: n 0
238: method (cdr method)))
239: ((> n 0)
240: ;; try next element of pattern
241: (setq n (1- n)
242: method (cdr method))
243: (if (< n 0)
244: ;; Too few elements in pattern.
245: (throw 'exit normal-indent)))
246: ((eq tem 'nil)
247: (throw 'exit (list normal-indent containing-form-start)))
248: ; ((eq tem '&lambda)
249: ; ;; abbrev for (&whole 4 &rest 1)
250: ; (throw 'exit
251: ; (cond ((null p)
252: ; (list (+ sexp-column 4) containing-form-start))
253: ; ((null (cdr p))
254: ; (+ sexp-column 1))
255: ; (t normal-indent))))
256: ((integerp tem)
257: (throw 'exit
258: (if (null p) ;not in subforms
259: (list (+ sexp-column tem) containing-form-start)
260: normal-indent)))
261: ((symbolp tem) ;a function to call
262: (throw 'exit
263: (funcall tem path state indent-point
264: sexp-column normal-indent)))
265: (t
266: ;; must be a destructing frob
267: (if (not (null p))
268: ;; descend
269: (setq method (cdr (cdr tem))
270: n nil)
271: (setq tem (car (cdr tem)))
272: (throw 'exit
273: (cond (tail
274: normal-indent)
275: ((eq tem 'nil)
276: (list normal-indent
277: containing-form-start))
278: ((integerp tem)
279: (list (+ sexp-column tem)
280: containing-form-start))
281: (t
282: (funcall tem path state indent-point
283: sexp-column normal-indent))))))))))))
284:
285: (defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent)
286: (if (not (null (cdr path)))
287: normal-indent
288: (save-excursion
289: (goto-char indent-point)
290: (beginning-of-line)
291: (skip-chars-forward " \t")
292: (list (cond ((looking-at "\\sw\\|\\s_")
293: ;; a tagbody tag
294: (+ sexp-column lisp-tag-indentation))
295: ((integerp lisp-tag-body-indentation)
296: (+ sexp-column lisp-tag-body-indentation))
297: ((eq lisp-tag-body-indentation 't)
298: (condition-case ()
299: (progn (backward-sexp 1) (current-column))
300: (error (1+ sexp-column))))
301: (t (+ sexp-column lisp-body-indent)))
302: ; (cond ((integerp lisp-tag-body-indentation)
303: ; (+ sexp-column lisp-tag-body-indentation))
304: ; ((eq lisp-tag-body-indentation 't)
305: ; normal-indent)
306: ; (t
307: ; (+ sexp-column lisp-body-indent)))
308: (elt state 1)
309: ))))
310:
311: (defun lisp-indent-do (path state indent-point sexp-column normal-indent)
312: (if (>= (car path) 3)
313: (let ((lisp-tag-body-indentation lisp-body-indent))
314: (funcall (function lisp-indent-tagbody)
315: path state indent-point sexp-column normal-indent))
316: (funcall (function lisp-indent-259)
317: '((&whole nil &rest
318: ;; the following causes wierd indentation
319: ;;(&whole 1 1 2 nil)
320: )
321: (&whole nil &rest 1))
322: path state indent-point sexp-column normal-indent)))
323:
324: (defun lisp-indent-function-lambda-hack (path state indent-point
325: sexp-column normal-indent)
326: ;; indent (function (lambda () <newline> <body-forms>)) kludgily.
327: (if (or (cdr path) ; wtf?
328: (> (car path) 3))
329: ;; line up under previous body form
330: normal-indent
331: ;; line up under function rather than under lambda in order to
332: ;; conserve horizontal space. (Which is what #' is for.)
333: (condition-case ()
334: (save-excursion
335: (backward-up-list 2)
336: (forward-char 1)
337: (if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
338: (+ lisp-body-indent -1 (current-column))
339: (+ sexp-column lisp-body-indent)))
340: (error (+ sexp-column lisp-body-indent)))))
341:
342:
343: (let ((l '((block 1)
344: (catch 1)
345: (case (4 &rest (&whole 2 &rest 1)))
346: (ccase . case) (ecase . case)
347: (typecase . case) (etypecase . case) (ctypecase . case)
348: (catch 1)
349: (cond (&rest (&whole 2 &rest 1)))
350: (block 1)
351: (defvar (4 2 2))
352: (defconstant . defvar) (defparameter . defvar)
353: (define-modify-macro
354: (4 &body))
355: (define-setf-method
356: (4 (&whole 4 &rest 1) &body))
357: (defsetf (4 (&whole 4 &rest 1) 4 &body))
358: (defun (4 (&whole 4 &rest 1) &body))
359: (defmacro . defun) (deftype . defun)
360: (defstruct ((&whole 4 &rest (&whole 2 &rest 1))
361: &rest (&whole 2 &rest 1)))
362: (destructuring-bind
363: ((&whole 6 &rest 1) 4 &body))
364: (do lisp-indent-do)
365: (do* . do)
366: (dolist ((&whole 4 2 1) &body))
367: (dotimes . dolist)
368: (eval-when 1)
369: (flet ((&whole 4 &rest (&whole 1 (&whole 4 &rest 1) &body))
370: &body))
371: (labels . flet)
372: (macrolet . flet)
373: ;; `else-body' style
374: (if (nil nil &body))
375: ;; single-else style (then and else equally indented)
376: (if (&rest nil))
377: ;(lambda ((&whole 4 &rest 1) &body))
378: (lambda ((&whole 4 &rest 1)
379: &rest lisp-indent-function-lambda-hack))
380: (let ((&whole 4 &rest (&whole 1 1 2)) &body))
381: (let* . let)
382: (locally 1)
383: ;(loop ...)
384: (multiple-value-bind
385: ((&whole 6 &rest 1) 4 &body))
386: (multiple-value-call
387: (4 &body))
388: (multiple-value-list 1)
389: (multiple-value-prog1 1)
390: (multiple-value-setq
391: (4 2))
392: ;; Combines the worst features of BLOCK, LET and TAGBODY
393: (prog ((&whole 4 &rest 1) &rest lisp-indent-tagbody))
394: (prog* . prog)
395: (prog1 1)
396: (prog2 2)
397: (progn 0)
398: (progv (4 4 &body))
399: (return 0)
400: (return-from (nil &body))
401: (tagbody lisp-indent-tagbody)
402: (throw 1)
403: (unless 1)
404: (unwind-protect
405: (5 &body))
406: (when 1))))
407: (while l
408: (put (car (car l)) 'common-lisp-indent-hook
409: (if (symbolp (cdr (car l)))
410: (get (cdr (car l)) 'common-lisp-indent-hook)
411: (car (cdr (car l)))))
412: (setq l (cdr l))))
413:
414:
415: ;(defun foo (x)
416: ; (tagbody
417: ; foo
418: ; (bar)
419: ; baz
420: ; (when (losing)
421: ; (with-big-loser
422: ; (yow)
423: ; ((lambda ()
424: ; foo)
425: ; big)))
426: ; (flet ((foo (bar baz zap)
427: ; (zip))
428: ; (zot ()
429: ; quux))
430: ; (do ()
431: ; ((lose)
432: ; (foo 1))
433: ; (quux)
434: ; foo
435: ; (lose))
436: ; (cond ((x)
437: ; (win 1 2
438: ; (foo)))
439: ; (t
440: ; (lose
441: ; 3))))))
442:
443:
444: ;(put 'while 'common-lisp-indent-hook 1)
445: ;(put 'defwrapper'common-lisp-indent-hook ...)
446: ;(put 'def 'common-lisp-indent-hook ...)
447: ;(put 'defflavor 'common-lisp-indent-hook ...)
448: ;(put 'defsubst 'common-lisp-indent-hook ...)
449:
450: ;;(put 'define-restart-name 'common-lisp-indent-hook '1)
451: ;(put 'with-restart 'common-lisp-indent-hook '((1 4 ((* 1))) (2 &body)))
452: ;(put 'restart-case 'common-lisp-indent-hook '((1 4) (* 2 ((0 1) (* 1)))))
453: ;(put 'define-condition 'common-lisp-indent-hook '((1 6) (2 6 ((* 1))) (3 4 ((* 1))) (4 &body)))
454: ;(put 'with-condition-handler 'common-lisp-indent-hook '((1 4 ((* 1))) (2 &body)))
455: ;(put 'condition-case 'common-lisp-indent-hook '((1 4) (* 2 ((0 1) (1 3) (2 &body)))))
456:
457:
458: ;;;; Turn it on.
459: ;(setq lisp-indent-hook 'common-lisp-indent-hook)
460:
461: ;; To disable this stuff, (setq lisp-indent-hook 'lisp-indent-hook)
462:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.