Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/slime/contrib/slime-indentation.el
990 views
1
2
(define-slime-contrib slime-indentation
3
"cl-indent.el as a slime-contrib module"
4
(:swank-dependencies swank-indentation)
5
(:on-load (run-hooks 'cl-indent:load-hook)))
6
7
8
;; redefine this for cl-indent:method
9
(defun slime-handle-indentation-update (alist)
10
"Update Lisp indent information for slime-indentation.el.
11
12
ALIST is a list of (SYMBOL-NAME . INDENT-SPEC) of proposed indentation
13
settings for `common-lisp-indent-function'. The appropriate property
14
is setup, unless the user already set one explicitly."
15
(dolist (info alist)
16
(let ((symbol (intern (car info)))
17
(indent (cdr info)))
18
(define-cl-indent (cons symbol
19
(etypecase indent
20
(number (list indent))
21
(cons (labels ((walk (indent)
22
(etypecase indent
23
((or number null) indent)
24
(cons (cons (walk (car indent))
25
(walk (cdr indent))))
26
(string (intern (downcase indent))))))
27
(list (walk indent))))
28
(string (intern (downcase indent))))))
29
(run-hook-with-args 'slime-indentation-update-hooks symbol indent))))
30
31
;; $ITI: cl-indent.el,v 1.6 1995/09/10 14:13:34 schrod Exp $
32
;; ----------------------------------------------------------------------
33
;; Copyright (C) 1987, 1993 Free Software Foundation, Inc.
34
;; Written by Richard Mlynarik July 1987
35
;; Merged with cl-indent-patches.el by Marco Baringer (2007-11-14)
36
;; Documented and intensively modified by Joachim Schrod
37
;; <[email protected]>, history at end.
38
;; Send bug reports, gripes, patches to me.
39
40
;;
41
;; cl-indent.el --- highly configurable indentation for Lisp modes
42
;;
43
44
;; This file is part of GNU Emacs.
45
46
;; GNU Emacs is free software; you can redistribute it and/or modify
47
;; it under the terms of the GNU General Public License as published by
48
;; the Free Software Foundation; either version 2, or (at your option)
49
;; any later version.
50
51
;; GNU Emacs is distributed in the hope that it will be useful,
52
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
53
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54
;; GNU General Public License for more details.
55
56
;; You should have received a copy of the GNU General Public License
57
;; along with GNU Emacs; see the file COPYING. If not, write to
58
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
59
60
61
;; ----------------------------------------------------------------------
62
63
;; USAGE:
64
65
;; This file delivers highly configurable indentation of Lisp code.
66
;; Eval (cl-indent) to use this indentation for a specific file,
67
;; (setq lisp-indent-function 'cl-indent:function) to use it for all
68
;; Lisp files.
69
70
;; The indentation for a specific form may be defined by
71
;; (define-cl-indent SPEC &optional MODE-METHODS). Indentation specs
72
;; for Common Lisp constructs are given already. Check the on-line
73
;; documentation of this function for more information.
74
75
;; Actually, the whole (`real') documentation of this source is stored
76
;; as the documentation strings of respective functions. Start with
77
;; #'define-cl-indent, you'll find references to all other relevant
78
;; functions.
79
80
;; It's also possible to specify specific indentations for a mode
81
;; (e.g., some special Lisp-mode) and even specific ones for a file.
82
;; File specific indentations are taken from the alist bound to
83
;; cl-indent:local-methods, you can set it in your `Local Variables'
84
;; section. Mode-specific methods are stored in hash tables, the mode
85
;; setup must bind cl-indent:mode-methods to the name of that hash
86
;; table.
87
88
;; You may want to override my global indentation specs. If you load
89
;; this file immediately, just issue some #'define-cl-indent calls. If
90
;; you use autoload, add an appropriate hook function to
91
;; 'cl-indent:load-hook.
92
93
;; I'm interested in feedback on this module. Do you use it, was it
94
;; useful to you? (Further development depends on the amount of people
95
;; who send feedback. :-)
96
;; Send email to <[email protected]>.
97
98
99
100
;; ------------------------------------------------------------
101
102
;;>> TODO
103
104
;; Urgently need better user documentation, it's hard to get a grasp
105
;; for the overall strategy how this package may be customized. One
106
;; has to look at too many function documentation strings.
107
108
;; Have to check if the usage of hash tables makes this package XEmacs
109
;; specific. If FSF Emacs doesn't have them, they might be emulated by
110
;; alists or obarrays. (I don't have FSF Emacs available, may somebody
111
;; please check this, maybe even send patches?)
112
113
;; Realize `parent method tables', to be able to inherit an indentation
114
;; method table. `(make-method-table &optional size parent)' ?! That's
115
;; needed before the CL specific indentation is moved to an own table,
116
;; as some modes (e.g., stil-mode) may inherit their indentation from
117
;; CL definitions.
118
119
;; Common Lisp specific indentation methods should be moved to a
120
;; method table, it's not good to have them globally for all kinds of
121
;; Lisp modes. How about a table for Elisp indentations as well?
122
123
;; special handling of keywords in forms, e.g.,
124
;;
125
;; :foo
126
;; bar
127
;; :baz
128
;; zap
129
;;
130
;; &key (like &body)??
131
132
;; &rest 1 in lambda-lists doesn't work, really want
133
;;
134
;; (foo bar
135
;; baz)
136
;;
137
;; not
138
;;
139
;; (foo bar
140
;; baz)
141
;;
142
;; Need something better than &rest for such cases. Perhaps a function
143
;; that just returns normal-point? Might work...
144
145
146
;;; ------------------------------------------------------------
147
;;;
148
;;; USER TOP-LEVEL FUNCTION
149
;;;
150
151
;;;###autoload
152
(defun cl-indent ()
153
"Switch on Common Lisp indentation for the current buffer.
154
May also be used as hook function, e.g., in lisp-mode-hook.
155
If you want to do use this indentation for all Lisp buffers, incl.
156
Emacs Lisp code, simply eval
157
(setq lisp-indent-function 'cl-indent:function)
158
You might want to do this in some setup file, e.g., in ~/.emacs ."
159
(interactive)
160
(make-local-variable 'lisp-indent-function)
161
(setq lisp-indent-function 'cl-indent:function))
162
163
164
165
;;; ------------------------------------------------------------
166
;;;
167
;;; Configuration:
168
;;;
169
170
(defvar cl-indent::maximum-backtracking 3
171
"Maximum depth to backtrack out from a sublist for structured indentation.
172
If this variable is 0, no backtracking will occur and forms such as flet
173
may not be correctly indented.")
174
175
(defvar cl-indent:tag-indentation 1
176
"*Indentation of tags relative to containing list.
177
This variable is used by the function cl-indent:tagbody.")
178
179
(defvar cl-indent:tag-body-indentation 3
180
"*Indentation of non-tagged lines relative to containing list.
181
This variable is used by the function cl-indent:tagbody to indent normal
182
lines (lines without tags).
183
The indentation is relative to the indentation of the parenthesis enclosing
184
he special form. If the value is t, the body of tags will be indented
185
as a block at the same indentation as the first s-expression following
186
the tag. In this case, any forms before the first tag are indented
187
by lisp-body-indent.")
188
189
190
191
;;; ============================================================
192
;;;
193
;;; compute the indentation of the current line
194
;;;
195
196
197
;;;###autoload
198
(defun common-lisp-indent-function (indent-point state)
199
"Old name of #'cl-indent:function."
200
(cl-indent:function indent-point state))
201
202
(make-obsolete #'common-lisp-indent-function #'cl-indent:function)
203
204
205
;;;###autoload
206
(defun cl-indent:function (indent-point state)
207
"Compute the indentation of the current line of Common Lisp code.
208
INDENT-POINT is the current point. STATE is the result of a
209
#'parse-partial-sexp from the start of the current function to the
210
start of the line this function was called.
211
212
The indentation is determined by the expressions point is in.
213
214
When this function is called, the column of point may be used as the
215
normal indentation. Therefore we call this position _normal
216
point_. Actually, if the first element of the current expression is a
217
list, it's at the start of this element. Otherwise it's at the start
218
of first expression on the same line as the last complete expression.
219
220
Within a quoted list or a non-form list, all subsequent lines are
221
indented to the column directly after the opening parenthesis. Quoted
222
lists are those that are prefixed with ?\`, ?\', or ?\#. Note that the
223
quote must be immediately in front of the opening parenthesis. I.e.,
224
if you want to use automatic code indentation in a macro expansion
225
formulated with a backquoted list, add a blank between the backquote
226
and the expansion form.
227
228
Within a list form, the indentation is determined by the indentation
229
method associated to the form symbol. (See #'cl-indent::method.)
230
231
** If the indentation method is nil, the form is assumed to be a
232
function call, arguments are aligned beneath each other if the first
233
argument was written behind the function symbol, otherwise they're
234
aligned below the function symbol.
235
236
** If the indentation method is a symbol, a function must be bound to
237
that symbol that will compute the current indentation. Such a function
238
is named an _indentation function_ and is called with 5 arguments:
239
240
(1) PATH is a list of numbers, the path from the top-level form to
241
the current structural element (the first element is number 0).
242
E.g., `foo' has a path of (0 3 1) in `((a b c (d foo) f) g)'.
243
(2) STATE is passed.
244
(3) INDENT-POINT is passed.
245
(4) SEXP-COLUMN is the column where the innermost form starts.
246
(5) NORMAL-INDENT is the column of normal point.
247
248
** If the indentation method is a list, this list specifies the form
249
structure and the indentation of each substructure. The possible list
250
structure and elements are described in #'cl-indent::form-method.
251
252
** If the indentation method is the number $n$, the first $n$
253
arguments are _distinguished arguments_; they are indented by 4
254
spaces. Further arguments are indented by lisp-body-indent. That's
255
roughly equivalent to '(4 4 ... &body)' with $n$ 4s.
256
257
** Furthermore values as described for #'lisp-indent-function may be
258
used for upward compatibility."
259
(let ((normal-indent (current-column)))
260
;; Walk up list levels until we see something
261
;; which does special things with subforms.
262
(let ((depth 0)
263
;; Path describes the position of point in terms of
264
;; list-structure with respect to contining lists.
265
;; `foo' has a path of (0 4 1) in `((a b c (d foo) f) g)'
266
(path ())
267
;; set non-nil when somebody works out the indentation to use
268
calculated
269
(last-point indent-point)
270
;; the position of the open-paren of the innermost containing list
271
(containing-form-start (elt state 1))
272
;; the column of the above
273
sexp-column)
274
;; Move to start of innermost containing list
275
(goto-char containing-form-start)
276
(setq sexp-column (current-column))
277
;; Look over successively less-deep containing forms
278
(while (and (not calculated)
279
(< depth cl-indent::maximum-backtracking))
280
(let ((containing-sexp (point)))
281
(forward-char 1)
282
(parse-partial-sexp (point) indent-point 1 t)
283
;; Move to the car of the relevant containing form
284
(let (tem function method)
285
(if (not (looking-at "\\sw\\|\\s_"))
286
;; This form doesn't seem to start with a symbol
287
(setq function nil method nil)
288
(setq tem (point))
289
(forward-sexp 1)
290
(setq function (downcase (buffer-substring tem (point))))
291
(goto-char tem)
292
(setq tem (intern-soft function)
293
method (get tem 'cl-indent:method))
294
(cond ((and (null method)
295
(string-match ":[^:]+" function))
296
;; The pleblisp package feature
297
(setq function (substring function
298
(1+ (match-beginning 0)))
299
method (get (intern-soft function)
300
'cl-indent:method)))
301
((and (null method))
302
;; backwards compatibility
303
(setq method (get tem 'lisp-indent-function)))))
304
(let ((n 0))
305
;; How far into the containing form is the current form?
306
(if (< (point) indent-point)
307
(while (condition-case ()
308
(progn
309
(forward-sexp 1)
310
(if (>= (point) indent-point)
311
nil
312
(parse-partial-sexp (point)
313
indent-point 1 t)
314
(setq n (1+ n))
315
t))
316
(error nil))))
317
(setq path (cons n path)))
318
319
;; backwards compatibility.
320
(cond ((null function))
321
((null method)
322
(if (null (cdr path))
323
;; (package prefix was stripped off above)
324
(setq method (cond ((string-match "\\`def"
325
function)
326
'(4 (&whole 4 &rest 1) &body))
327
((string-match "\\`\\(with\\|do\\)-"
328
function)
329
'(4 &body))))))
330
;; backwards compatibility. Bletch.
331
((eq method 'defun)
332
(setq method '(4 (&whole 4 &rest 1) &body))))
333
334
(cond ((and (eql (char-after (1- containing-sexp)) ?\') ; patched to only do this for ' and not `.
335
(not (eql (char-after (- containing-sexp 2)) ?\#)))
336
;; No indentation for "'(...)" elements
337
(setq calculated (1+ sexp-column)))
338
((eql (char-after (1- containing-sexp)) ?\#)
339
;; "#(...)"
340
(setq calculated (1+ sexp-column)))
341
((null method))
342
((integerp method)
343
;; convenient top-level hack.
344
;; (also compatible with lisp-indent-function)
345
;; The number specifies how many `distinguished'
346
;; forms there are before the body starts
347
;; Equivalent to (4 4 ... &body)
348
(setq calculated (cond ((cdr path)
349
normal-indent)
350
((<= (car path) method)
351
;; `distinguished' form
352
(list (+ sexp-column 4)
353
containing-form-start))
354
((= (car path) (1+ method))
355
;; first body form.
356
(+ sexp-column lisp-body-indent))
357
(t
358
;; other body form
359
normal-indent))))
360
((symbolp method)
361
(setq calculated (funcall method
362
path state indent-point
363
sexp-column normal-indent)))
364
(t
365
(setq calculated (cl-indent::form-method
366
method path state indent-point
367
sexp-column normal-indent)))))
368
369
(goto-char containing-sexp)
370
(setq last-point containing-sexp)
371
(if (not calculated)
372
(condition-case ()
373
(progn (backward-up-list 1)
374
(setq depth (1+ depth)))
375
(error (setq depth cl-indent::maximum-backtracking))))))
376
calculated)))
377
378
(defun cl-indent::normal (state)
379
"Compute normal indentation according to STATE and current position."
380
;; Actually, the current column (i.e., the normal point) _is_ a good
381
;; approximation for the normal indentation. But lists with a list
382
;; as the first element make problems if an &rest or an &body method
383
;; is in effect.
384
;;
385
;; There we can distinguish two cases:
386
;;
387
;; 1. ((foo) (bar)
388
;; (baz))
389
;; 2. ((foo)
390
;; (bar)
391
;; (baz))
392
;;
393
;; Both are used in do result-forms, or in cond-forms. If
394
;; #'cl-indent:function is called in the baz line, the normal point
395
;; will be at (foo), i.e., (baz) would be aligned below (foo). (Of
396
;; course, if the body indentation is 1, both (bar) and (baz) are
397
;; aligned below (foo).) But I want to enable the specification of
398
;; alignments like those shown above -- if the user did change the
399
;; alignment for the first expression of a body then it should be
400
;; used further on, after all. (As usually, we have to assume that
401
;; the user knows what he does.)
402
(let ((normal-point (point))
403
(current-sexp (elt state 1)))
404
;; A necessary precondition for the special situation outlined
405
;; above is that the normal point is directly after the start of
406
;; the current expression and that a list is there. Only then we
407
;; have to calculate the normal indentation, otherwise we can use
408
;; the column of normal point.
409
(if (and (= (1+ current-sexp) normal-point)
410
(looking-at "\\s("))
411
;; OK. Let's determine first the first expression in the line
412
;; with the last completed expression before the indentation point.
413
(let ((last-sexp (elt state 2)))
414
(goto-char last-sexp)
415
(beginning-of-line)
416
(parse-partial-sexp (point) last-sexp 0 t)
417
(backward-prefix-chars)
418
;; If we're now after the current expression, we're in case
419
;; 2. We simply use the current column then.
420
(if (> (point) current-sexp)
421
(current-column)
422
;; Here we have to care for case 1: We determine the
423
;; second element of the list and use its column.
424
(goto-char normal-point) ; start of the first element!
425
(forward-sexp 1)
426
(parse-partial-sexp (point) last-sexp 0 t)
427
(current-column)))
428
(current-column))))
429
430
(defun cl-indent::bad-method (m)
431
(error "%s has a badly-formed indentation method: %s"
432
;; Love them free variable references!!
433
function m))
434
435
;; Blame the crufty control structure on dynamic scoping
436
;; -- not on me!
437
(defun cl-indent::form-method (method path state indent-point
438
sexp-column normal-indent)
439
"Compute the current indentation according to METHOD.
440
The other arguments are those of an indentation function, see
441
#'cl-indent:function for further explanation.
442
443
METHOD is a list that specifies the indentation of a form:
444
445
method-list-spec : '(' method-list ')'
446
447
method-list : method * method-finish ?
448
449
method : indent-spec
450
| method-sublist
451
<< the subform must be a list that's indented
452
as specified >>
453
454
indent-spec : Number | Symbol | 'nil'
455
<< indent this subform $Number spaces or compute its
456
indentation by the indentation function bound to
457
Symbol. 'nil' tells to use normal function
458
indentation. >>
459
460
method-finish : '&rest' method
461
<< indent the rest of this form as specified by
462
method. >>
463
| '&body'
464
<< equivalent to `(&rest ,lisp-body-indent).
465
I.e., Indent all following forms by
466
lisp-body-indent spaces. >>
467
468
method-sublist : '(' '&whole' indent-spec method-list ')'
469
<< This whole subform has a basic indentation, as
470
specified by indent-spec. The indentations from
471
method-list are added to this basic indentation. >>
472
473
FIXME (-js): Maybe only list structures up to a depth of
474
'cl-indent::maximum-backtracking are supported. Have to analyze the
475
code for this. If that's the case this variable should be a constant.
476
"
477
(catch 'exit
478
(let ((p path)
479
(containing-form-start (elt state 1))
480
n tem)
481
;; Isn't tail-recursion wonderful?
482
(while p
483
;; This while loop is for destructuring.
484
;; p is set to (cdr p) each iteration.
485
(if (not (consp method)) (cl-indent::bad-method method))
486
(setq n (1- (car p)) ; FIXME: that might result in -1 !?
487
p (cdr p))
488
(while n
489
;; This while loop is for advancing along a method
490
;; until the relevant (possibly &rest/&body) pattern
491
;; is reached.
492
;; n is set to (1- n) and method to (cdr method)
493
;; each iteration.
494
; (message "trying %s for %s %s" method p function) (sit-for 1)
495
(setq tem (car method))
496
(cl-indent::check-method tem method)
497
498
(cond ((eq tem '&body)
499
;; &body means (&rest <lisp-body-indent>)
500
(throw 'exit
501
(if (null p)
502
(+ sexp-column lisp-body-indent)
503
normal-indent)))
504
((eq tem '&rest)
505
;; this pattern holds for all remaining forms
506
(setf method (list (second method))
507
n 0))
508
((> n 0)
509
;; try next element of pattern
510
(setq n (1- n)
511
method (cdr method))
512
(if (< n 0)
513
;; Too few elements in pattern.
514
(throw 'exit normal-indent)))
515
((eq tem 'nil)
516
(throw 'exit (list normal-indent containing-form-start)))
517
; ((eq tem '&lambda)
518
; ;; abbrev for (&whole 4 &rest 1)
519
; (throw 'exit
520
; (cond ((null p)
521
; (list (+ sexp-column 4) containing-form-start))
522
; ((null (cdr p))
523
; (+ sexp-column 1))
524
; (t normal-indent))))
525
((integerp tem)
526
(throw 'exit
527
(if (null p) ;not in subforms
528
(list (+ sexp-column tem) containing-form-start)
529
normal-indent)))
530
((symbolp tem) ;a function to call
531
(throw 'exit
532
(funcall tem path state indent-point
533
sexp-column normal-indent)))
534
(t
535
;; must be a destructing frob
536
(if (not (null p))
537
;; descend
538
(setq method (cdr (cdr tem))
539
n nil)
540
(setq tem (car (cdr tem)))
541
(throw 'exit
542
(cond ((eq tem 'nil)
543
(list normal-indent
544
containing-form-start))
545
((integerp tem)
546
(list (+ sexp-column tem)
547
containing-form-start))
548
(t
549
(funcall tem path state indent-point
550
sexp-column normal-indent))))))))))))
551
552
(defun cl-indent::check-method (tem method)
553
"Check validity of one indentation method element.
554
TEM is that indentation method and METHOD is the rest of the method list."
555
(if (eq tem 'nil)
556
;; default indentation
557
t
558
(if (and (eq tem '&body)
559
(null (cdr method)))
560
t
561
(if (and (eq tem '&rest)
562
(consp (cdr method))
563
(null (cdr (cdr method))))
564
t
565
(if (integerp tem)
566
t
567
(if (and (consp tem) ; destructuring
568
(eq (car tem) '&whole)
569
(or (symbolp (car (cdr tem)))
570
(integerp (car (cdr tem)))))
571
t
572
(if (and (symbolp tem) ; a function to call to do the work.
573
(null (cdr method)))
574
t
575
(cl-indent::bad-method method))))))))
576
577
578
579
;;; ------------------------------------------------------------
580
;;;
581
;;; A few indentation functions
582
;;;
583
584
(defun cl-indent:indent-tagbody (path state indent-point
585
sexp-column normal-indent)
586
(if (not (null (cdr path)))
587
normal-indent
588
(save-excursion
589
(goto-char indent-point)
590
(beginning-of-line)
591
(skip-chars-forward " \t")
592
(list (cond ((looking-at "\\sw\\|\\s_")
593
;; a tagbody tag
594
(+ sexp-column cl-indent:tag-indentation))
595
((integerp cl-indent:tag-body-indentation)
596
(+ sexp-column cl-indent:tag-body-indentation))
597
((eq cl-indent:tag-body-indentation 't)
598
(condition-case ()
599
(progn (backward-sexp 1) (current-column))
600
(error (1+ sexp-column))))
601
(t (+ sexp-column lisp-body-indent)))
602
; (cond ((integerp cl-indent:tag-body-indentation)
603
; (+ sexp-column cl-indent:tag-body-indentation))
604
; ((eq cl-indent:tag-body-indentation 't)
605
; normal-indent)
606
; (t
607
; (+ sexp-column lisp-body-indent)))
608
(elt state 1)
609
))))
610
611
(defun cl-indent:indent-do (path state indent-point
612
sexp-column normal-indent)
613
(let ((cl-indent:tag-body-indentation lisp-body-indent))
614
(funcall #'cl-indent:indent-tagbody
615
path state indent-point sexp-column normal-indent)))
616
617
(defun cl-indent:indent-function-lambda-hack (path state indent-point
618
sexp-column normal-indent)
619
;; indent (function (lambda () <newline> <body-forms>)) kludgily.
620
(if (or (cdr path) ; wtf?
621
(> (car path) 3))
622
;; line up under previous body form
623
normal-indent
624
;; line up under function rather than under lambda in order to
625
;; conserve horizontal space. (Which is what #' is for.)
626
(condition-case ()
627
(save-excursion
628
(backward-up-list 2)
629
(forward-char 1)
630
(if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)")
631
(+ lisp-body-indent -1 (current-column))
632
(+ sexp-column lisp-body-indent)))
633
(error (+ sexp-column lisp-body-indent)))))
634
635
(defun cl-indent:indent-defmethod (path state indent-point
636
sexp-column normal-indent)
637
;; Look for a method combination specifier...
638
(let* ((combined (if (and (>= (car path) 3)
639
(null (cdr path)))
640
(save-excursion
641
(goto-char (second state))
642
(forward-char)
643
(forward-sexp)
644
(forward-sexp)
645
(forward-sexp)
646
(backward-sexp)
647
(if (looking-at ":")
648
t
649
nil))
650
nil))
651
(method (if combined
652
'(4 4 (&whole 4 &rest 1) &body)
653
'(4 (&whole 4 &rest 1) &body))))
654
(funcall #'cl-indent::form-method
655
method
656
path state indent-point sexp-column normal-indent)))
657
658
(defun cl-indent:indent-defgeneric (path state indent-point
659
sexp-column normal-indent)
660
(let ((method '(4 4 &rest 2)))
661
(when (= 2 (length path))
662
(ignore-errors
663
(save-excursion
664
(save-match-data
665
(let ((case-fold-search t))
666
(goto-char (second state))
667
(down-list)
668
(skip-chars-forward " \t\n")
669
(when (looking-at ":method\\W")
670
(forward-sexp)
671
(forward-sexp)
672
(backward-sexp)
673
(setq method (if (looking-at ":")
674
'(4 (&whole 4 &rest 1) &body)
675
'((&whole 4 &rest 1) &body))
676
path (cdr path)))
677
(when (looking-at ":method-combination\\W")
678
(setq method '(4 &rest 2)
679
path (cdr path))))))))
680
(funcall #'cl-indent::form-method
681
method
682
path state indent-point sexp-column normal-indent)))
683
684
(defun cl-indent::line-number ()
685
"Compatability implementation of emacs23's line-number-at-pos."
686
(cond
687
((fboundp 'line-number-at-pos)
688
(line-number-at-pos))
689
((fboundp 'line-number)
690
(line-number nil t))
691
((fboundp 'count-lines)
692
(count-lines (point-min) (point)))
693
(t
694
(error "Don't know how to count the number of lines from the start of the (narrowed) buffer to point."))))
695
696
(defun cl-indent:indent-cond (path state indent-point sexp-column normal-indent)
697
"Handle indentation of cond.
698
699
Cond is either (&rest (&whole 2 1 &rest 1)) or (&rest (&whole 6 1
700
&rest 1)) depending on whether the first caluse is or isn't on
701
the same line as the cond symbol.
702
703
So if we have:
704
705
(cond (a b)
706
|
707
708
we line up the clauses after the cond symbol (6 space of
709
indentation). wherease if we have:
710
711
(cond
712
(a b)
713
|)
714
715
we line up the clauses two space past the form's indentation."
716
;; i'd bet my left pinky there's a better way to implement this...
717
(let (cond-line-number first-clause-line-number method here)
718
(save-excursion
719
;; narrow to the aera we're interested in because
720
;; cl-indent::line-number can, especially on tramp files, be
721
;; very slow.
722
(save-restriction
723
(narrow-to-region (save-excursion
724
(backward-up-list)
725
(point))
726
(point))
727
(setf here (point))
728
(backward-up-list)
729
(setf cond-line-number (cl-indent::line-number))
730
(down-list)
731
(forward-sexp 1)
732
(setf first-clause-line-number
733
(progn
734
(if (= 1 (first path))
735
;; we're indenting the first form. use the current line.
736
(goto-char here)
737
;; we're indenting some form which isn't the
738
;; first. find out which the line the first clause
739
;; starts on.
740
(forward-sexp 1)
741
(backward-sexp 1))
742
(cl-indent::line-number)))))
743
(cl-indent::form-method
744
(if (= cond-line-number first-clause-line-number)
745
'(&rest (&whole 6 &rest 1))
746
'(&rest (&whole 2 &rest 1)))
747
path state indent-point sexp-column normal-indent)))
748
749
750
;;; ============================================================
751
;;;
752
;;; Define and retrieve indentation method
753
;;;
754
755
(defun cl-indent::method (function)
756
"Returns the indentation method associated to FUNCTION (a string).
757
The indentation method is looked for subsequently as follows:
758
759
(1) An indentation method is searched by #'cl-indent::get-method.
760
761
(2) If FUNCTION is from a specific package, the package prefix is
762
discarded and the indentation method from that FUNCTION name is
763
used.
764
765
(4) If FUNCTION starts with 'def', the indentation method \"defun\" is used.
766
767
(5) If FUNCTION starts with 'while-' or 'do-', the indentation method
768
1 (i.e., one distinguished argument) is used.
769
770
If the method determined that way is a string, it's replaced by the
771
current indentation method of the symbol named by that string."
772
(let ((method
773
(cond ((cl-indent::get-method function))
774
((string-match ":[^:]+" function)
775
(cl-indent::method (substring function
776
(1+ (match-beginning 0)))))
777
((string-match "\\`def" function) "defun")
778
((string-match "\\`\\(with\\|do\\)-" function) 1))))
779
(if (stringp method)
780
(cl-indent::method method)
781
method)))
782
783
784
(defvar cl-indent:local-methods nil
785
"*Alist of source-local indentation methods.
786
Is typically set in a `Local Variables' section.")
787
(make-variable-buffer-local 'cl-indent:local-methods)
788
789
(defvar cl-indent:mode-methods nil
790
"*Name of hash table with indentation methods for the current buffer.
791
Is typically set for a mode, during mode setup or in a mode hook.")
792
(make-variable-buffer-local 'cl-indent:mode-methods)
793
794
795
(defun cl-indent::get-method (function)
796
"Retrieves an indentation method that is stored for FUNCTION (a string).
797
798
(1) Indentation methods may be specified for the current source file,
799
as an alist that's bound to cl-indent:local-methods . The alist
800
car is the function symbol, the cdr is the indentation method.
801
802
(2) Mode-specific indentation methods are stored in a hash table. The
803
name of that hash table is bound to cl-indent:mode-methods .
804
805
(3) Global indentation methods are stored as the value of the
806
property 'cl-indent:method. If there is no such property, the
807
property 'lisp-indent-function is checked, too, for compatibility."
808
(let ((symbol (intern-soft function)))
809
(or (cdr (assq symbol cl-indent:local-methods))
810
;; An error will be signaled if the value of
811
;; cl-indent:mode-methods is not a symbol naming an hash
812
;; table. That's fine with me, other packages shouldn't mess
813
;; around with my public names...
814
(and cl-indent:mode-methods
815
(gethash symbol (symbol-value cl-indent:mode-methods)))
816
(get symbol 'cl-indent:method)
817
(get symbol 'lisp-indent-function))))
818
819
820
;;;
821
;;; Try to indent cl:loop
822
;;;
823
824
(defun cl-indent-parse-state-depth (parse-state)
825
(car parse-state))
826
827
(defun cl-indent-parse-state-start (parse-state)
828
(car (cdr parse-state)))
829
830
(defun cl-indent-parse-state-prev (parse-state)
831
(car (cdr (cdr parse-state))))
832
833
;; Regexps matching various varieties of loop macro keyword ...
834
(defvar cl-indent-body-introducing-loop-macro-keyword
835
"do\\|finally\\|initially\\|doing\\|collect\\|collecting\\|append\\|appending"
836
"Regexp matching loop macro keywords which introduce body-forms")
837
838
;; This is so "and when" and "else when" get handled right
839
;; (not to mention "else do" !!!)
840
(defvar cl-indent-prefix-loop-macro-keyword
841
"and\\|else"
842
"Regexp matching loop macro keywords which are prefixes")
843
844
(defvar cl-indent-clause-joining-loop-macro-keyword
845
"and"
846
"Regexp matching 'and', and anything else there ever comes to be
847
like it ...")
848
849
;; This is handled right, but it's incomplete ...
850
;; (It could probably get arbitrarily long if I did *every* iteration-path)
851
(defvar cl-indent-indented-loop-macro-keyword
852
"into\\|by\\|upto\\|downto\\|above\\|below\\|on\\|in\\|being\\|=\\|first\\|then\\|from\\|to"
853
"Regexp matching keywords introducing loop subclauses. Always indented two")
854
855
(defvar cl-indent-indenting-loop-macro-keyword
856
"when\\|unless\\|if"
857
"Regexp matching keywords introducing conditional clauses.
858
Cause subsequent clauses to be indented")
859
860
(defvar cl-indent-loop-macro-else-keyword "else")
861
862
;;; Attempt to indent the loop macro ...
863
864
(defun cl-indent::indent-loop-macro
865
(path parse-state indent-point sexp-column normal-indent)
866
(list (cl-indent-indent-loop-macro-1 parse-state indent-point)
867
(cl-indent-parse-state-start parse-state)))
868
869
(defun cl-indent-indent-loop-macro-1 (parse-state indent-point)
870
(catch 'return-indentation
871
(save-excursion
872
;; Find first clause of loop macro, and use it to establish
873
;; base column for indentation
874
(goto-char (cl-indent-parse-state-start parse-state))
875
(let ((loop-start-column (current-column)))
876
(cl-indent-loop-advance-past-keyword-on-line)
877
(if (eolp)
878
(progn
879
(forward-line 1)
880
(end-of-line)
881
882
;; If indenting first line after "(loop <newline>"
883
;; cop out ...
884
885
(if (<= indent-point (point))
886
(throw 'return-indentation (+ 2 loop-start-column)))
887
(back-to-indentation)))
888
889
(let* ((case-fold-search t)
890
(loop-macro-first-clause (point))
891
(previous-expression-start (cl-indent-parse-state-prev parse-state))
892
(default-value (current-column))
893
(loop-body-p nil)
894
(loop-body-indentation nil)
895
(indented-clause-indentation (+ 2 default-value)))
896
;; Determine context of this loop clause, starting with the
897
;; expression immediately preceding the line we're trying to indent
898
(goto-char previous-expression-start)
899
;; Handle a body-introducing-clause which ends a line specially.
900
(if (looking-at cl-indent-body-introducing-loop-macro-keyword)
901
(let ((keyword-position (current-column)))
902
(setq loop-body-p t)
903
(setq loop-body-indentation
904
(if (cl-indent-loop-advance-past-keyword-on-line)
905
(current-column)
906
(back-to-indentation)
907
(if (/= (current-column) keyword-position)
908
(+ 2 (current-column))
909
(- keyword-position 3)))))
910
911
(back-to-indentation)
912
(if (< (point) loop-macro-first-clause)
913
(goto-char loop-macro-first-clause))
914
;; If there's an "and" or "else," advance over it.
915
;; If it is alone on the line, the next "cond" will treat it
916
;; as if there were a "when" and indent under it ...
917
(let ((exit nil))
918
(while (and (null exit)
919
(looking-at cl-indent-prefix-loop-macro-keyword))
920
(if (null (cl-indent-loop-advance-past-keyword-on-line))
921
(progn (setq exit t)
922
(back-to-indentation)))))
923
;; Found start of loop clause preceding the one we're trying to indent.
924
;; Glean context ...
925
(cond
926
((looking-at "(")
927
;; We're in the middle of a clause body ...
928
(setq loop-body-p t)
929
(setq loop-body-indentation (current-column)))
930
((looking-at cl-indent-body-introducing-loop-macro-keyword)
931
(setq loop-body-p t)
932
;; Know there's something else on the line (or would
933
;; have been caught above)
934
(cl-indent-loop-advance-past-keyword-on-line)
935
(setq loop-body-indentation (current-column)))
936
(t
937
(setq loop-body-p nil)
938
(if (or (looking-at cl-indent-indenting-loop-macro-keyword)
939
(looking-at cl-indent-prefix-loop-macro-keyword))
940
(setq default-value (+ 2 (current-column))))
941
(setq indented-clause-indentation (+ 2 (current-column)))
942
;; We still need loop-body-indentation for "syntax errors" ...
943
(goto-char previous-expression-start)
944
(setq loop-body-indentation (current-column)))))
945
946
;; Go to first non-blank character of the line we're trying to indent.
947
;; (if none, wind up poised on the new-line ...)
948
(goto-char indent-point)
949
(back-to-indentation)
950
(cond
951
((looking-at "(")
952
;; Clause body ...
953
loop-body-indentation)
954
((or (eolp) (looking-at ";"))
955
;; Blank line. If body-p, indent as body, else indent as
956
;; vanilla clause.
957
(if loop-body-p
958
loop-body-indentation
959
default-value))
960
((looking-at cl-indent-indented-loop-macro-keyword)
961
indented-clause-indentation)
962
((looking-at cl-indent-clause-joining-loop-macro-keyword)
963
(let ((stolen-indent-column nil))
964
(forward-line -1)
965
(while (and (null stolen-indent-column)
966
(> (point) loop-macro-first-clause))
967
(back-to-indentation)
968
(if (and (< (current-column) loop-body-indentation)
969
(looking-at "\\sw"))
970
(progn
971
(if (looking-at cl-indent-loop-macro-else-keyword)
972
(cl-indent-loop-advance-past-keyword-on-line))
973
(setq stolen-indent-column
974
(current-column)))
975
(forward-line -1)))
976
(if stolen-indent-column
977
stolen-indent-column
978
default-value)))
979
(t default-value)))))))
980
981
(defun cl-indent-loop-advance-past-keyword-on-line ()
982
(forward-word 1)
983
(block move-forward
984
(while (and (looking-at "\\s-") (not (eolp)))
985
(forward-char 1)
986
(when (looking-at "\\s<")
987
;; eat up the comment (sorry, this will fail for for lisp block comments
988
(while (and (not (looking-at "\\s>")) (not (eolp)))
989
(forward-char 1)))))
990
(if (eolp)
991
nil
992
(current-column)))
993
994
;;;###autoload
995
(defun define-cl-indent (spec &optional mode-methods)
996
"Define the cl-indent specification SPEC, maybe mode-specific.
997
The car of SPEC is the symbol for which the indentation shall be specified.
998
If the cdr is a symbol, then this symbol shall be indented like
999
the other symbol is indented _currently_ (i.e., eager evaluation is
1000
used, not lazy evaluation).
1001
Otherwise the cadr is taken as the indentation method. Check
1002
#'cl-indent:function for documentation about indentation methods. Note
1003
further that #'cl-indent::method interprets indentation methods that
1004
are strings as aliases, i.e., the indentation method of the string is
1005
looked up and returned (lazy evaluation).
1006
The optional argument MODE-METHODS may be bound to a hash table
1007
where this (presumedly mode-specific) indentation method shall be
1008
stored."
1009
(let* ((symbol (car spec))
1010
(indent (cdr spec))
1011
(method (if (symbolp indent)
1012
;; If an alias is defined, it might be mode-specific.
1013
;; Rebind cl-indent:mode-methods for lookup,
1014
;; that's possible as all symbols have dynamic
1015
;; scope in Emacs Lisp.
1016
(let ((cl-indent:mode-methods (and mode-methods
1017
'mode-methods)))
1018
(cl-indent::method (symbol-name indent)))
1019
(car indent))))
1020
(if mode-methods
1021
(puthash symbol method mode-methods)
1022
(put symbol 'cl-indent:method method))))
1023
1024
1025
1026
;;; ------------------------------------------------------------
1027
;;;
1028
;;; issue specifications for Common Lisp forms
1029
;;;
1030
1031
(mapcar #'define-cl-indent
1032
'((block 1)
1033
(case (4 &rest (&whole 2 &rest 3)))
1034
(ccase . case) (ecase . case)
1035
(typecase . case) (etypecase . case) (ctypecase . case)
1036
(handler-bind . let)
1037
(handler-case (4 &rest (&whole 2 4 &rest 2)))
1038
(catch 1)
1039
(cond cl-indent:indent-cond)
1040
(defvar (4 2 2))
1041
(defconstant . defvar) (defparameter . defvar)
1042
(defclass (6 6 (&whole 2 &rest 1) &rest 2))
1043
(define-modify-macro
1044
(4 &body))
1045
(defsetf (4 (&whole 4 &rest 1) 4 &body))
1046
(defun (4 (&whole 4 &rest 1) &body))
1047
(defmacro . defun) (define-setf-method . defun) (deftype . defun)
1048
(defgeneric cl-indent:indent-defgeneric)
1049
(defmethod cl-indent:indent-defmethod)
1050
(defstruct ((&whole 4 &rest (&whole 2 &rest 1))
1051
&rest (&whole 2 &rest 1)))
1052
(destructuring-bind
1053
((&whole 6 &rest 1) 4 &body))
1054
(do ((&whole 4 &rest (&whole 1 &rest 2)) ; ((arg step incr))
1055
(&whole 4 &rest 3) ; result: ((condition) (form) ...)
1056
&rest cl-indent:indent-do))
1057
(do* . do)
1058
(do-all-symbols (4 &body))
1059
(do-symbols (4 &body))
1060
(do-external-symbols (4 &body))
1061
(dolist ((&whole 4 2 1) &body))
1062
(dotimes . dolist)
1063
(eval-when 1)
1064
(flet ((&whole 4 &rest (&whole 1 (&whole 4 &rest 1) &body))
1065
&body))
1066
(labels . flet) (macrolet . flet)
1067
(if (&rest 4))
1068
;; FIXME: Which of those do I really want?
1069
;; (lambda ((&whole 4 &rest 1) &body))
1070
(lambda ((&whole 4 &rest 1)
1071
&rest cl-indent:indent-function-lambda-hack))
1072
(let ((&whole 4 &rest (&whole 1 1 2)) &body))
1073
(let* . let) (compiler-let . let)
1074
(locally 1)
1075
(loop cl-indent::indent-loop-macro)
1076
(multiple-value-bind
1077
((&whole 6 &rest 1) 4 &body))
1078
(multiple-value-call
1079
(4 &body))
1080
(multiple-value-list 1)
1081
(multiple-value-prog1 1)
1082
(multiple-value-setq
1083
(4 2))
1084
(print-unreadable-object 1)
1085
;; Combines the worst features of BLOCK, LET and TAGBODY
1086
(prog ((&whole 4 &rest 1) &rest cl-indent:indent-tagbody))
1087
(prog* . prog)
1088
(prog1 1)
1089
(prog2 2)
1090
(progn 0)
1091
(progv (4 4 &body))
1092
(restart-case . handler-case)
1093
(return 0)
1094
(return-from (nil &body))
1095
(tagbody cl-indent:indent-tagbody)
1096
(throw 1)
1097
(unless 1)
1098
(unwind-protect
1099
(5 &body))
1100
(values 0)
1101
(when 1)
1102
(with-accessors (6 4 &body))
1103
(with-compilation-unit (4 &body))
1104
(with-hash-table-iterator (4 &body))
1105
(with-output-to-string (4 &body))
1106
(with-input-from-string . with-output-to-string)
1107
(with-open-file (4 &body))
1108
(with-open-stream . with-open-file)
1109
(with-package-iterator (4 &body))
1110
(with-simple-restart (4 &body))
1111
(with-slots (6 4 &body))))
1112
1113
1114
;;; ======================================================================
1115
;;
1116
;; $ITIlog: cl-indent.el,v $
1117
;; Revision 1.6 1995/09/10 14:13:34 schrod
1118
;; Add aliassing of indentation methods.
1119
;; Discard unused variables. Quiet down the byte-compiler. Discard
1120
;; duplicate indentation specs.
1121
;; `Define-as' specs in #'define-cl-indent uses the mode-specific
1122
;; method table for lookup of the reference symbol's indentation method,
1123
;; if a table was supplied.
1124
;;
1125
;; Revision 1.5 1995/08/14 16:49:05 schrod
1126
;; Provide 'cl-indent, this module may not be required otherwise.
1127
;;
1128
;; Revision 1.4 1995/07/24 18:16:50 schrod
1129
;; Did not work due to spurious closing brace.
1130
;;
1131
;; Revision 1.3 1995/01/17 11:13:25 schrod
1132
;; Add support for mode-specific and local indentation methods. Don't
1133
;; need STIL indentation support any more, that's an own mode now.
1134
;; Provide a load hook to be able to adapt global indentation methods
1135
;; to personal preferences.
1136
;; All form symbols are finally checked for global indentation
1137
;; methods bound to 'lisp-indent-function, for upward compatibility to
1138
;; standard Lisp indentation.
1139
;; Renamed all symbols to start with `cl-indent:'. Private symbols
1140
;; use `::', similar to CL. #'define-cl-indent is an exception, as usual.
1141
;; I hope that the new names are more meaningful, too.
1142
;; Added some pointers to function documentation to the usage
1143
;; comments at the start. Mentioned additional future projects.
1144
;;
1145
;; Revision 1.2 1994/09/05 17:35:47 schrod
1146
;; Added documentation to every function.
1147
;; Added #'cl-indent and #'define-cl-indent as user-level functions.
1148
;; Renamed all functions from lisp-indent-* to cl-indent-* to avoid
1149
;; name clashes with `normal' lisp-mode indentation. In particular,
1150
;; rename #'lisp-indent-259 (what a ridiculous name to use for a
1151
;; function!) to #'cl-indent-by-method.
1152
;; Introduced #'cl-indent-normal to compute the normal (default)
1153
;; indentation, since #'current-column does not always deliver the
1154
;; correct result.
1155
;; Introduced #'get-cl-indent-method to encapsulate the storage of an
1156
;; indentation method. Might want to change this later anyhow, to support
1157
;; mode- and file-specific indentation.
1158
;; Check for a correct method is in an own function now,
1159
;; #'cl-indent-by-method was large enough already.
1160
;; #'lisp-indent-do is never called for the first two elements in a
1161
;; path, this test (and the else form) could be discarded.
1162
;; Add support for more CL constructs (CLOS, CLCS, condition stuff
1163
;; Define STIL constructs, this should be discarded with the
1164
;; introduction of mode-specific indentation methods.
1165
;;
1166
1167
(provide 'slime-indentation)
1168
1169