]> code.delx.au - gnu-emacs/blobdiff - lisp/vc/diff-mode.el
* lisp/vc/diff-mode.el (diff-hunk-file-names): Handle filenames with spaces.
[gnu-emacs] / lisp / vc / diff-mode.el
index 49b76a8e3bce82b15e3d28fcd1e9a35d841fc266..d9224b29c2e013bbef9c700ece9841f78d42d30b 100644 (file)
@@ -1,6 +1,6 @@
 ;;; diff-mode.el --- a mode for viewing/editing context diffs -*- lexical-binding: t -*-
 
-;; Copyright (C) 1998-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: convenience patch diff vc
@@ -178,7 +178,7 @@ when editing big diffs)."
     ["Unified -> Context"      diff-unified->context
      :help "Convert unified diffs to context diffs"]
     ;;["Fixup Headers"         diff-fixup-modifs       (not buffer-read-only)]
-    ["Remove trailing whitespace" diff-remove-trailing-whitespace
+    ["Remove trailing whitespace" diff-delete-trailing-whitespace
      :help "Remove trailing whitespace problems introduced by the diff"]
     ["Show trailing whitespace" whitespace-mode
      :style toggle :selected (bound-and-true-p whitespace-mode)
@@ -575,19 +575,21 @@ next hunk if TRY-HARDER is non-nil; otherwise signal an error."
 (easy-mmode-define-navigation
  diff-hunk diff-hunk-header-re "hunk" diff-end-of-hunk diff-restrict-view
  (when diff-auto-refine-mode
-   (setq diff--auto-refine-data (cons (current-buffer) (point-marker)))
-   (run-at-time 0.0 nil
-                (lambda ()
-                  (when diff--auto-refine-data
-                    (let ((buffer (car diff--auto-refine-data))
-                          (point (cdr diff--auto-refine-data)))
-                      (setq diff--auto-refine-data nil)
-                      (with-local-quit
-                        (when (buffer-live-p buffer)
-                          (with-current-buffer buffer
-                            (save-excursion
-                              (goto-char point)
-                              (diff-refine-hunk)))))))))))
+   (unless (prog1 diff--auto-refine-data
+             (setq diff--auto-refine-data
+                   (cons (current-buffer) (point-marker))))
+     (run-at-time 0.0 nil
+                  (lambda ()
+                    (when diff--auto-refine-data
+                      (let ((buffer (car diff--auto-refine-data))
+                            (point (cdr diff--auto-refine-data)))
+                        (setq diff--auto-refine-data nil)
+                        (with-local-quit
+                          (when (buffer-live-p buffer)
+                            (with-current-buffer buffer
+                              (save-excursion
+                                (goto-char point)
+                                (diff-refine-hunk))))))))))))
 
 (easy-mmode-define-navigation
  diff-file diff-file-header-re "file" diff-end-of-file)
@@ -819,9 +821,11 @@ If the OLD prefix arg is passed, tell the file NAME of the old file."
                       (progn (diff-hunk-prev) (point))
                     (error (point-min)))))
          (header-files
-          (if (looking-at "[-*][-*][-*] \\(\\S-+\\)\\(\\s-.*\\)?\n[-+][-+][-+] \\(\\S-+\\)")
-              (list (if old (match-string 1) (match-string 3))
-                    (if old (match-string 3) (match-string 1)))
+           ;; handle filenames with spaces;
+           ;; cf. diff-font-lock-keywords / diff-file-header-face
+          (if (looking-at "[-*][-*][-*] \\([^\t]+\\)\t.*\n[-+][-+][-+] \\([^\t]+\\)")
+              (list (if old (match-string 1) (match-string 2))
+                    (if old (match-string 2) (match-string 1)))
             (forward-line 1) nil)))
       (delq nil
            (append
@@ -830,6 +834,7 @@ If the OLD prefix arg is passed, tell the file NAME of the old file."
                          (re-search-backward "^Index: \\(.+\\)" limit t)))
               (list (match-string 1)))
             header-files
+             ;; this assumes that there are no spaces in filenames
             (when (re-search-backward
                    "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?"
                    nil t)
@@ -1296,7 +1301,7 @@ See `after-change-functions' for the meaning of BEG, END and LEN."
                           (re-search-forward diff-context-mid-hunk-header-re
                                              nil t)))))
           (when (and ;; Don't try to fixup changes in the hunk header.
-                 (> (car diff-unhandled-changes) start)
+                 (>= (car diff-unhandled-changes) start)
                  ;; Don't try to fixup changes in the mid-hunk header either.
                  (or (not mid)
                      (< (cdr diff-unhandled-changes) (match-beginning 0))
@@ -2048,35 +2053,71 @@ I.e. like `add-change-log-entry-other-window' but applied to all hunks."
       ;; When there's no more hunks, diff-hunk-next signals an error.
       (error nil))))
 
