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