Faster mercurial patch queue merging with emacs

As a follow-up to my previous post about merging mq reject in emacs, I thought I’d share some improvements to the process that I’ve made since then.

(defun switch-hg-reject ()
  (interactive)
  (let ((other-file
	 (if (string= (substring (buffer-file-name) -4 nil) ".rej")
	     (substring (buffer-file-name) 0 -4)
	   (concat (buffer-file-name) ".rej"))))
    (if (file-exists-p other-file)
	(save-selected-window
	  (switch-to-buffer-other-window (find-file-noselect other-file)))
      (message "No alternate reject file found"))))

(defun kill-hg-reject ()
  (interactive)
  (let ((reject-file (concat (buffer-file-name) ".rej")))
    (kill-buffer
     (find-buffer-visiting reject-file))))

(global-set-key (kbd "C-c r") 'switch-hg-reject)
(global-set-key (kbd "C-x r") 'kill-hg-reject)

It turns out that swapping back and forth between the reject and the original in a single window felt was quite inefficient. With these changes, the reject opens up in another window (think emacs terminology here) on C-c r, and I can kill it later with C-x r. This also works better with other modules like uniquify – the code from the previous post would fail when trying to access rejects associated with buffers name “Makefile.in|ipc”. No longer must you suffer the indignity of process! Merging can, and should, be fun! BEHOLD MY WORKS AND DESPAIR.

This entry was posted in code, emacs, mozilla. Bookmark the permalink.

7 Responses to Faster mercurial patch queue merging with emacs

  1. I see something genuinely interesting about your web site so I saved to fav.

  2. Anne Kramer says:

    this looks complicated for me though. I have been following your last post about this and looks forward to this post thinking that this wont be a complicated thing for me. Looking at those codes makes my head ache. I think I would need some help understanding these so that I can use the solution that you have shared.

    Anne Kramer
    Author of http://www.amazon.com/Learn-How-Blow-Glass-Instructions/dp/0986642606/ book

  3. * says:

    I used to be therefore frustrated beacuse That i couldn`t fix this problem. Browsing found your web site in the search engines in addition to issue is sorted. Appreciate it!

  4. Jim Blandy says:

    Even better! Here’s my rev:

    (defun switch-hg-reject ()
      (interactive)
      (unless (buffer-file-name)
        (error "Buffer is not visiting any file"))
      (let ((other-file
             (if (string-match "\\.rej$" (buffer-file-name))
                 (substring (buffer-file-name) 0 (match-beginning 0))
               (concat (buffer-file-name) ".rej"))))
        (unless (file-exists-p other-file)
          (error "Reject/original file not found: %s" other-file))
        (save-selected-window
          (find-file-other-window other-file))))
    
    (defun kill-hg-reject ()
      (interactive)
      (let ((reject-file (concat (buffer-file-name) ".rej")))
        (let ((buf (find-buffer-visiting reject-file)))
          (if buf (kill-buffer buf)
            (message "Not visiting reject file: %s" reject-file)))))
    
    (global-set-key (kbd "C-c r") 'switch-hg-reject)
    (global-set-key (kbd "C-x r") 'kill-hg-reject)
    
  5. Steve Fink says:

    Hm. I use a silly perl script I call ’em’ that you cut & paste the .rej filenames from the badnasty hg qpush message. It reparents them to $(hg root), scans them for the starting line of the first chunk, and then opens each .rej file along with original starting at the appropriate line number. So when running from /myhome/js/src, em js/src/file1.h.rej js/src/file2.cpp.rej will end up invoking something like emacs /myhome/js/src/file1.h.rej +228 /myhome/js/src/file1.h …(similar for file2)…

    That way, I get the reject and the original open in separate buffers, and don’t have to worry about the current working directory.

    I’ll have to try yours/jimb’s. They seem like they may be more betterer, at least if you added in the “jump to site of first conflict” thing.

  6. Jim Blandy says:

    Emacs should bring up .rej files in diff-mode, so C-c C-c anywhere in a diff should just jump to the spot in the file to which the hunk applies.

  7. Jim Blandy says:

    Apparently, I hadn’t actually re-loaded my new definition before I pasted it above. Here’s a version that works. [blush] I’ve made some changes:

    – C-x r is a prefix command for register and bookmark commands, , so I don’t want to override it for kill-hg-reject. Instead, giving C-c r a prefix argument invokes kill-hg-reject.

    – kill-hg-reject not only kills the buffer visiting the .rej file, but also closes windows displaying that buffer. If C-c r popped up a window to show the reject file, then C-u C-c r will restore the frame to showing only the patched file.

    (defun switch-hg-reject (kill-reject)
      "Switch between a .rej file and the file it applies to.
    With a prefix argument, kill the buffer visiting the reject file."
      (interactive "P")
      (unless (buffer-file-name)
        (error "Buffer is not visiting any file"))
      (if kill-reject
          (kill-hg-reject)
        (let ((other-file
               (if (string-match "\\.rej$" (buffer-file-name))
                   (substring (buffer-file-name) 0 (match-beginning 0))
                 (concat (buffer-file-name) ".rej"))))
          (unless (file-exists-p other-file)
            (error "Reject/original file not found: %s" other-file))
          (save-selected-window
            (find-file-other-window other-file)))))
    
    (defun kill-hg-reject ()
      (interactive)
      (let* ((reject-file
             (if (string-match "\\.rej$" (buffer-file-name))
                 (buffer-file-name)
               (concat (buffer-file-name) ".rej")))
             (buf (find-buffer-visiting reject-file)))
        (unless buf
          (error "Not visiting reject file: %s" reject-file))
        (delete-windows-on buf)
        (kill-buffer buf)))
    
    (global-set-key (kbd "C-c r") 'switch-hg-reject)
    

Leave a Reply to Anne Kramer Cancel reply

Your email address will not be published. Required fields are marked *