diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2005-08-22 14:38:51 +0000 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2005-08-22 14:38:51 +0000 |
commit | 48d59eda34ca5c4134ece124028a2d101ef97c8a (patch) | |
tree | 18b2656426614d45d4e9bca6d35b0210a6570615 /lisp/smerge-mode.el | |
parent | 18e1c39a823331377f538410041576140eec15ea (diff) | |
download | emacs-48d59eda34ca5c4134ece124028a2d101ef97c8a.tar.gz |
(smerge-basic-map): Bind smerge-combine-with-next.
(smerge-auto-leave): Make undo re-enable the mode.
(debug-ignored-errors): Add the user-error of impossible resolution.
(smerge-resolve): Move things around a bit, in preparation for later.
(smerge-diff): Don't fail if the buffer has no associated file.
(ediff-ancestor-buffer, ediff-quit-hook): Quieten byte-compiler.
(smerge-conflict-overlay): New function.
(smerge-match-conflict): Don't add text properties here.
(smerge-find-conflict): Instead, add an overlay here.
Also check for the case where we're inside a conflict already, so as to
obviate the need for font-lock-multiline, which is unbearably slow with
large conflicts and ciomplex font-lock patterns.
(smerge-remove-props): Remove overlay rather than text-properties.
(smerge-mode): Don't set font-lock-multiline.
Remove overlays when turned off.
Diffstat (limited to 'lisp/smerge-mode.el')
-rw-r--r-- | lisp/smerge-mode.el | 112 |
1 files changed, 84 insertions, 28 deletions
diff --git a/lisp/smerge-mode.el b/lisp/smerge-mode.el index 6ffbdc50cf5..912f3289158 100644 --- a/lisp/smerge-mode.el +++ b/lisp/smerge-mode.el @@ -53,7 +53,7 @@ (defvar smerge-mode) (defgroup smerge () - "Minor mode to resolve diff3 conflicts." + "Minor mode to highlight and resolve diff3 conflicts." :group 'tools :prefix "smerge-") @@ -69,13 +69,13 @@ (defcustom smerge-diff-switches (append '("-d" "-b") (if (listp diff-switches) diff-switches (list diff-switches))) - "*A list of strings specifying switches to be passed to diff. + "A list of strings specifying switches to be passed to diff. Used in `smerge-diff-base-mine' and related functions." :group 'smerge :type '(repeat string)) (defcustom smerge-auto-leave t - "*Non-nil means to leave `smerge-mode' when the last conflict is resolved." + "Non-nil means to leave `smerge-mode' when the last conflict is resolved." :group 'smerge :type 'boolean) @@ -138,6 +138,7 @@ Used in `smerge-diff-base-mine' and related functions." ("o" . smerge-keep-other) ("m" . smerge-keep-mine) ("E" . smerge-ediff) + ("C" . smerge-combine-with-next) ("\C-m" . smerge-keep-current) ("=" . ,(make-sparse-keymap "Diff")) ("=<" "base-mine" . smerge-diff-base-mine) @@ -257,6 +258,8 @@ Can be nil if the style is undecided, or else: (when (and smerge-auto-leave (save-excursion (goto-char (point-min)) (not (re-search-forward smerge-begin-re nil t)))) + (when (and (listp buffer-undo-list) smerge-mode) + (push (list 'apply 'smerge-mode 1) buffer-undo-list)) (smerge-mode -1))) @@ -316,6 +319,7 @@ Can be nil if the style is undecided, or else: "Mode-specific merge function. The function is called with no argument and with the match data set according to `smerge-match-conflict'.") +(add-to-list 'debug-ignored-errors "Don't know how to resolve") (defvar smerge-text-properties `(help-echo "merge conflict: mouse-3 shows a menu" @@ -323,10 +327,7 @@ according to `smerge-match-conflict'.") keymap (keymap (down-mouse-3 . smerge-popup-context-menu)))) (defun smerge-remove-props (&optional beg end) - (remove-text-properties - (or beg (match-beginning 0)) - (or end (match-end 0)) - smerge-text-properties)) + (remove-overlays beg end 'smerge 'conflict)) (defun smerge-popup-context-menu (event) "Pop up the Smerge mode context menu under mouse." @@ -368,8 +369,16 @@ some major modes. Uses `smerge-resolve-function' to do the actual work." ;; Trivial diff3 -A non-conflicts. ((and (eq (match-end 1) (match-end 3)) (eq (match-beginning 1) (match-beginning 3))) - ;; FIXME: Add "if [ diff -b MINE OTHER ]; then select OTHER; fi" (smerge-keep-n 3)) + ;; Mode-specific conflict resolution. + ((condition-case nil + (atomic-change-group + (funcall smerge-resolve-function) + t) + (error nil)) + ;; Nothing to do: the resolution function has done it already. + nil) + ;; FIXME: Add "if [ diff -b MINE OTHER ]; then select OTHER; fi" ((and (match-end 2) ;; FIXME: Add "diff -b BASE MINE | patch OTHER". ;; FIXME: Add "diff -b BASE OTHER | patch MINE". @@ -380,8 +389,7 @@ some major modes. Uses `smerge-resolve-function' to do the actual work." nil) ) (t - ;; Mode-specific conflict resolution. - (funcall smerge-resolve-function))) + (error "Don't know how to resolve"))) (smerge-auto-leave)) (defun smerge-keep-base () @@ -500,6 +508,10 @@ An error is raised if not inside a conflict." (re-search-forward smerge-begin-re end t)) ;; There's a nested conflict and we're after the the beginning ;; of the outer one but before the beginning of the inner one. + ;; Of course, maybe this is not a nested conflict but in that + ;; case it can only be something nastier that we don't know how + ;; to handle, so may as well arbitrarily decide to treat it as + ;; a nested conflict. --Stef (error "There is a nested conflict")) ((re-search-backward smerge-base-re start t) @@ -524,13 +536,6 @@ An error is raised if not inside a conflict." (setq mine-start other-start) (setq mine-end other-end))) - (let ((inhibit-read-only t) - (inhibit-modification-hooks t) - (m (buffer-modified-p))) - (unwind-protect - (add-text-properties start end smerge-text-properties) - (restore-buffer-modified-p m))) - (store-match-data (list start end mine-start mine-end base-start base-end @@ -540,17 +545,60 @@ An error is raised if not inside a conflict." t) (search-failed (error "Point not in conflict region"))))) +(defun smerge-conflict-overlay (pos) + "Return the conflict overlay at POS if any." + (let ((ols (overlays-at pos)) + conflict) + (dolist (ol ols) + (if (and (eq (overlay-get ol 'smerge) 'conflict) + (> (overlay-end ol) pos)) + (setq conflict ol))) + conflict)) + (defun smerge-find-conflict (&optional limit) "Find and match a conflict region. Intended as a font-lock MATCHER. The submatches are the same as in `smerge-match-conflict'. -Returns non-nil if a match is found between the point and LIMIT. -The point is moved to the end of the conflict." - (when (re-search-forward smerge-begin-re limit t) - (condition-case err - (progn - (smerge-match-conflict) - (goto-char (match-end 0))) - (error (smerge-find-conflict limit))))) +Returns non-nil if a match is found between point and LIMIT. +Point is moved to the end of the conflict." + (let ((found nil) + (pos (point)) + conflict) + ;; First check to see if point is already inside a conflict, using + ;; the conflict overlays. + (while (and (not found) (setq conflict (smerge-conflict-overlay pos))) + ;; Check the overlay's validity and kill it if it's out of date. + (condition-case nil + (progn + (goto-char (overlay-start conflict)) + (smerge-match-conflict) + (goto-char (match-end 0)) + (if (<= (point) pos) + (error "Matching backward!") + (setq found t))) + (error (smerge-remove-props + (overlay-start conflict) (overlay-end conflict)) + (goto-char pos)))) + ;; If we're not already inside a conflict, look for the next conflict + ;; and add/update its overlay. + (while (and (not found) (re-search-forward smerge-begin-re limit t)) + (condition-case nil + (progn + (smerge-match-conflict) + (goto-char (match-end 0)) + (let ((conflict (smerge-conflict-overlay (1- (point))))) + (if conflict + ;; Update its location, just in case it got messed up. + (move-overlay conflict (match-beginning 0) (match-end 0)) + (setq conflict (make-overlay (match-beginning 0) (match-end 0) + nil 'front-advance nil)) + (overlay-put conflict 'evaporate t) + (overlay-put conflict 'smerge 'conflict) + (let ((props smerge-text-properties)) + (while props + (overlay-put conflict (pop props) (pop props)))))) + (setq found t)) + (error nil))) + found)) (defun smerge-diff (n1 n2) (smerge-match-conflict) @@ -566,7 +614,12 @@ The point is moved to the end of the conflict." (file1 (make-temp-file "smerge1")) (file2 (make-temp-file "smerge2")) (dir default-directory) - (file (file-relative-name buffer-file-name)) + (file (if buffer-file-name (file-relative-name buffer-file-name))) + ;; We would want to use `emacs-mule-unix' for read&write, but we + ;; bump into problems with the coding-system used by diff to write + ;; the file names and the time stamps in the header. + ;; `buffer-file-coding-system' is not always correct either, but if + ;; the OS/user uses only one coding-system, then it works. (coding-system-for-read buffer-file-coding-system)) (write-region beg1 end1 file1 nil 'nomessage) (write-region beg2 end2 file2 nil 'nomessage) @@ -594,6 +647,8 @@ The point is moved to the end of the conflict." (defvar ediff-buffer-A) (defvar ediff-buffer-B) (defvar ediff-buffer-C) +(defvar ediff-ancestor-buffer) +(defvar ediff-quit-hook) ;;;###autoload (defun smerge-ediff (&optional name-mine name-other name-base) @@ -687,7 +742,6 @@ buffer names." \\{smerge-mode-map}" :group 'smerge :lighter " SMerge" (when (and (boundp 'font-lock-mode) font-lock-mode) - (set (make-local-variable 'font-lock-multiline) t) (save-excursion (if smerge-mode (font-lock-add-keywords nil smerge-font-lock-keywords 'append) @@ -695,7 +749,9 @@ buffer names." (goto-char (point-min)) (while (smerge-find-conflict) (save-excursion - (font-lock-fontify-region (match-beginning 0) (match-end 0) nil)))))) + (font-lock-fontify-region (match-beginning 0) (match-end 0) nil))))) + (unless smerge-mode + (smerge-remove-props (point-min) (point-max)))) (provide 'smerge-mode) |