Emacs, scripting and anything text oriented.

Do Ediff as I mean

Kaushal Modi
<2017-09-19>
Updated modi/ediff-dwim to the latest revision in my config.

In almost all of my ediff use cases, I would have windows open side-by-side in a frame, and then I would want to do a diff between the two using ediff-buffers.

But emacs doesn’t know that I obviously want to diff those two side-by-side buffers! So it always asks me to select the buffers to be diffed. The same problem is when using ediff-files too.

So I came up with the following helper function to pick the correct ediff command.

(defun modi/ediff-dwim ()
  "Do ediff as I mean.

If a region is active, call `ediff-regions-wordwise'.
Else if the frame has 2 windows with identical major modes,
  - Do `ediff-files' if the buffers are associated to files and the buffers
    have not been modified.
  - Do `ediff-buffers' otherwise.
Else if the current is a file buffer with a VC backend, call `vc-ediff'
Else call `ediff-buffers'."
  (interactive)
  (let* ((num-win (safe-length (window-list)))
         (bufa (get-buffer (buffer-name)))
         (filea (buffer-file-name bufa))
         (modea (with-current-buffer bufa major-mode))
         bufb fileb modeb)
    (save-excursion
      (other-window 1)
      (setq bufb (get-buffer (buffer-name)))
      (setq fileb (buffer-file-name bufb))
      (setq modeb (with-current-buffer bufb major-mode)))
    (cond
     ;; If a region is selected
     ((region-active-p)
      (call-interactively #'ediff-regions-wordwise))
     ;; Else if 2 windows with same major modes
     ((and (= 2 num-win)
           (eq modea modeb))
      (if ;; If either of the buffers is not associated to a file,
          ;; or if either of the buffers is modified
          (or (null filea)
              (null fileb)
              (buffer-modified-p bufa)
              (buffer-modified-p bufb))
          (progn
            (message "Running (ediff-buffers \"%s\" \"%s\") .." bufa bufb)
            (ediff-buffers bufa bufb))
        (progn
          (message "Running (ediff-files \"%s\" \"%s\") .." filea fileb)
          (ediff-files filea fileb))))
     ;; Else if file in current buffer has a vc backend
     ((and filea
           (vc-registered filea))
      (call-interactively #'vc-ediff))
     ;; Else call `ediff-buffers'
     (t
      (call-interactively #'ediff-buffers)))))

Find this function in my emacs config.


My favorite ediff settings are:

;; No separate frame for ediff control buffer
(setq ediff-window-setup-function #'ediff-setup-windows-plain)

;; Split windows horizontally in ediff (instead of vertically)
(setq ediff-split-window-function #'split-window-horizontally)