-(defun diff-remove-trailing-whitespace ()
-  "When on a buffer that contains a diff, inspects the
-differences and removes trailing whitespace (spaces, tabs) from
-the lines modified or introduced by this diff. Shows a message
-with the name of the altered buffers, which are unsaved.  If a
-file referenced on the diff has no buffer and needs to be fixed,
-a buffer visiting that file is created."
-  (interactive)
-  ;; We assume that the diff header has no trailing whitespace.
-  (let ((modified-buffers nil))
-    (save-excursion
-      (goto-char (point-min))
-      (while (re-search-forward "^[+!>].*[ \t]+$" (point-max) t)
-        (pcase-let ((`(,buf ,line-offset ,pos ,src ,_dst ,_switched)
-                     (diff-find-source-location t t)))
-          (when line-offset
-            (with-current-buffer buf
-              (save-excursion
-                (goto-char (+ (car pos) (cdr src)))
-                (beginning-of-line)
-                (when (re-search-forward "\\([ \t]+\\)$" (line-end-position) t)
-                  (unless (memq buf modified-buffers)
-                    (push buf modified-buffers))
-                  (replace-match ""))))))))
-    (if modified-buffers
-        (message "Deleted new trailing whitespace from: %s"
-                 (mapconcat (lambda (buf) (concat "`" (buffer-name buf) "'"))
-                            modified-buffers " "))
-      (message "No trailing whitespace fixes needed."))))
+(defun diff-delete-trailing-whitespace (&optional other-file)
+  "Remove trailing whitespace from lines modified in this diff.
+This edits both the current Diff mode buffer and the patched
+source file(s).  If `diff-jump-to-old-file' is non-nil, edit the
+original (unpatched) source file instead.  With a prefix argument
+OTHER-FILE, flip the choice of which source file to edit.
+
+If a file referenced in the diff has no buffer and needs to be
+fixed, visit it in a buffer."
+  (interactive "P")
+  (save-excursion
+    (goto-char (point-min))
+    (let* ((other (diff-xor other-file diff-jump-to-old-file))
+          (modified-buffers nil)
+          (style (save-excursion
+                   (when (re-search-forward diff-hunk-header-re nil t)
+                     (goto-char (match-beginning 0))
+                     (diff-hunk-style))))
+          (regexp (concat "^[" (if other "-<" "+>") "!]"
+                          (if (eq style 'context) " " "")
+                          ".*?\\([ \t]+\\)$"))
+          (inhibit-read-only t)
+          (end-marker (make-marker))
+          hunk-end)
+      ;; Move to the first hunk.
+      (re-search-forward diff-hunk-header-re nil 1)
+      (while (progn (save-excursion
+                     (re-search-forward diff-hunk-header-re nil 1)
+                     (setq hunk-end (point)))
+                   (< (point) hunk-end))
+       ;; For context diffs, search only in the appropriate half of
+       ;; the hunk.  For other diffs, search within the entire hunk.
+       (if (not (eq style 'context))
+           (set-marker end-marker hunk-end)
+         (let ((mid-hunk
+                (save-excursion
+                  (re-search-forward diff-context-mid-hunk-header-re hunk-end)
+                  (point))))
+           (if other
+               (set-marker end-marker mid-hunk)
+             (goto-char mid-hunk)
+             (set-marker end-marker hunk-end))))
+       (while (re-search-forward regexp end-marker t)
+         (let ((match-data (match-data)))
+           (pcase-let ((`(,buf ,line-offset ,pos ,src ,_dst ,_switched)
+                        (diff-find-source-location other-file)))
+             (when line-offset
+               ;; Remove the whitespace in the Diff mode buffer.
+               (set-match-data match-data)
+               (replace-match "" t t nil 1)
+               ;; Remove the whitespace in the source buffer.
+               (with-current-buffer buf
+                 (save-excursion
+                   (goto-char (+ (car pos) (cdr src)))
+                   (beginning-of-line)
+                   (when (re-search-forward "\\([ \t]+\\)$" (line-end-position) t)
+                     (unless (memq buf modified-buffers)
+                       (push buf modified-buffers))
+                     (replace-match ""))))))))
+       (goto-char hunk-end))
+      (if modified-buffers
+         (message "Deleted trailing whitespace from %s."
+                  (mapconcat (lambda (buf) (concat "`" (buffer-name buf) "'"))
+                             modified-buffers ", "))
+       (message "No trailing whitespace to delete.")))))
 
 ;; provide the package
 (provide 'diff-mode)