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