diff options
| author | Stefan Monnier | 2004-03-23 20:50:36 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2004-03-23 20:50:36 +0000 |
| commit | 22cd1973d54a817eb0b0a8e9a9bf6e07323817fa (patch) | |
| tree | 383324e2ddd359fcc39151443a5c1adc45426f47 | |
| parent | 5bd8d87b8563f93070292d95144b03793a930104 (diff) | |
| download | emacs-22cd1973d54a817eb0b0a8e9a9bf6e07323817fa.tar.gz emacs-22cd1973d54a817eb0b0a8e9a9bf6e07323817fa.zip | |
(diff-default-read-only): Change default.
(diff-mode-hook): Make it a defcustom. Add some options.
(diff-mode-map): Bind diff-refine-hook.
(diff-yank-handler): New var.
(diff-yank-function): New fun.
(diff-font-lock-keywords): Use them.
(diff-end-of-file): Handle case where file-header looks like diff text.
(diff-hunk-kill): Adjust to "new" hunk-next behavior.
(diff-file-kill): Delete a subsequent empty line, if applicable.
(diff-hunk-file-names): New fun, extracted from diff-tell-file-name.
(diff-find-file-name): Use it.
(diff-tell-file-name): New command.
(diff-mode): Be careful with view-mode.
(diff-delete-if-empty, diff-delete-empty-files, diff-make-unified):
New functions, for use in diff-mode-hook.
(diff-find-source-location): Catch "regex too large" errors.
(diff-apply-hunk, diff-test-hunk): Go to old or new file.
(diff-refine-hunk): New command.
| -rw-r--r-- | lisp/diff-mode.el | 225 |
1 files changed, 178 insertions, 47 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el index 14be2e841a3..9ae6bbee7c0 100644 --- a/lisp/diff-mode.el +++ b/lisp/diff-mode.el | |||
| @@ -38,20 +38,19 @@ | |||
| 38 | 38 | ||
| 39 | ;; Todo: | 39 | ;; Todo: |
| 40 | 40 | ||
| 41 | ;; - Improve narrowed-view support. | 41 | ;; - Add a `delete-after-apply' so C-c C-a automatically deletes hunks. |
| 42 | ;; - re-enable (conditionally) the `compile' support after improving it to use | 42 | ;; Also allow C-c C-a to delete already-applied hunks. |
| 43 | ;; the same code as diff-goto-source. | 43 | ;; |
| 44 | ;; - Support for # comments in context->unified. | 44 | ;; - Try `diff <file> <hunk>' to try and fuzzily discover the source location |
| 45 | ;; - Allow diff.el to use diff-mode. | 45 | ;; of a hunk. Show then the changes between <file> and <hunk> and make it |
| 46 | ;; This mostly means ability to jump from half-hunk to half-hunk | 46 | ;; possible to apply them to <file>, <hunk-src>, or <hunk-dst>. |
| 47 | ;; in context (and normal) diffs and to jump to the corresponding | 47 | ;; Or maybe just make it into a ".rej to diff3-markers converter". |
| 48 | ;; (i.e. new or old) file. | 48 | ;; |
| 49 | ;; - Refine hunk on a word-by-word basis. | ||
| 50 | ;; | ||
| 51 | ;; - Use the new next-error-function to allow C-x `. | ||
| 49 | ;; - Handle `diff -b' output in context->unified. | 52 | ;; - Handle `diff -b' output in context->unified. |
| 50 | 53 | ||
| 51 | ;; Low priority: | ||
| 52 | ;; - Spice up the minor-mode with font-lock support. | ||
| 53 | ;; - Recognize pcl-cvs' special string for `cvs-execute-single'. | ||
| 54 | |||
| 55 | ;;; Code: | 54 | ;;; Code: |
| 56 | 55 | ||
| 57 | (eval-when-compile (require 'cl)) | 56 | (eval-when-compile (require 'cl)) |
| @@ -63,7 +62,7 @@ | |||
| 63 | :group 'tools | 62 | :group 'tools |
| 64 | :group 'diff) | 63 | :group 'diff) |
| 65 | 64 | ||
| 66 | (defcustom diff-default-read-only t | 65 | (defcustom diff-default-read-only nil |
| 67 | "If non-nil, `diff-mode' buffers default to being read-only." | 66 | "If non-nil, `diff-mode' buffers default to being read-only." |
| 68 | :type 'boolean | 67 | :type 'boolean |
| 69 | :group 'diff-mode) | 68 | :group 'diff-mode) |
| @@ -87,8 +86,10 @@ when editing big diffs)." | |||
| 87 | :type 'boolean) | 86 | :type 'boolean) |
| 88 | 87 | ||
| 89 | 88 | ||
| 90 | (defvar diff-mode-hook nil | 89 | (defcustom diff-mode-hook nil |
| 91 | "Run after setting up the `diff-mode' major mode.") | 90 | "Run after setting up the `diff-mode' major mode." |
| 91 | :type 'hook | ||
| 92 | :options '(diff-delete-empty-files diff-make-unified)) | ||
| 92 | 93 | ||
| 93 | (defvar diff-outline-regexp | 94 | (defvar diff-outline-regexp |
| 94 | "\\([*+][*+][*+] [^0-9]\\|@@ ...\\|\\*\\*\\* [0-9].\\|--- [0-9]..\\)") | 95 | "\\([*+][*+][*+] [^0-9]\\|@@ ...\\|\\*\\*\\* [0-9].\\|--- [0-9]..\\)") |
| @@ -136,6 +137,7 @@ when editing big diffs)." | |||
| 136 | ;; From compilation-minor-mode. | 137 | ;; From compilation-minor-mode. |
| 137 | ("\C-c\C-c" . diff-goto-source) | 138 | ("\C-c\C-c" . diff-goto-source) |
| 138 | ;; Misc operations. | 139 | ;; Misc operations. |
| 140 | ("\C-c\C-r" . diff-refine-hunk) | ||
| 139 | ("\C-c\C-s" . diff-split-hunk) | 141 | ("\C-c\C-s" . diff-split-hunk) |
| 140 | ("\C-c\C-a" . diff-apply-hunk) | 142 | ("\C-c\C-a" . diff-apply-hunk) |
| 141 | ("\C-c\C-t" . diff-test-hunk)) | 143 | ("\C-c\C-t" . diff-test-hunk)) |
| @@ -241,8 +243,28 @@ when editing big diffs)." | |||
| 241 | "`diff-mode' face used to highlight nonexistent files in recursive diffs.") | 243 | "`diff-mode' face used to highlight nonexistent files in recursive diffs.") |
| 242 | (defvar diff-nonexistent-face 'diff-nonexistent-face) | 244 | (defvar diff-nonexistent-face 'diff-nonexistent-face) |
| 243 | 245 | ||
| 246 | (defconst diff-yank-handler '(diff-yank-function)) | ||
| 247 | (defun diff-yank-function (text) | ||
| 248 | (let ((mixed (next-single-property-change 0 'yank-handler text)) | ||
| 249 | (start (point))) | ||
| 250 | ;; First insert the text. | ||
| 251 | (insert text) | ||
| 252 | ;; If the text does not include any diff markers and if we're not | ||
| 253 | ;; yanking back into a diff-mode buffer, get rid of the prefixes. | ||
| 254 | (unless (or mixed (derived-mode-p 'diff-mode)) | ||
| 255 | (undo-boundary) ; Just in case the user wanted the prefixes. | ||
| 256 | (let ((re (save-excursion | ||
| 257 | (if (re-search-backward "^[><!][ \t]" start t) | ||
| 258 | (if (eq (char-after) ?!) | ||
| 259 | "^[!+- ][ \t]" "^[<>][ \t]") | ||
| 260 | "^[ <>!+-]")))) | ||
| 261 | (save-excursion | ||
| 262 | (while (re-search-backward re start t) | ||
| 263 | (replace-match "" t t))))))) | ||
| 264 | |||
| 265 | |||
| 244 | (defvar diff-font-lock-keywords | 266 | (defvar diff-font-lock-keywords |
| 245 | '(("^\\(@@ -[0-9,]+ \\+[0-9,]+ @@\\)\\(.*\\)$" ;unified | 267 | `(("^\\(@@ -[0-9,]+ \\+[0-9,]+ @@\\)\\(.*\\)$" ;unified |
| 246 | (1 diff-hunk-header-face) | 268 | (1 diff-hunk-header-face) |
| 247 | (2 diff-function-face)) | 269 | (2 diff-function-face)) |
| 248 | ("^--- .+ ----$" . diff-hunk-header-face) ;context | 270 | ("^--- .+ ----$" . diff-hunk-header-face) ;context |
| @@ -253,13 +275,14 @@ when editing big diffs)." | |||
| 253 | ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\(\\S-+\\)\\(.*[^*-]\\)?\n" | 275 | ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\(\\S-+\\)\\(.*[^*-]\\)?\n" |
| 254 | (0 diff-header-face) (2 diff-file-header-face prepend)) | 276 | (0 diff-header-face) (2 diff-file-header-face prepend)) |
| 255 | ("^[0-9,]+[acd][0-9,]+$" . diff-hunk-header-face) | 277 | ("^[0-9,]+[acd][0-9,]+$" . diff-hunk-header-face) |
| 256 | ("^!.*\n" . diff-changed-face) ;context | 278 | ("^!.*\n" (0 '(face diff-changed-face yank-handler ,diff-yank-handler))) |
| 257 | ("^[+>].*\n" . diff-added-face) | 279 | ("^[+>].*\n" (0 '(face diff-added-face yank-handler ,diff-yank-handler))) |
| 258 | ("^[-<].*\n" . diff-removed-face) | 280 | ("^[-<].*\n" (0 '(face diff-removed-face yank-handler ,diff-yank-handler))) |
| 259 | ("^Index: \\(.+\\).*\n" (0 diff-header-face) (1 diff-index-face prepend)) | 281 | ("^Index: \\(.+\\).*\n" (0 diff-header-face) (1 diff-index-face prepend)) |
| 260 | ("^Only in .*\n" . diff-nonexistent-face) | 282 | ("^Only in .*\n" . diff-nonexistent-face) |
| 261 | ("^#.*" . font-lock-string-face) | 283 | ("^#.*" . font-lock-string-face) |
| 262 | ("^[^-=+*!<>].*\n" . diff-context-face))) | 284 | ("^[^-=+*!<>].*\n" |
| 285 | (0 '(face diff-context-face yank-handler ,diff-yank-handler))))) | ||
| 263 | 286 | ||
| 264 | (defconst diff-font-lock-defaults | 287 | (defconst diff-font-lock-defaults |
| 265 | '(diff-font-lock-keywords t nil nil nil (font-lock-multiline . nil))) | 288 | '(diff-font-lock-keywords t nil nil nil (font-lock-multiline . nil))) |
| @@ -311,8 +334,11 @@ when editing big diffs)." | |||
| 311 | 334 | ||
| 312 | (defun diff-end-of-file () | 335 | (defun diff-end-of-file () |
| 313 | (re-search-forward "^[-+#!<>0-9@* \\]" nil t) | 336 | (re-search-forward "^[-+#!<>0-9@* \\]" nil t) |
| 314 | (re-search-forward "^[^-+#!<>0-9@* \\]" nil 'move) | 337 | (re-search-forward (concat "^[^-+#!<>0-9@* \\]\\|" diff-file-header-re) |
| 315 | (beginning-of-line)) | 338 | nil 'move) |
| 339 | (if (match-beginning 1) | ||
| 340 | (goto-char (match-beginning 1)) | ||
| 341 | (beginning-of-line))) | ||
| 316 | 342 | ||
| 317 | ;; Define diff-{hunk,file}-{prev,next} | 343 | ;; Define diff-{hunk,file}-{prev,next} |
| 318 | (easy-mmode-define-navigation | 344 | (easy-mmode-define-navigation |
| @@ -337,7 +363,8 @@ If the prefix ARG is given, restrict the view to the current file instead." | |||
| 337 | (interactive) | 363 | (interactive) |
| 338 | (diff-beginning-of-hunk) | 364 | (diff-beginning-of-hunk) |
| 339 | (let* ((start (point)) | 365 | (let* ((start (point)) |
| 340 | (nexthunk (ignore-errors (diff-hunk-next) (point))) | 366 | (nexthunk (when (re-search-forward diff-hunk-header-re nil t) |
| 367 | (match-beginning 0))) | ||
| 341 | (firsthunk (ignore-errors | 368 | (firsthunk (ignore-errors |
| 342 | (goto-char start) | 369 | (goto-char start) |
| 343 | (diff-beginning-of-file) (diff-hunk-next) (point))) | 370 | (diff-beginning-of-file) (diff-hunk-next) (point))) |
| @@ -363,6 +390,7 @@ If the prefix ARG is given, restrict the view to the current file instead." | |||
| 363 | (re-search-backward "^Index: " prevhunk t)))) | 390 | (re-search-backward "^Index: " prevhunk t)))) |
| 364 | (when index (setq start index)) | 391 | (when index (setq start index)) |
| 365 | (diff-end-of-file) | 392 | (diff-end-of-file) |
| 393 | (if (looking-at "^\n") (forward-char 1)) ;`tla' generates such diffs. | ||
| 366 | (kill-region start (point)))) | 394 | (kill-region start (point)))) |
| 367 | 395 | ||
| 368 | (defun diff-kill-junk () | 396 | (defun diff-kill-junk () |
| @@ -439,31 +467,55 @@ like \(diff-merge-strings \"b/foo\" \"b/bar\" \"/a/c/foo\")." | |||
| 439 | (match-string 4 str) | 467 | (match-string 4 str) |
| 440 | (substring str (match-end 6) (match-end 5)))))) | 468 | (substring str (match-end 6) (match-end 5)))))) |
| 441 | 469 | ||
| 442 | (defun diff-find-file-name (&optional old) | 470 | (defun diff-tell-file-name (old name) |
| 443 | "Return the file corresponding to the current patch. | 471 | "Tell Emacs where the find the source file of the current hunk. |
| 444 | Non-nil OLD means that we want the old file." | 472 | If the OLD prefix arg is passed, tell the file NAME of the old file." |
| 473 | (interactive | ||
| 474 | (let* ((old current-prefix-arg) | ||
| 475 | (fs (diff-hunk-file-names current-prefix-arg))) | ||
| 476 | (unless fs (error "No file name to look for")) | ||
| 477 | (list old (read-file-name (format "File for %s: " (car fs)) | ||
| 478 | nil (diff-find-file-name old) t)))) | ||
| 479 | (let ((fs (diff-hunk-file-names old))) | ||
| 480 | (unless fs (error "No file name to look for")) | ||
| 481 | (push (cons fs name) diff-remembered-files-alist))) | ||
| 482 | |||
| 483 | (defun diff-hunk-file-names (&optional old) | ||
| 484 | "Give the list of file names textually mentioned for the current hunk." | ||
| 445 | (save-excursion | 485 | (save-excursion |
| 446 | (unless (looking-at diff-file-header-re) | 486 | (unless (looking-at diff-file-header-re) |
| 447 | (or (ignore-errors (diff-beginning-of-file)) | 487 | (or (ignore-errors (diff-beginning-of-file)) |
| 448 | (re-search-forward diff-file-header-re nil t))) | 488 | (re-search-forward diff-file-header-re nil t))) |
| 449 | (let* ((limit (save-excursion | 489 | (let ((limit (save-excursion |
| 450 | (condition-case () | 490 | (condition-case () |
| 451 | (progn (diff-hunk-prev) (point)) | 491 | (progn (diff-hunk-prev) (point)) |
| 452 | (error (point-min))))) | 492 | (error (point-min))))) |
| 453 | (header-files | 493 | (header-files |
| 454 | (if (looking-at "[-*][-*][-*] \\(\\S-+\\)\\(\\s-.*\\)?\n[-+][-+][-+] \\(\\S-+\\)") | 494 | (if (looking-at "[-*][-*][-*] \\(\\S-+\\)\\(\\s-.*\\)?\n[-+][-+][-+] \\(\\S-+\\)") |
| 455 | (list (if old (match-string 1) (match-string 3)) | 495 | (list (if old (match-string 1) (match-string 3)) |
| 456 | (if old (match-string 3) (match-string 1))) | 496 | (if old (match-string 3) (match-string 1))) |
| 457 | (forward-line 1) nil)) | 497 | (forward-line 1) nil))) |
| 458 | (fs (append | 498 | (delq nil |
| 459 | (when (save-excursion | 499 | (append |
| 460 | (re-search-backward "^Index: \\(.+\\)" limit t)) | 500 | (when (and (not old) |
| 461 | (list (match-string 1))) | 501 | (save-excursion |
| 462 | header-files | 502 | (re-search-backward "^Index: \\(.+\\)" limit t))) |
| 463 | (when (re-search-backward "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" nil t) | 503 | (list (match-string 1))) |
| 464 | (list (if old (match-string 2) (match-string 4)) | 504 | header-files |
| 465 | (if old (match-string 4) (match-string 2)))))) | 505 | (when (re-search-backward |
| 466 | (fs (delq nil fs))) | 506 | "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" |
| 507 | nil t) | ||
| 508 | (list (if old (match-string 2) (match-string 4)) | ||
| 509 | (if old (match-string 4) (match-string 2))))))))) | ||
| 510 | |||
| 511 | (defun diff-find-file-name (&optional old) | ||
| 512 | "Return the file corresponding to the current patch. | ||
| 513 | Non-nil OLD means that we want the old file." | ||
| 514 | (save-excursion | ||
| 515 | (unless (looking-at diff-file-header-re) | ||
| 516 | (or (ignore-errors (diff-beginning-of-file)) | ||
| 517 | (re-search-forward diff-file-header-re nil t))) | ||
| 518 | (let ((fs (diff-hunk-file-names old))) | ||
| 467 | (or | 519 | (or |
| 468 | ;; use any previously used preference | 520 | ;; use any previously used preference |
| 469 | (cdr (assoc fs diff-remembered-files-alist)) | 521 | (cdr (assoc fs diff-remembered-files-alist)) |
| @@ -876,8 +928,14 @@ a diff with \\[diff-reverse-direction]." | |||
| 876 | (add-hook 'after-change-functions 'diff-after-change-function nil t) | 928 | (add-hook 'after-change-functions 'diff-after-change-function nil t) |
| 877 | (add-hook 'post-command-hook 'diff-post-command-hook nil t)) | 929 | (add-hook 'post-command-hook 'diff-post-command-hook nil t)) |
| 878 | ;; Neat trick from Dave Love to add more bindings in read-only mode: | 930 | ;; Neat trick from Dave Love to add more bindings in read-only mode: |
| 879 | (add-to-list 'minor-mode-overriding-map-alist | 931 | (let ((ro-bind (cons 'buffer-read-only diff-mode-shared-map))) |
| 880 | (cons 'buffer-read-only diff-mode-shared-map)) | 932 | (add-to-list 'minor-mode-overriding-map-alist ro-bind) |
| 933 | ;; Turn off this little trick in case the buffer is put in view-mode. | ||
| 934 | (add-hook 'view-mode-hook | ||
| 935 | `(lambda () | ||
| 936 | (setq minor-mode-overriding-map-alist | ||
| 937 | (delq ,ro-bind minor-mode-overriding-map-alist))) | ||
| 938 | nil t)) | ||
| 881 | ;; add-log support | 939 | ;; add-log support |
| 882 | (set (make-local-variable 'add-log-current-defun-function) | 940 | (set (make-local-variable 'add-log-current-defun-function) |
| 883 | 'diff-current-defun) | 941 | 'diff-current-defun) |
| @@ -897,6 +955,29 @@ a diff with \\[diff-reverse-direction]." | |||
| 897 | (add-hook 'after-change-functions 'diff-after-change-function nil t) | 955 | (add-hook 'after-change-functions 'diff-after-change-function nil t) |
| 898 | (add-hook 'post-command-hook 'diff-post-command-hook nil t))) | 956 | (add-hook 'post-command-hook 'diff-post-command-hook nil t))) |
| 899 | 957 | ||
| 958 | ;;; Handy hook functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 959 | |||
| 960 | (defun diff-delete-if-empty () | ||
| 961 | ;; An empty diff file means there's no more diffs to integrate, so we | ||
| 962 | ;; can just remove the file altogether. Very handy for .rej files if we | ||
| 963 | ;; remove hunks as we apply them. | ||
| 964 | (when (and buffer-file-name | ||
| 965 | (eq 0 (nth 7 (file-attributes buffer-file-name)))) | ||
| 966 | (delete-file buffer-file-name))) | ||
| 967 | |||
| 968 | (defun diff-delete-empty-files () | ||
| 969 | "Arrange for empty diff files to be removed." | ||
| 970 | (add-hook 'after-save-hook 'diff-delete-if-empty nil t)) | ||
| 971 | |||
| 972 | (defun diff-make-unified () | ||
| 973 | "Turn context diffs into unified diffs if applicable." | ||
| 974 | (if (save-excursion | ||
| 975 | (goto-char (point-min)) | ||
| 976 | (looking-at "\\*\\*\\* ")) | ||
| 977 | (let ((mod (buffer-modified-p))) | ||
| 978 | (unwind-protect | ||
| 979 | (diff-context->unified (point-min) (point-max)) | ||
| 980 | (restore-buffer-modified-p mod))))) | ||
| 900 | 981 | ||
| 901 | ;;; | 982 | ;;; |
| 902 | ;;; Misc operations that have proved useful at some point. | 983 | ;;; Misc operations that have proved useful at some point. |
| @@ -1060,12 +1141,17 @@ SWITCHED is non-nil if the patch is already applied." | |||
| 1060 | (goto-line (string-to-number line)) | 1141 | (goto-line (string-to-number line)) |
| 1061 | (let* ((orig-pos (point)) | 1142 | (let* ((orig-pos (point)) |
| 1062 | (switched nil) | 1143 | (switched nil) |
| 1144 | ;; FIXME: Check for case where both OLD and NEW are found. | ||
| 1063 | (pos (or (diff-find-text (car old)) | 1145 | (pos (or (diff-find-text (car old)) |
| 1064 | (progn (setq switched t) (diff-find-text (car new))) | 1146 | (progn (setq switched t) (diff-find-text (car new))) |
| 1065 | (progn (setq switched nil) | 1147 | (progn (setq switched nil) |
| 1066 | (diff-find-approx-text (car old))) | 1148 | (condition-case nil |
| 1149 | (diff-find-approx-text (car old)) | ||
| 1150 | (invalid-regexp nil))) ;Regex too big. | ||
| 1067 | (progn (setq switched t) | 1151 | (progn (setq switched t) |
| 1068 | (diff-find-approx-text (car new))) | 1152 | (condition-case nil |
| 1153 | (diff-find-approx-text (car new)) | ||
| 1154 | (invalid-regexp nil))) ;Regex too big. | ||
| 1069 | (progn (setq switched nil) nil)))) | 1155 | (progn (setq switched nil) nil)))) |
| 1070 | (nconc | 1156 | (nconc |
| 1071 | (list buf) | 1157 | (list buf) |
| @@ -1096,7 +1182,8 @@ the value of this variable when given an appropriate prefix argument). | |||
| 1096 | With a prefix argument, REVERSE the hunk." | 1182 | With a prefix argument, REVERSE the hunk." |
| 1097 | (interactive "P") | 1183 | (interactive "P") |
| 1098 | (destructuring-bind (buf line-offset pos old new &optional switched) | 1184 | (destructuring-bind (buf line-offset pos old new &optional switched) |
| 1099 | (diff-find-source-location nil reverse) | 1185 | ;; If REVERSE go to the new file, otherwise go to the old. |
| 1186 | (diff-find-source-location (not reverse) reverse) | ||
| 1100 | (cond | 1187 | (cond |
| 1101 | ((null line-offset) | 1188 | ((null line-offset) |
| 1102 | (error "Can't find the text to patch")) | 1189 | (error "Can't find the text to patch")) |
| @@ -1128,7 +1215,8 @@ With a prefix argument, REVERSE the hunk." | |||
| 1128 | With a prefix argument, try to REVERSE the hunk." | 1215 | With a prefix argument, try to REVERSE the hunk." |
| 1129 | (interactive "P") | 1216 | (interactive "P") |
| 1130 | (destructuring-bind (buf line-offset pos src dst &optional switched) | 1217 | (destructuring-bind (buf line-offset pos src dst &optional switched) |
| 1131 | (diff-find-source-location nil reverse) | 1218 | ;; If REVERSE go to the new file, otherwise go to the old. |
| 1219 | (diff-find-source-location (not reverse) reverse) | ||
| 1132 | (set-window-point (display-buffer buf) (+ (car pos) (cdr src))) | 1220 | (set-window-point (display-buffer buf) (+ (car pos) (cdr src))) |
| 1133 | (diff-hunk-status-msg line-offset (diff-xor reverse switched) t))) | 1221 | (diff-hunk-status-msg line-offset (diff-xor reverse switched) t))) |
| 1134 | 1222 | ||
| @@ -1173,6 +1261,49 @@ For use in `add-log-current-defun-function'." | |||
| 1173 | (goto-char (+ (car pos) (cdr src))) | 1261 | (goto-char (+ (car pos) (cdr src))) |
| 1174 | (add-log-current-defun)))))) | 1262 | (add-log-current-defun)))))) |
| 1175 | 1263 | ||
| 1264 | (defun diff-refine-hunk () | ||
| 1265 | "Refine the current hunk by ignoring space differences." | ||
| 1266 | (interactive) | ||
| 1267 | (let* ((char-offset (- (point) (progn (diff-beginning-of-hunk) (point)))) | ||
| 1268 | (opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b"))) | ||
| 1269 | (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") | ||
| 1270 | (error "Can't find line number")) | ||
| 1271 | (string-to-number (match-string 1)))) | ||
| 1272 | (hunk (delete-and-extract-region | ||
| 1273 | (point) (save-excursion (diff-end-of-hunk) (point)))) | ||
| 1274 | (lead (make-string (1- line-nb) ?\n)) ;Line nums start at 1. | ||
| 1275 | (file1 (make-temp-file "diff1")) | ||
| 1276 | (file2 (make-temp-file "diff2")) | ||
| 1277 | (coding-system-for-read buffer-file-coding-system) | ||
| 1278 | old new) | ||
| 1279 | (unwind-protect | ||
| 1280 | (save-excursion | ||
| 1281 | (setq old (diff-hunk-text hunk nil char-offset)) | ||
| 1282 | (setq new (diff-hunk-text hunk t char-offset)) | ||
| 1283 | (write-region (concat lead (car old)) nil file1 nil 'nomessage) | ||
| 1284 | (write-region (concat lead (car new)) nil file2 nil 'nomessage) | ||
| 1285 | (with-temp-buffer | ||
| 1286 | (let ((status | ||
| 1287 | (call-process diff-command nil t nil | ||
| 1288 | opts file1 file2))) | ||
| 1289 | (case status | ||
| 1290 | (0 nil) ;Nothing to reformat. | ||
| 1291 | (1 (goto-char (point-min)) | ||
| 1292 | ;; Remove the file-header. | ||
| 1293 | (when (re-search-forward diff-hunk-header-re nil t) | ||
| 1294 | (delete-region (point-min) (match-beginning 0)))) | ||
| 1295 | (t (goto-char (point-max)) | ||
| 1296 | (unless (bolp) (insert "\n")) | ||
| 1297 | (insert hunk))) | ||
| 1298 | (setq hunk (buffer-string)) | ||
| 1299 | (unless (memq status '(0 1)) | ||
| 1300 | (error "Diff returned: %s" status))))) | ||
| 1301 | ;; Whatever happens, put back some equivalent text: either the new | ||
| 1302 | ;; one or the original one in case some error happened. | ||
| 1303 | (insert hunk) | ||
| 1304 | (delete-file file1) | ||
| 1305 | (delete-file file2)))) | ||
| 1306 | |||
| 1176 | ;; provide the package | 1307 | ;; provide the package |
| 1177 | (provide 'diff-mode) | 1308 | (provide 'diff-mode) |
| 1178 | 1309 | ||