| 1 | ;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands. |
| 2 | |
| 3 | ;; Copyright (C) 1985 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Maintainer: FSF |
| 6 | ;; Keywords: lisp, languages |
| 7 | |
| 8 | ;; This file is part of GNU Emacs. |
| 9 | |
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
| 11 | ;; it under the terms of the GNU General Public License as published by |
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) |
| 13 | ;; any later version. |
| 14 | |
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | ;; GNU General Public License for more details. |
| 19 | |
| 20 | ;; You should have received a copy of the GNU General Public License |
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to |
| 22 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | |
| 26 | ;; The base major mode for editing Lisp code (used also for Emacs Lisp). |
| 27 | ;; This mode is documented in the Emacs manual |
| 28 | |
| 29 | ;;; Code: |
| 30 | |
| 31 | (defvar lisp-mode-syntax-table nil "") |
| 32 | (defvar emacs-lisp-mode-syntax-table nil "") |
| 33 | (defvar lisp-mode-abbrev-table nil "") |
| 34 | |
| 35 | (if (not emacs-lisp-mode-syntax-table) |
| 36 | (let ((i 0)) |
| 37 | (setq emacs-lisp-mode-syntax-table (make-syntax-table)) |
| 38 | (while (< i ?0) |
| 39 | (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table) |
| 40 | (setq i (1+ i))) |
| 41 | (setq i (1+ ?9)) |
| 42 | (while (< i ?A) |
| 43 | (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table) |
| 44 | (setq i (1+ i))) |
| 45 | (setq i (1+ ?Z)) |
| 46 | (while (< i ?a) |
| 47 | (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table) |
| 48 | (setq i (1+ i))) |
| 49 | (setq i (1+ ?z)) |
| 50 | (while (< i 128) |
| 51 | (modify-syntax-entry i "_ " emacs-lisp-mode-syntax-table) |
| 52 | (setq i (1+ i))) |
| 53 | (modify-syntax-entry ? " " emacs-lisp-mode-syntax-table) |
| 54 | (modify-syntax-entry ?\t " " emacs-lisp-mode-syntax-table) |
| 55 | (modify-syntax-entry ?\n "> " emacs-lisp-mode-syntax-table) |
| 56 | ;; Give CR the same syntax as newline, for selective-display. |
| 57 | (modify-syntax-entry ?\^m "> " emacs-lisp-mode-syntax-table) |
| 58 | (modify-syntax-entry ?\; "< " emacs-lisp-mode-syntax-table) |
| 59 | (modify-syntax-entry ?` "' " emacs-lisp-mode-syntax-table) |
| 60 | (modify-syntax-entry ?' "' " emacs-lisp-mode-syntax-table) |
| 61 | (modify-syntax-entry ?, "' " emacs-lisp-mode-syntax-table) |
| 62 | ;; Used to be singlequote; changed for flonums. |
| 63 | (modify-syntax-entry ?. "_ " emacs-lisp-mode-syntax-table) |
| 64 | (modify-syntax-entry ?# "' " emacs-lisp-mode-syntax-table) |
| 65 | (modify-syntax-entry ?\" "\" " emacs-lisp-mode-syntax-table) |
| 66 | (modify-syntax-entry ?\\ "\\ " emacs-lisp-mode-syntax-table) |
| 67 | (modify-syntax-entry ?\( "() " emacs-lisp-mode-syntax-table) |
| 68 | (modify-syntax-entry ?\) ")( " emacs-lisp-mode-syntax-table) |
| 69 | (modify-syntax-entry ?\[ "(] " emacs-lisp-mode-syntax-table) |
| 70 | (modify-syntax-entry ?\] ")[ " emacs-lisp-mode-syntax-table))) |
| 71 | |
| 72 | (if (not lisp-mode-syntax-table) |
| 73 | (progn (setq lisp-mode-syntax-table |
| 74 | (copy-syntax-table emacs-lisp-mode-syntax-table)) |
| 75 | (modify-syntax-entry ?\| "\" " lisp-mode-syntax-table) |
| 76 | (modify-syntax-entry ?\[ "_ " lisp-mode-syntax-table) |
| 77 | (modify-syntax-entry ?\] "_ " lisp-mode-syntax-table))) |
| 78 | |
| 79 | (define-abbrev-table 'lisp-mode-abbrev-table ()) |
| 80 | |
| 81 | (defun lisp-mode-variables (lisp-syntax) |
| 82 | (cond (lisp-syntax |
| 83 | (set-syntax-table lisp-mode-syntax-table))) |
| 84 | (setq local-abbrev-table lisp-mode-abbrev-table) |
| 85 | (make-local-variable 'paragraph-start) |
| 86 | (setq paragraph-start (concat "^$\\|" page-delimiter)) |
| 87 | (make-local-variable 'paragraph-separate) |
| 88 | (setq paragraph-separate paragraph-start) |
| 89 | (make-local-variable 'paragraph-ignore-fill-prefix) |
| 90 | (setq paragraph-ignore-fill-prefix t) |
| 91 | (make-local-variable 'indent-line-function) |
| 92 | (setq indent-line-function 'lisp-indent-line) |
| 93 | (make-local-variable 'indent-region-function) |
| 94 | (setq indent-region-function 'lisp-indent-region) |
| 95 | (make-local-variable 'parse-sexp-ignore-comments) |
| 96 | (setq parse-sexp-ignore-comments t) |
| 97 | (make-local-variable 'outline-regexp) |
| 98 | (setq outline-regexp ";;; \\|(....") |
| 99 | (make-local-variable 'comment-start) |
| 100 | (setq comment-start ";") |
| 101 | (make-local-variable 'comment-start-skip) |
| 102 | (setq comment-start-skip ";+ *") |
| 103 | (make-local-variable 'comment-column) |
| 104 | (setq comment-column 40) |
| 105 | (make-local-variable 'comment-indent-function) |
| 106 | (setq comment-indent-function 'lisp-comment-indent)) |
| 107 | \f |
| 108 | (defvar shared-lisp-mode-map () |
| 109 | "Keymap for commands shared by all sorts of Lisp modes.") |
| 110 | |
| 111 | (if shared-lisp-mode-map |
| 112 | () |
| 113 | (setq shared-lisp-mode-map (make-sparse-keymap)) |
| 114 | (define-key shared-lisp-mode-map "\e\C-q" 'indent-sexp) |
| 115 | (define-key shared-lisp-mode-map "\M-q" 'lisp-fill-paragraph) |
| 116 | (define-key shared-lisp-mode-map "\177" 'backward-delete-char-untabify) |
| 117 | (define-key shared-lisp-mode-map "\t" 'lisp-indent-line)) |
| 118 | |
| 119 | (defvar emacs-lisp-mode-map () |
| 120 | "Keymap for Emacs Lisp mode. |
| 121 | All commands in shared-lisp-mode-map are inherited by this map.") |
| 122 | |
| 123 | (if emacs-lisp-mode-map |
| 124 | () |
| 125 | (setq emacs-lisp-mode-map |
| 126 | (nconc (make-sparse-keymap) shared-lisp-mode-map)) |
| 127 | (define-key emacs-lisp-mode-map "\e\t" 'lisp-complete-symbol) |
| 128 | (define-key emacs-lisp-mode-map "\e\C-x" 'eval-defun)) |
| 129 | |
| 130 | (defun emacs-lisp-mode () |
| 131 | "Major mode for editing Lisp code to run in Emacs. |
| 132 | Commands: |
| 133 | Delete converts tabs to spaces as it moves back. |
| 134 | Blank lines separate paragraphs. Semicolons start comments. |
| 135 | \\{emacs-lisp-mode-map} |
| 136 | Entry to this mode calls the value of `emacs-lisp-mode-hook' |
| 137 | if that value is non-nil." |
| 138 | (interactive) |
| 139 | (kill-all-local-variables) |
| 140 | (use-local-map emacs-lisp-mode-map) |
| 141 | (set-syntax-table emacs-lisp-mode-syntax-table) |
| 142 | (setq major-mode 'emacs-lisp-mode) |
| 143 | (setq mode-name "Emacs-Lisp") |
| 144 | (lisp-mode-variables nil) |
| 145 | (run-hooks 'emacs-lisp-mode-hook)) |
| 146 | |
| 147 | (defvar lisp-mode-map () |
| 148 | "Keymap for ordinary Lisp mode. |
| 149 | All commands in `shared-lisp-mode-map' are inherited by this map.") |
| 150 | |
| 151 | (if lisp-mode-map |
| 152 | () |
| 153 | (setq lisp-mode-map |
| 154 | (nconc (make-sparse-keymap) shared-lisp-mode-map)) |
| 155 | (define-key lisp-mode-map "\e\C-x" 'lisp-eval-defun) |
| 156 | (define-key lisp-mode-map "\C-c\C-z" 'run-lisp)) |
| 157 | |
| 158 | (defun lisp-mode () |
| 159 | "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp. |
| 160 | Commands: |
| 161 | Delete converts tabs to spaces as it moves back. |
| 162 | Blank lines separate paragraphs. Semicolons start comments. |
| 163 | \\{lisp-mode-map} |
| 164 | Note that `run-lisp' may be used either to start an inferior Lisp job |
| 165 | or to switch back to an existing one. |
| 166 | |
| 167 | Entry to this mode calls the value of `lisp-mode-hook' |
| 168 | if that value is non-nil." |
| 169 | (interactive) |
| 170 | (kill-all-local-variables) |
| 171 | (use-local-map lisp-mode-map) |
| 172 | (setq major-mode 'lisp-mode) |
| 173 | (setq mode-name "Lisp") |
| 174 | (lisp-mode-variables t) |
| 175 | (set-syntax-table lisp-mode-syntax-table) |
| 176 | (run-hooks 'lisp-mode-hook)) |
| 177 | |
| 178 | ;; This will do unless shell.el is loaded. |
| 179 | (defun lisp-eval-defun nil |
| 180 | "Send the current defun to the Lisp process made by \\[run-lisp]." |
| 181 | (interactive) |
| 182 | (error "Process lisp does not exist")) |
| 183 | |
| 184 | (defvar lisp-interaction-mode-map () |
| 185 | "Keymap for Lisp Interaction moe. |
| 186 | All commands in `shared-lisp-mode-map' are inherited by this map.") |
| 187 | |
| 188 | (if lisp-interaction-mode-map |
| 189 | () |
| 190 | (setq lisp-interaction-mode-map |
| 191 | (nconc (make-sparse-keymap) shared-lisp-mode-map)) |
| 192 | (define-key lisp-interaction-mode-map "\e\C-x" 'eval-defun) |
| 193 | (define-key lisp-interaction-mode-map "\e\t" 'lisp-complete-symbol) |
| 194 | (define-key lisp-interaction-mode-map "\n" 'eval-print-last-sexp)) |
| 195 | |
| 196 | (defun lisp-interaction-mode () |
| 197 | "Major mode for typing and evaluating Lisp forms. |
| 198 | Like Lisp mode except that \\[eval-print-last-sexp] evals the Lisp expression |
| 199 | before point, and prints its value into the buffer, advancing point. |
| 200 | |
| 201 | Commands: |
| 202 | Delete converts tabs to spaces as it moves back. |
| 203 | Paragraphs are separated only by blank lines. |
| 204 | Semicolons start comments. |
| 205 | \\{lisp-interaction-mode-map} |
| 206 | Entry to this mode calls the value of `lisp-interaction-mode-hook' |
| 207 | if that value is non-nil." |
| 208 | (interactive) |
| 209 | (kill-all-local-variables) |
| 210 | (use-local-map lisp-interaction-mode-map) |
| 211 | (setq major-mode 'lisp-interaction-mode) |
| 212 | (setq mode-name "Lisp Interaction") |
| 213 | (set-syntax-table emacs-lisp-mode-syntax-table) |
| 214 | (lisp-mode-variables nil) |
| 215 | (run-hooks 'lisp-interaction-mode-hook)) |
| 216 | |
| 217 | (defun eval-print-last-sexp () |
| 218 | "Evaluate sexp before point; print value into current buffer." |
| 219 | (interactive) |
| 220 | (let ((standard-output (current-buffer))) |
| 221 | (terpri) |
| 222 | (eval-last-sexp t) |
| 223 | (terpri))) |
| 224 | \f |
| 225 | (defun eval-last-sexp (eval-last-sexp-arg-internal) |
| 226 | "Evaluate sexp before point; print value in minibuffer. |
| 227 | With argument, print output into current buffer." |
| 228 | (interactive "P") |
| 229 | (let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t)) |
| 230 | (opoint (point))) |
| 231 | (prin1 (let ((stab (syntax-table))) |
| 232 | (eval (unwind-protect |
| 233 | (save-excursion |
| 234 | (set-syntax-table emacs-lisp-mode-syntax-table) |
| 235 | (forward-sexp -1) |
| 236 | (save-restriction |
| 237 | (narrow-to-region (point-min) opoint) |
| 238 | (read (current-buffer)))) |
| 239 | (set-syntax-table stab))))))) |
| 240 | |
| 241 | (defun eval-defun (eval-defun-arg-internal) |
| 242 | "Evaluate defun that point is in or before. |
| 243 | Print value in minibuffer. |
| 244 | With argument, insert value in current buffer after the defun." |
| 245 | (interactive "P") |
| 246 | (let ((standard-output (if eval-defun-arg-internal (current-buffer) t))) |
| 247 | (prin1 (eval (save-excursion |
| 248 | (end-of-defun) |
| 249 | (beginning-of-defun) |
| 250 | (read (current-buffer))))))) |
| 251 | \f |
| 252 | (defun lisp-comment-indent () |
| 253 | (if (looking-at "\\s<\\s<\\s<") |
| 254 | (current-column) |
| 255 | (if (looking-at "\\s<\\s<") |
| 256 | (let ((tem (calculate-lisp-indent))) |
| 257 | (if (listp tem) (car tem) tem)) |
| 258 | (skip-chars-backward " \t") |
| 259 | (max (if (bolp) 0 (1+ (current-column))) |
| 260 | comment-column)))) |
| 261 | |
| 262 | (defconst lisp-indent-offset nil "") |
| 263 | (defconst lisp-indent-function 'lisp-indent-function "") |
| 264 | |
| 265 | (defun lisp-indent-line (&optional whole-exp) |
| 266 | "Indent current line as Lisp code. |
| 267 | With argument, indent any additional lines of the same expression |
| 268 | rigidly along with this one." |
| 269 | (interactive "P") |
| 270 | (let ((indent (calculate-lisp-indent)) shift-amt beg end |
| 271 | (pos (- (point-max) (point)))) |
| 272 | (beginning-of-line) |
| 273 | (setq beg (point)) |
| 274 | (skip-chars-forward " \t") |
| 275 | (if (looking-at "\\s<\\s<\\s<") |
| 276 | ;; Don't alter indentation of a ;;; comment line. |
| 277 | (goto-char (- (point-max) pos)) |
| 278 | (if (and (looking-at "\\s<") (not (looking-at "\\s<\\s<"))) |
| 279 | ;; Single-semicolon comment lines should be indented |
| 280 | ;; as comment lines, not as code. |
| 281 | (progn (indent-for-comment) (forward-char -1)) |
| 282 | (if (listp indent) (setq indent (car indent))) |
| 283 | (setq shift-amt (- indent (current-column))) |
| 284 | (if (zerop shift-amt) |
| 285 | nil |
| 286 | (delete-region beg (point)) |
| 287 | (indent-to indent))) |
| 288 | ;; If initial point was within line's indentation, |
| 289 | ;; position after the indentation. Else stay at same point in text. |
| 290 | (if (> (- (point-max) pos) (point)) |
| 291 | (goto-char (- (point-max) pos))) |
| 292 | ;; If desired, shift remaining lines of expression the same amount. |
| 293 | (and whole-exp (not (zerop shift-amt)) |
| 294 | (save-excursion |
| 295 | (goto-char beg) |
| 296 | (forward-sexp 1) |
| 297 | (setq end (point)) |
| 298 | (goto-char beg) |
| 299 | (forward-line 1) |
| 300 | (setq beg (point)) |
| 301 | (> end beg)) |
| 302 | (indent-code-rigidly beg end shift-amt))))) |
| 303 | |
| 304 | (defvar calculate-lisp-indent-last-sexp) |
| 305 | |
| 306 | (defun calculate-lisp-indent (&optional parse-start) |
| 307 | "Return appropriate indentation for current line as Lisp code. |
| 308 | In usual case returns an integer: the column to indent to. |
| 309 | Can instead return a list, whose car is the column to indent to. |
| 310 | This means that following lines at the same level of indentation |
| 311 | should not necessarily be indented the same way. |
| 312 | The second element of the list is the buffer position |
| 313 | of the start of the containing expression." |
| 314 | (save-excursion |
| 315 | (beginning-of-line) |
| 316 | (let ((indent-point (point)) |
| 317 | state paren-depth |
| 318 | ;; setting this to a number inhibits calling hook |
| 319 | (desired-indent nil) |
| 320 | (retry t) |
| 321 | calculate-lisp-indent-last-sexp containing-sexp) |
| 322 | (if parse-start |
| 323 | (goto-char parse-start) |
| 324 | (beginning-of-defun)) |
| 325 | ;; Find outermost containing sexp |
| 326 | (while (< (point) indent-point) |
| 327 | (setq state (parse-partial-sexp (point) indent-point 0))) |
| 328 | ;; Find innermost containing sexp |
| 329 | (while (and retry |
| 330 | state |
| 331 | (> (setq paren-depth (elt state 0)) 0)) |
| 332 | (setq retry nil) |
| 333 | (setq calculate-lisp-indent-last-sexp (elt state 2)) |
| 334 | (setq containing-sexp (elt state 1)) |
| 335 | ;; Position following last unclosed open. |
| 336 | (goto-char (1+ containing-sexp)) |
| 337 | ;; Is there a complete sexp since then? |
| 338 | (if (and calculate-lisp-indent-last-sexp |
| 339 | (> calculate-lisp-indent-last-sexp (point))) |
| 340 | ;; Yes, but is there a containing sexp after that? |
| 341 | (let ((peek (parse-partial-sexp calculate-lisp-indent-last-sexp |
| 342 | indent-point 0))) |
| 343 | (if (setq retry (car (cdr peek))) (setq state peek))))) |
| 344 | (if retry |
| 345 | nil |
| 346 | ;; Innermost containing sexp found |
| 347 | (goto-char (1+ containing-sexp)) |
| 348 | (if (not calculate-lisp-indent-last-sexp) |
| 349 | ;; indent-point immediately follows open paren. |
| 350 | ;; Don't call hook. |
| 351 | (setq desired-indent (current-column)) |
| 352 | ;; Find the start of first element of containing sexp. |
| 353 | (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) |
| 354 | (cond ((looking-at "\\s(") |
| 355 | ;; First element of containing sexp is a list. |
| 356 | ;; Indent under that list. |
| 357 | ) |
| 358 | ((> (save-excursion (forward-line 1) (point)) |
| 359 | calculate-lisp-indent-last-sexp) |
| 360 | ;; This is the first line to start within the containing sexp. |
| 361 | ;; It's almost certainly a function call. |
| 362 | (if (= (point) calculate-lisp-indent-last-sexp) |
| 363 | ;; Containing sexp has nothing before this line |
| 364 | ;; except the first element. Indent under that element. |
| 365 | nil |
| 366 | ;; Skip the first element, find start of second (the first |
| 367 | ;; argument of the function call) and indent under. |
| 368 | (progn (forward-sexp 1) |
| 369 | (parse-partial-sexp (point) |
| 370 | calculate-lisp-indent-last-sexp |
| 371 | 0 t))) |
| 372 | (backward-prefix-chars)) |
| 373 | (t |
| 374 | ;; Indent beneath first sexp on same line as |
| 375 | ;; calculate-lisp-indent-last-sexp. Again, it's |
| 376 | ;; almost certainly a function call. |
| 377 | (goto-char calculate-lisp-indent-last-sexp) |
| 378 | (beginning-of-line) |
| 379 | (parse-partial-sexp (point) calculate-lisp-indent-last-sexp |
| 380 | 0 t) |
| 381 | (backward-prefix-chars))))) |
| 382 | ;; Point is at the point to indent under unless we are inside a string. |
| 383 | ;; Call indentation hook except when overridden by lisp-indent-offset |
| 384 | ;; or if the desired indentation has already been computed. |
| 385 | (let ((normal-indent (current-column))) |
| 386 | (cond ((elt state 3) |
| 387 | ;; Inside a string, don't change indentation. |
| 388 | (goto-char indent-point) |
| 389 | (skip-chars-forward " \t") |
| 390 | (current-column)) |
| 391 | ((and (integerp lisp-indent-offset) containing-sexp) |
| 392 | ;; Indent by constant offset |
| 393 | (goto-char containing-sexp) |
| 394 | (+ (current-column) lisp-indent-offset)) |
| 395 | (desired-indent) |
| 396 | ((and (boundp 'lisp-indent-function) |
| 397 | lisp-indent-function |
| 398 | (not retry)) |
| 399 | (or (funcall lisp-indent-function indent-point state) |
| 400 | normal-indent)) |
| 401 | (t |
| 402 | normal-indent)))))) |
| 403 | |
| 404 | (defun lisp-indent-function (indent-point state) |
| 405 | (let ((normal-indent (current-column))) |
| 406 | (goto-char (1+ (elt state 1))) |
| 407 | (parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t) |
| 408 | (if (and (elt state 2) |
| 409 | (not (looking-at "\\sw\\|\\s_"))) |
| 410 | ;; car of form doesn't seem to be a a symbol |
| 411 | (progn |
| 412 | (if (not (> (save-excursion (forward-line 1) (point)) |
| 413 | calculate-lisp-indent-last-sexp)) |
| 414 | (progn (goto-char calculate-lisp-indent-last-sexp) |
| 415 | (beginning-of-line) |
| 416 | (parse-partial-sexp (point) |
| 417 | calculate-lisp-indent-last-sexp 0 t))) |
| 418 | ;; Indent under the list or under the first sexp on the same |
| 419 | ;; line as calculate-lisp-indent-last-sexp. Note that first |
| 420 | ;; thing on that line has to be complete sexp since we are |
| 421 | ;; inside the innermost containing sexp. |
| 422 | (backward-prefix-chars) |
| 423 | (current-column)) |
| 424 | (let ((function (buffer-substring (point) |
| 425 | (progn (forward-sexp 1) (point)))) |
| 426 | method) |
| 427 | (setq method (or (get (intern-soft function) 'lisp-indent-function) |
| 428 | (get (intern-soft function) 'lisp-indent-hook))) |
| 429 | (cond ((or (eq method 'defun) |
| 430 | (and (null method) |
| 431 | (> (length function) 3) |
| 432 | (string-match "\\`def" function))) |
| 433 | (lisp-indent-defform state indent-point)) |
| 434 | ((integerp method) |
| 435 | (lisp-indent-specform method state |
| 436 | indent-point normal-indent)) |
| 437 | (method |
| 438 | (funcall method state indent-point))))))) |
| 439 | |
| 440 | (defconst lisp-body-indent 2 |
| 441 | "Number of columns to indent the second line of a `(def...)' form.") |
| 442 | |
| 443 | (defun lisp-indent-specform (count state indent-point normal-indent) |
| 444 | (let ((containing-form-start (elt state 1)) |
| 445 | (i count) |
| 446 | body-indent containing-form-column) |
| 447 | ;; Move to the start of containing form, calculate indentation |
| 448 | ;; to use for non-distinguished forms (> count), and move past the |
| 449 | ;; function symbol. lisp-indent-function guarantees that there is at |
| 450 | ;; least one word or symbol character following open paren of containing |
| 451 | ;; form. |
| 452 | (goto-char containing-form-start) |
| 453 | (setq containing-form-column (current-column)) |
| 454 | (setq body-indent (+ lisp-body-indent containing-form-column)) |
| 455 | (forward-char 1) |
| 456 | (forward-sexp 1) |
| 457 | ;; Now find the start of the last form. |
| 458 | (parse-partial-sexp (point) indent-point 1 t) |
| 459 | (while (and (< (point) indent-point) |
| 460 | (condition-case () |
| 461 | (progn |
| 462 | (setq count (1- count)) |
| 463 | (forward-sexp 1) |
| 464 | (parse-partial-sexp (point) indent-point 1 t)) |
| 465 | (error nil)))) |
| 466 | ;; Point is sitting on first character of last (or count) sexp. |
| 467 | (if (> count 0) |
| 468 | ;; A distinguished form. If it is the first or second form use double |
| 469 | ;; lisp-body-indent, else normal indent. With lisp-body-indent bound |
| 470 | ;; to 2 (the default), this just happens to work the same with if as |
| 471 | ;; the older code, but it makes unwind-protect, condition-case, |
| 472 | ;; with-output-to-temp-buffer, et. al. much more tasteful. The older, |
| 473 | ;; less hacked, behavior can be obtained by replacing below with |
| 474 | ;; (list normal-indent containing-form-start). |
| 475 | (if (<= (- i count) 1) |
| 476 | (list (+ containing-form-column (* 2 lisp-body-indent)) |
| 477 | containing-form-start) |
| 478 | (list normal-indent containing-form-start)) |
| 479 | ;; A non-distinguished form. Use body-indent if there are no |
| 480 | ;; distinguished forms and this is the first undistinguished form, |
| 481 | ;; or if this is the first undistinguished form and the preceding |
| 482 | ;; distinguished form has indentation at least as great as body-indent. |
| 483 | (if (or (and (= i 0) (= count 0)) |
| 484 | (and (= count 0) (<= body-indent normal-indent))) |
| 485 | body-indent |
| 486 | normal-indent)))) |
| 487 | |
| 488 | (defun lisp-indent-defform (state indent-point) |
| 489 | (goto-char (car (cdr state))) |
| 490 | (forward-line 1) |
| 491 | (if (> (point) (car (cdr (cdr state)))) |
| 492 | (progn |
| 493 | (goto-char (car (cdr state))) |
| 494 | (+ lisp-body-indent (current-column))))) |
| 495 | |
| 496 | \f |
| 497 | ;; (put 'progn 'lisp-indent-function 0), say, causes progn to be indented |
| 498 | ;; like defun if the first form is placed on the next line, otherwise |
| 499 | ;; it is indented like any other form (i.e. forms line up under first). |
| 500 | |
| 501 | (put 'lambda 'lisp-indent-function 'defun) |
| 502 | (put 'autoload 'lisp-indent-function 'defun) |
| 503 | (put 'progn 'lisp-indent-function 0) |
| 504 | (put 'prog1 'lisp-indent-function 1) |
| 505 | (put 'prog2 'lisp-indent-function 2) |
| 506 | (put 'save-excursion 'lisp-indent-function 0) |
| 507 | (put 'save-window-excursion 'lisp-indent-function 0) |
| 508 | (put 'save-restriction 'lisp-indent-function 0) |
| 509 | (put 'save-match-data 'lisp-indent-function 0) |
| 510 | (put 'let 'lisp-indent-function 1) |
| 511 | (put 'let* 'lisp-indent-function 1) |
| 512 | (put 'while 'lisp-indent-function 1) |
| 513 | (put 'if 'lisp-indent-function 2) |
| 514 | (put 'catch 'lisp-indent-function 1) |
| 515 | (put 'condition-case 'lisp-indent-function 2) |
| 516 | (put 'unwind-protect 'lisp-indent-function 1) |
| 517 | (put 'with-output-to-temp-buffer 'lisp-indent-function 1) |
| 518 | |
| 519 | (defun indent-sexp (&optional endpos) |
| 520 | "Indent each line of the list starting just after point. |
| 521 | If optional arg ENDPOS is given, indent each line, stopping when |
| 522 | ENDPOS is encountered." |
| 523 | (interactive) |
| 524 | (let ((indent-stack (list nil)) |
| 525 | (next-depth 0) |
| 526 | (starting-point (point)) |
| 527 | (last-point (point)) |
| 528 | last-depth bol outer-loop-done inner-loop-done state this-indent) |
| 529 | ;; Get error now if we don't have a complete sexp after point. |
| 530 | (save-excursion (forward-sexp 1)) |
| 531 | (save-excursion |
| 532 | (setq outer-loop-done nil) |
| 533 | (while (if endpos (< (point) endpos) |
| 534 | (not outer-loop-done)) |
| 535 | (setq last-depth next-depth |
| 536 | inner-loop-done nil) |
| 537 | ;; Parse this line so we can learn the state |
| 538 | ;; to indent the next line. |
| 539 | ;; This inner loop goes through only once |
| 540 | ;; unless a line ends inside a string. |
| 541 | (while (and (not inner-loop-done) |
| 542 | (not (setq outer-loop-done (eobp)))) |
| 543 | (setq state (parse-partial-sexp (point) (progn (end-of-line) (point)) |
| 544 | nil nil state)) |
| 545 | (setq next-depth (car state)) |
| 546 | ;; If the line contains a comment other than the sort |
| 547 | ;; that is indented like code, |
| 548 | ;; indent it now with indent-for-comment. |
| 549 | ;; Comments indented like code are right already. |
| 550 | ;; In any case clear the in-comment flag in the state |
| 551 | ;; because parse-partial-sexp never sees the newlines. |
| 552 | (if (car (nthcdr 4 state)) |
| 553 | (progn (indent-for-comment) |
| 554 | (end-of-line) |
| 555 | (setcar (nthcdr 4 state) nil))) |
| 556 | ;; If this line ends inside a string, |
| 557 | ;; go straight to next line, remaining within the inner loop, |
| 558 | ;; and turn off the \-flag. |
| 559 | (if (car (nthcdr 3 state)) |
| 560 | (progn |
| 561 | (forward-line 1) |
| 562 | (setcar (nthcdr 5 state) nil)) |
| 563 | (setq inner-loop-done t))) |
| 564 | (and endpos |
| 565 | (<= next-depth 0) |
| 566 | (progn |
| 567 | (setq indent-stack (append indent-stack |
| 568 | (make-list (- next-depth) nil)) |
| 569 | last-depth (- last-depth next-depth) |
| 570 | next-depth 0))) |
| 571 | (or outer-loop-done |
| 572 | (setq outer-loop-done (<= next-depth 0))) |
| 573 | (if outer-loop-done |
| 574 | (forward-line 1) |
| 575 | (while (> last-depth next-depth) |
| 576 | (setq indent-stack (cdr indent-stack) |
| 577 | last-depth (1- last-depth))) |
| 578 | (while (< last-depth next-depth) |
| 579 | (setq indent-stack (cons nil indent-stack) |
| 580 | last-depth (1+ last-depth))) |
| 581 | ;; Now go to the next line and indent it according |
| 582 | ;; to what we learned from parsing the previous one. |
| 583 | (forward-line 1) |
| 584 | (setq bol (point)) |
| 585 | (skip-chars-forward " \t") |
| 586 | ;; But not if the line is blank, or just a comment |
| 587 | ;; (except for double-semi comments; indent them as usual). |
| 588 | (if (or (eobp) (looking-at "\\s<\\|\n")) |
| 589 | nil |
| 590 | (if (and (car indent-stack) |
| 591 | (>= (car indent-stack) 0)) |
| 592 | (setq this-indent (car indent-stack)) |
| 593 | (let ((val (calculate-lisp-indent |
| 594 | (if (car indent-stack) (- (car indent-stack)) |
| 595 | starting-point)))) |
| 596 | (if (integerp val) |
| 597 | (setcar indent-stack |
| 598 | (setq this-indent val)) |
| 599 | (setcar indent-stack (- (car (cdr val)))) |
| 600 | (setq this-indent (car val))))) |
| 601 | (if (/= (current-column) this-indent) |
| 602 | (progn (delete-region bol (point)) |
| 603 | (indent-to this-indent))))) |
| 604 | (or outer-loop-done |
| 605 | (setq outer-loop-done (= (point) last-point)) |
| 606 | (setq last-point (point))))))) |
| 607 | |
| 608 | ;; Indent every line whose first char is between START and END inclusive. |
| 609 | (defun lisp-indent-region (start end) |
| 610 | (save-excursion |
| 611 | (goto-char start) |
| 612 | (and (bolp) (not (eolp)) |
| 613 | (lisp-indent-line)) |
| 614 | (let ((endmark (copy-marker end))) |
| 615 | (indent-sexp endmark) |
| 616 | (set-marker endmark nil)))) |
| 617 | \f |
| 618 | ;;;; Lisp paragraph filling commands. |
| 619 | |
| 620 | (defun lisp-fill-paragraph (&optional justify) |
| 621 | "Like \\[fill-paragraph], but handle Emacs Lisp comments. |
| 622 | If any of the current line is a comment, fill the comment or the |
| 623 | paragraph of it that point is in, preserving the comment's indentation |
| 624 | and initial semicolons." |
| 625 | (interactive "P") |
| 626 | (let ( |
| 627 | ;; Non-nil if the current line contains a comment. |
| 628 | has-comment |
| 629 | |
| 630 | ;; If has-comment, the appropriate fill-prefix for the comment. |
| 631 | comment-fill-prefix |
| 632 | ) |
| 633 | |
| 634 | ;; Figure out what kind of comment we are looking at. |
| 635 | (save-excursion |
| 636 | (beginning-of-line) |
| 637 | (cond |
| 638 | |
| 639 | ;; A line with nothing but a comment on it? |
| 640 | ((looking-at "[ \t]*;[; \t]*") |
| 641 | (setq has-comment t |
| 642 | comment-fill-prefix (buffer-substring (match-beginning 0) |
| 643 | (match-end 0)))) |
| 644 | |
| 645 | ;; A line with some code, followed by a comment? Remember that the |
| 646 | ;; semi which starts the comment shouldn't be part of a string or |
| 647 | ;; character. |
| 648 | ((progn |
| 649 | (while (not (looking-at ";\\|$")) |
| 650 | (skip-chars-forward "^;\n\"\\\\?") |
| 651 | (cond |
| 652 | ((eq (char-after (point)) ?\\) (forward-char 2)) |
| 653 | ((memq (char-after (point)) '(?\" ??)) (forward-sexp 1)))) |
| 654 | (looking-at ";+[\t ]*")) |
| 655 | (setq has-comment t) |
| 656 | (setq comment-fill-prefix |
| 657 | (concat (make-string (current-column) ? ) |
| 658 | (buffer-substring (match-beginning 0) (match-end 0))))))) |
| 659 | |
| 660 | (if (not has-comment) |
| 661 | (fill-paragraph justify) |
| 662 | |
| 663 | ;; Narrow to include only the comment, and then fill the region. |
| 664 | (save-restriction |
| 665 | (narrow-to-region |
| 666 | ;; Find the first line we should include in the region to fill. |
| 667 | (save-excursion |
| 668 | (while (and (zerop (forward-line -1)) |
| 669 | (looking-at "^[ \t]*;"))) |
| 670 | ;; We may have gone to far. Go forward again. |
| 671 | (or (looking-at "^[ \t]*;") |
| 672 | (forward-line 1)) |
| 673 | (point)) |
| 674 | ;; Find the beginning of the first line past the region to fill. |
| 675 | (save-excursion |
| 676 | (while (progn (forward-line 1) |
| 677 | (looking-at "^[ \t]*;"))) |
| 678 | (point))) |
| 679 | |
| 680 | ;; Lines with only semicolons on them can be paragraph boundaries. |
| 681 | (let ((paragraph-start (concat paragraph-start "\\|^[ \t;]*$")) |
| 682 | (paragraph-separate (concat paragraph-start "\\|^[ \t;]*$")) |
| 683 | (fill-prefix comment-fill-prefix)) |
| 684 | (fill-paragraph justify)))))) |
| 685 | |
| 686 | \f |
| 687 | (defun indent-code-rigidly (start end arg &optional nochange-regexp) |
| 688 | "Indent all lines of code, starting in the region, sideways by ARG columns. |
| 689 | Does not affect lines starting inside comments or strings, assuming that |
| 690 | the start of the region is not inside them. |
| 691 | |
| 692 | Called from a program, takes args START, END, COLUMNS and NOCHANGE-REGEXP. |
| 693 | The last is a regexp which, if matched at the beginning of a line, |
| 694 | means don't indent that line." |
| 695 | (interactive "r\np") |
| 696 | (let (state) |
| 697 | (save-excursion |
| 698 | (goto-char end) |
| 699 | (setq end (point-marker)) |
| 700 | (goto-char start) |
| 701 | (or (bolp) |
| 702 | (setq state (parse-partial-sexp (point) |
| 703 | (progn |
| 704 | (forward-line 1) (point)) |
| 705 | nil nil state))) |
| 706 | (while (< (point) end) |
| 707 | (or (car (nthcdr 3 state)) |
| 708 | (and nochange-regexp |
| 709 | (looking-at nochange-regexp)) |
| 710 | ;; If line does not start in string, indent it |
| 711 | (let ((indent (current-indentation))) |
| 712 | (delete-region (point) (progn (skip-chars-forward " \t") (point))) |
| 713 | (or (eolp) |
| 714 | (indent-to (max 0 (+ indent arg)) 0)))) |
| 715 | (setq state (parse-partial-sexp (point) |
| 716 | (progn |
| 717 | (forward-line 1) (point)) |
| 718 | nil nil state)))))) |
| 719 | |
| 720 | (provide 'lisp-mode) |
| 721 | |
| 722 | ;;; lisp-mode.el ends here |