Update doc for advice changes.
[bpt/emacs.git] / lisp / indent.el
CommitLineData
b7d5bd82 1;;; indent.el --- indentation commands for Emacs -*- lexical-binding:t -*-
1a06eabd 2
ab422c4d 3;; Copyright (C) 1985, 1995, 2001-2013 Free Software Foundation, Inc.
483e630e 4
9750e079 5;; Maintainer: FSF
bd78fa1d 6;; Package: emacs
9750e079 7
483e630e
RM
8;; This file is part of GNU Emacs.
9
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
483e630e 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
483e630e
RM
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
483e630e 22
e41b2db1
ER
23;;; Commentary:
24
25;; Commands for making and changing indentation in text. These are
26;; described in the Emacs manual.
27
e5167999 28;;; Code:
483e630e 29
ddb3136e 30(defgroup indent nil
21751995 31 "Indentation commands."
ddb3136e 32 :group 'editing)
106b6d0e 33
ddb3136e 34(defcustom standard-indent 4
9201cc28 35 "Default number of columns for margin-changing functions to indent."
ddb3136e
RS
36 :group 'indent
37 :type 'integer)
38
f059f703 39(defvar indent-line-function 'indent-relative
a17b712b
SM
40 "Function to indent the current line.
41This function will be called with no arguments.
42If it is called somewhere where auto-indentation cannot be done
59b5f3a8 43\(e.g. inside a string), the function should simply return `noindent'.
a17b712b
SM
44Setting this function is all you need to make TAB indent appropriately.
45Don't rebind TAB unless you really need to.")
483e630e 46
20b1d079 47(defcustom tab-always-indent t
9201cc28 48 "Controls the operation of the TAB key.
20b1d079
SM
49If t, hitting TAB always just indents the current line.
50If nil, hitting TAB indents the current line if point is at the left margin
9450aaa0 51or in the line's indentation, otherwise it inserts a \"real\" TAB character.
51ef56c4
SM
52If `complete', TAB first tries to indent the current line, and if the line
53was already indented, then try to complete the thing at point.
54
9450aaa0 55Some programming language modes have their own variable to control this,
f321348b 56e.g., `c-tab-always-indent', and do not respect this variable."
20b1d079 57 :group 'indent
e073d74a
GM
58 :type '(choice
59 (const :tag "Always indent" t)
60 (const :tag "Indent if inside indentation, else TAB" nil)
61 (const :tag "Indent, or if already indented complete" complete)))
62
20b1d079 63
483e630e 64(defun indent-according-to-mode ()
1a2f8b73 65 "Indent line in proper way for current major mode.
e70b5064
CY
66Normally, this is done by calling the function specified by the
67variable `indent-line-function'. However, if the value of that
68variable is `indent-relative' or `indent-relative-maybe', handle
69it specially (since those functions are used for tabbing); in
70that case, indent by aligning to the previous non-blank line."
483e630e 71 (interactive)
f5632fb6 72 (syntax-propertize (line-end-position))
a17b712b
SM
73 (if (memq indent-line-function
74 '(indent-relative indent-relative-maybe))
75 ;; These functions are used for tabbing, but can't be used for
76 ;; indenting. Replace with something ad-hoc.
77 (let ((column (save-excursion
78 (beginning-of-line)
79 (skip-chars-backward "\n \t")
80 (beginning-of-line)
81 (current-indentation))))
82 (if (<= (current-column) (current-indentation))
83 (indent-line-to column)
84 (save-excursion (indent-line-to column))))
85 ;; The normal case.
86 (funcall indent-line-function)))
483e630e 87
a17b712b 88(defun indent-for-tab-command (&optional arg)
e70b5064
CY
89 "Indent the current line or region, or insert a tab, as appropriate.
90This function either inserts a tab, or indents the current line,
91or performs symbol completion, depending on `tab-always-indent'.
92The function called to actually indent the line or insert a tab
93is given by the variable `indent-line-function'.
94
95If a prefix argument is given, after this function indents the
96current line or inserts a tab, it also rigidly indents the entire
ae8ba409 97balanced expression which starts at the beginning of the current
e70b5064 98line, to reflect the current line's indentation.
1225a933 99
e70b5064
CY
100In most major modes, if point was in the current line's
101indentation, it is moved to the first non-whitespace character
102after indenting; otherwise it stays at the same position relative
103to the text.
1225a933 104
e70b5064
CY
105If `transient-mark-mode' is turned on and the region is active,
106this function instead calls `indent-region'. In this case, any
107prefix argument is ignored."
1225a933 108 (interactive "P")
a17b712b 109 (cond
17ee4625 110 ;; The region is active, indent it.
361a81d9 111 ((use-region-p)
17ee4625 112 (indent-region (region-beginning) (region-end)))
fe552b4c 113 ((or ;; indent-to-left-margin is only meant for indenting,
a17b712b
SM
114 ;; so we force it to always insert a tab here.
115 (eq indent-line-function 'indent-to-left-margin)
116 (and (not tab-always-indent)
f202a7a2
SM
117 (or (> (current-column) (current-indentation))
118 (eq this-command last-command))))
a17b712b 119 (insert-tab arg))
6dd697d9 120 (t
51ef56c4
SM
121 (let ((old-tick (buffer-chars-modified-tick))
122 (old-point (point))
123 (old-indent (current-indentation)))
1225a933
MB
124
125 ;; Indent the line.
126 (funcall indent-line-function)
127
51ef56c4
SM
128 (cond
129 ;; If the text was already indented right, try completion.
130 ((and (eq tab-always-indent 'complete)
131 (eq old-point (point))
132 (eq old-tick (buffer-chars-modified-tick)))
133 (completion-at-point))
134
135 ;; If a prefix argument was given, rigidly indent the following
136 ;; sexp to match the change in the current line's indentation.
137 (arg
138 (let ((end-marker
139 (save-excursion
140 (forward-line 0) (forward-sexp) (point-marker)))
141 (indentation-change (- (current-indentation) old-indent)))
142 (save-excursion
143 (forward-line 1)
144 (when (and (not (zerop indentation-change))
145 (< (point) end-marker))
146 (indent-rigidly (point) end-marker indentation-change))))))))))
a17b712b
SM
147
148(defun insert-tab (&optional arg)
149 (let ((count (prefix-numeric-value arg)))
5e9f80a8
RS
150 (if (and abbrev-mode
151 (eq (char-syntax (preceding-char)) ?w))
10992b01
RS
152 (expand-abbrev))
153 (if indent-tabs-mode
4424ce6f 154 (insert-char ?\t count)
10992b01 155 (indent-to (* tab-width (+ count (/ (current-column) tab-width)))))))
483e630e 156
b7d5bd82
TL
157(defun indent-rigidly--current-indentation (beg end)
158 "Return the smallest indentation in range from BEG to END.
159Blank lines are ignored."
160 (save-excursion
161 (save-match-data
162 (let ((beg (progn (goto-char beg) (line-beginning-position)))
163 indent)
164 (goto-char beg)
165 (while (re-search-forward "^\\s-*[[:print:]]" end t)
166 (setq indent (min (or indent (current-indentation))
167 (current-indentation))))
168 indent))))
169
170(defvar indent-rigidly-map
171 (let ((map (make-sparse-keymap)))
77221051
CY
172 (define-key map [left] 'indent-rigidly-left)
173 (define-key map [right] 'indent-rigidly-right)
174 (define-key map [S-left] 'indent-rigidly-left-to-tab-stop)
175 (define-key map [S-right] 'indent-rigidly-right-to-tab-stop)
176 map)
177 "Transient keymap for adjusting indentation interactively.
178It is activated by calling `indent-rigidly' interactively.")
b7d5bd82 179
77221051
CY
180(defun indent-rigidly (start end arg &optional interactive)
181 "Indent all lines starting in the region.
182If called interactively with no prefix argument, activate a
183transient mode in which the indentation can be adjusted interactively
184by typing \\<indent-rigidly-map>\\[indent-rigidly-left], \\[indent-rigidly-right], \\[indent-rigidly-left-to-tab-stop], or \\[indent-rigidly-right-to-tab-stop].
185Typing any other key deactivates the transient mode.
b7d5bd82 186
77221051
CY
187If called from a program, or interactively with prefix ARG,
188indent all lines starting in the region forward by ARG columns.
189If called from a program, START and END specify the beginning and
190end of the text to act on, in place of the region.
b7d5bd82 191
77221051
CY
192Negative values of ARG indent backward, so you can remove all
193indentation by specifying a large negative ARG."
b7d5bd82
TL
194 (interactive "r\nP\np")
195 (if (and (not arg) interactive)
196 (progn
7510b021
CY
197 (message
198 (substitute-command-keys
199 "Indent region with \\<indent-rigidly-map>\\[indent-rigidly-left], \\[indent-rigidly-right], \\[indent-rigidly-left-to-tab-stop], or \\[indent-rigidly-right-to-tab-stop]."))
8cd22a08 200 (set-transient-map indent-rigidly-map t))
b7d5bd82
TL
201 (save-excursion
202 (goto-char end)
203 (setq end (point-marker))
204 (goto-char start)
205 (or (bolp) (forward-line 1))
206 (while (< (point) end)
207 (let ((indent (current-indentation))
208 eol-flag)
209 (save-excursion
210 (skip-chars-forward " \t")
211 (setq eol-flag (eolp)))
212 (or eol-flag
642eb8b6 213 (indent-to (max 0 (+ indent (prefix-numeric-value arg))) 0))
b7d5bd82
TL
214 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
215 (forward-line 1))
216 (move-marker end nil))))
483e630e 217
77221051
CY
218(defun indent-rigidly--pop-undo ()
219 (and (memq last-command '(indent-rigidly-left indent-rigidly-right
220 indent-rigidly-left-to-tab-stop
221 indent-rigidly-right-to-tab-stop))
222 (consp buffer-undo-list)
223 (eq (car buffer-undo-list) nil)
224 (pop buffer-undo-list)))
225
226(defun indent-rigidly-left (beg end)
227 "Indent all lines between BEG and END leftward by one space."
228 (interactive "r")
229 (indent-rigidly--pop-undo)
230 (indent-rigidly
231 beg end
232 (if (eq (current-bidi-paragraph-direction) 'right-to-left) 1 -1)))
233
234(defun indent-rigidly-right (beg end)
235 "Indent all lines between BEG and END rightward by one space."
236 (interactive "r")
237 (indent-rigidly--pop-undo)
238 (indent-rigidly
239 beg end
240 (if (eq (current-bidi-paragraph-direction) 'right-to-left) -1 1)))
241
242(defun indent-rigidly-left-to-tab-stop (beg end)
243 "Indent all lines between BEG and END leftward to a tab stop."
244 (interactive "r")
245 (indent-rigidly--pop-undo)
246 (let* ((current (indent-rigidly--current-indentation beg end))
247 (rtl (eq (current-bidi-paragraph-direction) 'right-to-left))
248 (next (indent--next-tab-stop current (if rtl nil 'prev))))
249 (indent-rigidly beg end (- next current))))
250
251(defun indent-rigidly-right-to-tab-stop (beg end)
252 "Indent all lines between BEG and END rightward to a tab stop."
253 (interactive "r")
254 (indent-rigidly--pop-undo)
255 (let* ((current (indent-rigidly--current-indentation beg end))
256 (rtl (eq (current-bidi-paragraph-direction) 'right-to-left))
257 (next (indent--next-tab-stop current (if rtl 'prev))))
258 (indent-rigidly beg end (- next current))))
259
106b6d0e
RS
260(defun indent-line-to (column)
261 "Indent current line to COLUMN.
262This function removes or adds spaces and tabs at beginning of line
263only if necessary. It leaves point at end of indentation."
ca2a3cb7
BG
264 (back-to-indentation)
265 (let ((cur-col (current-column)))
266 (cond ((< cur-col column)
cd6d305e 267 (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width)
a80a30b3
RS
268 (delete-region (point)
269 (progn (skip-chars-backward " ") (point))))
ca2a3cb7
BG
270 (indent-to column))
271 ((> cur-col column) ; too far right (after tab?)
34c3f2b8 272 (delete-region (progn (move-to-column column t) (point))
ca2a3cb7 273 (progn (back-to-indentation) (point)))))))
106b6d0e
RS
274
275(defun current-left-margin ()
276 "Return the left margin to use for this line.
277This is the value of the buffer-local variable `left-margin' plus the value
278of the `left-margin' text-property at the start of the line."
279 (save-excursion
280 (back-to-indentation)
281 (max 0
34c3f2b8
BG
282 (+ left-margin (or (get-text-property
283 (if (and (eobp) (not (bobp)))
284 (1- (point)) (point))
285 'left-margin) 0)))))
106b6d0e 286
34c3f2b8 287(defun move-to-left-margin (&optional n force)
106b6d0e
RS
288 "Move to the left margin of the current line.
289With optional argument, move forward N-1 lines first.
34c3f2b8
BG
290The column moved to is the one given by the `current-left-margin' function.
291If the line's indentation appears to be wrong, and this command is called
292interactively or with optional argument FORCE, it will be fixed."
293 (interactive (list (prefix-numeric-value current-prefix-arg) t))
106b6d0e 294 (beginning-of-line n)
54505d72 295 (skip-chars-forward " \t")
1d1c5af9
RS
296 (if (minibufferp (current-buffer))
297 (if (save-excursion (beginning-of-line) (bobp))
298 (goto-char (minibuffer-prompt-end))
299 (beginning-of-line))
300 (let ((lm (current-left-margin))
301 (cc (current-column)))
302 (cond ((> cc lm)
303 (if (> (move-to-column lm force) lm)
304 ;; If lm is in a tab and we are not forcing, move before tab
305 (backward-char 1)))
306 ((and force (< cc lm))
307 (indent-to-left-margin))))))
106b6d0e 308
f202a7a2 309;; This used to be the default indent-line-function,
483e630e
RM
310;; used in Fundamental Mode, Text Mode, etc.
311(defun indent-to-left-margin ()
34c3f2b8 312 "Indent current line to the column given by `current-left-margin'."
caadec43
RS
313 (save-excursion (indent-line-to (current-left-margin)))
314 ;; If we are within the indentation, move past it.
315 (when (save-excursion
316 (skip-chars-backward " \t")
317 (bolp))
318 (skip-chars-forward " \t")))
106b6d0e 319
34c3f2b8
BG
320(defun delete-to-left-margin (&optional from to)
321 "Remove left margin indentation from a region.
322This deletes to the column given by `current-left-margin'.
323In no case will it delete non-whitespace.
324Args FROM and TO are optional; default is the whole buffer."
106b6d0e 325 (save-excursion
34c3f2b8 326 (goto-char (or to (point-max)))
106b6d0e 327 (setq to (point-marker))
34c3f2b8 328 (goto-char (or from (point-min)))
106b6d0e
RS
329 (or (bolp) (forward-line 1))
330 (while (< (point) to)
34c3f2b8 331 (delete-region (point) (progn (move-to-left-margin nil t) (point)))
106b6d0e
RS
332 (forward-line 1))
333 (move-marker to nil)))
334
a5b3d1b8 335(defun set-left-margin (from to width)
106b6d0e 336 "Set the left margin of the region to WIDTH.
a5b3d1b8
LT
337If `auto-fill-mode' is active, re-fill the region to fit the new margin.
338
339Interactively, WIDTH is the prefix argument, if specified.
340Without prefix argument, the command prompts for WIDTH."
106b6d0e 341 (interactive "r\nNSet left margin to column: ")
106b6d0e
RS
342 (save-excursion
343 ;; If inside indentation, start from BOL.
344 (goto-char from)
345 (skip-chars-backward " \t")
346 (if (bolp) (setq from (point)))
34c3f2b8 347 ;; Place end after whitespace
106b6d0e 348 (goto-char to)
34c3f2b8 349 (skip-chars-forward " \t")
106b6d0e 350 (setq to (point-marker)))
34c3f2b8
BG
351 ;; Delete margin indentation first, but keep paragraph indentation.
352 (delete-to-left-margin from to)
a5b3d1b8
LT
353 (put-text-property from to 'left-margin width)
354 (indent-rigidly from to width)
34c3f2b8 355 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
356 (move-marker to nil))
357
a5b3d1b8 358(defun set-right-margin (from to width)
106b6d0e 359 "Set the right margin of the region to WIDTH.
a5b3d1b8
LT
360If `auto-fill-mode' is active, re-fill the region to fit the new margin.
361
362Interactively, WIDTH is the prefix argument, if specified.
363Without prefix argument, the command prompts for WIDTH."
8cf19007 364 (interactive "r\nNSet right margin to width: ")
106b6d0e
RS
365 (save-excursion
366 (goto-char from)
367 (skip-chars-backward " \t")
368 (if (bolp) (setq from (point))))
a5b3d1b8 369 (put-text-property from to 'right-margin width)
34c3f2b8 370 (if auto-fill-function (save-excursion (fill-region from to nil t t))))
106b6d0e
RS
371
372(defun alter-text-property (from to prop func &optional object)
373 "Programmatically change value of a text-property.
374For each region between FROM and TO that has a single value for PROPERTY,
375apply FUNCTION to that value and sets the property to the function's result.
376Optional fifth argument OBJECT specifies the string or buffer to operate on."
377 (let ((begin from)
378 end val)
379 (while (setq val (get-text-property begin prop object)
380 end (text-property-not-all begin to prop val object))
381 (put-text-property begin end prop (funcall func val) object)
382 (setq begin end))
383 (if (< begin to)
384 (put-text-property begin to prop (funcall func val) object))))
385
386(defun increase-left-margin (from to inc)
387 "Increase or decrease the left-margin of the region.
388With no prefix argument, this adds `standard-indent' of indentation.
389A prefix arg (optional third arg INC noninteractively) specifies the amount
390to change the margin by, in characters.
391If `auto-fill-mode' is active, re-fill the region to fit the new margin."
392 (interactive "*r\nP")
393 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
394 (save-excursion
395 (goto-char from)
396 (skip-chars-backward " \t")
397 (if (bolp) (setq from (point)))
398 (goto-char to)
399 (setq to (point-marker)))
106b6d0e 400 (alter-text-property from to 'left-margin
34c3f2b8
BG
401 (lambda (v) (max (- left-margin) (+ inc (or v 0)))))
402 (indent-rigidly from to inc)
403 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
404 (move-marker to nil))
405
406(defun decrease-left-margin (from to inc)
407 "Make the left margin of the region smaller.
408With no prefix argument, decrease the indentation by `standard-indent'.
409A prefix arg (optional third arg INC noninteractively) specifies the amount
410to change the margin by, in characters.
411If `auto-fill-mode' is active, re-fill the region to fit the new margin."
412 (interactive "*r\nP")
413 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
414 (increase-left-margin from to (- inc)))
415
416(defun increase-right-margin (from to inc)
417 "Increase the right-margin of the region.
418With no prefix argument, increase the right margin by `standard-indent'.
419A prefix arg (optional third arg INC noninteractively) specifies the amount
420to change the margin by, in characters. A negative argument decreases
421the right margin width.
422If `auto-fill-mode' is active, re-fill the region to fit the new margin."
423 (interactive "r\nP")
6faab05f 424 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
106b6d0e
RS
425 (save-excursion
426 (alter-text-property from to 'right-margin
6faab05f 427 (lambda (v) (+ inc (or v 0))))
106b6d0e
RS
428 (if auto-fill-function
429 (fill-region from to nil t t))))
430
431(defun decrease-right-margin (from to inc)
432 "Make the right margin of the region smaller.
433With no prefix argument, decrease the right margin by `standard-indent'.
434A prefix arg (optional third arg INC noninteractively) specifies the amount
435of width to remove, in characters. A negative argument increases
436the right margin width.
437If `auto-fill-mode' is active, re-fills region to fit in new margin."
438 (interactive "*r\nP")
439 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
440 (increase-right-margin from to (- inc)))
483e630e 441
34c3f2b8
BG
442(defun beginning-of-line-text (&optional n)
443 "Move to the beginning of the text on this line.
444With optional argument, move forward N-1 lines first.
445From the beginning of the line, moves past the left-margin indentation, the
446fill-prefix, and any indentation used for centering or right-justifying the
f1180544 447line, but does not move past any whitespace that was explicitly inserted
34c3f2b8
BG
448\(such as a tab used to indent the first line of a paragraph)."
449 (interactive "p")
450 (beginning-of-line n)
451 (skip-chars-forward " \t")
452 ;; Skip over fill-prefix.
f1180544 453 (if (and fill-prefix
34c3f2b8
BG
454 (not (string-equal fill-prefix "")))
455 (if (equal fill-prefix
f1180544 456 (buffer-substring
34c3f2b8
BG
457 (point) (min (point-max) (+ (length fill-prefix) (point)))))
458 (forward-char (length fill-prefix)))
7d43e2ad 459 (if (and adaptive-fill-mode adaptive-fill-regexp
34c3f2b8
BG
460 (looking-at adaptive-fill-regexp))
461 (goto-char (match-end 0))))
462 ;; Skip centering or flushright indentation
463 (if (memq (current-justification) '(center right))
464 (skip-chars-forward " \t")))
465
483e630e 466(defvar indent-region-function nil
3704e77e
RS
467 "Short cut function to indent region using `indent-according-to-mode'.
468A value of nil means really run `indent-according-to-mode' on each line.")
483e630e 469
1d9cc345 470(defun indent-region (start end &optional column)
483e630e 471 "Indent each nonblank line in the region.
1a2f8b73
RS
472A numeric prefix argument specifies a column: indent each line to that column.
473
474With no prefix argument, the command chooses one of these methods and
475indents all the lines with it:
476
477 1) If `fill-prefix' is non-nil, insert `fill-prefix' at the
478 beginning of each line in the region that does not already begin
479 with it.
480 2) If `indent-region-function' is non-nil, call that function
481 to indent the region.
e70b5064 482 3) Indent each line via `indent-according-to-mode'.
1a2f8b73
RS
483
484Called from a program, START and END specify the region to indent.
485If the third argument COLUMN is an integer, it specifies the
486column to indent to; if it is nil, use one of the three methods above."
483e630e 487 (interactive "r\nP")
e70b5064 488 (cond
b7d5bd82 489 ;; If a numeric prefix is given, indent to that column.
e70b5064 490 (column
88a2603a 491 (setq column (prefix-numeric-value column))
483e630e
RM
492 (save-excursion
493 (goto-char end)
494 (setq end (point-marker))
495 (goto-char start)
496 (or (bolp) (forward-line 1))
497 (while (< (point) end)
498 (delete-region (point) (progn (skip-chars-forward " \t") (point)))
499 (or (eolp)
106b6d0e 500 (indent-to column 0))
b7d5bd82 501 (forward-line 1))
2a96c2a7 502 (move-marker end nil)))
b7d5bd82 503 ;; If a fill-prefix is specified, use it.
e70b5064
CY
504 (fill-prefix
505 (save-excursion
506 (goto-char end)
507 (setq end (point-marker))
508 (goto-char start)
509 (let ((regexp (regexp-quote fill-prefix)))
510 (while (< (point) end)
511 (or (looking-at regexp)
512 (and (bolp) (eolp))
513 (insert fill-prefix))
514 (forward-line 1)))))
b7d5bd82 515 ;; Use indent-region-function is available.
e70b5064
CY
516 (indent-region-function
517 (funcall indent-region-function start end))
b7d5bd82
TL
518 ;; Else, use a default implementation that calls indent-line-function on
519 ;; each line.
e70b5064
CY
520 (t
521 (save-excursion
522 (setq end (copy-marker end))
523 (goto-char start)
b9e20952
LL
524 (let ((pr (unless (minibufferp)
525 (make-progress-reporter "Indenting region..." (point) end))))
526 (while (< (point) end)
527 (or (and (bolp) (eolp))
528 (indent-according-to-mode))
b7d5bd82 529 (forward-line 1)
b9e20952
LL
530 (and pr (progress-reporter-update pr (point))))
531 (and pr (progress-reporter-done pr))
b7d5bd82 532 (move-marker end nil)))))
2a96c2a7
SM
533 ;; In most cases, reindenting modifies the buffer, but it may also
534 ;; leave it unmodified, in which case we have to deactivate the mark
535 ;; by hand.
536 (deactivate-mark))
483e630e
RM
537
538(defun indent-relative-maybe ()
1fd63d9b
EZ
539 "Indent a new line like previous nonblank line.
540If the previous nonblank line has no indent points beyond the
541column point starts at, this command does nothing.
542
543See also `indent-relative'."
483e630e
RM
544 (interactive)
545 (indent-relative t))
546
547(defun indent-relative (&optional unindented-ok)
548 "Space out to under next indent point in previous nonblank line.
549An indent point is a non-whitespace character following whitespace.
f6f53207
RS
550The following line shows the indentation points in this line.
551 ^ ^ ^ ^ ^ ^ ^ ^ ^
483e630e 552If the previous nonblank line has no indent points beyond the
1fd63d9b
EZ
553column point starts at, `tab-to-tab-stop' is done instead, unless
554this command is invoked with a numeric argument, in which case it
555does nothing.
556
557See also `indent-relative-maybe'."
483e630e 558 (interactive "P")
5e9f80a8
RS
559 (if (and abbrev-mode
560 (eq (char-syntax (preceding-char)) ?w))
561 (expand-abbrev))
483e630e
RM
562 (let ((start-column (current-column))
563 indent)
564 (save-excursion
565 (beginning-of-line)
566 (if (re-search-backward "^[^\n]" nil t)
567 (let ((end (save-excursion (forward-line 1) (point))))
568 (move-to-column start-column)
569 ;; Is start-column inside a tab on this line?
570 (if (> (current-column) start-column)
571 (backward-char 1))
572 (or (looking-at "[ \t]")
573 unindented-ok
574 (skip-chars-forward "^ \t" end))
575 (skip-chars-forward " \t" end)
576 (or (= (point) end) (setq indent (current-column))))))
577 (if indent
578 (let ((opoint (point-marker)))
483e630e
RM
579 (indent-to indent 0)
580 (if (> opoint (point))
581 (goto-char opoint))
582 (move-marker opoint nil))
583 (tab-to-tab-stop))))
584
ddb3136e 585(defcustom tab-stop-list
b7d5bd82 586 nil
9201cc28 587 "List of tab stop positions used by `tab-to-tab-stop'.
b7d5bd82
TL
588This should be a list of integers, ordered from smallest to largest.
589It implicitly extends to infinity by repeating the last step (e.g. '(1 2 5)
590is equivalent to '(1 2 5 8 11)).
591If the list has less than 2 elements, `tab-width' is used as the \"last step\"."
ddb3136e
RS
592 :group 'indent
593 :type '(repeat integer))
44b275c4 594(put 'tab-stop-list 'safe-local-variable 'listp)
483e630e 595
a17b712b
SM
596(defvar edit-tab-stops-map
597 (let ((map (make-sparse-keymap)))
598 (define-key map "\C-x\C-s" 'edit-tab-stops-note-changes)
599 (define-key map "\C-c\C-c" 'edit-tab-stops-note-changes)
600 map)
601 "Keymap used in `edit-tab-stops'.")
483e630e
RM
602
603(defvar edit-tab-stops-buffer nil
bc57b735
LT
604 "Buffer whose tab stops are being edited.
605This matters if the variable `tab-stop-list' is local in that buffer.")
483e630e
RM
606
607(defun edit-tab-stops ()
608 "Edit the tab stops used by `tab-to-tab-stop'.
609Creates a buffer *Tab Stops* containing text describing the tab stops.
610A colon indicates a column where there is a tab stop.
611You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops-note-changes] to make changes take effect."
612 (interactive)
613 (setq edit-tab-stops-buffer (current-buffer))
614 (switch-to-buffer (get-buffer-create "*Tab Stops*"))
615 (use-local-map edit-tab-stops-map)
b7d5bd82 616 (setq-local indent-tabs-mode nil)
483e630e
RM
617 (overwrite-mode 1)
618 (setq truncate-lines t)
619 (erase-buffer)
620 (let ((tabs tab-stop-list))
621 (while tabs
622 (indent-to (car tabs) 0)
623 (insert ?:)
624 (setq tabs (cdr tabs))))
625 (let ((count 0))
626 (insert ?\n)
627 (while (< count 8)
628 (insert (+ count ?0))
629 (insert " ")
630 (setq count (1+ count)))
631 (insert ?\n)
632 (while (> count 0)
633 (insert "0123456789")
634 (setq count (1- count))))
635 (insert "\nTo install changes, type C-c C-c")
636 (goto-char (point-min)))
637
638(defun edit-tab-stops-note-changes ()
639 "Put edited tab stops into effect."
640 (interactive)
641 (let (tabs)
642 (save-excursion
643 (goto-char 1)
644 (end-of-line)
645 (while (search-backward ":" nil t)
646 (setq tabs (cons (current-column) tabs))))
647 (bury-buffer (prog1 (current-buffer)
648 (switch-to-buffer edit-tab-stops-buffer)))
649 (setq tab-stop-list tabs))
650 (message "Tab stops installed"))
651
b7d5bd82
TL
652(defun indent--next-tab-stop (column &optional prev)
653 "Return the next tab stop after COLUMN.
654If PREV is non-nil, return the previous one instead."
655 (let ((tabs tab-stop-list))
656 (while (and tabs (>= column (car tabs)))
657 (setq tabs (cdr tabs)))
658 (if tabs
659 (if (not prev)
660 (car tabs)
661 (let ((prevtabs (cdr (memq (car tabs) (reverse tab-stop-list)))))
662 (if (null prevtabs) 0
663 (if (= column (car prevtabs))
664 (or (nth 1 prevtabs) 0)
665 (car prevtabs)))))
666 ;; We passed the end of tab-stop-list: guess a continuation.
667 (let* ((last2 (last tab-stop-list 2))
668 (step (if (cdr last2) (- (cadr last2) (car last2)) tab-width))
669 (last (or (cadr last2) (car last2) 0)))
670 ;; Repeat the last tab's length.
671 (+ last (* step (if prev
672 (if (<= column last) -1 (/ (- column last 1) step))
673 (1+ (/ (- column last) step)))))))))
674
483e630e
RM
675(defun tab-to-tab-stop ()
676 "Insert spaces or tabs to next defined tab-stop column.
677The variable `tab-stop-list' is a list of columns at which there are tab stops.
678Use \\[edit-tab-stops] to edit them interactively."
679 (interactive)
a2964053
RS
680 (and abbrev-mode (= (char-syntax (preceding-char)) ?w)
681 (expand-abbrev))
b7d5bd82
TL
682 (let ((nexttab (indent--next-tab-stop (current-column))))
683 (delete-horizontal-space t)
684 (indent-to nexttab)))
483e630e
RM
685
686(defun move-to-tab-stop ()
687 "Move point to next defined tab-stop column.
fbf8f564
RS
688The variable `tab-stop-list' is a list of columns at which there are tab stops.
689Use \\[edit-tab-stops] to edit them interactively."
690 (interactive)
b7d5bd82
TL
691 (let ((nexttab (indent--next-tab-stop (current-column))))
692 (let ((before (point)))
693 (move-to-column nexttab t)
694 (save-excursion
695 (goto-char before)
696 ;; If we just added a tab, or moved over one,
697 ;; delete any superfluous spaces before the old point.
698 (if (and (eq (preceding-char) ?\s)
699 (eq (following-char) ?\t))
700 (let ((tabend (* (/ (current-column) tab-width) tab-width)))
701 (while (and (> (current-column) tabend)
702 (eq (preceding-char) ?\s))
703 (forward-char -1))
704 (delete-region (point) before)))))))
fbf8f564 705
483e630e 706(define-key global-map "\t" 'indent-for-tab-command)
a17b712b 707(define-key esc-map "\C-\\" 'indent-region)
483e630e
RM
708(define-key ctl-x-map "\t" 'indent-rigidly)
709(define-key esc-map "i" 'tab-to-tab-stop)
1a06eabd
ER
710
711;;; indent.el ends here