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