30

When I configure a custom layout and then just need to temporary look into one file fullscreen and once I want that layout back - I need manually to reflow it.

I would like a plugin/elisp code to save my layouts and to be able to switch between saved layouts.

UPDATE

Thank you all.

abo-abo suggestion to use winner mode is really nice and I got it working in zero time.

wasamasa suggested a bunch of great plugins I have never heared of and provided information how to use registers.

Jordon Biondo explained me how to use the registers and this stuff is actually what I wanted in the simplest way.

Thank you all.

6 Answers 6

32

The built in way to do this is with registers.

For instance use C-xrwa to save the current window configuration to register a.

Then you can use the built in binding C-x1 to run delete-other-windows

after you're done looking at the single file, use C-xrja to pop back to the saved window configuration in register a.

In short:

C-xrwa (save config into register)

C-x1 (delete other windows)

C-xrja (reapply saved window config)


I do find registers to be unwieldy though, I use a custom window config stack to manage my configs.

I have two bindings that push the current config onto the stack, and pop and apply the top config.

So in your sceneario, I would perform my push binding, then C-x 1, then perform my pop binding.

Here is the code:

(defvar winstack-stack '()
  "A Stack holding window configurations.
Use `winstack-push' and
`winstack-pop' to modify it.")

(defun winstack-push()
  "Push the current window configuration onto `winstack-stack'."
  (interactive)
  (if (and (window-configuration-p (first winstack-stack))
         (compare-window-configurations (first winstack-stack) (current-window-configuration)))
      (message "Current config already pushed")
    (progn (push (current-window-configuration) winstack-stack)
           (message (concat "pushed " (number-to-string
                                       (length (window-list (selected-frame)))) " frame config")))))

(defun winstack-pop()
  "Pop the last window configuration off `winstack-stack' and apply it."
  (interactive)
  (if (first winstack-stack)
      (progn (set-window-configuration (pop winstack-stack))
             (message "popped"))
    (message "End of window stack")))

You can then bind winstack-push to something like C-cC-u, and winstack-pop to C-cC-o to easily jump around.

3
  • This is very very very nice! Oct 27, 2014 at 14:33
  • Is this configuration saved in "a" being mantained across sessions (if I restart Emacs will still be there?). Thanks! Jan 11, 2021 at 13:26
  • Could you please replace the calls to (first with a call to (car ? The effect is the same, but the difference is that first is a function from deprecated cl package. I recently removed or updated all packages that were depending on this, and as result your functions winstack-push and winstack-pop stopped working due to Symbol’s function definition is void: first. It does work with car though.
    – Hi-Angel
    Mar 14 at 8:41
24

I use winner-mode. Here's my setup:

(winner-mode)
(global-set-key [f7] 'winner-undo)
(global-set-key [C-f7] 'winner-redo)
(global-set-key [f9] 'delete-other-windows)
(global-set-key [C-f9] 'delete-window)

I don't know if there's a way to bookmark a layout or something, but being able to continuously switch back to previous layout is enough for me.

1
  • wow, just being able to switch back to previous layout does A LOT for me. Thanks! Oct 27, 2014 at 14:23
11

Emacs offers registers to save and apply data such as your current window configuration, this can be done with C-x r w and C-x r j. However this approach gets unwieldy since you need to remember the window registers.

There are a few packages to improve this. iregister makes this basic feature more inspectable and interactive. The other ones I'm aware of use it without impacting the registers, such as elscreen and escreen which use the header bar to display tabs. workgroups and workgroups2 are two newer and more extensive approaches to this problem. I personally didn't like either and therefore wrote my own that's somewhere in between and has hopefully less bugs and complexity.

4
  • That's great stuff about registers but how should I use them in this case? I will check out the plugins you have listed to see if any success for me :) Oct 27, 2014 at 14:32
  • You save your current layout to a register, do some changes, then once you want to switch to its old state restore the layout from the register. The packages I've listed lift you from the mental burden of doing this every time you want to switch layouts.
    – wasamasa
    Oct 27, 2014 at 14:33
  • is it possible to create a certain window configuration during startup (in my .emacs file) and then save it to a register? I tried (window-configuration-to-register "1") as a command in my .emacs, but it did not work
    – p.m
    Aug 19, 2019 at 8:01
  • Try using desktop.el for that, it has been combined successfully with eyebrowse before.
    – wasamasa
    Aug 19, 2019 at 8:15
2

You can save the current window layout to a register and then restore it using jump-to-register. The command window-configuration-to-register is bound to C-x r w by default.

For example, when you have your windows arranged in a useful way you can save them to registe i using: C-x r w i and restore the layout later using C-x r j i.

1
  • 1
    Ha, three of us answered about registers at the same time.
    – glucas
    Oct 27, 2014 at 14:35
2

Zygospore provides a quick fix for the situation where you have multiple windows open, and want to temporarily maximize one of them. It modifies the behaviour of C-x 1. When you have multiple windows open, it behaves like the default delete-other-windows, and removes all the windows except for the one you are viewing. When you hit it again, it restores the other windows.

Winner-mode provides a more general solution, but zygospore is great for temporarily zooming in on a single window in a frame. The best thing is it doesn't use any new keybindings - it re-defines C-x 1 in a very intuitive way, so there are no new bindings to learn.

2

This is a interesting question. Several years ago I investigated all the solutions. Only workgroups2.el is heavy weight enough to cover all the corner cases.

But workgroups2 UI is a disaster. For example, if you enable worksgroup-mode (as its README suggested), the previous layout will be automatically loaded during emacs startup. That make startup extremely slow EVERY time.

My solution is to treat workgroups2 as a collection of API instead a usable tool out of box. So I change its default UI interaction by using ivy-mode (https://github.com/abo-abo/swiper) from @abo-abo

enter image description here

Toggle full window is easy, use APIs from winner-mode is enough.

Here is the complete code (I only use M-x toggle-full-window, M-x wg-create-workgroup and M-x my-wg-switch-workgroup, you also need install swiper, as I mentioned above),

(defun toggle-full-window()
  "Toggle the full view of selected window"
  (interactive)
  ;; @see http://www.gnu.org/software/emacs/manual/html_node/elisp/Splitting-Windows.html
  (if (window-parent)
      (delete-other-windows)
    (winner-undo)))

(setq wg-use-default-session-file nil)
;; don't open last workgroup automatically in `wg-open-session',
;; I only want to check available workgroups! Nothing more.
(setq wg-load-last-workgroup nil)
(setq wg-open-this-wg nil)

;(workgroups-mode 1) ; put this one at the bottom of .emacs
;; by default, the sessions are saved in "~/.emacs_workgroups"
(autoload 'wg-create-workgroup "workgroups2" nil t)

(defun my-wg-switch-workgroup ()
  (interactive)
  (let (group-names selected-group)
    (unless (featurep 'workgroups2)
      (require 'workgroups2))
    (setq group-names
          (mapcar (lambda (group)
                    ;; re-shape list for the ivy-read
                    (cons (wg-workgroup-name group) group))
                  (wg-session-workgroup-list (read (f-read-text (file-truename wg-session-file))))))
    (ivy-read "work groups" group-names
              :action (lambda (group)
                        (wg-find-session-file wg-default-session-file)
                        (wg-switch-to-workgroup group)))))

(eval-after-load 'workgroups2
  '(progn
     ;; make sure wg-create-workgroup always success
     (defadvice wg-create-workgroup (around wg-create-workgroup-hack activate)
       (unless (file-exists-p (wg-get-session-file))
         (wg-reset t)
         (wg-save-session t))

       (unless wg-current-session
         ;; code extracted from `wg-open-session'.
         ;; open session but do NOT load any workgroup.
         (let ((session (read (f-read-text (file-truename wg-session-file)))))
           (setf (wg-session-file-name session) wg-session-file)
           (wg-reset-internal (wg-unpickel-session-parameters session))))
       ad-do-it
       ;; save the session file in real time
       (wg-save-session t))

     (defadvice wg-reset (after wg-reset-hack activate)
       (wg-save-session t))

     ;; I'm fine to to override the original workgroup
     (defadvice wg-unique-workgroup-name-p (around wg-unique-workgroup-name-p-hack activate)
       (setq ad-return-value t))))

UPDATE: I'm the maintainer of workgroups2 now. You don't need above hack any more.

Use wg-create-workgroup to create a new work group and save it, use wg-open-workgroup to open saved workgroup.

Your Answer

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

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