aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/diff-mode.el
diff options
context:
space:
mode:
authorStefan Monnier2007-10-09 04:12:24 +0000
committerStefan Monnier2007-10-09 04:12:24 +0000
commitbe36f934da2f42f5fb57cd1a3202a4d402e3e107 (patch)
treebb9a0fa3b3972f7b862dba395fc4a5441d14bbfd /lisp/diff-mode.el
parent9f2e22a06dfa082f6519ff3c5b1403d66e848a8f (diff)
downloademacs-be36f934da2f42f5fb57cd1a3202a4d402e3e107.tar.gz
emacs-be36f934da2f42f5fb57cd1a3202a4d402e3e107.zip
(diff-hunk-style): New fun.
(diff-end-of-hunk): Use it. (diff-context->unified): Use the new `apply' undo element, if applicable, so as to save undo-log space. (diff-fine-change): New face. (diff-fine-highlight-preproc): New function. (diff-fine-highlight): New command.
Diffstat (limited to 'lisp/diff-mode.el')
-rw-r--r--lisp/diff-mode.el211
1 files changed, 146 insertions, 65 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el
index d4244126f23..706a532938d 100644
--- a/lisp/diff-mode.el
+++ b/lisp/diff-mode.el
@@ -386,12 +386,15 @@ when editing big diffs)."
386(defconst diff-file-header-re (concat "^\\(--- .+\n\\+\\+\\+ \\|\\*\\*\\* .+\n--- \\|[^-+!<>0-9@* ]\\).+\n" (substring diff-hunk-header-re 1))) 386(defconst diff-file-header-re (concat "^\\(--- .+\n\\+\\+\\+ \\|\\*\\*\\* .+\n--- \\|[^-+!<>0-9@* ]\\).+\n" (substring diff-hunk-header-re 1)))
387(defvar diff-narrowed-to nil) 387(defvar diff-narrowed-to nil)
388 388
389(defun diff-end-of-hunk (&optional style) 389(defun diff-hunk-style (&optional style)
390 (when (looking-at diff-hunk-header-re) 390 (when (looking-at diff-hunk-header-re)
391 (unless style 391 (setq style (cdr (assq (char-after) '((?@ . unified) (?* . context)))))
392 ;; Especially important for unified (because headers are ambiguous).
393 (setq style (cdr (assq (char-after) '((?@ . unified) (?* . context))))))
394 (goto-char (match-end 0))) 392 (goto-char (match-end 0)))
393 style)
394
395(defun diff-end-of-hunk (&optional style)
396 ;; Especially important for unified (because headers are ambiguous).
397 (setq style (diff-hunk-style style))
395 (let ((end (and (re-search-forward (case style 398 (let ((end (and (re-search-forward (case style
396 ;; A `unified' header is ambiguous. 399 ;; A `unified' header is ambiguous.
397 (unified (concat "^[^-+# \\]\\|" 400 (unified (concat "^[^-+# \\]\\|"
@@ -843,68 +846,89 @@ With a prefix argument, convert unified format to context format."
843 (diff-unified->context start end) 846 (diff-unified->context start end)
844 (unless (markerp end) (setq end (copy-marker end t))) 847 (unless (markerp end) (setq end (copy-marker end t)))
845 (let ( ;;(diff-inhibit-after-change t) 848 (let ( ;;(diff-inhibit-after-change t)
846 (inhibit-read-only t)) 849 (inhibit-read-only t))
847 (save-excursion 850 (save-excursion
848 (goto-char start) 851 (goto-char start)
849 (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)$" nil t) 852 (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)$" nil t)
850 (< (point) end)) 853 (< (point) end))
851 (combine-after-change-calls 854 (combine-after-change-calls
852 (if (match-beginning 2) 855 (if (match-beginning 2)
853 ;; we matched a file header 856 ;; we matched a file header
854 (progn 857 (progn
855 ;; use reverse order to make sure the indices are kept valid 858 ;; use reverse order to make sure the indices are kept valid
856 (replace-match "+++" t t nil 3) 859 (replace-match "+++" t t nil 3)
857 (replace-match "---" t t nil 2)) 860 (replace-match "---" t t nil 2))
858 ;; we matched a hunk header 861 ;; we matched a hunk header
859 (let ((line1s (match-string 4)) 862 (let ((line1s (match-string 4))
860 (line1e (match-string 5)) 863 (line1e (match-string 5))
861 (pt1 (match-beginning 0))) 864 (pt1 (match-beginning 0))
862 (replace-match "") 865 ;; Variables to use the special undo function.
863 (unless (re-search-forward 866 (old-undo buffer-undo-list)
864 "^--- \\([0-9]+\\),\\(-?[0-9]+\\) ----$" nil t) 867 (old-end (marker-position end))
865 (error "Can't find matching `--- n1,n2 ----' line")) 868 (reversible t))
866 (let ((line2s (match-string 1)) 869 (replace-match "")
867 (line2e (match-string 2)) 870 (unless (re-search-forward
868 (pt2 (progn 871 "^--- \\([0-9]+\\),\\(-?[0-9]+\\) ----$" nil t)
869 (delete-region (progn (beginning-of-line) (point)) 872 (error "Can't find matching `--- n1,n2 ----' line"))
870 (progn (forward-line 1) (point))) 873 (let ((line2s (match-string 1))
871 (point-marker)))) 874 (line2e (match-string 2))
872 (goto-char pt1) 875 (pt2 (progn
873 (forward-line 1) 876 (delete-region (progn (beginning-of-line) (point))
874 (while (< (point) pt2) 877 (progn (forward-line 1) (point)))
875 (case (char-after) 878 (point-marker))))
876 ((?! ?-) (delete-char 2) (insert "-") (forward-line 1)) 879 (goto-char pt1)
877 (?\s ;merge with the other half of the chunk 880 (forward-line 1)
878 (let* ((endline2 881 (while (< (point) pt2)
879 (save-excursion 882 (case (char-after)
880 (goto-char pt2) (forward-line 1) (point))) 883 (?! (delete-char 2) (insert "-") (forward-line 1))
881 (c (char-after pt2))) 884 (?- (forward-char 1) (delete-char 1) (forward-line 1))
882 (case c 885 (?\s ;merge with the other half of the chunk
883 ((?! ?+) 886 (let* ((endline2
884 (insert "+" 887 (save-excursion
885 (prog1 (buffer-substring (+ pt2 2) endline2) 888 (goto-char pt2) (forward-line 1) (point))))
886 (delete-region pt2 endline2)))) 889 (case (char-after pt2)
887 (?\s ;FIXME: check consistency 890 ((?! ?+)
888 (delete-region pt2 endline2) 891 (insert "+"
889 (delete-char 1) 892 (prog1 (buffer-substring (+ pt2 2) endline2)
890 (forward-line 1)) 893 (delete-region pt2 endline2))))
891 (?\\ (forward-line 1)) 894 (?\s
892 (t (delete-char 1) (forward-line 1))))) 895 (unless (= (- endline2 pt2)
893 (t (forward-line 1)))) 896 (- (line-beginning-position 2) (point)))
894 (while (looking-at "[+! ] ") 897 ;; If the two lines we're merging don't have the
895 (if (/= (char-after) ?!) (forward-char 1) 898 ;; same length (can happen with "diff -b"), then
896 (delete-char 1) (insert "+")) 899 ;; diff-unified->context will not properly undo
897 (delete-char 1) (forward-line 1)) 900 ;; this operation.
898 (save-excursion 901 (setq reversible nil))
899 (goto-char pt1) 902 (delete-region pt2 endline2)
900 (insert "@@ -" line1s "," 903 (delete-char 1)
901 (number-to-string (- (string-to-number line1e) 904 (forward-line 1))
902 (string-to-number line1s) 905 (?\\ (forward-line 1))
903 -1)) 906 (t (setq reversible nil)
904 " +" line2s "," 907 (delete-char 1) (forward-line 1)))))
905 (number-to-string (- (string-to-number line2e) 908 (t (setq reversible nil) (forward-line 1))))
906 (string-to-number line2s) 909 (while (looking-at "[+! ] ")
907 -1)) " @@"))))))))))) 910 (if (/= (char-after) ?!) (forward-char 1)
911 (delete-char 1) (insert "+"))
912 (delete-char 1) (forward-line 1))
913 (save-excursion
914 (goto-char pt1)
915 (insert "@@ -" line1s ","
916 (number-to-string (- (string-to-number line1e)
917 (string-to-number line1s)
918 -1))
919 " +" line2s ","
920 (number-to-string (- (string-to-number line2e)
921 (string-to-number line2s)
922 -1)) " @@"))
923 (set-marker pt2 nil)
924 ;; The whole procedure succeeded, let's replace the myriad
925 ;; of undo elements with just a single special one.
926 (unless (or (not reversible) (eq buffer-undo-list t))
927 (setq buffer-undo-list
928 (cons (list 'apply (- old-end end) pt1 (point)
929 'diff-unified->context pt1 (point))
930 old-undo)))
931 )))))))))
908 932
909(defun diff-reverse-direction (start end) 933(defun diff-reverse-direction (start end)
910 "Reverse the direction of the diffs. 934 "Reverse the direction of the diffs.
@@ -1610,6 +1634,63 @@ For use in `add-log-current-defun-function'."
1610 (delete-file file1) 1634 (delete-file file1)
1611 (delete-file file2)))) 1635 (delete-file file2))))
1612 1636
1637;;; Fine change highlighting.
1638
1639(defface diff-fine-change
1640 '((t :background "yellow"))
1641 "Face used for char-based changes shown by `diff-fine-highlight'.")
1642
1643(defun diff-fine-highlight-preproc ()
1644 (while (re-search-forward "^." nil t)
1645 ;; Replace the hunk's leading prefix (+, -, !, <, or >) on each line
1646 ;; with something constant, otherwise it'll be flagged as changes
1647 ;; (since it's typically "-" on one side and "+" on the other).
1648 ;; Note that we keep the same number of chars: we treat the prefix
1649 ;; as part of the texts-to-diff, so that finding the right char
1650 ;; afterwards will be easier. This only makes sense because we make
1651 ;; diffs at char-granularity.
1652 (replace-match " ")))
1653
1654(defun diff-fine-highlight ()
1655 "Highlight changes of hunk at point at a finer granularity."
1656 (interactive)
1657 (require 'smerge-mode)
1658 (diff-beginning-of-hunk 'try-harder)
1659 (let* ((style (diff-hunk-style)) ;Skips the hunk header as well.
1660 (beg (point))
1661 (props '((diff-mode . fine) (face diff-fine-change)))
1662 (end (progn (diff-end-of-hunk) (point))))
1663
1664 (remove-overlays beg end 'diff-mode 'fine)
1665
1666 (goto-char beg)
1667 (case style
1668 (unified
1669 (while (re-search-forward "^\\(?:-.*\n\\)+\\(\\)\\(?:\\+.*\n\\)+" end t)
1670 (smerge-refine-subst (match-beginning 0) (match-end 1)
1671 (match-end 1) (match-end 0)
1672 props 'diff-fine-highlight-preproc)))
1673 (context
1674 (let* ((middle (save-excursion (re-search-forward "^---")))
1675 (other middle))
1676 (while (re-search-forward "^\\(?:!.*\n\\)+" middle t)
1677 (smerge-refine-subst (match-beginning 0) (match-end 0)
1678 (save-excursion
1679 (goto-char other)
1680 (re-search-forward "^\\(?:!.*\n\\)+" end)
1681 (setq other (match-end 0))
1682 (match-beginning 0))
1683 other
1684 props 'diff-fine-highlight-preproc))))
1685 (t ;; Normal diffs.
1686 (let ((beg1 (1+ (point))))
1687 (when (re-search-forward "^---.*\n" end t)
1688 ;; It's a combined add&remove, so there's something to do.
1689 (smerge-refine-subst beg1 (match-beginning 0)
1690 (match-end 0) end
1691 props 'diff-fine-highlight-preproc)))))))
1692
1693
1613;; provide the package 1694;; provide the package
1614(provide 'diff-mode) 1695(provide 'diff-mode)
1615 1696