|
|
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.