|
|
1.1 ! root 1: ;; Lisp mode, and its idiosyncratic commands. ! 2: ;; Copyright (C) 1985 Richard M. Stallman. ! 3: ! 4: ;; This file is part of GNU Emacs. ! 5: ! 6: ;; GNU Emacs is distributed in the hope that it will be useful, ! 7: ;; but WITHOUT ANY WARRANTY. No author or distributor ! 8: ;; accepts responsibility to anyone for the consequences of using it ! 9: ;; or for whether it serves any particular purpose or works at all, ! 10: ;; unless he says so in writing. Refer to the GNU Emacs General Public ! 11: ;; License for full details. ! 12: ! 13: ;; Everyone is granted permission to copy, modify and redistribute ! 14: ;; GNU Emacs, but only under the conditions described in the ! 15: ;; GNU Emacs General Public License. A copy of this license is ! 16: ;; supposed to have been given to you along with GNU Emacs so you ! 17: ;; can know your rights and responsibilities. It should be in a ! 18: ;; file named COPYING. Among other things, the copyright notice ! 19: ;; and this notice must be preserved on all copies. ! 20: ! 21: ! 22: (defvar lisp-mode-syntax-table nil "") ! 23: (defvar lisp-mode-abbrev-table nil "") ! 24: ! 25: (if (not lisp-mode-syntax-table) ! 26: (let ((i 0)) ! 27: (setq lisp-mode-syntax-table (make-syntax-table)) ! 28: (set-syntax-table lisp-mode-syntax-table) ! 29: (while (< i ?0) ! 30: (modify-syntax-entry i "_ ") ! 31: (setq i (1+ i))) ! 32: (setq i (1+ ?9)) ! 33: (while (< i ?A) ! 34: (modify-syntax-entry i "_ ") ! 35: (setq i (1+ i))) ! 36: (setq i (1+ ?Z)) ! 37: (while (< i ?a) ! 38: (modify-syntax-entry i "_ ") ! 39: (setq i (1+ i))) ! 40: (setq i (1+ ?z)) ! 41: (while (< i 128) ! 42: (modify-syntax-entry i "_ ") ! 43: (setq i (1+ i))) ! 44: (modify-syntax-entry ? " ") ! 45: (modify-syntax-entry ?\t " ") ! 46: (modify-syntax-entry ?\n "> ") ! 47: (modify-syntax-entry ?\f "> ") ! 48: (modify-syntax-entry ?\; "< ") ! 49: (modify-syntax-entry ?` "' ") ! 50: (modify-syntax-entry ?' "' ") ! 51: (modify-syntax-entry ?, "' ") ! 52: (modify-syntax-entry ?. "' ") ! 53: (modify-syntax-entry ?# "' ") ! 54: (modify-syntax-entry ?\" "\" ") ! 55: (modify-syntax-entry ?\\ "\\ ") ! 56: (modify-syntax-entry ?\( "() ") ! 57: (modify-syntax-entry ?\) ")( "))) ! 58: ! 59: (define-abbrev-table 'lisp-mode-abbrev-table ()) ! 60: ! 61: (defun lisp-mode-variables () ! 62: (set-syntax-table lisp-mode-syntax-table) ! 63: (setq local-abbrev-table lisp-mode-abbrev-table) ! 64: (make-local-variable 'paragraph-start) ! 65: (setq paragraph-start (concat "^$\\|" page-delimiter)) ! 66: (make-local-variable 'paragraph-separate) ! 67: (setq paragraph-separate paragraph-start) ! 68: (make-local-variable 'indent-line-function) ! 69: (setq indent-line-function 'lisp-indent-line) ! 70: (make-local-variable 'comment-start) ! 71: (setq comment-start ";") ! 72: (make-local-variable 'comment-start-skip) ! 73: (setq comment-start-skip ";+ *") ! 74: (make-local-variable 'comment-column) ! 75: (setq comment-column 40) ! 76: (make-local-variable 'comment-indent-hook) ! 77: (setq comment-indent-hook 'lisp-comment-indent)) ! 78: ! 79: (defun lisp-mode-commands (map) ! 80: (define-key map "\e\C-q" 'indent-sexp) ! 81: (define-key map "\177" 'backward-delete-char-untabify) ! 82: (define-key map "\t" 'lisp-indent-line)) ! 83: ! 84: (defvar emacs-lisp-mode-map (make-sparse-keymap) "") ! 85: (define-key emacs-lisp-mode-map "\e\C-x" 'eval-defun) ! 86: (lisp-mode-commands emacs-lisp-mode-map) ! 87: ! 88: (defun emacs-lisp-mode () ! 89: "Major mode for editing Lisp code to run in Emacs. ! 90: Commands: ! 91: Delete converts tabs to spaces as it moves back. ! 92: Blank lines separate paragraphs. Semicolons start comments. ! 93: \\{emacs-lisp-mode-map} ! 94: Entry to this mode calls the value of emacs-lisp-mode-hook ! 95: if that value is non-nil." ! 96: (interactive) ! 97: (kill-all-local-variables) ! 98: (use-local-map emacs-lisp-mode-map) ! 99: (setq major-mode 'emacs-lisp-mode) ! 100: (setq mode-name "Emacs-Lisp") ! 101: (lisp-mode-variables) ! 102: (run-hooks 'emacs-lisp-mode-hook)) ! 103: ! 104: (defvar lisp-mode-map (make-sparse-keymap)) ! 105: (define-key lisp-mode-map "\e\C-x" 'lisp-send-defun) ! 106: (lisp-mode-commands lisp-mode-map) ! 107: ! 108: (defun lisp-mode () ! 109: "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp. ! 110: Commands: ! 111: Delete converts tabs to spaces as it moves back. ! 112: Blank lines separate paragraphs. Semicolons start comments. ! 113: \\{lisp-mode-map} ! 114: Entry to this mode calls the value of lisp-mode-hook ! 115: if that value is non-nil." ! 116: (interactive) ! 117: (kill-all-local-variables) ! 118: (use-local-map lisp-mode-map) ! 119: (setq major-mode 'lisp-mode) ! 120: (setq mode-name "Lisp") ! 121: (lisp-mode-variables) ! 122: (run-hooks 'lisp-mode-hook)) ! 123: ! 124: ;; This will do unless shell.el is loaded. ! 125: (defun lisp-send-defun nil ! 126: "Send the current defun to the Lisp process made by M-x run-lisp." ! 127: (interactive) ! 128: (error "Process lisp does not exist")) ! 129: ! 130: (defvar lisp-interaction-mode-map (make-sparse-keymap)) ! 131: (lisp-mode-commands lisp-interaction-mode-map) ! 132: (define-key lisp-interaction-mode-map "\e\C-x" 'eval-defun) ! 133: (define-key lisp-interaction-mode-map "\n" 'eval-print-last-sexp) ! 134: ! 135: (defun lisp-interaction-mode () ! 136: "Major mode for typing and evaluating Lisp forms. ! 137: Like Lisp mode except that \\[eval-print-last-sexp] evals the Lisp expression ! 138: before point, and prints its value into the buffer, advancing point. ! 139: ! 140: Commands: ! 141: Delete converts tabs to spaces as it moves back. ! 142: Paragraphs are separated only by blank lines. Semicolons start comments. ! 143: \\{lisp-interaction-mode-map} ! 144: Entry to this mode calls the value of lisp-interaction-mode-hook ! 145: if that value is non-nil." ! 146: (interactive) ! 147: (kill-all-local-variables) ! 148: (use-local-map lisp-interaction-mode-map) ! 149: (setq major-mode 'lisp-interaction-mode) ! 150: (setq mode-name "Lisp Interaction") ! 151: (lisp-mode-variables) ! 152: (run-hooks 'lisp-interaction-mode-hook)) ! 153: ! 154: (defun eval-print-last-sexp (arg) ! 155: "Evaluate sexp before point; print value into current buffer." ! 156: (interactive "P") ! 157: (eval-region ! 158: (let ((stab (syntax-table))) ! 159: (unwind-protect ! 160: (save-excursion ! 161: (set-syntax-table lisp-mode-syntax-table) ! 162: (forward-sexp -1) ! 163: (point)) ! 164: (set-syntax-table stab))) ! 165: (point) ! 166: (current-buffer))) ! 167: ! 168: (defun eval-last-sexp (arg) ! 169: "Evaluate sexp before point; print value in minibuffer. ! 170: With argument, print output into current buffer." ! 171: (interactive "P") ! 172: (eval-region ! 173: (let ((stab (syntax-table))) ! 174: (unwind-protect ! 175: (save-excursion ! 176: (set-syntax-table lisp-mode-syntax-table) ! 177: (forward-sexp -1) ! 178: (point)) ! 179: (set-syntax-table stab))) ! 180: (point) ! 181: (if arg (current-buffer) t))) ! 182: ! 183: (defun eval-defun (arg) ! 184: "Evaluate defun that point is in or before. ! 185: Print value in minibuffer. ! 186: With argument, insert value in current buffer after the defun." ! 187: (interactive "P") ! 188: (save-excursion ! 189: (end-of-defun) ! 190: (let ((end (point))) ! 191: (beginning-of-defun) ! 192: (eval-region (point) end ! 193: (if arg (current-buffer) t))))) ! 194: ! 195: (defun lisp-comment-indent () ! 196: (if (looking-at ";;;") ! 197: (current-column) ! 198: (if (looking-at ";;") ! 199: (let ((tem (calculate-lisp-indent))) ! 200: (if (listp tem) (car tem) tem)) ! 201: (skip-chars-backward " \t") ! 202: (max (if (bolp) 0 (1+ (current-column))) ! 203: comment-column)))) ! 204: ! 205: (defconst lisp-indent-offset nil "") ! 206: (defconst lisp-indent-hook 'lisp-indent-hook "") ! 207: ! 208: (defun lisp-indent-line (&optional whole-exp) ! 209: "Indent current line as Lisp code. ! 210: With argument, indent any additional lines of the same expression ! 211: rigidly along with this one." ! 212: (interactive "P") ! 213: (let ((indent (calculate-lisp-indent)) shift-amt beg end ! 214: (pos (- (point-max) (point)))) ! 215: (beginning-of-line) ! 216: (setq beg (point)) ! 217: (skip-chars-forward " \t") ! 218: (if (looking-at "[ \t]*;;;") ! 219: ;; Don't alter indentation of a ;;; comment line. ! 220: nil ! 221: (if (listp indent) (setq indent (car indent))) ! 222: (setq shift-amt (- indent (current-column))) ! 223: (if (zerop shift-amt) ! 224: nil ! 225: (delete-region beg (point)) ! 226: (indent-to indent)) ! 227: ;; If initial point was within line's indentation, ! 228: ;; position after the indentation. Else stay at same point in text. ! 229: (if (> (- (point-max) pos) (point)) ! 230: (goto-char (- (point-max) pos))) ! 231: ;; If desired, shift remaining lines of expression the same amount. ! 232: (and whole-exp (not (zerop shift-amt)) ! 233: (save-excursion ! 234: (goto-char beg) ! 235: (forward-sexp 1) ! 236: (setq end (point)) ! 237: (goto-char beg) ! 238: (forward-line 1) ! 239: (setq beg (point)) ! 240: (> end beg)) ! 241: (indent-code-rigidly beg end shift-amt))))) ! 242: ! 243: (defun calculate-lisp-indent (&optional parse-start) ! 244: "Return appropriate indentation for current line as Lisp code. ! 245: In usual case returns an integer: the column to indent to. ! 246: Can instead return a list, whose car is the column to indent to. ! 247: This means that following lines at the same level of indentation ! 248: should not necessarily be indented the same way. ! 249: The second element of the list is the buffer position ! 250: of the start of the containing expression." ! 251: (save-excursion ! 252: (beginning-of-line) ! 253: (let ((indent-point (point)) state paren-depth desired-indent (retry t) ! 254: last-sexp containing-sexp) ! 255: (if parse-start ! 256: (goto-char parse-start) ! 257: (beginning-of-defun)) ! 258: ;; Find outermost containing sexp ! 259: (while (< (point) indent-point) ! 260: (setq state (parse-partial-sexp (point) indent-point 0))) ! 261: ;; Find innermost containing sexp ! 262: (while (and retry (setq paren-depth (car state)) (> paren-depth 0)) ! 263: (setq retry nil) ! 264: (setq last-sexp (nth 2 state)) ! 265: (setq containing-sexp (car (cdr state))) ! 266: ;; Position following last unclosed open. ! 267: (goto-char (1+ containing-sexp)) ! 268: ;; Is there a complete sexp since then? ! 269: (if (and last-sexp (> last-sexp (point))) ! 270: ;; Yes, but is there a containing sexp after that? ! 271: (let ((peek (parse-partial-sexp last-sexp indent-point 0))) ! 272: (if (setq retry (car (cdr peek))) (setq state peek)))) ! 273: (if (not retry) ! 274: ;; Innermost containing sexp found ! 275: (progn ! 276: (goto-char (1+ containing-sexp)) ! 277: (if (not last-sexp) ! 278: ;; indent-point immediately follows open paren. ! 279: ;; Don't call hook. ! 280: (setq desired-indent (current-column)) ! 281: ;; Move to first sexp after containing open paren ! 282: (parse-partial-sexp (point) last-sexp 0 t) ! 283: (cond ! 284: ((looking-at "\\s(") ! 285: ;; Looking at a list. Don't call hook. ! 286: (if (not (> (save-excursion (forward-line 1) (point)) ! 287: last-sexp)) ! 288: (progn (goto-char last-sexp) ! 289: (beginning-of-line) ! 290: (parse-partial-sexp (point) last-sexp 0 t))) ! 291: ;; Indent under the list or under the first sexp on the ! 292: ;; same line as last-sexp. Note that first thing on that ! 293: ;; line has to be complete sexp since we are inside the ! 294: ;; innermost containing sexp. ! 295: (backward-prefix-chars) ! 296: (setq desired-indent (current-column))) ! 297: ((> (save-excursion (forward-line 1) (point)) ! 298: last-sexp) ! 299: ;; Last sexp is on same line as containing sexp. ! 300: ;; It's almost certainly a function call. ! 301: (parse-partial-sexp (point) last-sexp 0 t) ! 302: (if (/= (point) last-sexp) ! 303: ;; Indent beneath first argument or, if only one sexp ! 304: ;; on line, indent beneath that. ! 305: (progn (forward-sexp 1) ! 306: (parse-partial-sexp (point) last-sexp 0 t))) ! 307: (backward-prefix-chars)) ! 308: (t ! 309: ;; Indent beneath first sexp on same line as last-sexp. ! 310: ;; Again, it's almost certainly a function call. ! 311: (goto-char last-sexp) ! 312: (beginning-of-line) ! 313: (parse-partial-sexp (point) last-sexp 0 t) ! 314: (backward-prefix-chars))))))) ! 315: ;; Point is at the point to indent under unless we are inside a string. ! 316: ;; Call indentation hook except when overriden by lisp-indent-offset ! 317: ;; or if the desired indentation has already been computed. ! 318: (cond ((car (nthcdr 3 state)) ! 319: ;; Inside a string, don't change indentation. ! 320: (goto-char indent-point) ! 321: (skip-chars-forward " \t") ! 322: (setq desired-indent (current-column))) ! 323: ((and (integerp lisp-indent-offset) containing-sexp) ! 324: ;; Indent by constant offset ! 325: (goto-char containing-sexp) ! 326: (setq desired-indent (+ lisp-indent-offset (current-column)))) ! 327: ((not (or desired-indent ! 328: (and (boundp 'lisp-indent-hook) ! 329: lisp-indent-hook ! 330: (not retry) ! 331: (setq desired-indent ! 332: (funcall lisp-indent-hook indent-point state))))) ! 333: ;; Use default indentation if not computed yet ! 334: (setq desired-indent (current-column)))) ! 335: desired-indent))) ! 336: ! 337: (defun lisp-indent-hook (indent-point state) ! 338: (let ((normal-indent (current-column))) ! 339: (save-excursion ! 340: (goto-char (1+ (car (cdr state)))) ! 341: (re-search-forward "\\sw\\|\\s_") ! 342: (if (/= (point) (car (cdr state))) ! 343: (let ((function (buffer-substring (progn (forward-char -1) (point)) ! 344: (progn (forward-sexp 1) (point)))) ! 345: method) ! 346: (setq method (get (intern-soft function) 'lisp-indent-hook)) ! 347: (if (or (eq method 'defun) ! 348: (and (null method) ! 349: (> (length function) 3) ! 350: (string-equal (substring function 0 3) "def"))) ! 351: (lisp-indent-defform state indent-point) ! 352: (if (integerp method) ! 353: (lisp-indent-specform method state indent-point) ! 354: (if method ! 355: (funcall method state indent-point))))))))) ! 356: ! 357: (defconst lisp-body-indent 2 "") ! 358: ! 359: (defun lisp-indent-specform (count state indent-point) ! 360: (let ((containing-form-start (car (cdr state))) (i count) ! 361: body-indent containing-form-column) ! 362: ;; Move to the start of containing form, calculate indentation ! 363: ;; to use for non-distinguished forms (> count), and move past the ! 364: ;; function symbol. lisp-indent-hook guarantees that there is at ! 365: ;; least one word or symbol character following open paren of containing ! 366: ;; form. ! 367: (goto-char containing-form-start) ! 368: (setq containing-form-column (current-column)) ! 369: (setq body-indent (+ lisp-body-indent containing-form-column)) ! 370: (forward-char 1) ! 371: (forward-sexp 1) ! 372: ;; Now find the start of the last form. ! 373: (parse-partial-sexp (point) indent-point 1 t) ! 374: (while (and (< (point) indent-point) ! 375: (condition-case nil ! 376: (progn ! 377: (setq count (1- count)) ! 378: (forward-sexp 1) ! 379: (parse-partial-sexp (point) indent-point 1 t)) ! 380: (error nil)))) ! 381: ;; Point is sitting on first character of last (or count) sexp. ! 382: (if (> count 0) ! 383: ;; A distinguished form. If it is the first or second form use double ! 384: ;; lisp-body-indent, else normal indent. With lisp-body-indent bound ! 385: ;; to 2 (the default), this just happens to work the same with if as ! 386: ;; the older code, but it makes unwind-protect, condition-case, ! 387: ;; with-output-to-temp-buffer, et. al. much more tasteful. The older, ! 388: ;; less hacked, behavior can be obtained by replacing below with ! 389: ;; (list normal-indent containing-form-start). ! 390: (if (<= (- i count) 1) ! 391: (list (+ containing-form-column (* 2 lisp-body-indent)) ! 392: containing-form-start) ! 393: (list normal-indent containing-form-start)) ! 394: ;; A non-distinguished form. Use body-indent if there are no distinguished ! 395: ;; forms and this is the first undistinguished form, or if this is the ! 396: ;; first undistinguished form and the preceding distinguished form has ! 397: ;; indentation at least as great as body-indent. ! 398: (if (or (and (= i 0) (= count 0)) ! 399: (and (= count 0) (<= body-indent normal-indent))) ! 400: body-indent ! 401: normal-indent)))) ! 402: ! 403: (defun lisp-indent-defform (state indent-point) ! 404: (goto-char (car (cdr state))) ! 405: (forward-line 1) ! 406: (if (> (point) (car (cdr (cdr state)))) ! 407: (progn ! 408: (goto-char (car (cdr state))) ! 409: (+ lisp-body-indent (current-column))))) ! 410: ! 411: ;; (put 'progn 'lisp-indent-hook 0), say, causes progn to be indented ! 412: ;; like defun if the first form is placed on the next line, otherwise ! 413: ;; it is indented like any other form (i.e. forms line up under first). ! 414: ! 415: (put 'lambda 'lisp-indent-hook 'defun) ! 416: (put 'progn 'lisp-indent-hook 0) ! 417: (put 'prog1 'lisp-indent-hook 1) ! 418: (put 'save-excursion 'lisp-indent-hook 0) ! 419: (put 'save-window-excursion 'lisp-indent-hook 0) ! 420: (put 'save-restriction 'lisp-indent-hook 0) ! 421: (put 'let 'lisp-indent-hook 1) ! 422: (put 'let* 'lisp-indent-hook 1) ! 423: (put 'while 'lisp-indent-hook 1) ! 424: (put 'if 'lisp-indent-hook 2) ! 425: (put 'catch 'lisp-indent-hook 1) ! 426: (put 'condition-case 'lisp-indent-hook 2) ! 427: (put 'unwind-protect 'lisp-indent-hook 1) ! 428: (put 'with-output-to-temp-buffer 'lisp-indent-hook 1) ! 429: ! 430: (defun indent-sexp () ! 431: "Indent each line of the list starting just after point." ! 432: (interactive) ! 433: (let ((indent-stack (list nil)) (next-depth 0) bol ! 434: outer-loop-done inner-loop-done state this-indent) ! 435: (save-excursion (forward-sexp 1)) ! 436: (save-excursion ! 437: (setq outer-loop-done nil) ! 438: (while (not outer-loop-done) ! 439: (setq last-depth next-depth ! 440: innerloop-done nil) ! 441: (while (and (not innerloop-done) ! 442: (not (setq outer-loop-done (eobp)))) ! 443: (setq state (parse-partial-sexp (point) (progn (end-of-line) (point)) ! 444: nil nil state)) ! 445: (setq next-depth (car state)) ! 446: (if (car (nthcdr 4 state)) ! 447: (progn (indent-for-comment) ! 448: (end-of-line) ! 449: (setcar (nthcdr 4 state) nil))) ! 450: (if (car (nthcdr 3 state)) ! 451: (progn ! 452: (forward-line 1) ! 453: (setcar (nthcdr 5 state) nil)) ! 454: (setq innerloop-done t))) ! 455: (if (setq outer-loop-done (<= next-depth 0)) ! 456: nil ! 457: (while (> last-depth next-depth) ! 458: (setq indent-stack (cdr indent-stack) ! 459: last-depth (1- last-depth))) ! 460: (while (< last-depth next-depth) ! 461: (setq indent-stack (cons nil indent-stack) ! 462: last-depth (1+ last-depth))) ! 463: (forward-line 1) ! 464: (setq bol (point)) ! 465: (skip-chars-forward " \t") ! 466: (if (or (eobp) (looking-at "[;\n]")) ! 467: nil ! 468: (if (and (car indent-stack) ! 469: (>= (car indent-stack) 0)) ! 470: (setq this-indent (car indent-stack)) ! 471: (let ((val (calculate-lisp-indent ! 472: (if (car indent-stack) (- (car indent-stack)))))) ! 473: (if (integerp val) ! 474: (setcar indent-stack ! 475: (setq this-indent val)) ! 476: (setcar indent-stack (- (car (cdr val)))) ! 477: (setq this-indent (car val))))) ! 478: (if (/= (current-column) this-indent) ! 479: (progn (delete-region bol (point)) ! 480: (indent-to this-indent))))))))) ! 481: ! 482: (defun indent-code-rigidly (start end arg &optional nochange-regexp) ! 483: "Indent all lines of code, starting in the region, sideways by ARG columns. ! 484: Does not affect lines starting inside comments or strings, ! 485: assuming that the start of the region is not inside them. ! 486: Called from a program, takes args START, END, COLUMNS and NOCHANGE-REGEXP. ! 487: The last is a regexp which, if matched at the beginning of a line, ! 488: means don't indent that line." ! 489: (interactive "r\np") ! 490: (let (state) ! 491: (save-excursion ! 492: (goto-char end) ! 493: (setq end (point-marker)) ! 494: (goto-char start) ! 495: (or (bolp) ! 496: (setq state (parse-partial-sexp (point) ! 497: (progn ! 498: (forward-line 1) (point)) ! 499: nil nil state))) ! 500: (while (< (point) end) ! 501: (or (car (nthcdr 3 state)) ! 502: (and nochange-regexp ! 503: (looking-at nochange-regexp)) ! 504: ;; If line does not start in string, indent it ! 505: (let ((indent (current-indentation))) ! 506: (delete-region (point) (progn (skip-chars-forward " \t") (point))) ! 507: (or (eolp) ! 508: (indent-to (max 0 (+ indent arg)) 0)))) ! 509: (setq state (parse-partial-sexp (point) ! 510: (progn ! 511: (forward-line 1) (point)) ! 512: nil nil state)))))) ! 513:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.