From 07875ee72bffac01a1978d0367883d6ceb88cc55 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Wed, 25 Apr 2012 23:06:51 +0800 Subject: Fix whitespace highlighting of context diffs. * lisp/vc/diff-mode.el (diff-setup-whitespace): New function. (diff-mode): Use it. * lisp/vc/diff.el (diff-sentinel): * lisp/vc/vc.el (vc-diff-finish): Call diff-setup-whitespace to assign Whitespace mode variables based on diff style. Fixes: debbugs:8612 --- lisp/vc/diff-mode.el | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'lisp/vc/diff-mode.el') diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 8b6b85dd22e..c92371fc90b 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1283,11 +1283,7 @@ a diff with \\[diff-reverse-direction]. (set (make-local-variable 'end-of-defun-function) 'diff-end-of-file) - ;; Set up `whitespace-mode' so that turning it on will show trailing - ;; whitespace problems on the modified lines of the diff. - (set (make-local-variable 'whitespace-style) '(face trailing)) - (set (make-local-variable 'whitespace-trailing-regexp) - "^[-\+!<>].*?\\([\t ]+\\)$") + (diff-setup-whitespace) (setq buffer-read-only diff-default-read-only) ;; setup change hooks @@ -1332,6 +1328,22 @@ the mode if ARG is omitted or nil. ;;; Handy hook functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun diff-setup-whitespace () + "Set up Whitespace mode variables for the current Diff mode buffer. +This sets `whitespace-style' and `whitespace-trailing-regexp' so +that Whitespace mode shows trailing whitespace problems on the +modified lines of the diff." + (set (make-local-variable 'whitespace-style) '(face trailing)) + (let ((style (save-excursion + (goto-char (point-min)) + (when (re-search-forward diff-hunk-header-re nil t) + (goto-char (match-beginning 0)) + (diff-hunk-style))))) + (set (make-local-variable 'whitespace-trailing-regexp) + (if (eq style 'context) + "^[-\+!] .*?\\([\t ]+\\)$" + "^[-\+!<>].*?\\([\t ]+\\)$")))) + (defun diff-delete-if-empty () ;; An empty diff file means there's no more diffs to integrate, so we ;; can just remove the file altogether. Very handy for .rej files if we -- cgit v1.2.3 From 8b71081d301534a7fa4816530f4c3af61c67d038 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Thu, 26 Apr 2012 11:43:32 +0800 Subject: Allow undoing in read-only diff-mode buffers. * lisp/vc/diff-mode.el (diff-undo): New command. (diff-mode-shared-map): Bind it to / and [remap undo]. Fixes: debbugs:5302 --- lisp/ChangeLog | 3 +++ lisp/vc/diff-mode.el | 28 +++++++++++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) (limited to 'lisp/vc/diff-mode.el') diff --git a/lisp/ChangeLog b/lisp/ChangeLog index bb40b542792..e7b0a0e1bf6 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -14,6 +14,9 @@ 2012-04-26 Chong Yidong + * vc/diff-mode.el (diff-undo): New command (Bug#5302). + (diff-mode-shared-map): Bind it to / and [remap undo]. + * vc/ediff-wind.el (ediff-setup-windows-default): New function. (ediff-window-setup-function): Use it as the default, to set up windows based on whether the current frame is graphical (Bug#2138). diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index c92371fc90b..067fc1c1f2b 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -107,8 +107,7 @@ when editing big diffs)." ;;;; (easy-mmode-defmap diff-mode-shared-map - '(;; From Pavel Machek's patch-mode. - ("n" . diff-hunk-next) + '(("n" . diff-hunk-next) ("N" . diff-file-next) ("p" . diff-hunk-prev) ("P" . diff-file-prev) @@ -116,27 +115,17 @@ when editing big diffs)." ([backtab] . diff-hunk-prev) ("k" . diff-hunk-kill) ("K" . diff-file-kill) - ;; From compilation-minor-mode. - ("}" . diff-file-next) + ("}" . diff-file-next) ; From compilation-minor-mode. ("{" . diff-file-prev) ("\C-m" . diff-goto-source) ([mouse-2] . diff-goto-source) - ;; From XEmacs's diff-mode. ("W" . widen) - ;;("." . diff-goto-source) ;display-buffer - ;;("f" . diff-goto-source) ;find-file - ("o" . diff-goto-source) ;other-window - ;;("w" . diff-goto-source) ;other-frame - ;;("N" . diff-narrow) - ;;("h" . diff-show-header) - ;;("j" . diff-show-difference) ;jump to Nth diff - ;;("q" . diff-quit) - ;; Not useful if you have to metafy them. - ;;(" " . scroll-up) - ;;("\177" . scroll-down) + ("o" . diff-goto-source) ; other-window ("A" . diff-ediff-patch) ("r" . diff-restrict-view) - ("R" . diff-reverse-direction)) + ("R" . diff-reverse-direction) + ("/" . diff-undo) + ([remap undo] . diff-undo)) "Basic keymap for `diff-mode', bound to various prefix keys." :inherit special-mode-map) @@ -1904,6 +1893,11 @@ For use in `add-log-current-defun-function'." (match-end 0) end props 'diff-refine-preproc)))))))) +(defun diff-undo (&optional arg) + "Perform `undo', ignoring the buffer's read-only status." + (interactive "P") + (let ((inhibit-read-only t)) + (undo arg))) (defun diff-add-change-log-entries-other-window () "Iterate through the current diff and create ChangeLog entries. -- cgit v1.2.3 From cb3e7ae07a6ad7c46f5d67984d54f10f19103bef Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Thu, 26 Apr 2012 16:00:47 +0800 Subject: 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 --- lisp/ChangeLog | 11 +++++ lisp/vc/diff-mode.el | 118 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 82 insertions(+), 47 deletions(-) (limited to 'lisp/vc/diff-mode.el') diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e7b0a0e1bf6..a709c017416 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,14 @@ +2012-04-26 Chong Yidong + + * 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 * 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") 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)) -- cgit v1.2.3