comparison lisp/smerge-mode.el @ 54402:8bf3846fc7dd

2004-03-15 Masatake YAMATO <jet@gyve.org> Added context menu support in smerge mode. Most of the part is written by Stefan Monnier. * smerge-mode.el (smerge-context-menu-map, smerge-context-menu): New keyman and menu. (smerge-text-properties): New function. (smerge-remove-props): New function. (smerge-popup-context-menu): New function. (smerge-resolve): Call `smerge-remove-props'. (smerge-keep-base, smerge-keep-other, smerge-keep-mine): Ditto. (smerge-keep-current): Ditto. (smerge-kill-current): New function. (smerge-match-conflict): Detect the file as `a same-diff conflict' if the filename is "ANCESTOR". Put text properties.
author Masatake YAMATO <jet@gyve.org>
date Mon, 15 Mar 2004 11:27:47 +0000
parents 118715eba3b3
children 85cd76b8b78c fac24544c283
comparison
equal deleted inserted replaced
54401:7f6dab15e141 54402:8bf3846fc7dd
1 ;;; smerge-mode.el --- Minor mode to resolve diff3 conflicts 1 ;;; smerge-mode.el --- Minor mode to resolve diff3 conflicts
2 2
3 ;; Copyright (C) 1999, 2000, 01, 03, 2004 Free Software Foundation, Inc. 3 ;; Copyright (C) 1999, 2000, 01, 03, 2004 Free Software Foundation, Inc.
4 4
5 ;; Author: Stefan Monnier <monnier@cs.yale.edu> 5 ;; Author: Stefan Monnier <monnier@cs.yale.edu>
6 ;; Keywords: merge diff3 cvs conflict 6 ;; Keywords: revision-control merge diff3 cvs conflict
7 ;; Revision: $Id: smerge-mode.el,v 1.24 2003/10/06 16:34:59 fx Exp $
8 7
9 ;; This file is part of GNU Emacs. 8 ;; This file is part of GNU Emacs.
10 9
11 ;; GNU Emacs is free software; you can redistribute it and/or modify 10 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by 11 ;; it under the terms of the GNU General Public License as published by
185 ["Combine" smerge-combine-with-next 184 ["Combine" smerge-combine-with-next
186 :help "Combine current conflict with next" 185 :help "Combine current conflict with next"
187 :active (smerge-check 1)] 186 :active (smerge-check 1)]
188 )) 187 ))
189 188
189 (easy-mmode-defmap smerge-context-menu-map
190 `(([down-mouse-3] . smerge-activate-context-menu))
191 "Keymap for context menu appeared on conflicts area.")
192 (easy-menu-define smerge-context-menu nil
193 "Context menu for mine area in `smerge-mode'."
194 '(nil
195 ["Keep Current" smerge-keep-current :help "Use current (at point) version"]
196 ["Kill Current" smerge-kill-current :help "Remove current (at point) version"]
197 ["Keep All" smerge-keep-all :help "Keep all three versions"]
198 "---"
199 ["More..." (popup-menu smerge-mode-menu) :help "Show full SMerge mode menu"]
200 ))
201
190 (defconst smerge-font-lock-keywords 202 (defconst smerge-font-lock-keywords
191 '((smerge-find-conflict 203 '((smerge-find-conflict
192 (1 smerge-mine-face prepend t) 204 (1 smerge-mine-face prepend t)
193 (2 smerge-base-face prepend t) 205 (2 smerge-base-face prepend t)
194 (3 smerge-other-face prepend t) 206 (3 smerge-other-face prepend t)
281 (lambda () (error "Don't know how to resolve")) 293 (lambda () (error "Don't know how to resolve"))
282 "Mode-specific merge function. 294 "Mode-specific merge function.
283 The function is called with no argument and with the match data set 295 The function is called with no argument and with the match data set
284 according to `smerge-match-conflict'.") 296 according to `smerge-match-conflict'.")
285 297
298 (defvar smerge-text-properties
299 `(help-echo "merge conflict: mouse-3 shows a menu"
300 ;; mouse-face highlight
301 keymap (keymap (down-mouse-3 . smerge-popup-context-menu))))
302
303 (defun smerge-remove-props (&optional beg end)
304 (remove-text-properties
305 (or beg (match-beginning 0))
306 (or end (match-end 0))
307 smerge-text-properties))
308
309 (defun smerge-popup-context-menu (event)
310 "Pop up the Smerge mode context menu under mouse."
311 (interactive "e")
312 (if (and smerge-mode
313 (save-excursion (mouse-set-point event) (smerge-check 1)))
314 (progn
315 (mouse-set-point event)
316 (smerge-match-conflict)
317 (let ((i (smerge-get-current))
318 o)
319 (if (<= i 0)
320 ;; Out of range
321 (popup-menu smerge-mode-menu)
322 ;; Install overlay.
323 (setq o (make-overlay (match-beginning i) (match-end i)))
324 (overlay-put o 'face 'highlight)
325 (sit-for 0)
326 (popup-menu (if (smerge-check 2)
327 smerge-mode-menu
328 smerge-context-menu))
329 ;; Delete overlay.
330 (delete-overlay o))))
331 ;; There's no conflict at point, the text-props are just obsolete.
332 (save-excursion
333 (let ((beg (re-search-backward smerge-end-re nil t))
334 (end (re-search-forward smerge-begin-re nil t)))
335 (smerge-remove-props (or beg (point-min)) (or end (point-max)))
336 (push event unread-command-events)))))
337
286 (defun smerge-resolve () 338 (defun smerge-resolve ()
287 "Resolve the conflict at point intelligently. 339 "Resolve the conflict at point intelligently.
288 This relies on mode-specific knowledge and thus only works in 340 This relies on mode-specific knowledge and thus only works in
289 some major modes. Uses `smerge-resolve-function' to do the actual work." 341 some major modes. Uses `smerge-resolve-function' to do the actual work."
290 (interactive) 342 (interactive)
291 (smerge-match-conflict) 343 (smerge-match-conflict)
344 (smerge-remove-props)
292 (funcall smerge-resolve-function) 345 (funcall smerge-resolve-function)
293 (smerge-auto-leave)) 346 (smerge-auto-leave))
294 347
295 (defun smerge-keep-base () 348 (defun smerge-keep-base ()
296 "Revert to the base version." 349 "Revert to the base version."
297 (interactive) 350 (interactive)
298 (smerge-match-conflict) 351 (smerge-match-conflict)
299 (smerge-ensure-match 2) 352 (smerge-ensure-match 2)
353 (smerge-remove-props)
300 (replace-match (match-string 2) t t) 354 (replace-match (match-string 2) t t)
301 (smerge-auto-leave)) 355 (smerge-auto-leave))
302 356
303 (defun smerge-keep-other () 357 (defun smerge-keep-other ()
304 "Use \"other\" version." 358 "Use \"other\" version."
305 (interactive) 359 (interactive)
306 (smerge-match-conflict) 360 (smerge-match-conflict)
307 ;;(smerge-ensure-match 3) 361 ;;(smerge-ensure-match 3)
362 (smerge-remove-props)
308 (replace-match (match-string 3) t t) 363 (replace-match (match-string 3) t t)
309 (smerge-auto-leave)) 364 (smerge-auto-leave))
310 365
311 (defun smerge-keep-mine () 366 (defun smerge-keep-mine ()
312 "Keep your version." 367 "Keep your version."
313 (interactive) 368 (interactive)
314 (smerge-match-conflict) 369 (smerge-match-conflict)
315 ;;(smerge-ensure-match 1) 370 ;;(smerge-ensure-match 1)
371 (smerge-remove-props)
316 (replace-match (match-string 1) t t) 372 (replace-match (match-string 1) t t)
317 (smerge-auto-leave)) 373 (smerge-auto-leave))
318 374
319 (defun smerge-get-current () 375 (defun smerge-get-current ()
320 (let ((i 3)) 376 (let ((i 3))
328 "Use the current (under the cursor) version." 384 "Use the current (under the cursor) version."
329 (interactive) 385 (interactive)
330 (smerge-match-conflict) 386 (smerge-match-conflict)
331 (let ((i (smerge-get-current))) 387 (let ((i (smerge-get-current)))
332 (if (<= i 0) (error "Not inside a version") 388 (if (<= i 0) (error "Not inside a version")
389 (smerge-remove-props)
333 (replace-match (match-string i) t t) 390 (replace-match (match-string i) t t)
391 (smerge-auto-leave))))
392
393 (defun smerge-kill-current ()
394 "Remove the current (under the cursor) version."
395 (interactive)
396 (smerge-match-conflict)
397 (let ((i (smerge-get-current)))
398 (if (<= i 0) (error "Not inside a version")
399 (smerge-remove-props)
400 (replace-match (mapconcat
401 (lambda (j)
402 (match-string j))
403 (remove i '(1 2 3)) "") t t)
334 (smerge-auto-leave)))) 404 (smerge-auto-leave))))
335 405
336 (defun smerge-diff-base-mine () 406 (defun smerge-diff-base-mine ()
337 "Diff 'base' and 'mine' version in current conflict region." 407 "Diff 'base' and 'mine' version in current conflict region."
338 (interactive) 408 (interactive)
387 (set (make-local-variable 'smerge-conflict-style) 'diff3-A) 457 (set (make-local-variable 'smerge-conflict-style) 'diff3-A)
388 (setq base-end mine-end) 458 (setq base-end mine-end)
389 (setq mine-end (match-beginning 0)) 459 (setq mine-end (match-beginning 0))
390 (setq base-start (match-end 0))) 460 (setq base-start (match-end 0)))
391 461
392 ((string= filename (file-name-nondirectory 462 ((string= filename (file-name-nondirectory
393 (or buffer-file-name ""))) 463 (or buffer-file-name "")))
394 ;; a 2-parts conflict 464 ;; a 2-parts conflict
395 (set (make-local-variable 'smerge-conflict-style) 'diff3-E)) 465 (set (make-local-variable 'smerge-conflict-style) 'diff3-E))
396 466
397 ((and (not base-start) 467 ((and (not base-start)
398 (or (eq smerge-conflict-style 'diff3-A) 468 (or (eq smerge-conflict-style 'diff3-A)
399 (string-match "^[.0-9]+\\'" filename))) 469 (equal filename "ANCESTOR")
400 ;; a same-diff conflict 470 (string-match "\\`[.0-9]+\\'" filename)))
401 (setq base-start mine-start) 471 ;; a same-diff conflict
402 (setq base-end mine-end) 472 (setq base-start mine-start)
403 (setq mine-start other-start) 473 (setq base-end mine-end)
404 (setq mine-end other-end))) 474 (setq mine-start other-start)
405 475 (setq mine-end other-end)))
476
477 (let ((inhibit-read-only t)
478 (inhibit-modification-hooks t)
479 (m (buffer-modified-p)))
480 (unwind-protect
481 (add-text-properties start end smerge-text-properties)
482 (restore-buffer-modified-p m)))
483
406 (store-match-data (list start end 484 (store-match-data (list start end
407 mine-start mine-end 485 mine-start mine-end
408 base-start base-end 486 base-start base-end
409 other-start other-end 487 other-start other-end
410 (when base-start (1- base-start)) base-start 488 (when base-start (1- base-start)) base-start