diff options
Diffstat (limited to 'lisp/diff-mode.el')
| -rw-r--r-- | lisp/diff-mode.el | 116 |
1 files changed, 97 insertions, 19 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el index 64199147c21..a1bd0afa126 100644 --- a/lisp/diff-mode.el +++ b/lisp/diff-mode.el | |||
| @@ -155,7 +155,7 @@ when editing big diffs)." | |||
| 155 | ("\C-c\C-u" . diff-context->unified) | 155 | ("\C-c\C-u" . diff-context->unified) |
| 156 | ;; `d' because it duplicates the context :-( --Stef | 156 | ;; `d' because it duplicates the context :-( --Stef |
| 157 | ("\C-c\C-d" . diff-unified->context) | 157 | ("\C-c\C-d" . diff-unified->context) |
| 158 | ("\C-c\C-w" . diff-refine-hunk) | 158 | ("\C-c\C-w" . diff-refine-ignore-spaces-hunk) |
| 159 | ("\C-c\C-f" . next-error-follow-minor-mode)) | 159 | ("\C-c\C-f" . next-error-follow-minor-mode)) |
| 160 | "Keymap for `diff-mode'. See also `diff-mode-shared-map'.") | 160 | "Keymap for `diff-mode'. See also `diff-mode-shared-map'.") |
| 161 | 161 | ||
| @@ -164,12 +164,23 @@ when editing big diffs)." | |||
| 164 | '("Diff" | 164 | '("Diff" |
| 165 | ["Jump to Source" diff-goto-source t] | 165 | ["Jump to Source" diff-goto-source t] |
| 166 | ["Apply hunk" diff-apply-hunk t] | 166 | ["Apply hunk" diff-apply-hunk t] |
| 167 | ["Test applying hunk" diff-test-hunk t] | ||
| 167 | ["Apply diff with Ediff" diff-ediff-patch t] | 168 | ["Apply diff with Ediff" diff-ediff-patch t] |
| 168 | ["-----" nil nil] | 169 | "-----" |
| 169 | ["Reverse direction" diff-reverse-direction t] | 170 | ["Reverse direction" diff-reverse-direction t] |
| 170 | ["Context -> Unified" diff-context->unified t] | 171 | ["Context -> Unified" diff-context->unified t] |
| 171 | ["Unified -> Context" diff-unified->context t] | 172 | ["Unified -> Context" diff-unified->context t] |
| 172 | ;;["Fixup Headers" diff-fixup-modifs (not buffer-read-only)] | 173 | ;;["Fixup Headers" diff-fixup-modifs (not buffer-read-only)] |
| 174 | "-----" | ||
| 175 | ["Split hunk" diff-split-hunk (diff-splittable-p)] | ||
| 176 | ["Refine hunk" diff-refine-ignore-spaces-hunk t] | ||
| 177 | ["Kill current hunk" diff-hunk-kill t] | ||
| 178 | ["Kill current file's hunks" diff-file-kill t] | ||
| 179 | "-----" | ||
| 180 | ["Previous Hunk" diff-hunk-prev t] | ||
| 181 | ["Next Hunk" diff-hunk-next t] | ||
| 182 | ["Previous File" diff-file-prev t] | ||
| 183 | ["Next File" diff-file-next t] | ||
| 173 | )) | 184 | )) |
| 174 | 185 | ||
| 175 | (defcustom diff-minor-mode-prefix "\C-c=" | 186 | (defcustom diff-minor-mode-prefix "\C-c=" |
| @@ -390,13 +401,26 @@ when editing big diffs)." | |||
| 390 | ;; The return value is used by easy-mmode-define-navigation. | 401 | ;; The return value is used by easy-mmode-define-navigation. |
| 391 | (goto-char (or end (point-max))))) | 402 | (goto-char (or end (point-max))))) |
| 392 | 403 | ||
| 393 | (defun diff-beginning-of-hunk () | 404 | (defun diff-beginning-of-hunk (&optional try-harder) |
| 405 | "Move back to beginning of hunk. | ||
| 406 | If TRY-HARDER is non-nil, try to cater to the case where we're not in a hunk | ||
| 407 | but in the file header instead, in which case move forward to the first hunk." | ||
| 394 | (beginning-of-line) | 408 | (beginning-of-line) |
| 395 | (unless (looking-at diff-hunk-header-re) | 409 | (unless (looking-at diff-hunk-header-re) |
| 396 | (forward-line 1) | 410 | (forward-line 1) |
| 397 | (condition-case () | 411 | (condition-case () |
| 398 | (re-search-backward diff-hunk-header-re) | 412 | (re-search-backward diff-hunk-header-re) |
| 399 | (error (error "Can't find the beginning of the hunk"))))) | 413 | (error |
| 414 | (if (not try-harder) | ||
| 415 | (error "Can't find the beginning of the hunk") | ||
| 416 | (diff-beginning-of-file-and-junk) | ||
| 417 | (diff-hunk-next)))))) | ||
| 418 | |||
| 419 | (defun diff-unified-hunk-p () | ||
| 420 | (save-excursion | ||
| 421 | (ignore-errors | ||
| 422 | (diff-beginning-of-hunk) | ||
| 423 | (looking-at "^@@")))) | ||
| 400 | 424 | ||
| 401 | (defun diff-beginning-of-file () | 425 | (defun diff-beginning-of-file () |
| 402 | (beginning-of-line) | 426 | (beginning-of-line) |
| @@ -425,7 +449,7 @@ when editing big diffs)." | |||
| 425 | If the prefix ARG is given, restrict the view to the current file instead." | 449 | If the prefix ARG is given, restrict the view to the current file instead." |
| 426 | (interactive "P") | 450 | (interactive "P") |
| 427 | (save-excursion | 451 | (save-excursion |
| 428 | (if arg (diff-beginning-of-file) (diff-beginning-of-hunk)) | 452 | (if arg (diff-beginning-of-file) (diff-beginning-of-hunk 'try-harder)) |
| 429 | (narrow-to-region (point) | 453 | (narrow-to-region (point) |
| 430 | (progn (if arg (diff-end-of-file) (diff-end-of-hunk)) | 454 | (progn (if arg (diff-end-of-file) (diff-end-of-hunk)) |
| 431 | (point))) | 455 | (point))) |
| @@ -453,18 +477,37 @@ If the prefix ARG is given, restrict the view to the current file instead." | |||
| 453 | (diff-end-of-hunk) | 477 | (diff-end-of-hunk) |
| 454 | (kill-region start (point))))) | 478 | (kill-region start (point))))) |
| 455 | 479 | ||
| 480 | (defun diff-beginning-of-file-and-junk () | ||
| 481 | "Go to the beginning of file-related diff-info. | ||
| 482 | This is like `diff-beginning-of-file' except it tries to skip back over leading | ||
| 483 | data such as \"Index: ...\" and such." | ||
| 484 | (let ((start (point)) | ||
| 485 | (file (condition-case err (progn (diff-beginning-of-file) (point)) | ||
| 486 | (error err))) | ||
| 487 | ;; prevhunk is one of the limits. | ||
| 488 | (prevhunk (save-excursion (ignore-errors (diff-hunk-prev) (point)))) | ||
| 489 | err) | ||
| 490 | (when (consp file) | ||
| 491 | ;; Presumably, we started before the file header, in the leading junk. | ||
| 492 | (setq err file) | ||
| 493 | (diff-file-next) | ||
| 494 | (setq file (point))) | ||
| 495 | (let ((index (save-excursion | ||
| 496 | (re-search-backward "^Index: " prevhunk t)))) | ||
| 497 | (when index (setq file index)) | ||
| 498 | (if (<= file start) | ||
| 499 | (goto-char file) | ||
| 500 | ;; File starts *after* the starting point: we really weren't in | ||
| 501 | ;; a file diff but elsewhere. | ||
| 502 | (goto-char start) | ||
| 503 | (signal (car err) (cdr err)))))) | ||
| 504 | |||
| 456 | (defun diff-file-kill () | 505 | (defun diff-file-kill () |
| 457 | "Kill current file's hunks." | 506 | "Kill current file's hunks." |
| 458 | (interactive) | 507 | (interactive) |
| 459 | (diff-beginning-of-file) | 508 | (diff-beginning-of-file-and-junk) |
| 460 | (let* ((start (point)) | 509 | (let* ((start (point)) |
| 461 | (prevhunk (save-excursion | ||
| 462 | (ignore-errors | ||
| 463 | (diff-hunk-prev) (point)))) | ||
| 464 | (index (save-excursion | ||
| 465 | (re-search-backward "^Index: " prevhunk t))) | ||
| 466 | (inhibit-read-only t)) | 510 | (inhibit-read-only t)) |
| 467 | (when index (setq start index)) | ||
| 468 | (diff-end-of-file) | 511 | (diff-end-of-file) |
| 469 | (if (looking-at "^\n") (forward-char 1)) ;`tla' generates such diffs. | 512 | (if (looking-at "^\n") (forward-char 1)) ;`tla' generates such diffs. |
| 470 | (kill-region start (point)))) | 513 | (kill-region start (point)))) |
| @@ -491,6 +534,13 @@ If the prefix ARG is given, restrict the view to the current file instead." | |||
| 491 | (while (re-search-forward re end t) (incf n)) | 534 | (while (re-search-forward re end t) (incf n)) |
| 492 | n))) | 535 | n))) |
| 493 | 536 | ||
| 537 | (defun diff-splittable-p () | ||
| 538 | (save-excursion | ||
| 539 | (beginning-of-line) | ||
| 540 | (and (looking-at "^[-+ ]") | ||
| 541 | (progn (forward-line -1) (looking-at "^[-+ ]")) | ||
| 542 | (diff-unified-hunk-p)))) | ||
| 543 | |||
| 494 | (defun diff-split-hunk () | 544 | (defun diff-split-hunk () |
| 495 | "Split the current (unified diff) hunk at point into two hunks." | 545 | "Split the current (unified diff) hunk at point into two hunks." |
| 496 | (interactive) | 546 | (interactive) |
| @@ -585,9 +635,11 @@ If the OLD prefix arg is passed, tell the file NAME of the old file." | |||
| 585 | (list (if old (match-string 2) (match-string 4)) | 635 | (list (if old (match-string 2) (match-string 4)) |
| 586 | (if old (match-string 4) (match-string 2))))))))) | 636 | (if old (match-string 4) (match-string 2))))))))) |
| 587 | 637 | ||
| 588 | (defun diff-find-file-name (&optional old prefix) | 638 | (defun diff-find-file-name (&optional old batch prefix) |
| 589 | "Return the file corresponding to the current patch. | 639 | "Return the file corresponding to the current patch. |
| 590 | Non-nil OLD means that we want the old file. | 640 | Non-nil OLD means that we want the old file. |
| 641 | Non-nil BATCH means to prefer returning an incorrect answer than to prompt | ||
| 642 | the user. | ||
| 591 | PREFIX is only used internally: don't use it." | 643 | PREFIX is only used internally: don't use it." |
| 592 | (save-excursion | 644 | (save-excursion |
| 593 | (unless (looking-at diff-file-header-re) | 645 | (unless (looking-at diff-file-header-re) |
| @@ -622,7 +674,10 @@ PREFIX is only used internally: don't use it." | |||
| 622 | (boundp 'cvs-pcl-cvs-dirchange-re) | 674 | (boundp 'cvs-pcl-cvs-dirchange-re) |
| 623 | (save-excursion | 675 | (save-excursion |
| 624 | (re-search-backward cvs-pcl-cvs-dirchange-re nil t)) | 676 | (re-search-backward cvs-pcl-cvs-dirchange-re nil t)) |
| 625 | (diff-find-file-name old (match-string 1))) | 677 | (diff-find-file-name old batch (match-string 1))) |
| 678 | ;; Invent something, if necessary. | ||
| 679 | (when batch | ||
| 680 | (or (car fs) default-directory)) | ||
| 626 | ;; if all else fails, ask the user | 681 | ;; if all else fails, ask the user |
| 627 | (let ((file (read-file-name (format "Use file %s: " (or (first fs) "")) | 682 | (let ((file (read-file-name (format "Use file %s: " (or (first fs) "")) |
| 628 | nil (first fs) t (first fs)))) | 683 | nil (first fs) t (first fs)))) |
| @@ -670,7 +725,12 @@ else cover the whole bufer." | |||
| 670 | (let ((line1 (match-string 4)) | 725 | (let ((line1 (match-string 4)) |
| 671 | (lines1 (match-string 5)) | 726 | (lines1 (match-string 5)) |
| 672 | (line2 (match-string 6)) | 727 | (line2 (match-string 6)) |
| 673 | (lines2 (match-string 7))) | 728 | (lines2 (match-string 7)) |
| 729 | ;; Variables to use the special undo function. | ||
| 730 | (old-undo buffer-undo-list) | ||
| 731 | (old-end (marker-position end)) | ||
| 732 | (start (match-beginning 0)) | ||
| 733 | (reversible t)) | ||
| 674 | (replace-match | 734 | (replace-match |
| 675 | (concat "***************\n*** " line1 "," | 735 | (concat "***************\n*** " line1 "," |
| 676 | (number-to-string (+ (string-to-number line1) | 736 | (number-to-string (+ (string-to-number line1) |
| @@ -712,6 +772,14 @@ else cover the whole bufer." | |||
| 712 | (if (not (save-excursion (re-search-forward "^+" nil t))) | 772 | (if (not (save-excursion (re-search-forward "^+" nil t))) |
| 713 | (delete-region (point) (point-max)) | 773 | (delete-region (point) (point-max)) |
| 714 | (let ((modif nil) (delete nil)) | 774 | (let ((modif nil) (delete nil)) |
| 775 | (if (save-excursion (re-search-forward "^\\+.*\n-" nil t)) | ||
| 776 | ;; Normally, lines in a substitution come with | ||
| 777 | ;; first the removals and then the additions, and | ||
| 778 | ;; the context->unified function follows this | ||
| 779 | ;; convention, of course. Yet, other alternatives | ||
| 780 | ;; are valid as well, but they preclude the use of | ||
| 781 | ;; context->unified as an undo command. | ||
| 782 | (setq reversible nil)) | ||
| 715 | (while (not (eobp)) | 783 | (while (not (eobp)) |
| 716 | (case (char-after) | 784 | (case (char-after) |
| 717 | (?\s (insert " ") (setq modif nil) (backward-char 1)) | 785 | (?\s (insert " ") (setq modif nil) (backward-char 1)) |
| @@ -730,7 +798,15 @@ else cover the whole bufer." | |||
| 730 | (forward-line 1) | 798 | (forward-line 1) |
| 731 | (when delete | 799 | (when delete |
| 732 | (delete-region last-pt (point)) | 800 | (delete-region last-pt (point)) |
| 733 | (setq delete nil))))))))))))))) | 801 | (setq delete nil))))))) |
| 802 | (unless (or (not reversible) (eq buffer-undo-list t)) | ||
| 803 | ;; Drop the many undo entries and replace them with | ||
| 804 | ;; a single entry that uses diff-context->unified to do | ||
| 805 | ;; the work. | ||
| 806 | (setq buffer-undo-list | ||
| 807 | (cons (list 'apply (- old-end end) start (point-max) | ||
| 808 | 'diff-context->unified start (point-max)) | ||
| 809 | old-undo))))))))))) | ||
| 734 | 810 | ||
| 735 | (defun diff-context->unified (start end &optional to-context) | 811 | (defun diff-context->unified (start end &optional to-context) |
| 736 | "Convert context diffs to unified diffs. | 812 | "Convert context diffs to unified diffs. |
| @@ -1289,7 +1365,8 @@ SRC and DST are the two variants of text as returned by `diff-hunk-text'. | |||
| 1289 | SWITCHED is non-nil if the patch is already applied." | 1365 | SWITCHED is non-nil if the patch is already applied." |
| 1290 | (save-excursion | 1366 | (save-excursion |
| 1291 | (let* ((other (diff-xor other-file diff-jump-to-old-file)) | 1367 | (let* ((other (diff-xor other-file diff-jump-to-old-file)) |
| 1292 | (char-offset (- (point) (progn (diff-beginning-of-hunk) (point)))) | 1368 | (char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder) |
| 1369 | (point)))) | ||
| 1293 | ;; Check that the hunk is well-formed. Otherwise diff-mode and | 1370 | ;; Check that the hunk is well-formed. Otherwise diff-mode and |
| 1294 | ;; the user may disagree on what constitutes the hunk | 1371 | ;; the user may disagree on what constitutes the hunk |
| 1295 | ;; (e.g. because an empty line truncates the hunk mid-course), | 1372 | ;; (e.g. because an empty line truncates the hunk mid-course), |
| @@ -1461,10 +1538,11 @@ For use in `add-log-current-defun-function'." | |||
| 1461 | (goto-char (+ (car pos) (cdr src))) | 1538 | (goto-char (+ (car pos) (cdr src))) |
| 1462 | (add-log-current-defun)))))) | 1539 | (add-log-current-defun)))))) |
| 1463 | 1540 | ||
| 1464 | (defun diff-refine-hunk () | 1541 | (defun diff-refine-ignore-spaces-hunk () |
| 1465 | "Refine the current hunk by ignoring space differences." | 1542 | "Refine the current hunk by ignoring space differences." |
| 1466 | (interactive) | 1543 | (interactive) |
| 1467 | (let* ((char-offset (- (point) (progn (diff-beginning-of-hunk) (point)))) | 1544 | (let* ((char-offset (- (point) (progn (diff-beginning-of-hunk 'try-harder) |
| 1545 | (point)))) | ||
| 1468 | (opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b"))) | 1546 | (opts (case (char-after) (?@ "-bu") (?* "-bc") (t "-b"))) |
| 1469 | (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") | 1547 | (line-nb (and (or (looking-at "[^0-9]+\\([0-9]+\\)") |
| 1470 | (error "Can't find line number")) | 1548 | (error "Can't find line number")) |