Enhance diff-mode with Ivy

  |   Source

My current job requires me to review the freelancer's patches and apply them to our code branch under Perforce control. Due to my client's security policy, the freelancer can only work on isolated sandbox environment and can't access our code base directly.

I need two steps to finish the task:

  • Open the freelancer's patch in diff-mode
  • Run diff-apply-hunk to apply the hunks interactively

The problem is diff-mode always ask me to specify the file to be patched.

I read the code of diff-apply-hunk. The logic of diff-apply-hunk is simple. It tries different algorithms to guess the right file to patch. When the algorithms fail, it calls API read-file-name to ask me to provide the file path manually. If right file is found, the algorithms will work again and read-file-name will never be used for other hunks.

Here is my solution. I can find the file to patch in recent opened files because I store all of them by (setq recentf-max-saved-items 2048). I plan to use ivy-read from Ivy to locate the file at first. If this step fails , I can still fall back on original API read-file-name.

Here is the code

(defvar ffip-read-file-name-hijacked-p nil)
(defun ffip-diff-apply-hunk (&optional reverse)
  (interactive "P")
  (unless recentf-mode (recentf-mode 1))
  (setq ffip-read-file-name-hijacked-p t)
  (defadvice read-file-name (around ffip-read-file-name-hack activate)
      (let* ((args (ad-get-args 0))
             (file-name (file-name-nondirectory (nth 2 args)))
             (cands (remove nil (mapcar (lambda (s) (if (string-match-p (format "%s$" file-name) s) s))
                                        (mapcar #'substring-no-properties recentf-list))))
             (rlt (ivy-read "Recentf: " cands)))
        (if rlt (setq ad-return-value rlt) rlt ad-doit)))
  (diff-apply-hunk reverse)
  (setq ffip-read-file-name-hijacked-p nil))

Please note ffip-diff-apply-hunk can replace diff-apply-hunk.

BTW, I can edit the patch on the spot when applying hunks. Similar to the work flow of git add --patch.

The solution is added into https://github.com/technomancy/find-file-in-project.

Comments powered by Disqus