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