comparison lisp/smerge-mode.el @ 65129:8303172e4c68

(smerge-remove-props): Make the args non-optional. (smerge-keep-n): Remove props. (smerge-keep-base, smerge-keep-other, smerge-keep-mine) (smerge-keep-current, smerge-kill-current): Don't remove props anymore now that it's done in smerge-keep-n. (smerge-refined-change): New face. (smerge-refine-chopup-region, smerge-refine-highlight-change) (smerge-refine): New funs. (smerge-basic-map): Bind smerge-refine.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Thu, 25 Aug 2005 20:13:38 +0000
parents 52de8046c483
children ebbbce58e84c 2d92f5c9d6ae
comparison
equal deleted inserted replaced
65128:62d66d39f609 65129:8303172e4c68
127 :group 'smerge) 127 :group 'smerge)
128 ;; backward-compatibility alias 128 ;; backward-compatibility alias
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)
135 ("r" . smerge-resolve) 139 ("r" . smerge-resolve)
136 ("a" . smerge-keep-all) 140 ("a" . smerge-keep-all)
137 ("b" . smerge-keep-base) 141 ("b" . smerge-keep-base)
138 ("o" . smerge-keep-other) 142 ("o" . smerge-keep-other)
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)
145 ("=>" "base-other" . smerge-diff-base-other) 150 ("=>" "base-other" . smerge-diff-base-other)
146 ("==" "mine-other" . smerge-diff-mine-other)) 151 ("==" "mine-other" . smerge-diff-mine-other))
275 (delete-region (match-end 1) (match-beginning 2))) 280 (delete-region (match-end 1) (match-beginning 2)))
276 (delete-region (match-beginning 0) (min (match-beginning 1) mb2)) 281 (delete-region (match-beginning 0) (min (match-beginning 1) mb2))
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)))
283 289
284 (defun smerge-combine-with-next () 290 (defun smerge-combine-with-next ()
324 (defvar smerge-text-properties 330 (defvar smerge-text-properties
325 `(help-echo "merge conflict: mouse-3 shows a menu" 331 `(help-echo "merge conflict: mouse-3 shows a menu"
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)
333 "Pop up the Smerge mode context menu under mouse." 340 "Pop up the Smerge mode context menu under mouse."
334 (interactive "e") 341 (interactive "e")
395 (defun smerge-keep-base () 402 (defun smerge-keep-base ()
396 "Revert to the base version." 403 "Revert to the base version."
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
404 (defun smerge-keep-other () 410 (defun smerge-keep-other ()
405 "Use \"other\" version." 411 "Use \"other\" version."
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
413 (defun smerge-keep-mine () 418 (defun smerge-keep-mine ()
414 "Keep your version." 419 "Keep your version."
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
422 (defun smerge-get-current () 426 (defun smerge-get-current ()
423 (let ((i 3)) 427 (let ((i 3))
431 "Use the current (under the cursor) version." 435 "Use the current (under the cursor) version."
432 (interactive) 436 (interactive)
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
440 (defun smerge-kill-current () 443 (defun smerge-kill-current ()
441 "Remove the current (under the cursor) version." 444 "Remove the current (under the cursor) version."
442 (interactive) 445 (interactive)
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)))
450 (push n left))) 452 (push n left)))
451 (if (and (cdr left) 453 (if (and (cdr left)
598 (overlay-put conflict (pop props) (pop props)))))) 600 (overlay-put conflict (pop props) (pop props))))))
599 (setq found t)) 601 (setq found t))
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)
606 (smerge-ensure-match n2) 686 (smerge-ensure-match n2)
607 (let ((name1 (aref smerge-match-names n1)) 687 (let ((name1 (aref smerge-match-names n1))