diff options
| author | Teemu Likonen | 2013-10-08 02:17:49 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2013-10-08 02:17:49 -0400 |
| commit | b7d5bd823c239a8ee3613abcc4e24fe290a673d0 (patch) | |
| tree | 46792f6184ff85dcdc20a09f3a1351763f2586c5 | |
| parent | d180bde8e49f2475adbbd987d3f98dde20c9b18e (diff) | |
| download | emacs-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/NEWS | 7 | ||||
| -rw-r--r-- | lisp/ChangeLog | 15 | ||||
| -rw-r--r-- | lisp/indent.el | 170 |
3 files changed, 140 insertions, 52 deletions
| @@ -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. | ||
| 167 | You 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. | ||
| 170 | Its 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. |
| 167 | As a command it was a special case of `split-window-below', and as such | 174 | As a command it was a special case of `split-window-below', and as such |
| 168 | superfluous. After being reimplemented in Lisp, its interactive form | 175 | superfluous. 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 @@ | |||
| 1 | 2013-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 | |||
| 10 | 2013-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 | |||
| 1 | 2013-10-08 Bastien Guerry <bzg@gnu.org> | 16 | 2013-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. | ||
| 159 | Blank 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. |
| 159 | Called from a program, takes three arguments, START, END and ARG. | 193 | Called from a program, takes three arguments, START, END and ARG. |
| 160 | You can remove all indentation from a region by giving a large negative ARG." | 194 | You can remove all indentation from a region by giving a large negative ARG. |
| 161 | (interactive "r\np") | 195 | If used interactively and no prefix argument is given, use a transient |
| 162 | (save-excursion | 196 | mode 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) | 201 | and <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 | |||
| 405 | column to indent to; if it is nil, use one of the three methods above." | 446 | column 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'. |
| 498 | This should be a list of integers, ordered from smallest to largest." | 547 | This should be a list of integers, ordered from smallest to largest. |
| 548 | It implicitly extends to infinity by repeating the last step (e.g. '(1 2 5) | ||
| 549 | is equivalent to '(1 2 5 8 11)). | ||
| 550 | If 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. | ||
| 613 | If 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. |
| 562 | The variable `tab-stop-list' is a list of columns at which there are tab stops. | 636 | The 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. |
| 578 | The variable `tab-stop-list' is a list of columns at which there are tab stops. | 647 | The variable `tab-stop-list' is a list of columns at which there are tab stops. |
| 579 | Use \\[edit-tab-stops] to edit them interactively." | 648 | Use \\[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) |