Mercurial > emacs
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)) |