Load cl here since cc-defs doesn't do it. This is necessary for
[bpt/emacs.git] / lisp / indent.el
CommitLineData
1a06eabd
ER
1;;; indent.el --- indentation commands for Emacs
2
61294601 3;; Copyright (C) 1985, 1995, 2001 Free Software Foundation, Inc.
483e630e 4
9750e079
ER
5;; Maintainer: FSF
6
483e630e
RM
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
e5167999 11;; the Free Software Foundation; either version 2, or (at your option)
483e630e
RM
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
b578f267
EN
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22;; Boston, MA 02111-1307, USA.
483e630e 23
e41b2db1
ER
24;;; Commentary:
25
26;; Commands for making and changing indentation in text. These are
27;; described in the Emacs manual.
28
e5167999 29;;; Code:
483e630e 30
ddb3136e
RS
31(defgroup indent nil
32 "Indentation commands"
33 :group 'editing)
106b6d0e 34
ddb3136e
RS
35(defcustom standard-indent 4
36 "*Default number of columns for margin-changing functions to indent."
37 :group 'indent
38 :type 'integer)
39
f059f703 40(defvar indent-line-function 'indent-relative
a17b712b
SM
41 "Function to indent the current line.
42This function will be called with no arguments.
43If it is called somewhere where auto-indentation cannot be done
44\(f.ex. inside a string), the function should simply return `noindent'.
45Setting this function is all you need to make TAB indent appropriately.
46Don't rebind TAB unless you really need to.")
483e630e 47
20b1d079
SM
48(defcustom tab-always-indent t
49 "*Controls the operation of the TAB key.
50If t, hitting TAB always just indents the current line.
51If nil, hitting TAB indents the current line if point is at the left margin
f202a7a2 52 or in the line's indentation, otherwise it insert a \"real\" tab character."
20b1d079 53 :group 'indent
fe552b4c 54 :type '(choice (const nil) (const t) (const always)))
20b1d079 55
483e630e 56(defun indent-according-to-mode ()
1a2f8b73
RS
57 "Indent line in proper way for current major mode.
58The buffer-local variable `indent-line-function' determines how to do this,
59but the functions `indent-relative' and `indent-relative-maybe' are
60special; we don't actually use them here."
483e630e 61 (interactive)
a17b712b
SM
62 (if (memq indent-line-function
63 '(indent-relative indent-relative-maybe))
64 ;; These functions are used for tabbing, but can't be used for
65 ;; indenting. Replace with something ad-hoc.
66 (let ((column (save-excursion
67 (beginning-of-line)
68 (skip-chars-backward "\n \t")
69 (beginning-of-line)
70 (current-indentation))))
71 (if (<= (current-column) (current-indentation))
72 (indent-line-to column)
73 (save-excursion (indent-line-to column))))
74 ;; The normal case.
75 (funcall indent-line-function)))
483e630e 76
a17b712b 77(defun indent-for-tab-command (&optional arg)
20b1d079
SM
78 "Indent line in proper way for current major mode or insert a tab.
79Depending on `tab-always-indent', either insert a tab or indent.
b9ce5694
GM
80If initial point was within line's indentation, position after
81the indentation. Else stay at same point in text.
20b1d079 82The function actually called to indent is determined by the value of
eca1e29e 83`indent-line-function'."
34a71c1e 84 (interactive "P")
a17b712b 85 (cond
fe552b4c 86 ((or ;; indent-to-left-margin is only meant for indenting,
a17b712b
SM
87 ;; so we force it to always insert a tab here.
88 (eq indent-line-function 'indent-to-left-margin)
89 (and (not tab-always-indent)
f202a7a2
SM
90 (or (> (current-column) (current-indentation))
91 (eq this-command last-command))))
a17b712b
SM
92 (insert-tab arg))
93 ;; Those functions are meant specifically for tabbing and not for
94 ;; indenting, so we can't pass them to indent-according-to-mode.
95 ((memq indent-line-function '(indent-relative indent-relative-maybe))
96 (funcall indent-line-function))
97 (t ;; The normal case.
98 (indent-according-to-mode))))
99
100(defun insert-tab (&optional arg)
101 (let ((count (prefix-numeric-value arg)))
5e9f80a8
RS
102 (if (and abbrev-mode
103 (eq (char-syntax (preceding-char)) ?w))
10992b01
RS
104 (expand-abbrev))
105 (if indent-tabs-mode
4424ce6f 106 (insert-char ?\t count)
10992b01 107 (indent-to (* tab-width (+ count (/ (current-column) tab-width)))))))
483e630e
RM
108
109(defun indent-rigidly (start end arg)
110 "Indent all lines starting in the region sideways by ARG columns.
5a0f9388
EZ
111Called from a program, takes three arguments, START, END and ARG.
112You can remove all indentation from a region by giving a large negative ARG."
483e630e
RM
113 (interactive "r\np")
114 (save-excursion
115 (goto-char end)
116 (setq end (point-marker))
117 (goto-char start)
118 (or (bolp) (forward-line 1))
119 (while (< (point) end)
c1194ae8
RS
120 (let ((indent (current-indentation))
121 eol-flag)
122 (save-excursion
123 (skip-chars-forward " \t")
124 (setq eol-flag (eolp)))
125 (or eol-flag
126 (indent-to (max 0 (+ indent arg)) 0))
127 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
483e630e
RM
128 (forward-line 1))
129 (move-marker end nil)))
130
106b6d0e
RS
131(defun indent-line-to (column)
132 "Indent current line to COLUMN.
133This function removes or adds spaces and tabs at beginning of line
134only if necessary. It leaves point at end of indentation."
ca2a3cb7
BG
135 (back-to-indentation)
136 (let ((cur-col (current-column)))
137 (cond ((< cur-col column)
cd6d305e 138 (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width)
a80a30b3
RS
139 (delete-region (point)
140 (progn (skip-chars-backward " ") (point))))
ca2a3cb7
BG
141 (indent-to column))
142 ((> cur-col column) ; too far right (after tab?)
34c3f2b8 143 (delete-region (progn (move-to-column column t) (point))
ca2a3cb7 144 (progn (back-to-indentation) (point)))))))
106b6d0e
RS
145
146(defun current-left-margin ()
147 "Return the left margin to use for this line.
148This is the value of the buffer-local variable `left-margin' plus the value
149of the `left-margin' text-property at the start of the line."
150 (save-excursion
151 (back-to-indentation)
152 (max 0
34c3f2b8
BG
153 (+ left-margin (or (get-text-property
154 (if (and (eobp) (not (bobp)))
155 (1- (point)) (point))
156 'left-margin) 0)))))
106b6d0e 157
34c3f2b8 158(defun move-to-left-margin (&optional n force)
106b6d0e
RS
159 "Move to the left margin of the current line.
160With optional argument, move forward N-1 lines first.
34c3f2b8
BG
161The column moved to is the one given by the `current-left-margin' function.
162If the line's indentation appears to be wrong, and this command is called
163interactively or with optional argument FORCE, it will be fixed."
164 (interactive (list (prefix-numeric-value current-prefix-arg) t))
106b6d0e 165 (beginning-of-line n)
54505d72 166 (skip-chars-forward " \t")
1d1c5af9
RS
167 (if (minibufferp (current-buffer))
168 (if (save-excursion (beginning-of-line) (bobp))
169 (goto-char (minibuffer-prompt-end))
170 (beginning-of-line))
171 (let ((lm (current-left-margin))
172 (cc (current-column)))
173 (cond ((> cc lm)
174 (if (> (move-to-column lm force) lm)
175 ;; If lm is in a tab and we are not forcing, move before tab
176 (backward-char 1)))
177 ((and force (< cc lm))
178 (indent-to-left-margin))))))
106b6d0e 179
f202a7a2 180;; This used to be the default indent-line-function,
483e630e
RM
181;; used in Fundamental Mode, Text Mode, etc.
182(defun indent-to-left-margin ()
34c3f2b8 183 "Indent current line to the column given by `current-left-margin'."
106b6d0e
RS
184 (indent-line-to (current-left-margin)))
185
34c3f2b8
BG
186(defun delete-to-left-margin (&optional from to)
187 "Remove left margin indentation from a region.
188This deletes to the column given by `current-left-margin'.
189In no case will it delete non-whitespace.
190Args FROM and TO are optional; default is the whole buffer."
106b6d0e 191 (save-excursion
34c3f2b8 192 (goto-char (or to (point-max)))
106b6d0e 193 (setq to (point-marker))
34c3f2b8 194 (goto-char (or from (point-min)))
106b6d0e
RS
195 (or (bolp) (forward-line 1))
196 (while (< (point) to)
34c3f2b8 197 (delete-region (point) (progn (move-to-left-margin nil t) (point)))
106b6d0e
RS
198 (forward-line 1))
199 (move-marker to nil)))
200
201(defun set-left-margin (from to lm)
202 "Set the left margin of the region to WIDTH.
203If `auto-fill-mode' is active, re-fill the region to fit the new margin."
204 (interactive "r\nNSet left margin to column: ")
205 (if (interactive-p) (setq lm (prefix-numeric-value lm)))
206 (save-excursion
207 ;; If inside indentation, start from BOL.
208 (goto-char from)
209 (skip-chars-backward " \t")
210 (if (bolp) (setq from (point)))
34c3f2b8 211 ;; Place end after whitespace
106b6d0e 212 (goto-char to)
34c3f2b8 213 (skip-chars-forward " \t")
106b6d0e 214 (setq to (point-marker)))
34c3f2b8
BG
215 ;; Delete margin indentation first, but keep paragraph indentation.
216 (delete-to-left-margin from to)
106b6d0e 217 (put-text-property from to 'left-margin lm)
34c3f2b8
BG
218 (indent-rigidly from to lm)
219 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
220 (move-marker to nil))
221
222(defun set-right-margin (from to lm)
223 "Set the right margin of the region to WIDTH.
224If `auto-fill-mode' is active, re-fill the region to fit the new margin."
8cf19007 225 (interactive "r\nNSet right margin to width: ")
106b6d0e
RS
226 (if (interactive-p) (setq lm (prefix-numeric-value lm)))
227 (save-excursion
228 (goto-char from)
229 (skip-chars-backward " \t")
230 (if (bolp) (setq from (point))))
231 (put-text-property from to 'right-margin lm)
34c3f2b8 232 (if auto-fill-function (save-excursion (fill-region from to nil t t))))
106b6d0e
RS
233
234(defun alter-text-property (from to prop func &optional object)
235 "Programmatically change value of a text-property.
236For each region between FROM and TO that has a single value for PROPERTY,
237apply FUNCTION to that value and sets the property to the function's result.
238Optional fifth argument OBJECT specifies the string or buffer to operate on."
239 (let ((begin from)
240 end val)
241 (while (setq val (get-text-property begin prop object)
242 end (text-property-not-all begin to prop val object))
243 (put-text-property begin end prop (funcall func val) object)
244 (setq begin end))
245 (if (< begin to)
246 (put-text-property begin to prop (funcall func val) object))))
247
248(defun increase-left-margin (from to inc)
249 "Increase or decrease the left-margin of the region.
250With no prefix argument, this adds `standard-indent' of indentation.
251A prefix arg (optional third arg INC noninteractively) specifies the amount
252to change the margin by, in characters.
253If `auto-fill-mode' is active, re-fill the region to fit the new margin."
254 (interactive "*r\nP")
255 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
256 (save-excursion
257 (goto-char from)
258 (skip-chars-backward " \t")
259 (if (bolp) (setq from (point)))
260 (goto-char to)
261 (setq to (point-marker)))
106b6d0e 262 (alter-text-property from to 'left-margin
34c3f2b8
BG
263 (lambda (v) (max (- left-margin) (+ inc (or v 0)))))
264 (indent-rigidly from to inc)
265 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
266 (move-marker to nil))
267
268(defun decrease-left-margin (from to inc)
269 "Make the left margin of the region smaller.
270With no prefix argument, decrease the indentation by `standard-indent'.
271A prefix arg (optional third arg INC noninteractively) specifies the amount
272to change the margin by, in characters.
273If `auto-fill-mode' is active, re-fill the region to fit the new margin."
274 (interactive "*r\nP")
275 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
276 (increase-left-margin from to (- inc)))
277
278(defun increase-right-margin (from to inc)
279 "Increase the right-margin of the region.
280With no prefix argument, increase the right margin by `standard-indent'.
281A prefix arg (optional third arg INC noninteractively) specifies the amount
282to change the margin by, in characters. A negative argument decreases
283the right margin width.
284If `auto-fill-mode' is active, re-fill the region to fit the new margin."
285 (interactive "r\nP")
286 (if (interactive-p)
287 (setq inc (if inc (prefix-numeric-value current-prefix-arg)
288 standard-indent)))
289 (save-excursion
290 (alter-text-property from to 'right-margin
34c3f2b8 291 (lambda (v) (+ inc (or v 0))))
106b6d0e
RS
292 (if auto-fill-function
293 (fill-region from to nil t t))))
294
295(defun decrease-right-margin (from to inc)
296 "Make the right margin of the region smaller.
297With no prefix argument, decrease the right margin by `standard-indent'.
298A prefix arg (optional third arg INC noninteractively) specifies the amount
299of width to remove, in characters. A negative argument increases
300the right margin width.
301If `auto-fill-mode' is active, re-fills region to fit in new margin."
302 (interactive "*r\nP")
303 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
304 (increase-right-margin from to (- inc)))
483e630e 305
34c3f2b8
BG
306(defun beginning-of-line-text (&optional n)
307 "Move to the beginning of the text on this line.
308With optional argument, move forward N-1 lines first.
309From the beginning of the line, moves past the left-margin indentation, the
310fill-prefix, and any indentation used for centering or right-justifying the
f1180544 311line, but does not move past any whitespace that was explicitly inserted
34c3f2b8
BG
312\(such as a tab used to indent the first line of a paragraph)."
313 (interactive "p")
314 (beginning-of-line n)
315 (skip-chars-forward " \t")
316 ;; Skip over fill-prefix.
f1180544 317 (if (and fill-prefix
34c3f2b8
BG
318 (not (string-equal fill-prefix "")))
319 (if (equal fill-prefix
f1180544 320 (buffer-substring
34c3f2b8
BG
321 (point) (min (point-max) (+ (length fill-prefix) (point)))))
322 (forward-char (length fill-prefix)))
7d43e2ad 323 (if (and adaptive-fill-mode adaptive-fill-regexp
34c3f2b8
BG
324 (looking-at adaptive-fill-regexp))
325 (goto-char (match-end 0))))
326 ;; Skip centering or flushright indentation
327 (if (memq (current-justification) '(center right))
328 (skip-chars-forward " \t")))
329
483e630e 330(defvar indent-region-function nil
3704e77e
RS
331 "Short cut function to indent region using `indent-according-to-mode'.
332A value of nil means really run `indent-according-to-mode' on each line.")
483e630e 333
1d9cc345 334(defun indent-region (start end &optional column)
483e630e 335 "Indent each nonblank line in the region.
1a2f8b73
RS
336A numeric prefix argument specifies a column: indent each line to that column.
337
338With no prefix argument, the command chooses one of these methods and
339indents all the lines with it:
340
341 1) If `fill-prefix' is non-nil, insert `fill-prefix' at the
342 beginning of each line in the region that does not already begin
343 with it.
344 2) If `indent-region-function' is non-nil, call that function
345 to indent the region.
346 3) Indent each line as specified by the variable `indent-line-function'.
347
348Called from a program, START and END specify the region to indent.
349If the third argument COLUMN is an integer, it specifies the
350column to indent to; if it is nil, use one of the three methods above."
483e630e 351 (interactive "r\nP")
88a2603a 352 (if (null column)
483e630e
RM
353 (if fill-prefix
354 (save-excursion
355 (goto-char end)
356 (setq end (point-marker))
357 (goto-char start)
358 (let ((regexp (regexp-quote fill-prefix)))
88a2603a
RS
359 (while (< (point) end)
360 (or (looking-at regexp)
361 (and (bolp) (eolp))
362 (insert fill-prefix))
363 (forward-line 1))))
483e630e
RM
364 (if indent-region-function
365 (funcall indent-region-function start end)
366 (save-excursion
a17b712b 367 (setq end (copy-marker end))
88a2603a 368 (goto-char start)
88a2603a 369 (while (< (point) end)
232acca7 370 (or (and (bolp) (eolp))
88a2603a
RS
371 (funcall indent-line-function))
372 (forward-line 1))
373 (move-marker end nil))))
374 (setq column (prefix-numeric-value column))
483e630e
RM
375 (save-excursion
376 (goto-char end)
377 (setq end (point-marker))
378 (goto-char start)
379 (or (bolp) (forward-line 1))
380 (while (< (point) end)
381 (delete-region (point) (progn (skip-chars-forward " \t") (point)))
382 (or (eolp)
106b6d0e 383 (indent-to column 0))
483e630e
RM
384 (forward-line 1))
385 (move-marker end nil))))
386
387(defun indent-relative-maybe ()
1fd63d9b
EZ
388 "Indent a new line like previous nonblank line.
389If the previous nonblank line has no indent points beyond the
390column point starts at, this command does nothing.
391
392See also `indent-relative'."
483e630e
RM
393 (interactive)
394 (indent-relative t))
395
396(defun indent-relative (&optional unindented-ok)
397 "Space out to under next indent point in previous nonblank line.
398An indent point is a non-whitespace character following whitespace.
f6f53207
RS
399The following line shows the indentation points in this line.
400 ^ ^ ^ ^ ^ ^ ^ ^ ^
483e630e 401If the previous nonblank line has no indent points beyond the
1fd63d9b
EZ
402column point starts at, `tab-to-tab-stop' is done instead, unless
403this command is invoked with a numeric argument, in which case it
404does nothing.
405
406See also `indent-relative-maybe'."
483e630e 407 (interactive "P")
5e9f80a8
RS
408 (if (and abbrev-mode
409 (eq (char-syntax (preceding-char)) ?w))
410 (expand-abbrev))
483e630e
RM
411 (let ((start-column (current-column))
412 indent)
413 (save-excursion
414 (beginning-of-line)
415 (if (re-search-backward "^[^\n]" nil t)
416 (let ((end (save-excursion (forward-line 1) (point))))
417 (move-to-column start-column)
418 ;; Is start-column inside a tab on this line?
419 (if (> (current-column) start-column)
420 (backward-char 1))
421 (or (looking-at "[ \t]")
422 unindented-ok
423 (skip-chars-forward "^ \t" end))
424 (skip-chars-forward " \t" end)
425 (or (= (point) end) (setq indent (current-column))))))
426 (if indent
427 (let ((opoint (point-marker)))
483e630e
RM
428 (indent-to indent 0)
429 (if (> opoint (point))
430 (goto-char opoint))
431 (move-marker opoint nil))
432 (tab-to-tab-stop))))
433
ddb3136e 434(defcustom tab-stop-list
483e630e 435 '(8 16 24 32 40 48 56 64 72 80 88 96 104 112 120)
0f6ca6cf 436 "*List of tab stop positions used by `tab-to-tab-stop'.
ddb3136e
RS
437This should be a list of integers, ordered from smallest to largest."
438 :group 'indent
439 :type '(repeat integer))
483e630e 440
a17b712b
SM
441(defvar edit-tab-stops-map
442 (let ((map (make-sparse-keymap)))
443 (define-key map "\C-x\C-s" 'edit-tab-stops-note-changes)
444 (define-key map "\C-c\C-c" 'edit-tab-stops-note-changes)
445 map)
446 "Keymap used in `edit-tab-stops'.")
483e630e
RM
447
448(defvar edit-tab-stops-buffer nil
bc57b735
LT
449 "Buffer whose tab stops are being edited.
450This matters if the variable `tab-stop-list' is local in that buffer.")
483e630e
RM
451
452(defun edit-tab-stops ()
453 "Edit the tab stops used by `tab-to-tab-stop'.
454Creates a buffer *Tab Stops* containing text describing the tab stops.
455A colon indicates a column where there is a tab stop.
456You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops-note-changes] to make changes take effect."
457 (interactive)
458 (setq edit-tab-stops-buffer (current-buffer))
459 (switch-to-buffer (get-buffer-create "*Tab Stops*"))
460 (use-local-map edit-tab-stops-map)
461 (make-local-variable 'indent-tabs-mode)
462 (setq indent-tabs-mode nil)
463 (overwrite-mode 1)
464 (setq truncate-lines t)
465 (erase-buffer)
466 (let ((tabs tab-stop-list))
467 (while tabs
468 (indent-to (car tabs) 0)
469 (insert ?:)
470 (setq tabs (cdr tabs))))
471 (let ((count 0))
472 (insert ?\n)
473 (while (< count 8)
474 (insert (+ count ?0))
475 (insert " ")
476 (setq count (1+ count)))
477 (insert ?\n)
478 (while (> count 0)
479 (insert "0123456789")
480 (setq count (1- count))))
481 (insert "\nTo install changes, type C-c C-c")
482 (goto-char (point-min)))
483
484(defun edit-tab-stops-note-changes ()
485 "Put edited tab stops into effect."
486 (interactive)
487 (let (tabs)
488 (save-excursion
489 (goto-char 1)
490 (end-of-line)
491 (while (search-backward ":" nil t)
492 (setq tabs (cons (current-column) tabs))))
493 (bury-buffer (prog1 (current-buffer)
494 (switch-to-buffer edit-tab-stops-buffer)))
495 (setq tab-stop-list tabs))
496 (message "Tab stops installed"))
497
498(defun tab-to-tab-stop ()
499 "Insert spaces or tabs to next defined tab-stop column.
500The variable `tab-stop-list' is a list of columns at which there are tab stops.
501Use \\[edit-tab-stops] to edit them interactively."
502 (interactive)
a2964053
RS
503 (and abbrev-mode (= (char-syntax (preceding-char)) ?w)
504 (expand-abbrev))
483e630e
RM
505 (let ((tabs tab-stop-list))
506 (while (and tabs (>= (current-column) (car tabs)))
507 (setq tabs (cdr tabs)))
508 (if tabs
9d840bec 509 (let ((opoint (point)))
19b70460 510 (delete-horizontal-space t)
9d840bec 511 (indent-to (car tabs)))
483e630e
RM
512 (insert ?\ ))))
513
514(defun move-to-tab-stop ()
515 "Move point to next defined tab-stop column.
fbf8f564
RS
516The variable `tab-stop-list' is a list of columns at which there are tab stops.
517Use \\[edit-tab-stops] to edit them interactively."
518 (interactive)
519 (let ((tabs tab-stop-list))
520 (while (and tabs (>= (current-column) (car tabs)))
521 (setq tabs (cdr tabs)))
522 (if tabs
523 (let ((before (point)))
524 (move-to-column (car tabs) t)
525 (save-excursion
526 (goto-char before)
527 ;; If we just added a tab, or moved over one,
528 ;; delete any superfluous spaces before the old point.
529 (if (and (eq (preceding-char) ?\ )
530 (eq (following-char) ?\t))
531 (let ((tabend (* (/ (current-column) tab-width) tab-width)))
532 (while (and (> (current-column) tabend)
533 (eq (preceding-char) ?\ ))
534 (forward-char -1))
535 (delete-region (point) before))))))))
536
483e630e 537(define-key global-map "\t" 'indent-for-tab-command)
a17b712b 538(define-key esc-map "\C-\\" 'indent-region)
483e630e
RM
539(define-key ctl-x-map "\t" 'indent-rigidly)
540(define-key esc-map "i" 'tab-to-tab-stop)
1a06eabd 541
ab5796a9 542;;; arch-tag: f402b2a7-e44f-492f-b5b8-38996020b7c3
1a06eabd 543;;; indent.el ends here