Enhance diff-mode with Ivy
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)
(cond
(ffip-read-file-name-hijacked-p
(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)))
(t
ad-do-it)))
(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.