9

Looking for a solution on how to restore my window layout after an Ediff session, I found a blog post, where the author suggests:

(winner-mode)
(add-hook 'ediff-after-quit-hook-internal 'winner-undo)

This seems to almost work well for me. I say almost because I invoke M-x ediff-buffers from Helm, and quiting the Ediff session brings me back to the original layout with the dead Helm menu from where I chose M-x ediff-buffers.

Let me explain:

  1. At any point I have several windows open with a window layout L1.
  2. I want to ediff some buffers, so I press M-x: This re-uses one of the windows in L1 to open up a Helm autocompletion menu. So far so good.
  3. I choose ediff-buffers, and then the two buffers to compare, one after the other
  4. This takes me to an ediff session where I can check differences etc.
  5. Once I am done. I quit my ediff-session.
  6. I would like to go back to my layout L1 in step #1. However, Emacs (winner-mode) takes me back to step #2, where one of the Emacs windows in L1 was used to show the options in Helm. This is pointless since I am done with my ediff session.

How can I restore windows to my original layout L1?

Setup:

This is all in Emacs 25.0.50.1 on OS X. More specifically, GNU Emacs 25.0.50.1 (x86_64-apple-darwin14.0.0, NS appkit-1343.16 Version 10.10.1 (Build 14B25))

3 Answers 3

12

What you want can be achieved cleanly using hook provided by ediff (which if read the documentation seem to be provided for this exact purpose), advices are not needed. The relevant hooks are

1) ediff-quit-hook, from the documentation

Hooks to run in the Ediff control buffer after finishing Ediff.

2) ediff-before-setup-hook

Hooks to run before Ediff begins to set up windows and buffers. This hook can be used to save the previous window config, which can be restored on ediff-quit or ediff-suspend.

The approach is similar to @abo-abo's approach. We save the window configuration before ediff is setup using the ediff-before-setup-hook and restore the stored window configuration in ediff-quit-hook.

(defvar my-ediff-last-windows nil)

(defun my-store-pre-ediff-winconfig ()
  (setq my-ediff-last-windows (current-window-configuration)))

(defun my-restore-pre-ediff-winconfig ()
  (set-window-configuration my-ediff-last-windows))

(add-hook 'ediff-before-setup-hook #'my-store-pre-ediff-winconfig)
(add-hook 'ediff-quit-hook #'my-restore-pre-ediff-winconfig)
5

Look at what you made me do, I was so happy with my ugly hack, and now it's fixed:

(defvar ediff-last-windows nil
  "Last ediff window configuration.")

(defun ediff-restore-windows ()
  "Restore window configuration to `ediff-last-windows'."
  (set-window-configuration ediff-last-windows)
  (remove-hook 'ediff-after-quit-hook-internal
               'ediff-restore-windows))

(defadvice ediff-buffers (around ediff-restore-windows activate)
  (setq ediff-last-windows (current-window-configuration))
  (add-hook 'ediff-after-quit-hook-internal 'ediff-restore-windows)
  ad-do-it)
4
  • 1
    My elisp knowledge is limited. What is the difference between this answer and the accepted one? Both do almost the same thing, but this one uses defadvice and seem to use remove-hook, that the other does not. Could you give a brief explanation? Thanks you!
    – nephewtom
    Commented Nov 4, 2017 at 21:34
  • 2
    It's better to avoid defadvice if possible. It's powerful, which makes it fast to come up with a quick solution, but in the end it's harder to maintain.
    – abo-abo
    Commented Nov 6, 2017 at 17:11
  • If it's better to avoid defadvice, then in the end, is the answer from @Iqbal answer better than the one from @abo-abo ?
    – glmorous
    Commented Jan 7, 2020 at 19:55
  • Seems "ad-do-it" is removed in the 26.3 manual. The doc for it is found in older manual ftp.gnu.org/old-gnu/Manuals/elisp-manual-21-2.8/html_chapter/… . Commented Apr 12, 2021 at 18:10
0

The accepted answer works well for ediff-buffers. It doesn't seem to work well for ediff-regions-linewise and ediff-regions-wordwise.

The problem is that ediff-before-setup-hook is called too late with ediff-regions-linewise and ediff-regions-wordwise when also setting ediff-split-window-function and ediff-window-setup-function. The window configuration, at least for me, changes prior to the hook. This causes the ediff-before-setup-hook to capture the wrong window configuration.

So, the following uses "before" advice to act like the setup hook. We then use the ediff-quit-hook to reset the windows on completion.

(defvar my-ediff-last-windows nil
  "Window configuration prior to calling `ediff-buffers',
`ediff-regions-linewise', or `ediff-regions-wordwise'.")

(defun my-ediff-restore-last-windows ()
  "Set window configuration to `my-ediff-last-windows'."
  (cond (my-ediff-last-windows
         (set-window-configuration my-ediff-last-windows)
         (setq my-ediff-last-windows nil))))

(add-hook 'ediff-quit-hook #'my-ediff-restore-last-windows)

(defadvice ediff-buffers (before ediff-buffers-advice activate)
  (setq my-ediff-last-windows (current-window-configuration)))

(defadvice ediff-regions-linewise (before ediff-regions-linewise-advice activate)
  (setq my-ediff-last-windows (current-window-configuration)))

(defadvice ediff-regions-wordwise (before ediff-regions-wordwise-advice activate)
  (setq my-ediff-last-windows (current-window-configuration)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.