*** empty log message ***
[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
52 or in the line's indentation, otherwise it insert a `real' tab character."
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)
e30ce098 90 (> (current-column) (current-indentation))))
a17b712b
SM
91 (insert-tab arg))
92 ;; Those functions are meant specifically for tabbing and not for
93 ;; indenting, so we can't pass them to indent-according-to-mode.
94 ((memq indent-line-function '(indent-relative indent-relative-maybe))
95 (funcall indent-line-function))
96 (t ;; The normal case.
97 (indent-according-to-mode))))
98
99(defun insert-tab (&optional arg)
100 (let ((count (prefix-numeric-value arg)))
5e9f80a8
RS
101 (if (and abbrev-mode
102 (eq (char-syntax (preceding-char)) ?w))
10992b01
RS
103 (expand-abbrev))
104 (if indent-tabs-mode
4424ce6f 105 (insert-char ?\t count)
10992b01 106 (indent-to (* tab-width (+ count (/ (current-column) tab-width)))))))
483e630e
RM
107
108(defun indent-rigidly (start end arg)
109 "Indent all lines starting in the region sideways by ARG columns.
5a0f9388
EZ
110Called from a program, takes three arguments, START, END and ARG.
111You can remove all indentation from a region by giving a large negative ARG."
483e630e
RM
112 (interactive "r\np")
113 (save-excursion
114 (goto-char end)
115 (setq end (point-marker))
116 (goto-char start)
117 (or (bolp) (forward-line 1))
118 (while (< (point) end)
c1194ae8
RS
119 (let ((indent (current-indentation))
120 eol-flag)
121 (save-excursion
122 (skip-chars-forward " \t")
123 (setq eol-flag (eolp)))
124 (or eol-flag
125 (indent-to (max 0 (+ indent arg)) 0))
126 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
483e630e
RM
127 (forward-line 1))
128 (move-marker end nil)))
129
106b6d0e
RS
130(defun indent-line-to (column)
131 "Indent current line to COLUMN.
132This function removes or adds spaces and tabs at beginning of line
133only if necessary. It leaves point at end of indentation."
ca2a3cb7
BG
134 (back-to-indentation)
135 (let ((cur-col (current-column)))
136 (cond ((< cur-col column)
cd6d305e 137 (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width)
a80a30b3
RS
138 (delete-region (point)
139 (progn (skip-chars-backward " ") (point))))
ca2a3cb7
BG
140 (indent-to column))
141 ((> cur-col column) ; too far right (after tab?)
34c3f2b8 142 (delete-region (progn (move-to-column column t) (point))
ca2a3cb7 143 (progn (back-to-indentation) (point)))))))
106b6d0e
RS
144
145(defun current-left-margin ()
146 "Return the left margin to use for this line.
147This is the value of the buffer-local variable `left-margin' plus the value
148of the `left-margin' text-property at the start of the line."
149 (save-excursion
150 (back-to-indentation)
151 (max 0
34c3f2b8
BG
152 (+ left-margin (or (get-text-property
153 (if (and (eobp) (not (bobp)))
154 (1- (point)) (point))
155 'left-margin) 0)))))
106b6d0e 156
34c3f2b8 157(defun move-to-left-margin (&optional n force)
106b6d0e
RS
158 "Move to the left margin of the current line.
159With optional argument, move forward N-1 lines first.
34c3f2b8
BG
160The column moved to is the one given by the `current-left-margin' function.
161If the line's indentation appears to be wrong, and this command is called
162interactively or with optional argument FORCE, it will be fixed."
163 (interactive (list (prefix-numeric-value current-prefix-arg) t))
106b6d0e 164 (beginning-of-line n)
54505d72
RS
165 (skip-chars-forward " \t")
166 (let ((lm (current-left-margin))
167 (cc (current-column)))
168 (cond ((> cc lm)
169 (if (> (move-to-column lm force) lm)
170 ;; If lm is in a tab and we are not forcing, move before tab
171 (backward-char 1)))
172 ((and force (< cc lm))
173 (indent-to-left-margin)))))
106b6d0e 174
483e630e
RM
175;; This is the default indent-line-function,
176;; used in Fundamental Mode, Text Mode, etc.
177(defun indent-to-left-margin ()
34c3f2b8 178 "Indent current line to the column given by `current-left-margin'."
106b6d0e
RS
179 (indent-line-to (current-left-margin)))
180
34c3f2b8
BG
181(defun delete-to-left-margin (&optional from to)
182 "Remove left margin indentation from a region.
183This deletes to the column given by `current-left-margin'.
184In no case will it delete non-whitespace.
185Args FROM and TO are optional; default is the whole buffer."
106b6d0e 186 (save-excursion
34c3f2b8 187 (goto-char (or to (point-max)))
106b6d0e 188 (setq to (point-marker))
34c3f2b8 189 (goto-char (or from (point-min)))
106b6d0e
RS
190 (or (bolp) (forward-line 1))
191 (while (< (point) to)
34c3f2b8 192 (delete-region (point) (progn (move-to-left-margin nil t) (point)))
106b6d0e
RS
193 (forward-line 1))
194 (move-marker to nil)))
195
196(defun set-left-margin (from to lm)
197 "Set the left margin of the region to WIDTH.
198If `auto-fill-mode' is active, re-fill the region to fit the new margin."
199 (interactive "r\nNSet left margin to column: ")
200 (if (interactive-p) (setq lm (prefix-numeric-value lm)))
201 (save-excursion
202 ;; If inside indentation, start from BOL.
203 (goto-char from)
204 (skip-chars-backward " \t")
205 (if (bolp) (setq from (point)))
34c3f2b8 206 ;; Place end after whitespace
106b6d0e 207 (goto-char to)
34c3f2b8 208 (skip-chars-forward " \t")
106b6d0e 209 (setq to (point-marker)))
34c3f2b8
BG
210 ;; Delete margin indentation first, but keep paragraph indentation.
211 (delete-to-left-margin from to)
106b6d0e 212 (put-text-property from to 'left-margin lm)
34c3f2b8
BG
213 (indent-rigidly from to lm)
214 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
215 (move-marker to nil))
216
217(defun set-right-margin (from to lm)
218 "Set the right margin of the region to WIDTH.
219If `auto-fill-mode' is active, re-fill the region to fit the new margin."
8cf19007 220 (interactive "r\nNSet right margin to width: ")
106b6d0e
RS
221 (if (interactive-p) (setq lm (prefix-numeric-value lm)))
222 (save-excursion
223 (goto-char from)
224 (skip-chars-backward " \t")
225 (if (bolp) (setq from (point))))
226 (put-text-property from to 'right-margin lm)
34c3f2b8 227 (if auto-fill-function (save-excursion (fill-region from to nil t t))))
106b6d0e
RS
228
229(defun alter-text-property (from to prop func &optional object)
230 "Programmatically change value of a text-property.
231For each region between FROM and TO that has a single value for PROPERTY,
232apply FUNCTION to that value and sets the property to the function's result.
233Optional fifth argument OBJECT specifies the string or buffer to operate on."
234 (let ((begin from)
235 end val)
236 (while (setq val (get-text-property begin prop object)
237 end (text-property-not-all begin to prop val object))
238 (put-text-property begin end prop (funcall func val) object)
239 (setq begin end))
240 (if (< begin to)
241 (put-text-property begin to prop (funcall func val) object))))
242
243(defun increase-left-margin (from to inc)
244 "Increase or decrease the left-margin of the region.
245With no prefix argument, this adds `standard-indent' of indentation.
246A prefix arg (optional third arg INC noninteractively) specifies the amount
247to change the margin by, in characters.
248If `auto-fill-mode' is active, re-fill the region to fit the new margin."
249 (interactive "*r\nP")
250 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
251 (save-excursion
252 (goto-char from)
253 (skip-chars-backward " \t")
254 (if (bolp) (setq from (point)))
255 (goto-char to)
256 (setq to (point-marker)))
106b6d0e 257 (alter-text-property from to 'left-margin
34c3f2b8
BG
258 (lambda (v) (max (- left-margin) (+ inc (or v 0)))))
259 (indent-rigidly from to inc)
260 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
261 (move-marker to nil))
262
263(defun decrease-left-margin (from to inc)
264 "Make the left margin of the region smaller.
265With no prefix argument, decrease the indentation by `standard-indent'.
266A prefix arg (optional third arg INC noninteractively) specifies the amount
267to change the margin by, in characters.
268If `auto-fill-mode' is active, re-fill the region to fit the new margin."
269 (interactive "*r\nP")
270 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
271 (increase-left-margin from to (- inc)))
272
273(defun increase-right-margin (from to inc)
274 "Increase the right-margin of the region.
275With no prefix argument, increase the right margin by `standard-indent'.
276A prefix arg (optional third arg INC noninteractively) specifies the amount
277to change the margin by, in characters. A negative argument decreases
278the right margin width.
279If `auto-fill-mode' is active, re-fill the region to fit the new margin."
280 (interactive "r\nP")
281 (if (interactive-p)
282 (setq inc (if inc (prefix-numeric-value current-prefix-arg)
283 standard-indent)))
284 (save-excursion
285 (alter-text-property from to 'right-margin
34c3f2b8 286 (lambda (v) (+ inc (or v 0))))
106b6d0e
RS
287 (if auto-fill-function
288 (fill-region from to nil t t))))
289
290(defun decrease-right-margin (from to inc)
291 "Make the right margin of the region smaller.
292With no prefix argument, decrease the right margin by `standard-indent'.
293A prefix arg (optional third arg INC noninteractively) specifies the amount
294of width to remove, in characters. A negative argument increases
295the right margin width.
296If `auto-fill-mode' is active, re-fills region to fit in new margin."
297 (interactive "*r\nP")
298 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
299 (increase-right-margin from to (- inc)))
483e630e 300
34c3f2b8
BG
301(defun beginning-of-line-text (&optional n)
302 "Move to the beginning of the text on this line.
303With optional argument, move forward N-1 lines first.
304From the beginning of the line, moves past the left-margin indentation, the
305fill-prefix, and any indentation used for centering or right-justifying the
306line, but does not move past any whitespace that was explicitly inserted
307\(such as a tab used to indent the first line of a paragraph)."
308 (interactive "p")
309 (beginning-of-line n)
310 (skip-chars-forward " \t")
311 ;; Skip over fill-prefix.
312 (if (and fill-prefix
313 (not (string-equal fill-prefix "")))
314 (if (equal fill-prefix
315 (buffer-substring
316 (point) (min (point-max) (+ (length fill-prefix) (point)))))
317 (forward-char (length fill-prefix)))
7d43e2ad 318 (if (and adaptive-fill-mode adaptive-fill-regexp
34c3f2b8
BG
319 (looking-at adaptive-fill-regexp))
320 (goto-char (match-end 0))))
321 ;; Skip centering or flushright indentation
322 (if (memq (current-justification) '(center right))
323 (skip-chars-forward " \t")))
324
483e630e 325(defvar indent-region-function nil
3704e77e
RS
326 "Short cut function to indent region using `indent-according-to-mode'.
327A value of nil means really run `indent-according-to-mode' on each line.")
483e630e 328
1d9cc345 329(defun indent-region (start end &optional column)
483e630e 330 "Indent each nonblank line in the region.
1a2f8b73
RS
331A numeric prefix argument specifies a column: indent each line to that column.
332
333With no prefix argument, the command chooses one of these methods and
334indents all the lines with it:
335
336 1) If `fill-prefix' is non-nil, insert `fill-prefix' at the
337 beginning of each line in the region that does not already begin
338 with it.
339 2) If `indent-region-function' is non-nil, call that function
340 to indent the region.
341 3) Indent each line as specified by the variable `indent-line-function'.
342
343Called from a program, START and END specify the region to indent.
344If the third argument COLUMN is an integer, it specifies the
345column to indent to; if it is nil, use one of the three methods above."
483e630e 346 (interactive "r\nP")
88a2603a 347 (if (null column)
483e630e
RM
348 (if fill-prefix
349 (save-excursion
350 (goto-char end)
351 (setq end (point-marker))
352 (goto-char start)
353 (let ((regexp (regexp-quote fill-prefix)))
88a2603a
RS
354 (while (< (point) end)
355 (or (looking-at regexp)
356 (and (bolp) (eolp))
357 (insert fill-prefix))
358 (forward-line 1))))
483e630e
RM
359 (if indent-region-function
360 (funcall indent-region-function start end)
361 (save-excursion
a17b712b 362 (setq end (copy-marker end))
88a2603a 363 (goto-char start)
88a2603a 364 (while (< (point) end)
232acca7 365 (or (and (bolp) (eolp))
88a2603a
RS
366 (funcall indent-line-function))
367 (forward-line 1))
368 (move-marker end nil))))
369 (setq column (prefix-numeric-value column))
483e630e
RM
370 (save-excursion
371 (goto-char end)
372 (setq end (point-marker))
373 (goto-char start)
374 (or (bolp) (forward-line 1))
375 (while (< (point) end)
376 (delete-region (point) (progn (skip-chars-forward " \t") (point)))
377 (or (eolp)
106b6d0e 378 (indent-to column 0))
483e630e
RM
379 (forward-line 1))
380 (move-marker end nil))))
381
382(defun indent-relative-maybe ()
1fd63d9b
EZ
383 "Indent a new line like previous nonblank line.
384If the previous nonblank line has no indent points beyond the
385column point starts at, this command does nothing.
386
387See also `indent-relative'."
483e630e
RM
388 (interactive)
389 (indent-relative t))
390
391(defun indent-relative (&optional unindented-ok)
392 "Space out to under next indent point in previous nonblank line.
393An indent point is a non-whitespace character following whitespace.
f6f53207
RS
394The following line shows the indentation points in this line.
395 ^ ^ ^ ^ ^ ^ ^ ^ ^
483e630e 396If the previous nonblank line has no indent points beyond the
1fd63d9b
EZ
397column point starts at, `tab-to-tab-stop' is done instead, unless
398this command is invoked with a numeric argument, in which case it
399does nothing.
400
401See also `indent-relative-maybe'."
483e630e 402 (interactive "P")
5e9f80a8
RS
403 (if (and abbrev-mode
404 (eq (char-syntax (preceding-char)) ?w))
405 (expand-abbrev))
483e630e
RM
406 (let ((start-column (current-column))
407 indent)
408 (save-excursion
409 (beginning-of-line)
410 (if (re-search-backward "^[^\n]" nil t)
411 (let ((end (save-excursion (forward-line 1) (point))))
412 (move-to-column start-column)
413 ;; Is start-column inside a tab on this line?
414 (if (> (current-column) start-column)
415 (backward-char 1))
416 (or (looking-at "[ \t]")
417 unindented-ok
418 (skip-chars-forward "^ \t" end))
419 (skip-chars-forward " \t" end)
420 (or (= (point) end) (setq indent (current-column))))))
421 (if indent
422 (let ((opoint (point-marker)))
483e630e
RM
423 (indent-to indent 0)
424 (if (> opoint (point))
425 (goto-char opoint))
426 (move-marker opoint nil))
427 (tab-to-tab-stop))))
428
ddb3136e 429(defcustom tab-stop-list
483e630e 430 '(8 16 24 32 40 48 56 64 72 80 88 96 104 112 120)
0f6ca6cf 431 "*List of tab stop positions used by `tab-to-tab-stop'.
ddb3136e
RS
432This should be a list of integers, ordered from smallest to largest."
433 :group 'indent
434 :type '(repeat integer))
483e630e 435
a17b712b
SM
436(defvar edit-tab-stops-map
437 (let ((map (make-sparse-keymap)))
438 (define-key map "\C-x\C-s" 'edit-tab-stops-note-changes)
439 (define-key map "\C-c\C-c" 'edit-tab-stops-note-changes)
440 map)
441 "Keymap used in `edit-tab-stops'.")
483e630e
RM
442
443(defvar edit-tab-stops-buffer nil
444 "Buffer whose tab stops are being edited--in case
445the variable `tab-stop-list' is local in that buffer.")
446
447(defun edit-tab-stops ()
448 "Edit the tab stops used by `tab-to-tab-stop'.
449Creates a buffer *Tab Stops* containing text describing the tab stops.
450A colon indicates a column where there is a tab stop.
451You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops-note-changes] to make changes take effect."
452 (interactive)
453 (setq edit-tab-stops-buffer (current-buffer))
454 (switch-to-buffer (get-buffer-create "*Tab Stops*"))
455 (use-local-map edit-tab-stops-map)
456 (make-local-variable 'indent-tabs-mode)
457 (setq indent-tabs-mode nil)
458 (overwrite-mode 1)
459 (setq truncate-lines t)
460 (erase-buffer)
461 (let ((tabs tab-stop-list))
462 (while tabs
463 (indent-to (car tabs) 0)
464 (insert ?:)
465 (setq tabs (cdr tabs))))
466 (let ((count 0))
467 (insert ?\n)
468 (while (< count 8)
469 (insert (+ count ?0))
470 (insert " ")
471 (setq count (1+ count)))
472 (insert ?\n)
473 (while (> count 0)
474 (insert "0123456789")
475 (setq count (1- count))))
476 (insert "\nTo install changes, type C-c C-c")
477 (goto-char (point-min)))
478
479(defun edit-tab-stops-note-changes ()
480 "Put edited tab stops into effect."
481 (interactive)
482 (let (tabs)
483 (save-excursion
484 (goto-char 1)
485 (end-of-line)
486 (while (search-backward ":" nil t)
487 (setq tabs (cons (current-column) tabs))))
488 (bury-buffer (prog1 (current-buffer)
489 (switch-to-buffer edit-tab-stops-buffer)))
490 (setq tab-stop-list tabs))
491 (message "Tab stops installed"))
492
493(defun tab-to-tab-stop ()
494 "Insert spaces or tabs to next defined tab-stop column.
495The variable `tab-stop-list' is a list of columns at which there are tab stops.
496Use \\[edit-tab-stops] to edit them interactively."
497 (interactive)
a2964053
RS
498 (and abbrev-mode (= (char-syntax (preceding-char)) ?w)
499 (expand-abbrev))
483e630e
RM
500 (let ((tabs tab-stop-list))
501 (while (and tabs (>= (current-column) (car tabs)))
502 (setq tabs (cdr tabs)))
503 (if tabs
9d840bec 504 (let ((opoint (point)))
19b70460 505 (delete-horizontal-space t)
9d840bec 506 (indent-to (car tabs)))
483e630e
RM
507 (insert ?\ ))))
508
509(defun move-to-tab-stop ()
510 "Move point to next defined tab-stop column.
fbf8f564
RS
511The variable `tab-stop-list' is a list of columns at which there are tab stops.
512Use \\[edit-tab-stops] to edit them interactively."
513 (interactive)
514 (let ((tabs tab-stop-list))
515 (while (and tabs (>= (current-column) (car tabs)))
516 (setq tabs (cdr tabs)))
517 (if tabs
518 (let ((before (point)))
519 (move-to-column (car tabs) t)
520 (save-excursion
521 (goto-char before)
522 ;; If we just added a tab, or moved over one,
523 ;; delete any superfluous spaces before the old point.
524 (if (and (eq (preceding-char) ?\ )
525 (eq (following-char) ?\t))
526 (let ((tabend (* (/ (current-column) tab-width) tab-width)))
527 (while (and (> (current-column) tabend)
528 (eq (preceding-char) ?\ ))
529 (forward-char -1))
530 (delete-region (point) before))))))))
531
483e630e 532(define-key global-map "\t" 'indent-for-tab-command)
a17b712b 533(define-key esc-map "\C-\\" 'indent-region)
483e630e
RM
534(define-key ctl-x-map "\t" 'indent-rigidly)
535(define-key esc-map "i" 'tab-to-tab-stop)
1a06eabd
ER
536
537;;; indent.el ends here