aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Likonen2013-10-08 02:17:49 -0400
committerStefan Monnier2013-10-08 02:17:49 -0400
commitb7d5bd823c239a8ee3613abcc4e24fe290a673d0 (patch)
tree46792f6184ff85dcdc20a09f3a1351763f2586c5
parentd180bde8e49f2475adbbd987d3f98dde20c9b18e (diff)
downloademacs-b7d5bd823c239a8ee3613abcc4e24fe290a673d0.tar.gz
emacs-b7d5bd823c239a8ee3613abcc4e24fe290a673d0.zip
* indent.el: Provide interactive indent-rigidly mode. Use lexical-binding.
(indent-rigidly--current-indentation): New function. (indent-rigidly-map): New var. (indent-rigidly): Use it to provide interactive mode. (indent-region): Add progress reporter. (tab-stop-list): Make it implicitly extend to infinity by repeating the last step. (indent--next-tab-stop): New function to implement this behavior. (tab-to-tab-stop, move-to-tab-stop): Use it. Fixes: debbugs:8196
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/ChangeLog15
-rw-r--r--lisp/indent.el170
3 files changed, 140 insertions, 52 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 560c54c0f83..00e47907cde 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -163,6 +163,13 @@ and this variable has been marked obsolete.
163 163
164* Editing Changes in Emacs 24.4 164* Editing Changes in Emacs 24.4
165 165
166** C-x TAB enters a transient interactive mode.
167You can then use the left/right cursor keys to move the block of text.
168
169** `tab-stop-list' is now implicitly extended to infinity.
170Its default value is changed to nil which means a tab stop every
171`tab-width' columns.
172
166** `split-window' is no longer a command, just a non-interactive function. 173** `split-window' is no longer a command, just a non-interactive function.
167As a command it was a special case of `split-window-below', and as such 174As a command it was a special case of `split-window-below', and as such
168superfluous. After being reimplemented in Lisp, its interactive form 175superfluous. After being reimplemented in Lisp, its interactive form
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a15e512086d..f9161dc29d0 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,18 @@
12013-10-08 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * indent.el: Use lexical-binding.
4 (indent-region): Add progress reporter.
5 (tab-stop-list): Make it implicitly extend to infinity by repeating the
6 last step.
7 (indent--next-tab-stop): New function to implement this behavior.
8 (tab-to-tab-stop, move-to-tab-stop): Use it.
9
102013-10-08 Teemu Likonen <tlikonen@iki.fi>
11
12 * indent.el (indent-rigidly--current-indentation): New function.
13 (indent-rigidly-map): New var.
14 (indent-rigidly): Use it to provide interactive mode (bug#8196).
15
12013-10-08 Bastien Guerry <bzg@gnu.org> 162013-10-08 Bastien Guerry <bzg@gnu.org>
2 17
3 * register.el (insert-register): Fix 2013-10-07T01:28:34Z!sdl.web@gmail.com. 18 * register.el (insert-register): Fix 2013-10-07T01:28:34Z!sdl.web@gmail.com.
diff --git a/lisp/indent.el b/lisp/indent.el
index c7e2c72950a..434d73dc5bb 100644
--- a/lisp/indent.el
+++ b/lisp/indent.el
@@ -1,4 +1,4 @@
1;;; indent.el --- indentation commands for Emacs 1;;; indent.el --- indentation commands for Emacs -*- lexical-binding:t -*-
2 2
3;; Copyright (C) 1985, 1995, 2001-2013 Free Software Foundation, Inc. 3;; Copyright (C) 1985, 1995, 2001-2013 Free Software Foundation, Inc.
4 4
@@ -154,27 +154,68 @@ prefix argument is ignored."
154 (insert-char ?\t count) 154 (insert-char ?\t count)
155 (indent-to (* tab-width (+ count (/ (current-column) tab-width))))))) 155 (indent-to (* tab-width (+ count (/ (current-column) tab-width)))))))
156 156
157(defun indent-rigidly (start end arg) 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)))
172 (define-key map [left]
173 (lambda (beg end) (interactive "r") (indent-rigidly beg end -1)))
174
175 (define-key map [right]
176 (lambda (beg end) (interactive "r") (indent-rigidly beg end 1)))
177
178 (define-key map [S-right]
179 (lambda (beg end) (interactive "r")
180 (let* ((current (indent-rigidly--current-indentation beg end))
181 (next (indent--next-tab-stop current)))
182 (indent-rigidly beg end (- next current)))))
183
184 (define-key map [S-left]
185 (lambda (beg end) (interactive "r")
186 (let* ((current (indent-rigidly--current-indentation beg end))
187 (next (indent--next-tab-stop current 'prev)))
188 (indent-rigidly beg end (- next current)))))
189 map))
190
191(defun indent-rigidly (start end arg &optional interactive)
158 "Indent all lines starting in the region sideways by ARG columns. 192 "Indent all lines starting in the region sideways by ARG columns.
159Called from a program, takes three arguments, START, END and ARG. 193Called from a program, takes three arguments, START, END and ARG.
160You can remove all indentation from a region by giving a large negative ARG." 194You can remove all indentation from a region by giving a large negative ARG.
161 (interactive "r\np") 195If used interactively and no prefix argument is given, use a transient
162 (save-excursion 196mode that lets you move the text with cursor keys."
163 (goto-char end) 197 (interactive "r\nP\np")
164 (setq end (point-marker)) 198 (if (and (not arg) interactive)
165 (goto-char start) 199 (progn
166 (or (bolp) (forward-line 1)) 200 (message "Edit region indentation with <left>, <right>, <S-left> \
167 (while (< (point) end) 201and <S-right>.")
168 (let ((indent (current-indentation)) 202 (set-temporary-overlay-map indent-rigidly-map t))
169 eol-flag) 203 (save-excursion
170 (save-excursion 204 (goto-char end)
171 (skip-chars-forward " \t") 205 (setq end (point-marker))
172 (setq eol-flag (eolp))) 206 (goto-char start)
173 (or eol-flag 207 (or (bolp) (forward-line 1))
174 (indent-to (max 0 (+ indent arg)) 0)) 208 (while (< (point) end)
175 (delete-region (point) (progn (skip-chars-forward " \t") (point)))) 209 (let ((indent (current-indentation))
176 (forward-line 1)) 210 eol-flag)
177 (move-marker end nil))) 211 (save-excursion
212 (skip-chars-forward " \t")
213 (setq eol-flag (eolp)))
214 (or eol-flag
215 (indent-to (max 0 (+ indent arg)) 0))
216 (delete-region (point) (progn (skip-chars-forward " \t") (point))))
217 (forward-line 1))
218 (move-marker end nil))))
178 219
179(defun indent-line-to (column) 220(defun indent-line-to (column)
180 "Indent current line to COLUMN. 221 "Indent current line to COLUMN.
@@ -405,6 +446,7 @@ If the third argument COLUMN is an integer, it specifies the
405column to indent to; if it is nil, use one of the three methods above." 446column to indent to; if it is nil, use one of the three methods above."
406 (interactive "r\nP") 447 (interactive "r\nP")
407 (cond 448 (cond
449 ;; If a numeric prefix is given, indent to that column.
408 (column 450 (column
409 (setq column (prefix-numeric-value column)) 451 (setq column (prefix-numeric-value column))
410 (save-excursion 452 (save-excursion
@@ -416,8 +458,9 @@ column to indent to; if it is nil, use one of the three methods above."
416 (delete-region (point) (progn (skip-chars-forward " \t") (point))) 458 (delete-region (point) (progn (skip-chars-forward " \t") (point)))
417 (or (eolp) 459 (or (eolp)
418 (indent-to column 0)) 460 (indent-to column 0))
419 (forward-line 1)) 461 (forward-line 1))
420 (move-marker end nil))) 462 (move-marker end nil)))
463 ;; If a fill-prefix is specified, use it.
421 (fill-prefix 464 (fill-prefix
422 (save-excursion 465 (save-excursion
423 (goto-char end) 466 (goto-char end)
@@ -429,17 +472,23 @@ column to indent to; if it is nil, use one of the three methods above."
429 (and (bolp) (eolp)) 472 (and (bolp) (eolp))
430 (insert fill-prefix)) 473 (insert fill-prefix))
431 (forward-line 1))))) 474 (forward-line 1)))))
475 ;; Use indent-region-function is available.
432 (indent-region-function 476 (indent-region-function
433 (funcall indent-region-function start end)) 477 (funcall indent-region-function start end))
478 ;; Else, use a default implementation that calls indent-line-function on
479 ;; each line.
434 (t 480 (t
435 (save-excursion 481 (save-excursion
436 (setq end (copy-marker end)) 482 (setq end (copy-marker end))
437 (goto-char start) 483 (goto-char start)
484 (let ((pr (make-progress-reporter "Indenting region..." (point) end)))
438 (while (< (point) end) 485 (while (< (point) end)
439 (or (and (bolp) (eolp)) 486 (or (and (bolp) (eolp))
440 (indent-according-to-mode)) 487 (indent-according-to-mode))
441 (forward-line 1)) 488 (forward-line 1)
442 (move-marker end nil)))) 489 (progress-reporter-update pr (point)))
490 (progress-reporter-done pr)
491 (move-marker end nil)))))
443 ;; In most cases, reindenting modifies the buffer, but it may also 492 ;; In most cases, reindenting modifies the buffer, but it may also
444 ;; leave it unmodified, in which case we have to deactivate the mark 493 ;; leave it unmodified, in which case we have to deactivate the mark
445 ;; by hand. 494 ;; by hand.
@@ -493,9 +542,12 @@ See also `indent-relative-maybe'."
493 (tab-to-tab-stop)))) 542 (tab-to-tab-stop))))
494 543
495(defcustom tab-stop-list 544(defcustom tab-stop-list
496 '(8 16 24 32 40 48 56 64 72 80 88 96 104 112 120) 545 nil
497 "List of tab stop positions used by `tab-to-tab-stop'. 546 "List of tab stop positions used by `tab-to-tab-stop'.
498This should be a list of integers, ordered from smallest to largest." 547This should be a list of integers, ordered from smallest to largest.
548It implicitly extends to infinity by repeating the last step (e.g. '(1 2 5)
549is equivalent to '(1 2 5 8 11)).
550If the list has less than 2 elements, `tab-width' is used as the \"last step\"."
499 :group 'indent 551 :group 'indent
500 :type '(repeat integer)) 552 :type '(repeat integer))
501(put 'tab-stop-list 'safe-local-variable 'listp) 553(put 'tab-stop-list 'safe-local-variable 'listp)
@@ -520,8 +572,7 @@ You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops
520 (setq edit-tab-stops-buffer (current-buffer)) 572 (setq edit-tab-stops-buffer (current-buffer))
521 (switch-to-buffer (get-buffer-create "*Tab Stops*")) 573 (switch-to-buffer (get-buffer-create "*Tab Stops*"))
522 (use-local-map edit-tab-stops-map) 574 (use-local-map edit-tab-stops-map)
523 (make-local-variable 'indent-tabs-mode) 575 (setq-local indent-tabs-mode nil)
524 (setq indent-tabs-mode nil)
525 (overwrite-mode 1) 576 (overwrite-mode 1)
526 (setq truncate-lines t) 577 (setq truncate-lines t)
527 (erase-buffer) 578 (erase-buffer)
@@ -557,6 +608,29 @@ You can add or remove colons and then do \\<edit-tab-stops-map>\\[edit-tab-stops
557 (setq tab-stop-list tabs)) 608 (setq tab-stop-list tabs))
558 (message "Tab stops installed")) 609 (message "Tab stops installed"))
559 610
611(defun indent--next-tab-stop (column &optional prev)
612 "Return the next tab stop after COLUMN.
613If PREV is non-nil, return the previous one instead."
614 (let ((tabs tab-stop-list))
615 (while (and tabs (>= column (car tabs)))
616 (setq tabs (cdr tabs)))
617 (if tabs
618 (if (not prev)
619 (car tabs)
620 (let ((prevtabs (cdr (memq (car tabs) (reverse tab-stop-list)))))
621 (if (null prevtabs) 0
622 (if (= column (car prevtabs))
623 (or (nth 1 prevtabs) 0)
624 (car prevtabs)))))
625 ;; We passed the end of tab-stop-list: guess a continuation.
626 (let* ((last2 (last tab-stop-list 2))
627 (step (if (cdr last2) (- (cadr last2) (car last2)) tab-width))
628 (last (or (cadr last2) (car last2) 0)))
629 ;; Repeat the last tab's length.
630 (+ last (* step (if prev
631 (if (<= column last) -1 (/ (- column last 1) step))
632 (1+ (/ (- column last) step)))))))))
633
560(defun tab-to-tab-stop () 634(defun tab-to-tab-stop ()
561 "Insert spaces or tabs to next defined tab-stop column. 635 "Insert spaces or tabs to next defined tab-stop column.
562The variable `tab-stop-list' is a list of columns at which there are tab stops. 636The variable `tab-stop-list' is a list of columns at which there are tab stops.
@@ -564,37 +638,29 @@ Use \\[edit-tab-stops] to edit them interactively."
564 (interactive) 638 (interactive)
565 (and abbrev-mode (= (char-syntax (preceding-char)) ?w) 639 (and abbrev-mode (= (char-syntax (preceding-char)) ?w)
566 (expand-abbrev)) 640 (expand-abbrev))
567 (let ((tabs tab-stop-list)) 641 (let ((nexttab (indent--next-tab-stop (current-column))))
568 (while (and tabs (>= (current-column) (car tabs))) 642 (delete-horizontal-space t)
569 (setq tabs (cdr tabs))) 643 (indent-to nexttab)))
570 (if tabs
571 (progn
572 (delete-horizontal-space t)
573 (indent-to (car tabs)))
574 (insert ?\s))))
575 644
576(defun move-to-tab-stop () 645(defun move-to-tab-stop ()
577 "Move point to next defined tab-stop column. 646 "Move point to next defined tab-stop column.
578The variable `tab-stop-list' is a list of columns at which there are tab stops. 647The variable `tab-stop-list' is a list of columns at which there are tab stops.
579Use \\[edit-tab-stops] to edit them interactively." 648Use \\[edit-tab-stops] to edit them interactively."
580 (interactive) 649 (interactive)
581 (let ((tabs tab-stop-list)) 650 (let ((nexttab (indent--next-tab-stop (current-column))))
582 (while (and tabs (>= (current-column) (car tabs))) 651 (let ((before (point)))
583 (setq tabs (cdr tabs))) 652 (move-to-column nexttab t)
584 (if tabs 653 (save-excursion
585 (let ((before (point))) 654 (goto-char before)
586 (move-to-column (car tabs) t) 655 ;; If we just added a tab, or moved over one,
587 (save-excursion 656 ;; delete any superfluous spaces before the old point.
588 (goto-char before) 657 (if (and (eq (preceding-char) ?\s)
589 ;; If we just added a tab, or moved over one, 658 (eq (following-char) ?\t))
590 ;; delete any superfluous spaces before the old point. 659 (let ((tabend (* (/ (current-column) tab-width) tab-width)))
591 (if (and (eq (preceding-char) ?\s) 660 (while (and (> (current-column) tabend)
592 (eq (following-char) ?\t)) 661 (eq (preceding-char) ?\s))
593 (let ((tabend (* (/ (current-column) tab-width) tab-width))) 662 (forward-char -1))
594 (while (and (> (current-column) tabend) 663 (delete-region (point) before)))))))
595 (eq (preceding-char) ?\s))
596 (forward-char -1))
597 (delete-region (point) before))))))))
598 664
599(define-key global-map "\t" 'indent-for-tab-command) 665(define-key global-map "\t" 'indent-for-tab-command)
600(define-key esc-map "\C-\\" 'indent-region) 666(define-key esc-map "\C-\\" 'indent-region)