Some documenting of load-prefer-newer
[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
197 (message "Edit region indentation with <left>, <right>, <S-left> \
198and <S-right>.")
199 (set-temporary-overlay-map indent-rigidly-map t))
200 (save-excursion
201 (goto-char end)
202 (setq end (point-marker))
203 (goto-char start)
204 (or (bolp) (forward-line 1))
205 (while (< (point) end)
206 (let ((indent (current-indentation))
207 eol-flag)
208 (save-excursion
209 (skip-chars-forward " \t")
210 (setq eol-flag (eolp)))
211 (or eol-flag
642eb8b6 212 (indent-to (max 0 (+ indent (prefix-numeric-value arg))) 0))
b7d5bd82
TL
213 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
214 (forward-line 1))
215 (move-marker end nil))))
483e630e 216
77221051
CY
217(defun indent-rigidly--pop-undo ()
218 (and (memq last-command '(indent-rigidly-left indent-rigidly-right
219 indent-rigidly-left-to-tab-stop
220 indent-rigidly-right-to-tab-stop))
221 (consp buffer-undo-list)
222 (eq (car buffer-undo-list) nil)
223 (pop buffer-undo-list)))
224
225(defun indent-rigidly-left (beg end)
226 "Indent all lines between BEG and END leftward by one space."
227 (interactive "r")
228 (indent-rigidly--pop-undo)
229 (indent-rigidly
230 beg end
231 (if (eq (current-bidi-paragraph-direction) 'right-to-left) 1 -1)))
232
233(defun indent-rigidly-right (beg end)
234 "Indent all lines between BEG and END rightward by one space."
235 (interactive "r")
236 (indent-rigidly--pop-undo)
237 (indent-rigidly
238 beg end
239 (if (eq (current-bidi-paragraph-direction) 'right-to-left) -1 1)))
240
241(defun indent-rigidly-left-to-tab-stop (beg end)
242 "Indent all lines between BEG and END leftward to a tab stop."
243 (interactive "r")
244 (indent-rigidly--pop-undo)
245 (let* ((current (indent-rigidly--current-indentation beg end))
246 (rtl (eq (current-bidi-paragraph-direction) 'right-to-left))
247 (next (indent--next-tab-stop current (if rtl nil 'prev))))
248 (indent-rigidly beg end (- next current))))
249
250(defun indent-rigidly-right-to-tab-stop (beg end)
251 "Indent all lines between BEG and END rightward to a tab stop."
252 (interactive "r")
253 (indent-rigidly--pop-undo)
254 (let* ((current (indent-rigidly--current-indentation beg end))
255 (rtl (eq (current-bidi-paragraph-direction) 'right-to-left))
256 (next (indent--next-tab-stop current (if rtl 'prev))))
257 (indent-rigidly beg end (- next current))))
258
106b6d0e
RS
259(defun indent-line-to (column)
260 "Indent current line to COLUMN.
261This function removes or adds spaces and tabs at beginning of line
262only if necessary. It leaves point at end of indentation."
ca2a3cb7
BG
263 (back-to-indentation)
264 (let ((cur-col (current-column)))
265 (cond ((< cur-col column)
cd6d305e 266 (if (>= (- column (* (/ cur-col tab-width) tab-width)) tab-width)
a80a30b3
RS
267 (delete-region (point)
268 (progn (skip-chars-backward " ") (point))))
ca2a3cb7
BG
269 (indent-to column))
270 ((> cur-col column) ; too far right (after tab?)
34c3f2b8 271 (delete-region (progn (move-to-column column t) (point))
ca2a3cb7 272 (progn (back-to-indentation) (point)))))))
106b6d0e
RS
273
274(defun current-left-margin ()
275 "Return the left margin to use for this line.
276This is the value of the buffer-local variable `left-margin' plus the value
277of the `left-margin' text-property at the start of the line."
278 (save-excursion
279 (back-to-indentation)
280 (max 0
34c3f2b8
BG
281 (+ left-margin (or (get-text-property
282 (if (and (eobp) (not (bobp)))
283 (1- (point)) (point))
284 'left-margin) 0)))))
106b6d0e 285
34c3f2b8 286(defun move-to-left-margin (&optional n force)
106b6d0e
RS
287 "Move to the left margin of the current line.
288With optional argument, move forward N-1 lines first.
34c3f2b8
BG
289The column moved to is the one given by the `current-left-margin' function.
290If the line's indentation appears to be wrong, and this command is called
291interactively or with optional argument FORCE, it will be fixed."
292 (interactive (list (prefix-numeric-value current-prefix-arg) t))
106b6d0e 293 (beginning-of-line n)
54505d72 294 (skip-chars-forward " \t")
1d1c5af9
RS
295 (if (minibufferp (current-buffer))
296 (if (save-excursion (beginning-of-line) (bobp))
297 (goto-char (minibuffer-prompt-end))
298 (beginning-of-line))
299 (let ((lm (current-left-margin))
300 (cc (current-column)))
301 (cond ((> cc lm)
302 (if (> (move-to-column lm force) lm)
303 ;; If lm is in a tab and we are not forcing, move before tab
304 (backward-char 1)))
305 ((and force (< cc lm))
306 (indent-to-left-margin))))))
106b6d0e 307
f202a7a2 308;; This used to be the default indent-line-function,
483e630e
RM
309;; used in Fundamental Mode, Text Mode, etc.
310(defun indent-to-left-margin ()
34c3f2b8 311 "Indent current line to the column given by `current-left-margin'."
caadec43
RS
312 (save-excursion (indent-line-to (current-left-margin)))
313 ;; If we are within the indentation, move past it.
314 (when (save-excursion
315 (skip-chars-backward " \t")
316 (bolp))
317 (skip-chars-forward " \t")))
106b6d0e 318
34c3f2b8
BG
319(defun delete-to-left-margin (&optional from to)
320 "Remove left margin indentation from a region.
321This deletes to the column given by `current-left-margin'.
322In no case will it delete non-whitespace.
323Args FROM and TO are optional; default is the whole buffer."
106b6d0e 324 (save-excursion
34c3f2b8 325 (goto-char (or to (point-max)))
106b6d0e 326 (setq to (point-marker))
34c3f2b8 327 (goto-char (or from (point-min)))
106b6d0e
RS
328 (or (bolp) (forward-line 1))
329 (while (< (point) to)
34c3f2b8 330 (delete-region (point) (progn (move-to-left-margin nil t) (point)))
106b6d0e
RS
331 (forward-line 1))
332 (move-marker to nil)))
333
a5b3d1b8 334(defun set-left-margin (from to width)
106b6d0e 335 "Set the left margin of the region to WIDTH.
a5b3d1b8
LT
336If `auto-fill-mode' is active, re-fill the region to fit the new margin.
337
338Interactively, WIDTH is the prefix argument, if specified.
339Without prefix argument, the command prompts for WIDTH."
106b6d0e 340 (interactive "r\nNSet left margin to column: ")
106b6d0e
RS
341 (save-excursion
342 ;; If inside indentation, start from BOL.
343 (goto-char from)
344 (skip-chars-backward " \t")
345 (if (bolp) (setq from (point)))
34c3f2b8 346 ;; Place end after whitespace
106b6d0e 347 (goto-char to)
34c3f2b8 348 (skip-chars-forward " \t")
106b6d0e 349 (setq to (point-marker)))
34c3f2b8
BG
350 ;; Delete margin indentation first, but keep paragraph indentation.
351 (delete-to-left-margin from to)
a5b3d1b8
LT
352 (put-text-property from to 'left-margin width)
353 (indent-rigidly from to width)
34c3f2b8 354 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
355 (move-marker to nil))
356
a5b3d1b8 357(defun set-right-margin (from to width)
106b6d0e 358 "Set the right margin of the region to WIDTH.
a5b3d1b8
LT
359If `auto-fill-mode' is active, re-fill the region to fit the new margin.
360
361Interactively, WIDTH is the prefix argument, if specified.
362Without prefix argument, the command prompts for WIDTH."
8cf19007 363 (interactive "r\nNSet right margin to width: ")
106b6d0e
RS
364 (save-excursion
365 (goto-char from)
366 (skip-chars-backward " \t")
367 (if (bolp) (setq from (point))))
a5b3d1b8 368 (put-text-property from to 'right-margin width)
34c3f2b8 369 (if auto-fill-function (save-excursion (fill-region from to nil t t))))
106b6d0e
RS
370
371(defun alter-text-property (from to prop func &optional object)
372 "Programmatically change value of a text-property.
373For each region between FROM and TO that has a single value for PROPERTY,
374apply FUNCTION to that value and sets the property to the function's result.
375Optional fifth argument OBJECT specifies the string or buffer to operate on."
376 (let ((begin from)
377 end val)
378 (while (setq val (get-text-property begin prop object)
379 end (text-property-not-all begin to prop val object))
380 (put-text-property begin end prop (funcall func val) object)
381 (setq begin end))
382 (if (< begin to)
383 (put-text-property begin to prop (funcall func val) object))))
384
385(defun increase-left-margin (from to inc)
386 "Increase or decrease the left-margin of the region.
387With no prefix argument, this adds `standard-indent' of indentation.
388A prefix arg (optional third arg INC noninteractively) specifies the amount
389to change the margin by, in characters.
390If `auto-fill-mode' is active, re-fill the region to fit the new margin."
391 (interactive "*r\nP")
392 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
393 (save-excursion
394 (goto-char from)
395 (skip-chars-backward " \t")
396 (if (bolp) (setq from (point)))
397 (goto-char to)
398 (setq to (point-marker)))
106b6d0e 399 (alter-text-property from to 'left-margin
34c3f2b8
BG
400 (lambda (v) (max (- left-margin) (+ inc (or v 0)))))
401 (indent-rigidly from to inc)
402 (if auto-fill-function (save-excursion (fill-region from to nil t t)))
106b6d0e
RS
403 (move-marker to nil))
404
405(defun decrease-left-margin (from to inc)
406 "Make the left margin of the region smaller.
407With no prefix argument, decrease the indentation by `standard-indent'.
408A prefix arg (optional third arg INC noninteractively) specifies the amount
409to change the margin by, in characters.
410If `auto-fill-mode' is active, re-fill the region to fit the new margin."
411 (interactive "*r\nP")
412 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
413 (increase-left-margin from to (- inc)))
414
415(defun increase-right-margin (from to inc)
416 "Increase the right-margin of the region.
417With no prefix argument, increase the right margin by `standard-indent'.
418A prefix arg (optional third arg INC noninteractively) specifies the amount
419to change the margin by, in characters. A negative argument decreases
420the right margin width.
421If `auto-fill-mode' is active, re-fill the region to fit the new margin."
422 (interactive "r\nP")
6faab05f 423 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
106b6d0e
RS
424 (save-excursion
425 (alter-text-property from to 'right-margin
6faab05f 426 (lambda (v) (+ inc (or v 0))))
106b6d0e
RS
427 (if auto-fill-function
428 (fill-region from to nil t t))))
429
430(defun decrease-right-margin (from to inc)
431 "Make the right margin of the region smaller.
432With no prefix argument, decrease the right margin by `standard-indent'.
433A prefix arg (optional third arg INC noninteractively) specifies the amount
434of width to remove, in characters. A negative argument increases
435the right margin width.
436If `auto-fill-mode' is active, re-fills region to fit in new margin."
437 (interactive "*r\nP")
438 (setq inc (if inc (prefix-numeric-value inc) standard-indent))
439 (increase-right-margin from to (- inc)))
483e630e 440
34c3f2b8
BG
441(defun beginning-of-line-text (&optional n)
442 "Move to the beginning of the text on this line.
443With optional argument, move forward N-1 lines first.
444From the beginning of the line, moves past the left-margin indentation, the
445fill-prefix, and any indentation used for centering or right-justifying the
f1180544 446line, but does not move past any whitespace that was explicitly inserted
34c3f2b8
BG
447\(such as a tab used to indent the first line of a paragraph)."
448 (interactive "p")
449 (beginning-of-line n)
450 (skip-chars-forward " \t")
451 ;; Skip over fill-prefix.
f1180544 452 (if (and fill-prefix
34c3f2b8
BG
453 (not (string-equal fill-prefix "")))
454 (if (equal fill-prefix
f1180544 455 (buffer-substring
34c3f2b8
BG
456 (point) (min (point-max) (+ (length fill-prefix) (point)))))
457 (forward-char (length fill-prefix)))
7d43e2ad 458 (if (and adaptive-fill-mode adaptive-fill-regexp
34c3f2b8
BG
459 (looking-at adaptive-fill-regexp))
460 (goto-char (match-end 0))))
461 ;; Skip centering or flushright indentation
462 (if (memq (current-justification) '(center right))
463 (skip-chars-forward " \t")))
464
483e630e 465(defvar indent-region-function nil
3704e77e
RS
466 "Short cut function to indent region using `indent-according-to-mode'.
467A value of nil means really run `indent-according-to-mode' on each line.")
483e630e 468
1d9cc345 469(defun indent-region (start end &optional column)
483e630e 470 "Indent each nonblank line in the region.
1a2f8b73
RS
471A numeric prefix argument specifies a column: indent each line to that column.
472
473With no prefix argument, the command chooses one of these methods and
474indents all the lines with it:
475
476 1) If `fill-prefix' is non-nil, insert `fill-prefix' at the
477 beginning of each line in the region that does not already begin
478 with it.
479 2) If `indent-region-function' is non-nil, call that function
480 to indent the region.
e70b5064 481 3) Indent each line via `indent-according-to-mode'.
1a2f8b73
RS
482
483Called from a program, START and END specify the region to indent.
484If the third argument COLUMN is an integer, it specifies the
485column to indent to; if it is nil, use one of the three methods above."
483e630e 486 (interactive "r\nP")
e70b5064 487 (cond
b7d5bd82 488 ;; If a numeric prefix is given, indent to that column.
e70b5064 489 (column
88a2603a 490 (setq column (prefix-numeric-value column))
483e630e
RM
491 (save-excursion
492 (goto-char end)
493 (setq end (point-marker))
494 (goto-char start)
495 (or (bolp) (forward-line 1))
496 (while (< (point) end)
497 (delete-region (point) (progn (skip-chars-forward " \t") (point)))
498 (or (eolp)
106b6d0e 499 (indent-to column 0))
b7d5bd82 500 (forward-line 1))
2a96c2a7 501 (move-marker end nil)))
b7d5bd82 502 ;; If a fill-prefix is specified, use it.
e70b5064
CY
503 (fill-prefix
504 (save-excursion
505 (goto-char end)
506 (setq end (point-marker))
507 (goto-char start)
508 (let ((regexp (regexp-quote fill-prefix)))
509 (while (< (point) end)
510 (or (looking-at regexp)
511 (and (bolp) (eolp))
512 (insert fill-prefix))
513 (forward-line 1)))))
b7d5bd82 514 ;; Use indent-region-function is available.
e70b5064
CY
515 (indent-region-function
516 (funcall indent-region-function start end))
b7d5bd82
TL
517 ;; Else, use a default implementation that calls indent-line-function on
518 ;; each line.
e70b5064
CY
519 (t
520 (save-excursion
521 (setq end (copy-marker end))
522 (goto-char start)
b9e20952
LL
523 (let ((pr (unless (minibufferp)
524 (make-progress-reporter "Indenting region..." (point) end))))
525 (while (< (point) end)
526 (or (and (bolp) (eolp))
527 (indent-according-to-mode))
b7d5bd82 528 (forward-line 1)
b9e20952
LL
529 (and pr (progress-reporter-update pr (point))))
530 (and pr (progress-reporter-done pr))
b7d5bd82 531 (move-marker end nil)))))
2a96c2a7
SM
532 ;; In most cases, reindenting modifies the buffer, but it may also
533 ;; leave it unmodified, in which case we have to deactivate the mark
534 ;; by hand.
535 (deactivate-mark))
483e630e
RM
536
537(defun indent-relative-maybe ()
1fd63d9b
EZ
538 "Indent a new line like previous nonblank line.
539If the previous nonblank line has no indent points beyond the
540column point starts at, this command does nothing.
541
542See also `indent-relative'."
483e630e
RM
543 (interactive)
544 (indent-relative t))
545
546(defun indent-relative (&optional unindented-ok)
547 "Space out to under next indent point in previous nonblank line.
548An indent point is a non-whitespace character following whitespace.
f6f53207
RS
549The following line shows the indentation points in this line.
550 ^ ^ ^ ^ ^ ^ ^ ^ ^
483e630e 551If the previous nonblank line has no indent points beyond the
1fd63d9b
EZ
552column point starts at, `tab-to-tab-stop' is done instead, unless
553this command is invoked with a numeric argument, in which case it
554does nothing.
555
556See also `indent-relative-maybe'."
483e630e 557 (interactive "P")
5e9f80a8
RS
558 (if (and abbrev-mode
559 (eq (char-syntax (preceding-char)) ?w))
560 (expand-abbrev))
483e630e
RM
561 (let ((start-column (current-column))
562 indent)
563 (save-excursion
564 (beginning-of-line)
565 (if (re-search-backward "^[^\n]" nil t)
566 (let ((end (save-excursion (forward-line 1) (point))))
567 (move-to-column start-column)
568 ;; Is start-column inside a tab on this line?
569 (if (> (current-column) start-column)
570 (backward-char 1))
571 (or (looking-at "[ \t]")
572 unindented-ok
573 (skip-chars-forward "^ \t" end))
574 (skip-chars-forward " \t" end)
575 (or (= (point) end) (setq indent (current-column))))))
576 (if indent
577 (let ((opoint (point-marker)))
483e630e
RM
578 (indent-to indent 0)
579 (if (> opoint (point))
580 (goto-char opoint))
581 (move-marker opoint nil))
582 (tab-to-tab-stop))))
583
ddb3136e 584(defcustom tab-stop-list
b7d5bd82 585 nil
9201cc28 586 "List of tab stop positions used by `tab-to-tab-stop'.
b7d5bd82
TL
587This should be a list of integers, ordered from smallest to largest.
588It implicitly extends to infinity by repeating the last step (e.g. '(1 2 5)
589is equivalent to '(1 2 5 8 11)).
590If the list has less than 2 elements, `tab-width' is used as the \"last step\"."
ddb3136e
RS
591 :group 'indent
592 :type '(repeat integer))
44b275c4 593(put 'tab-stop-list 'safe-local-variable 'listp)
483e630e 594
a17b712b
SM
595(defvar edit-tab-stops-map
596 (let ((map (make-sparse-keymap)))
597 (define-key map "\C-x\C-s" 'edit-tab-stops-note-changes)
598 (define-key map "\C-c\C-c" 'edit-tab-stops-note-changes)
599 map)
600 "Keymap used in `edit-tab-stops'.")
483e630e
RM
601
602(defvar edit-tab-stops-buffer nil
bc57b735
LT
603 "Buffer whose tab stops are being edited.
604This matters if the variable `tab-stop-list' is local in that buffer.")
483e630e
RM
605
606(defun edit-tab-stops ()
607 "Edit the tab stops used by `tab-to-tab-stop'.
608Creates a buffer *Tab Stops* containing text describing the tab stops.
609A colon indicates a column where there is a tab stop.
610You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops-note-changes] to make changes take effect."
611 (interactive)
612 (setq edit-tab-stops-buffer (current-buffer))
613 (switch-to-buffer (get-buffer-create "*Tab Stops*"))
614 (use-local-map edit-tab-stops-map)
b7d5bd82 615 (setq-local indent-tabs-mode nil)
483e630e
RM
616 (overwrite-mode 1)
617 (setq truncate-lines t)
618 (erase-buffer)
619 (let ((tabs tab-stop-list))
620 (while tabs
621 (indent-to (car tabs) 0)
622 (insert ?:)
623 (setq tabs (cdr tabs))))
624 (let ((count 0))
625 (insert ?\n)
626 (while (< count 8)
627 (insert (+ count ?0))
628 (insert " ")
629 (setq count (1+ count)))
630 (insert ?\n)
631 (while (> count 0)
632 (insert "0123456789")
633 (setq count (1- count))))
634 (insert "\nTo install changes, type C-c C-c")
635 (goto-char (point-min)))
636
637(defun edit-tab-stops-note-changes ()
638 "Put edited tab stops into effect."
639 (interactive)
640 (let (tabs)
641 (save-excursion
642 (goto-char 1)
643 (end-of-line)
644 (while (search-backward ":" nil t)
645 (setq tabs (cons (current-column) tabs))))
646 (bury-buffer (prog1 (current-buffer)
647 (switch-to-buffer edit-tab-stops-buffer)))
648 (setq tab-stop-list tabs))
649 (message "Tab stops installed"))
650
b7d5bd82
TL
651(defun indent--next-tab-stop (column &optional prev)
652 "Return the next tab stop after COLUMN.
653If PREV is non-nil, return the previous one instead."
654 (let ((tabs tab-stop-list))
655 (while (and tabs (>= column (car tabs)))
656 (setq tabs (cdr tabs)))
657 (if tabs
658 (if (not prev)
659 (car tabs)
660 (let ((prevtabs (cdr (memq (car tabs) (reverse tab-stop-list)))))
661 (if (null prevtabs) 0
662 (if (= column (car prevtabs))
663 (or (nth 1 prevtabs) 0)
664 (car prevtabs)))))
665 ;; We passed the end of tab-stop-list: guess a continuation.
666 (let* ((last2 (last tab-stop-list 2))
667 (step (if (cdr last2) (- (cadr last2) (car last2)) tab-width))
668 (last (or (cadr last2) (car last2) 0)))
669 ;; Repeat the last tab's length.
670 (+ last (* step (if prev
671 (if (<= column last) -1 (/ (- column last 1) step))
672 (1+ (/ (- column last) step)))))))))
673
483e630e
RM
674(defun tab-to-tab-stop ()
675 "Insert spaces or tabs to next defined tab-stop column.
676The variable `tab-stop-list' is a list of columns at which there are tab stops.
677Use \\[edit-tab-stops] to edit them interactively."
678 (interactive)
a2964053
RS
679 (and abbrev-mode (= (char-syntax (preceding-char)) ?w)
680 (expand-abbrev))
b7d5bd82
TL
681 (let ((nexttab (indent--next-tab-stop (current-column))))
682 (delete-horizontal-space t)
683 (indent-to nexttab)))
483e630e
RM
684
685(defun move-to-tab-stop ()
686 "Move point to next defined tab-stop column.
fbf8f564
RS
687The variable `tab-stop-list' is a list of columns at which there are tab stops.
688Use \\[edit-tab-stops] to edit them interactively."
689 (interactive)
b7d5bd82
TL
690 (let ((nexttab (indent--next-tab-stop (current-column))))
691 (let ((before (point)))
692 (move-to-column nexttab t)
693 (save-excursion
694 (goto-char before)
695 ;; If we just added a tab, or moved over one,
696 ;; delete any superfluous spaces before the old point.
697 (if (and (eq (preceding-char) ?\s)
698 (eq (following-char) ?\t))
699 (let ((tabend (* (/ (current-column) tab-width) tab-width)))
700 (while (and (> (current-column) tabend)
701 (eq (preceding-char) ?\s))
702 (forward-char -1))
703 (delete-region (point) before)))))))
fbf8f564 704
483e630e 705(define-key global-map "\t" 'indent-for-tab-command)
a17b712b 706(define-key esc-map "\C-\\" 'indent-region)
483e630e
RM
707(define-key ctl-x-map "\t" 'indent-rigidly)
708(define-key esc-map "i" 'tab-to-tab-stop)
1a06eabd
ER
709
710;;; indent.el ends here