Skip to content

Instantly share code, notes, and snippets.

@dse
Created September 23, 2017 00:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dse/ba94f8724d1b8f30e5cdbb64ff553527 to your computer and use it in GitHub Desktop.
Save dse/ba94f8724d1b8f30e5cdbb64ff553527 to your computer and use it in GitHub Desktop.
;; Stolen from:
;; http://mikehucka.postach.io/post/modifying-emacss-vc-diff-for-word-oriented-diffs
;;
;; Improvements:
;; - Be smarter about adding --word-diff to `vc-git-diff-switches' and
;; not clobbering any existing settings.
;; - Use `defface' as the docstring for `make-face' recommends.
;; - Base face defaults on `diff-added' and `diff-removed'.
;; - Rename `vc-diff-deleted-face' to `vc-diff-removed-face' for
;; consistency with existing face naming conventions.
;; - Refactor so the advice can easily be redefined.
;; - Be smarter about when to invoke the advice.
;;
;; TODO:
;; - make this work in vc-svn as well.
;; - make this work universally in vc, maybe.
;; - make this work universally in diff, maybe.
;; - recognize git diff --word-diff=<mode>
;; (`plain' is the default for <mode>)
;; - recognize git diff --word-diff-regex=<regex>
;; - recognize git diff --color-words[=<regex>]
(defun dse/init/vc/git/setup-word-diffs ()
(defun dse/init/vc/git/setup-word-diffs/eval-after-load ()
(cond ((listp vc-git-diff-switches)
(add-to-list 'vc-git-diff-switches "--word-diff" 'append))
((stringp vc-git-diff-switches)
(cond
((equal vc-git-diff-switches "")
(setq vc-git-diff-switches "--word-diff"))
((not (string-match "\\(\\`\\| \\)--word-diff\\(\\'\\| \\)" vc-git-diff-switches))
(setq vc-git-diff-switches (concat vc-git-diff-switches " --word-diff")))))
((not vc-git-diff-switches)
(setq vc-git-diff-switches '("--word-diff"))))
(defface vc-diff-added-face
'((default :inherit diff-added))
"Face used to highlight added words.")
(defface vc-diff-removed-face
'((default :inherit diff-removed))
"Face used to highlight removed words.")
(defun vc-git-diff-word-advice ()
(when (and (or (and (listp vc-git-diff-switches)
(member "--word-diff" vc-git-diff-switches))
(and (stringp vc-git-diff-switches)
(string-match "\\(\\`\\| \\)--word-diff\\(\\'\\| \\)" vc-git-diff-switches)))
(equal diff-vc-backend 'Git))
(save-window-excursion
(with-current-buffer "*vc-diff*"
(let ((inhibit-read-only t))
(goto-char (point-min))
(while (re-search-forward "\\({\\(\\+\\)\\|\\[\\(-\\)\\)" nil t)
(let* ((front-start (match-beginning 0))
(front-end (match-end 0))
(addition-p (match-beginning 2))
back-start
back-end)
(cond (addition-p
(re-search-forward "\\+}" nil t)
(setq back-start (match-beginning 0))
(setq back-end (match-end 0)))
(t
(re-search-forward "\\-\\]" nil t)
(setq back-start (match-beginning 0))
(setq back-end (match-end 0))))
(if addition-p
(overlay-put (make-overlay front-end back-start)
'face 'vc-diff-added-face)
(overlay-put (make-overlay front-end back-start)
'face 'vc-diff-removed-face))
;; Make sure to delete back-to-front, because the text will shift.
(delete-region back-start back-end)
(delete-region front-start front-end)
(goto-char front-end)))
(goto-char (point-min)))))))
(defadvice vc-diff (after vc-diff-advice last activate compile)
(vc-git-diff-word-advice)))
(eval-after-load 'vc-git #'dse/init/vc/git/setup-word-diffs/eval-after-load))
(dse/init/vc/git/setup-word-diffs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment