1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-03 08:30:09 +00:00

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
This commit is contained in:
Chong Yidong 2012-04-26 16:00:47 +08:00
parent 8b71081d30
commit cb3e7ae07a
2 changed files with 82 additions and 47 deletions

View File

@ -1,3 +1,14 @@
2012-04-26 Chong Yidong <cyd@gnu.org>
* 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 (Bug#6005).
(diff-file-junk-re): Add bzr's "modified file" tag (Bug#6041).
2012-04-26 Stefan Monnier <monnier@iro.umontreal.ca>
* vc/vc-mtn.el:

View File

@ -434,6 +434,7 @@ See http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01990.html")
style)
(defun diff-end-of-hunk (&optional style donttrustheader)
"Advance to the end of the current hunk, and return its position."
(let (end)
(when (looking-at diff-hunk-header-re)
;; 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")
(goto-char (or end (point-max)))))
(defun diff-beginning-of-hunk (&optional try-harder)
"Move back to beginning of hunk.
If TRY-HARDER is non-nil, try to cater to the case where we're not in a hunk
but in the file header instead, in which case move forward to the first hunk."
"Move back to the previous hunk beginning, and return its position.
If point is in a file header rather than a hunk, advance to the
next hunk if TRY-HARDER is non-nil; otherwise signal an error."
(beginning-of-line)
(unless (looking-at diff-hunk-header-re)
(if (looking-at diff-hunk-header-re)
(point)
(forward-line 1)
(condition-case ()
(re-search-backward diff-hunk-header-re)
(error
(if (not try-harder)
(error "Can't find the beginning of the hunk")
(diff-beginning-of-file-and-junk)
(diff-hunk-next))))))
(unless try-harder
(error "Can't find the beginning of the hunk"))
(diff-beginning-of-file-and-junk)
(diff-hunk-next)
(point)))))
(defun diff-unified-hunk-p ()
(save-excursion
@ -536,44 +539,72 @@ but in the file header instead, in which case move forward to the first hunk."
(easy-mmode-define-navigation
diff-file diff-file-header-re "file" diff-end-of-file)
(defun diff-bounds-of-hunk ()
"Return the bounds of the diff hunk at point.
The return value is a list (BEG END), which are the hunk's start
and end positions. Signal an error if no hunk is found. If
point is in a file header, return the bounds of the next hunk."
(save-excursion
(let ((pos (point))
(beg (diff-beginning-of-hunk t))
(end (diff-end-of-hunk)))
(cond ((>= end pos)
(list beg end))
;; If this hunk ends above POS, consider the next hunk.
((re-search-forward diff-hunk-header-re nil t)
(list (match-beginning 0) (diff-end-of-hunk)))
(t (error "No hunk found"))))))
(defun diff-bounds-of-file ()
"Return the bounds of the file segment at point.
The return value is a list (BEG END), which are the segment's
start and end positions."
(save-excursion
(let ((pos (point))
(beg (progn (diff-beginning-of-file-and-junk)
(point))))
(diff-end-of-file)
;; bzr puts a newline after the last hunk.
(while (looking-at "^\n")
(forward-char 1))
(if (> pos (point))
(error "Not inside a file diff"))
(list beg (point)))))
(defun diff-restrict-view (&optional arg)
"Restrict the view to the current hunk.
If the prefix ARG is given, restrict the view to the current file instead."
(interactive "P")
(save-excursion
(if arg (diff-beginning-of-file) (diff-beginning-of-hunk 'try-harder))
(narrow-to-region (point)
(progn (if arg (diff-end-of-file) (diff-end-of-hunk))
(point)))
(set (make-local-variable 'diff-narrowed-to) (if arg 'file 'hunk))))
(apply 'narrow-to-region
(if arg (diff-bounds-of-file) (diff-bounds-of-hunk)))
(set (make-local-variable 'diff-narrowed-to) (if arg 'file 'hunk)))
(defun diff-hunk-kill ()
"Kill current hunk."
"Kill the hunk at point."
(interactive)
(diff-beginning-of-hunk)
(let* ((start (point))
;; Search the second match, since we're looking at the first.
(nexthunk (when (re-search-forward diff-hunk-header-re nil t 2)
(match-beginning 0)))
(firsthunk (ignore-errors
(goto-char start)
(diff-beginning-of-file) (diff-hunk-next) (point)))
(nextfile (ignore-errors (diff-file-next) (point)))
(let* ((hunk-bounds (diff-bounds-of-hunk))
(file-bounds (ignore-errors (diff-bounds-of-file)))
;; If the current hunk is the only one for its file, kill the
;; file header too.
(bounds (if (and file-bounds
(progn (goto-char (car file-bounds))
(= (progn (diff-hunk-next) (point))
(car hunk-bounds)))
(progn (goto-char (cadr hunk-bounds))
;; bzr puts a newline after the last hunk.
(while (looking-at "^\n")
(forward-char 1))
(= (point) (cadr file-bounds))))
file-bounds
hunk-bounds))
(inhibit-read-only t))
(goto-char start)
(if (and firsthunk (= firsthunk start)
(or (null nexthunk)
(and nextfile (> nexthunk nextfile))))
;; It's the only hunk for this file, so kill the file.
(diff-file-kill)
(diff-end-of-hunk)
(kill-region start (point)))))
(apply 'kill-region bounds)
(goto-char (car bounds))))
;; "index ", "old mode", "new mode", "new file mode" and
;; "deleted file mode" are output by git-diff.
(defconst diff-file-junk-re
"diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode")
"diff \\|index \\|\\(?:deleted file\\|new\\(?: file\\)?\\|old\\) mode\\|=== modified file")
(defun diff-beginning-of-file-and-junk ()
"Go to the beginning of file-related diff-info.
@ -625,13 +656,8 @@ data such as \"Index: ...\" and such."
(defun diff-file-kill ()
"Kill current file's hunks."
(interactive)
(let ((orig (point))
(start (progn (diff-beginning-of-file-and-junk) (point)))
(inhibit-read-only t))
(diff-end-of-file)
(if (looking-at "^\n") (forward-char 1)) ;`tla' generates such diffs.
(if (> orig (point)) (error "Not inside a file diff"))
(kill-region start (point))))
(let ((inhibit-read-only t))
(apply 'kill-region (diff-bounds-of-file))))
(defun diff-kill-junk ()
"Kill spurious empty diffs."
@ -667,7 +693,7 @@ data such as \"Index: ...\" and such."
(interactive)
(beginning-of-line)
(let ((pos (point))
(start (progn (diff-beginning-of-hunk) (point))))
(start (diff-beginning-of-hunk)))
(unless (looking-at diff-hunk-header-re-unified)
(error "diff-split-hunk only works on unified context diffs"))
(forward-line 1)
@ -1589,8 +1615,7 @@ SWITCHED is non-nil if the patch is already applied.
NOPROMPT, if non-nil, means not to prompt the user."
(save-excursion
(let* ((other (diff-xor other-file diff-jump-to-old-file))
(char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder)
(point))))
(char-offset (- (point) (diff-beginning-of-hunk t)))
;; Check that the hunk is well-formed. Otherwise diff-mode and
;; the user may disagree on what constitutes the hunk
;; (e.g. because an empty line truncates the hunk mid-course),
@ -1777,8 +1802,7 @@ For use in `add-log-current-defun-function'."
(defun diff-ignore-whitespace-hunk ()
"Re-diff the current hunk, ignoring whitespace differences."
(interactive)
(let* ((char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder)
(point))))
(let* ((char-offset (- (point) (diff-beginning-of-hunk t)))
(opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b")))
(line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)")
(error "Can't find line number"))
@ -1854,7 +1878,7 @@ For use in `add-log-current-defun-function'."
(interactive)
(require 'smerge-mode)
(save-excursion
(diff-beginning-of-hunk 'try-harder)
(diff-beginning-of-hunk t)
(let* ((start (point))
(style (diff-hunk-style)) ;Skips the hunk header as well.
(beg (point))