aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/ChangeLog12
-rw-r--r--lisp/smerge-mode.el92
2 files changed, 98 insertions, 6 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 586500e7b30..ce08638a6be 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,15 @@
12005-08-25 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * smerge-mode.el (smerge-remove-props): Make the args non-optional.
4 (smerge-keep-n): Remove props.
5 (smerge-keep-base, smerge-keep-other, smerge-keep-mine)
6 (smerge-keep-current, smerge-kill-current): Don't remove props anymore
7 now that it's done in smerge-keep-n.
8 (smerge-refined-change): New face.
9 (smerge-refine-chopup-region, smerge-refine-highlight-change)
10 (smerge-refine): New funs.
11 (smerge-basic-map): Bind smerge-refine.
12
12005-08-25 Juri Linkov <juri@jurta.org> 132005-08-25 Juri Linkov <juri@jurta.org>
2 14
3 * progmodes/grep.el (grep, grep-mode): Make buffer-local variables 15 * progmodes/grep.el (grep, grep-mode): Make buffer-local variables
diff --git a/lisp/smerge-mode.el b/lisp/smerge-mode.el
index 912f3289158..71fb650da7d 100644
--- a/lisp/smerge-mode.el
+++ b/lisp/smerge-mode.el
@@ -129,6 +129,10 @@ Used in `smerge-diff-base-mine' and related functions."
129(put 'smerge-markers-face 'face-alias 'smerge-markers) 129(put 'smerge-markers-face 'face-alias 'smerge-markers)
130(defvar smerge-markers-face 'smerge-markers) 130(defvar smerge-markers-face 'smerge-markers)
131 131
132(defface smerge-refined-change
133 '((t :background "yellow"))
134 "Face used for char-based changes shown by `smerge-refine'.")
135
132(easy-mmode-defmap smerge-basic-map 136(easy-mmode-defmap smerge-basic-map
133 `(("n" . smerge-next) 137 `(("n" . smerge-next)
134 ("p" . smerge-prev) 138 ("p" . smerge-prev)
@@ -139,6 +143,7 @@ Used in `smerge-diff-base-mine' and related functions."
139 ("m" . smerge-keep-mine) 143 ("m" . smerge-keep-mine)
140 ("E" . smerge-ediff) 144 ("E" . smerge-ediff)
141 ("C" . smerge-combine-with-next) 145 ("C" . smerge-combine-with-next)
146 ("R" . smerge-refine)
142 ("\C-m" . smerge-keep-current) 147 ("\C-m" . smerge-keep-current)
143 ("=" . ,(make-sparse-keymap "Diff")) 148 ("=" . ,(make-sparse-keymap "Diff"))
144 ("=<" "base-mine" . smerge-diff-base-mine) 149 ("=<" "base-mine" . smerge-diff-base-mine)
@@ -277,6 +282,7 @@ Can be nil if the style is undecided, or else:
277 (smerge-auto-leave))) 282 (smerge-auto-leave)))
278 283
279(defun smerge-keep-n (n) 284(defun smerge-keep-n (n)
285 (smerge-remove-props (match-beginning 0) (match-end 0))
280 ;; We used to use replace-match, but that did not preserve markers so well. 286 ;; We used to use replace-match, but that did not preserve markers so well.
281 (delete-region (match-end n) (match-end 0)) 287 (delete-region (match-end n) (match-end 0))
282 (delete-region (match-beginning 0) (match-beginning n))) 288 (delete-region (match-beginning 0) (match-beginning n)))
@@ -326,7 +332,8 @@ according to `smerge-match-conflict'.")
326 ;; mouse-face highlight 332 ;; mouse-face highlight
327 keymap (keymap (down-mouse-3 . smerge-popup-context-menu)))) 333 keymap (keymap (down-mouse-3 . smerge-popup-context-menu))))
328 334
329(defun smerge-remove-props (&optional beg end) 335(defun smerge-remove-props (beg end)
336 (remove-overlays beg end 'smerge 'refine)
330 (remove-overlays beg end 'smerge 'conflict)) 337 (remove-overlays beg end 'smerge 'conflict))
331 338
332(defun smerge-popup-context-menu (event) 339(defun smerge-popup-context-menu (event)
@@ -397,7 +404,6 @@ some major modes. Uses `smerge-resolve-function' to do the actual work."
397 (interactive) 404 (interactive)
398 (smerge-match-conflict) 405 (smerge-match-conflict)
399 (smerge-ensure-match 2) 406 (smerge-ensure-match 2)
400 (smerge-remove-props)
401 (smerge-keep-n 2) 407 (smerge-keep-n 2)
402 (smerge-auto-leave)) 408 (smerge-auto-leave))
403 409
@@ -406,7 +412,6 @@ some major modes. Uses `smerge-resolve-function' to do the actual work."
406 (interactive) 412 (interactive)
407 (smerge-match-conflict) 413 (smerge-match-conflict)
408 ;;(smerge-ensure-match 3) 414 ;;(smerge-ensure-match 3)
409 (smerge-remove-props)
410 (smerge-keep-n 3) 415 (smerge-keep-n 3)
411 (smerge-auto-leave)) 416 (smerge-auto-leave))
412 417
@@ -415,7 +420,6 @@ some major modes. Uses `smerge-resolve-function' to do the actual work."
415 (interactive) 420 (interactive)
416 (smerge-match-conflict) 421 (smerge-match-conflict)
417 ;;(smerge-ensure-match 1) 422 ;;(smerge-ensure-match 1)
418 (smerge-remove-props)
419 (smerge-keep-n 1) 423 (smerge-keep-n 1)
420 (smerge-auto-leave)) 424 (smerge-auto-leave))
421 425
@@ -433,7 +437,6 @@ some major modes. Uses `smerge-resolve-function' to do the actual work."
433 (smerge-match-conflict) 437 (smerge-match-conflict)
434 (let ((i (smerge-get-current))) 438 (let ((i (smerge-get-current)))
435 (if (<= i 0) (error "Not inside a version") 439 (if (<= i 0) (error "Not inside a version")
436 (smerge-remove-props)
437 (smerge-keep-n i) 440 (smerge-keep-n i)
438 (smerge-auto-leave)))) 441 (smerge-auto-leave))))
439 442
@@ -443,7 +446,6 @@ some major modes. Uses `smerge-resolve-function' to do the actual work."
443 (smerge-match-conflict) 446 (smerge-match-conflict)
444 (let ((i (smerge-get-current))) 447 (let ((i (smerge-get-current)))
445 (if (<= i 0) (error "Not inside a version") 448 (if (<= i 0) (error "Not inside a version")
446 (smerge-remove-props)
447 (let ((left nil)) 449 (let ((left nil))
448 (dolist (n '(3 2 1)) 450 (dolist (n '(3 2 1))
449 (if (and (match-end n) (/= (match-end n) (match-end i))) 451 (if (and (match-end n) (/= (match-end n) (match-end i)))
@@ -600,6 +602,84 @@ Point is moved to the end of the conflict."
600 (error nil))) 602 (error nil)))
601 found)) 603 found))
602 604
605(defun smerge-refine-chopup-region (beg end file)
606 "Chopup the region into small elements, one per line."
607 ;; ediff chops up into words, where the definition of a word is
608 ;; customizable. Instead we here keep only one char per line.
609 ;; The advantages are that there's nothing to configure, that we get very
610 ;; fine results, and that it's trivial to map the line numbers in the
611 ;; output of diff back into buffer positions. The disadvantage is that it
612 ;; can take more time to compute the diff and that the result is sometimes
613 ;; too fine. I'm not too concerned about the slowdown because conflicts
614 ;; are usually significantly smaller than the whole file. As for the
615 ;; problem of too-fine-refinement, I have found it to be unimportant
616 ;; especially when you consider the cases where the fine-grain is just
617 ;; what you want.
618 (let ((buf (current-buffer)))
619 (with-temp-buffer
620 (insert-buffer-substring buf beg end)
621 (goto-char (point-min))
622 (while (not (eobp))
623 (forward-char 1)
624 (unless (eq (char-before) ?\n) (insert ?\n)))
625 (let ((coding-system-for-write 'emacs-mule))
626 (write-region (point-min) (point-max) file nil 'nomessage)))))
627
628(defun smerge-refine-highlight-change (buf beg match-num1 match-num2)
629 (let* ((startline (string-to-number (match-string match-num1)))
630 (ol (make-overlay
631 (+ beg startline -1)
632 (+ beg (if (match-end match-num2)
633 (string-to-number (match-string match-num2))
634 startline))
635 buf
636 'front-advance nil)))
637 (overlay-put ol 'smerge 'refine)
638 (overlay-put ol 'evaporate t)
639 (overlay-put ol 'face 'smerge-refined-change)))
640
641
642(defun smerge-refine ()
643 "Highlight the parts of the conflict that are different."
644 (interactive)
645 ;; FIXME: make it work with 3-way conflicts.
646 (smerge-match-conflict)
647 (remove-overlays (match-beginning 0) (match-end 0) 'smerge 'refine)
648 (smerge-ensure-match 1)
649 (smerge-ensure-match 3)
650 (let ((buf (current-buffer))
651 ;; Read them before the match-data gets clobbered.
652 (beg1 (match-beginning 1)) (end1 (match-end 1))
653 (beg2 (match-beginning 3)) (end2 (match-end 3))
654 (file1 (make-temp-file "smerge1"))
655 (file2 (make-temp-file "smerge2")))
656
657 ;; Chop up regions into smaller elements and save into files.
658 (smerge-refine-chopup-region beg1 end1 file1)
659 (smerge-refine-chopup-region beg2 end2 file2)
660
661 ;; Call diff on those files.
662 (unwind-protect
663 (with-temp-buffer
664 (let ((coding-system-for-read 'emacs-mule))
665 (call-process diff-command nil t nil file1 file2))
666 ;; Process diff's output.
667 (goto-char (point-min))
668 (while (not (eobp))
669 (if (not (looking-at "\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?\\([acd]\\)\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?$"))
670 (error "Unexpected patch hunk header: %s"
671 (buffer-substring (point) (line-end-position)))
672 (let ((op (char-after (match-beginning 3))))
673 (when (memq op '(?d ?c))
674 (smerge-refine-highlight-change buf beg1 1 2))
675 (when (memq op '(?a ?c))
676 (smerge-refine-highlight-change buf beg2 4 5)))
677 (forward-line 1) ;Skip hunk header.
678 (and (re-search-forward "^[0-9]" nil 'move) ;Skip hunk body.
679 (goto-char (match-beginning 0))))))
680 (delete-file file1)
681 (delete-file file2))))
682
603(defun smerge-diff (n1 n2) 683(defun smerge-diff (n1 n2)
604 (smerge-match-conflict) 684 (smerge-match-conflict)
605 (smerge-ensure-match n1) 685 (smerge-ensure-match n1)