diff options
| author | Chong Yidong | 2012-04-26 16:00:47 +0800 |
|---|---|---|
| committer | Chong Yidong | 2012-04-26 16:00:47 +0800 |
| commit | cb3e7ae07a6ad7c46f5d67984d54f10f19103bef (patch) | |
| tree | aa9ca6d11414681b5af651e2d9739865faf2f76a | |
| parent | 8b71081d301534a7fa4816530f4c3af61c67d038 (diff) | |
| download | emacs-cb3e7ae07a6ad7c46f5d67984d54f10f19103bef.tar.gz emacs-cb3e7ae07a6ad7c46f5d67984d54f10f19103bef.zip | |
Fixes for diff-hunk-kill.
* lisp/vc/diff-mode.el (diff-beginning-of-hunk): Return a meaningful
value, for symmetry with diff-end-of-hunk.
(diff-split-hunk, diff-find-source-location)
(diff-ignore-whitespace-hunk, diff-refine-hunk): Use it.
(diff-bounds-of-hunk, diff-bounds-of-file): New functions.
(diff-restrict-view, diff-hunk-kill, diff-file-kill): Use them to
compute the relevant hunk or file properly.
(diff-file-junk-re): Add bzr's "modified file" tag.
Fixes: debbugs:6041 debbugs:6005
| -rw-r--r-- | lisp/ChangeLog | 11 | ||||
| -rw-r--r-- | lisp/vc/diff-mode.el | 118 |
2 files changed, 82 insertions, 47 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e7b0a0e1bf6..a709c017416 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,14 @@ | |||
| 1 | 2012-04-26 Chong Yidong <cyd@gnu.org> | ||
| 2 | |||
| 3 | * vc/diff-mode.el (diff-beginning-of-hunk): Return a meaningful | ||
| 4 | value, for symmetry with diff-end-of-hunk. | ||
| 5 | (diff-split-hunk, diff-find-source-location) | ||
| 6 | (diff-ignore-whitespace-hunk, diff-refine-hunk): Use it. | ||
| 7 | (diff-bounds-of-hunk, diff-bounds-of-file): New functions. | ||
| 8 | (diff-restrict-view, diff-hunk-kill, diff-file-kill): Use them to | ||
| 9 | compute the relevant hunk or file properly (Bug#6005). | ||
| 10 | (diff-file-junk-re): Add bzr's "modified file" tag (Bug#6041). | ||
| 11 | |||
| 1 | 2012-04-26 Stefan Monnier <monnier@iro.umontreal.ca> | 12 | 2012-04-26 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 13 | ||
| 3 | * vc/vc-mtn.el: | 14 | * vc/vc-mtn.el: |
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 067fc1c1f2b..f3f7d8ce61b 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el | |||
| @@ -434,6 +434,7 @@ See http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01990.html") | |||
| 434 | style) | 434 | style) |
| 435 | 435 | ||
| 436 | (defun diff-end-of-hunk (&optional style donttrustheader) | 436 | (defun diff-end-of-hunk (&optional style donttrustheader) |
| 437 | "Advance to the end of the current hunk, and return its position." | ||
| 437 | (let (end) | 438 | (let (end) |
| 438 | (when (looking-at diff-hunk-header-re) | 439 | (when (looking-at diff-hunk-header-re) |
| 439 | ;; Especially important for unified (because headers are ambiguous). | 440 | ;; Especially important for unified (because headers are ambiguous). |
| @@ -481,19 +482,21 @@ See http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01990.html") | |||
| 481 | (goto-char (or end (point-max))))) | 482 | (goto-char (or end (point-max))))) |
| 482 | 483 | ||
| 483 | (defun diff-beginning-of-hunk (&optional try-harder) | 484 | (defun diff-beginning-of-hunk (&optional try-harder) |
| 484 | "Move back to beginning of hunk. | 485 | "Move back to the previous hunk beginning, and return its position. |
| 485 | If TRY-HARDER is non-nil, try to cater to the case where we're not in a hunk | 486 | If point is in a file header rather than a hunk, advance to the |
| 486 | but in the file header instead, in which case move forward to the first hunk." | 487 | next hunk if TRY-HARDER is non-nil; otherwise signal an error." |
| 487 | (beginning-of-line) | 488 | (beginning-of-line) |
| 488 | (unless (looking-at diff-hunk-header-re) | 489 | (if (looking-at diff-hunk-header-re) |
| 490 | (point) | ||
| 489 | (forward-line 1) | 491 | (forward-line 1) |
| 490 | (condition-case () | 492 | (condition-case () |
| 491 | (re-search-backward diff-hunk-header-re) | 493 | (re-search-backward diff-hunk-header-re) |
| 492 | (error | 494 | (error |
| 493 | (if (not try-harder) | 495 | (unless try-harder |
| 494 | (error "Can't find the beginning of the hunk") | 496 | (error "Can't find the beginning of the hunk")) |
| 495 | (diff-beginning-of-file-and-junk) | 497 | (diff-beginning-of-file-and-junk) |
| 496 | (diff-hunk-next)))))) | 498 | (diff-hunk-next) |
| 499 | (point))))) | ||
| 497 | 500 | ||
| 498 | (defun diff-unified-hunk-p () | 501 | (defun diff-unified-hunk-p () |
| 499 | (save-excursion | 502 | (save-excursion |
| @@ -536,44 +539,72 @@ but in the file header instead, in which case move forward to the first hunk." | |||
| 536 | (easy-mmode-define-navigation | 539 | (easy-mmode-define-navigation |
| 537 | diff-file diff-file-header-re "file" diff-end-of-file) | 540 | diff-file diff-file-header-re "file" diff-end-of-file) |
| 538 | 541 | ||
| 542 | (defun diff-bounds-of-hunk () | ||
| 543 | "Return the bounds of the diff hunk at point. | ||
| 544 | The return value is a list (BEG END), which are the hunk's start | ||
| 545 | and end positions. Signal an error if no hunk is found. If | ||
| 546 | point is in a file header, return the bounds of the next hunk." | ||
| 547 | (save-excursion | ||
| 548 | (let ((pos (point)) | ||
| 549 | (beg (diff-beginning-of-hunk t)) | ||
| 550 | (end (diff-end-of-hunk))) | ||
| 551 | (cond ((>= end pos) | ||
| 552 | (list beg end)) | ||
| 553 | ;; If this hunk ends above POS, consider the next hunk. | ||
| 554 | ((re-search-forward diff-hunk-header-re nil t) | ||
| 555 | (list (match-beginning 0) (diff-end-of-hunk))) | ||
| 556 | (t (error "No hunk found")))))) | ||
| 557 | |||
| 558 | (defun diff-bounds-of-file () | ||
| 559 | "Return the bounds of the file segment at point. | ||
| 560 | The return value is a list (BEG END), which are the segment's | ||
| 561 | start and end positions." | ||
| 562 | (save-excursion | ||
| 563 | (let ((pos (point)) | ||
| 564 | (beg (progn (diff-beginning-of-file-and-junk) | ||
| 565 | (point)))) | ||
| 566 | (diff-end-of-file) | ||
| 567 | ;; bzr puts a newline after the last hunk. | ||
| 568 | (while (looking-at "^\n") | ||
| 569 | (forward-char 1)) | ||
| 570 | (if (> pos (point)) | ||
| 571 | (error "Not inside a file diff")) | ||
| 572 | (list beg (point))))) | ||
| 573 | |||
| 539 | (defun diff-restrict-view (&optional arg) | 574 | (defun diff-restrict-view (&optional arg) |
| 540 | "Restrict the view to the current hunk. | 575 | "Restrict the view to the current hunk. |
| 541 | If the prefix ARG is given, restrict the view to the current file instead." | 576 | If the prefix ARG is given, restrict the view to the current file instead." |
| 542 | (interactive "P") | 577 | (interactive "P") |
| 543 | (save-excursion | 578 | (apply 'narrow-to-region |
| 544 | (if arg (diff-beginning-of-file) (diff-beginning-of-hunk 'try-harder)) | 579 | (if arg (diff-bounds-of-file) (diff-bounds-of-hunk))) |
| 545 | (narrow-to-region (point) | 580 | (set (make-local-variable 'diff-narrowed-to) (if arg 'file 'hunk))) |
| 546 | (progn (if arg (diff-end-of-file) (diff-end-of-hunk)) | ||
| 547 | (point))) | ||
| 548 | (set (make-local-variable 'diff-narrowed-to) (if arg 'file 'hunk)))) | ||
| 549 | |||
| 550 | 581 | ||
| 551 | (defun diff-hunk-kill () | 582 | (defun diff-hunk-kill () |
| 552 | "Kill current hunk." | 583 | "Kill the hunk at point." |
| 553 | (interactive) | 584 | (interactive) |
| 554 | (diff-beginning-of-hunk) | 585 | (let* ((hunk-bounds (diff-bounds-of-hunk)) |
| 555 | (let* ((start (point)) | 586 | (file-bounds (ignore-errors (diff-bounds-of-file))) |
| 556 | ;; Search the second match, since we're looking at the first. | 587 | ;; If the current hunk is the only one for its file, kill the |
| 557 | (nexthunk (when (re-search-forward diff-hunk-header-re nil t 2) | 588 | ;; file header too. |
| 558 | (match-beginning 0))) | 589 | (bounds (if (and file-bounds |
| 559 | (firsthunk (ignore-errors | 590 | (progn (goto-char (car file-bounds)) |
| 560 | (goto-char start) | 591 | (= (progn (diff-hunk-next) (point)) |
| 561 | (diff-beginning-of-file) (diff-hunk-next) (point))) | 592 | (car hunk-bounds))) |
| 562 | (nextfile (ignore-errors (diff-file-next) (point))) | 593 | (progn (goto-char (cadr hunk-bounds)) |
| 594 | ;; bzr puts a newline after the last hunk. | ||
| 595 | (while (looking-at "^\n") | ||
| 596 | (forward-char 1)) | ||
| 597 | (= (point) (cadr file-bounds)))) | ||
| 598 | file-bounds | ||
| 599 | hunk-bounds)) | ||
| 563 | (inhibit-read-only t)) | 600 | (inhibit-read-only t)) |
| 564 | (goto-char start) | 601 | (apply 'kill-region bounds) |
| 565 | (if (and firsthunk (= firsthunk start) | 602 | (goto-char (car bounds)))) |
| 566 | (or (null nexthunk) | ||
| 567 | (and nextfile (> nexthunk nextfile)))) | ||
| 568 | ;; It's the only hunk for this file, so kill the file. | ||
| 569 | (diff-file-kill) | ||
| 570 | (diff-end-of-hunk) | ||
| 571 | (kill-region start (point))))) | ||
| 572 | 603 | ||
| 573 | ;; "index ", "old mode", "new mode", "new file mode" and | 604 | ;; "index ", "old mode", "new mode", "new file mode" and |
| 574 | ;; "deleted file mode" are output by git-diff. | 605 | ;; "deleted file mode" are output by git-diff. |
| 575 | (defconst diff-file-junk-re | 606 | (defconst diff-file-junk-re |
| 576 | "diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode") | 607 | "diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode\\|=== modified file") |
| 577 | 608 | ||
| 578 | (defun diff-beginning-of-file-and-junk () | 609 | (defun diff-beginning-of-file-and-junk () |
| 579 | "Go to the beginning of file-related diff-info. | 610 | "Go to the beginning of file-related diff-info. |
| @@ -625,13 +656,8 @@ data such as \"Index: ...\" and such." | |||
| 625 | (defun diff-file-kill () | 656 | (defun diff-file-kill () |
| 626 | "Kill current file's hunks." | 657 | "Kill current file's hunks." |
| 627 | (interactive) | 658 | (interactive) |
| 628 | (let ((orig (point)) | 659 | (let ((inhibit-read-only t)) |
| 629 | (start (progn (diff-beginning-of-file-and-junk) (point))) | 660 | (apply 'kill-region (diff-bounds-of-file)))) |
| 630 | (inhibit-read-only t)) | ||
| 631 | (diff-end-of-file) | ||
| 632 | (if (looking-at "^\n") (forward-char 1)) ;`tla' generates such diffs. | ||
| 633 | (if (> orig (point)) (error "Not inside a file diff")) | ||
| 634 | (kill-region start (point)))) | ||
| 635 | 661 | ||
| 636 | (defun diff-kill-junk () | 662 | (defun diff-kill-junk () |
| 637 | "Kill spurious empty diffs." | 663 | "Kill spurious empty diffs." |
| @@ -667,7 +693,7 @@ data such as \"Index: ...\" and such." | |||
| 667 | (interactive) | 693 | (interactive) |
| 668 | (beginning-of-line) | 694 | (beginning-of-line) |
| 669 | (let ((pos (point)) | 695 | (let ((pos (point)) |
| 670 | (start (progn (diff-beginning-of-hunk) (point)))) | 696 | (start (diff-beginning-of-hunk))) |
| 671 | (unless (looking-at diff-hunk-header-re-unified) | 697 | (unless (looking-at diff-hunk-header-re-unified) |
| 672 | (error "diff-split-hunk only works on unified context diffs")) | 698 | (error "diff-split-hunk only works on unified context diffs")) |
| 673 | (forward-line 1) | 699 | (forward-line 1) |
| @@ -1589,8 +1615,7 @@ SWITCHED is non-nil if the patch is already applied. | |||
| 1589 | NOPROMPT, if non-nil, means not to prompt the user." | 1615 | NOPROMPT, if non-nil, means not to prompt the user." |
| 1590 | (save-excursion | 1616 | (save-excursion |
| 1591 | (let* ((other (diff-xor other-file diff-jump-to-old-file)) | 1617 | (let* ((other (diff-xor other-file diff-jump-to-old-file)) |
| 1592 | (char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder) | 1618 | (char-offset (- (point) (diff-beginning-of-hunk t))) |
| 1593 | (point)))) | ||
| 1594 | ;; Check that the hunk is well-formed. Otherwise diff-mode and | 1619 | ;; Check that the hunk is well-formed. Otherwise diff-mode and |
| 1595 | ;; the user may disagree on what constitutes the hunk | 1620 | ;; the user may disagree on what constitutes the hunk |
| 1596 | ;; (e.g. because an empty line truncates the hunk mid-course), | 1621 | ;; (e.g. because an empty line truncates the hunk mid-course), |
| @@ -1777,8 +1802,7 @@ For use in `add-log-current-defun-function'." | |||
| 1777 | (defun diff-ignore-whitespace-hunk () | 1802 | (defun diff-ignore-whitespace-hunk () |
| 1778 | "Re-diff the current hunk, ignoring whitespace differences." | 1803 | "Re-diff the current hunk, ignoring whitespace differences." |
| 1779 | (interactive) | 1804 | (interactive) |
| 1780 | (let* ((char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder) | 1805 | (let* ((char-offset (- (point) (diff-beginning-of-hunk t))) |
| 1781 | (point)))) | ||
| 1782 | (opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b"))) | 1806 | (opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b"))) |
| 1783 | (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") | 1807 | (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") |
| 1784 | (error "Can't find line number")) | 1808 | (error "Can't find line number")) |
| @@ -1854,7 +1878,7 @@ For use in `add-log-current-defun-function'." | |||
| 1854 | (interactive) | 1878 | (interactive) |
| 1855 | (require 'smerge-mode) | 1879 | (require 'smerge-mode) |
| 1856 | (save-excursion | 1880 | (save-excursion |
| 1857 | (diff-beginning-of-hunk 'try-harder) | 1881 | (diff-beginning-of-hunk t) |
| 1858 | (let* ((start (point)) | 1882 | (let* ((start (point)) |
| 1859 | (style (diff-hunk-style)) ;Skips the hunk header as well. | 1883 | (style (diff-hunk-style)) ;Skips the hunk header as well. |
| 1860 | (beg (point)) | 1884 | (beg (point)) |