aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2012-04-26 16:00:47 +0800
committerChong Yidong2012-04-26 16:00:47 +0800
commitcb3e7ae07a6ad7c46f5d67984d54f10f19103bef (patch)
treeaa9ca6d11414681b5af651e2d9739865faf2f76a
parent8b71081d301534a7fa4816530f4c3af61c67d038 (diff)
downloademacs-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/ChangeLog11
-rw-r--r--lisp/vc/diff-mode.el118
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 @@
12012-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
12012-04-26 Stefan Monnier <monnier@iro.umontreal.ca> 122012-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.
485If TRY-HARDER is non-nil, try to cater to the case where we're not in a hunk 486If point is in a file header rather than a hunk, advance to the
486but in the file header instead, in which case move forward to the first hunk." 487next 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.
544The return value is a list (BEG END), which are the hunk's start
545and end positions. Signal an error if no hunk is found. If
546point 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.
560The return value is a list (BEG END), which are the segment's
561start 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.
541If the prefix ARG is given, restrict the view to the current file instead." 576If 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.
1589NOPROMPT, if non-nil, means not to prompt the user." 1615NOPROMPT, 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))