Skip to content

mattiasdrp/pokemacs-layout

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Pokemacs layout

Pokemacs layout provides a way to save window layouts and apply them. Unlike desktop-save, it’s not about saving the state of your Emacs but more about restoring your windows the way you want them.

Table of Contents

Introduction

A friend of mine had a wide screen and told me about his morning routine:

  • Split horizontally thrice
  • Start magit
  • Lock the window
  • Split vertically
  • Compile
  • Lock the window
  • Split vertically
  • Open a LSP buffer
  • Lock the window

    I had just received a wide screen and the idea of having to do that whenever I wanted to open Emacs frightened me. I started with a simple function to help my friends:

    (defun pokemacs-restore-session (&optional columns)
      "Restore a session by creating the proper buffers."
      (interactive "P")
      (when use-visual-fill (visual-fill-column-mode -1))
      (setq columns-number (or columns pokemacs-columns))
      (setq current-prefix-arg nil)
      (setq middle-window (selected-window))
      (dotimes (_ (- columns-number 2))
        (setq middle-window (split-window-right))
        (select-window middle-window)
        (balance-windows))
      (select-window middle-window)
      ;; Third window, start with magit
      (setq magit-window (split-window-right))
      (select-window magit-window)
      (with-selected-window magit-window
        (defvar magit-display-buffer-function)
        (let ((magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1))
          (magit-status-quick))
        ;; Lock after creating the magit buffer otherwise it's created in another window
        (locked-window-buffer-mode))
      ;; Fourth window below magit is the compilation window,
      ;; create a buffer without compiling
      (setq compilation-window (split-window-below))
      (select-window compilation-window)
      (set-window-buffer (selected-window) (get-buffer-create "*compilation*"))
      (with-selected-window compilation-window
        (locked-window-buffer-mode))
      ;; Fifth window below compilation is the lsp-help window,
      ;; create a buffer without calling lsp
      (setq lsp-window (split-window-below))
      (select-window lsp-window)
      (set-window-buffer (selected-window) (get-buffer-create "*lsp-help*"))
      (with-selected-window lsp-window
        (locked-window-buffer-mode))
      (select-window middle-window)
      (balance-windows))
        

And then I thought: “Hey, I’m sure I could create a simple layout type and allow for more customisations, let’s do it!”. This is the result of this experiment.

Getting started

Currently this package is not in any package manager but you can use it easily with elpaca or straight:

(use-package pokemacs-layout
  :ensure (:host github :repo "mattiasdrp/pokemacs-layout")
  :commands pokemacs-layout-apply pokemacs-layout-monitor-names
  pokemacs-restore-session pokemacs-layout-current-monitor)

Or, if you don’t use use-package:

(require 'pokemacs-layout)

Just make sure that pokemacs-layout.el is in load-path

How to use?

Main architecture

A layout is a plist of '(:monitor monitor :windows windows-layout :sides sides-layout :children children-layout).

Let’s break it down.

Monitor

The :monitor property specifies on which monitor this frame should be created. As you’ll usually apply a layout from a monitor, it’s not recommended to specify a :monitor property for the main layout.

Window layout

A window layout is a list of alists:

Simple layout

  • 3 columns, no actions
(defvar pokemacs-layout-simple-3C
  '((column . ())
    (column . ())
    (none . ())))

;; Or:
(defvar pokemacs-layout-even-simpler-3C
  '((column . (nil nil 3))))

You can already use these layout with

(pokemacs-layout--apply-layout pokemacs-layout-simple-3C)
(pokemacs-layout--apply-layout pokemacs-layout-even-simpler-3C)

(if you read this README in emacs you can evaluate the source blocks with C-c C-c and see the results immediately – use winner-undo to go back to the previous layout)

This simple example shows the skeleton of a window layout: (split . action). Currently split can be:

  • column (split horizontally)
  • row (split vertically)
  • none (don’t split this window)

An action is composed of three fields (fill lock number):

  • fill is anything to help creating the buffer in the window (nil, a buffer name, a function call…)
  • lock is t if this window should be locked, meaning no other buffer can spawn there
  • number to repeat this alist multiple times

Complex layout

  • 3 columns, the last one is also split in 3 with 3 specific buffers
(defvar pokemacs-layout-complex
  '((column . (nil nil 2))
    (none . ('((row . (magit-status-quick t))
               (row . ("*compilation*" t))
               (none . ("*lsp-help*" t))) nil nil))))
(pokemacs-layout--apply-layout pokemacs-layout-complex)

This layout will create three columns:

  • The first two will be the current buffer duplicated in two windows
  • The third one is split in three locked rows:
    • The first one is created by executing (magit-status-quick)
    • The second one is created with the compilation buffer (created if it doesn’t exist)
    • The third one is like the second one but with the lsp-help buffer

Side layout

A side layout is an alist of each side associated to its layout.

Simple side

(defvar pokemacs-layout-simple-right-side
  '((right . ((1 "*Messages*" t)
              (2 "*scratch*" t)))))

And you can see the result with

(pokemacs-layout--apply-layout-sides-alist pokemacs-layout-simple-right-side)

An side is a list of slots (number fill lock):

  • number is the slot index (starts at 1)
  • fill is anything to help creating the buffer in the window (nil, a buffer name, a function call…)
  • lock is t if this window should be locked, meaning no other buffer can spawn there

Children layout

Finally, the :children is a list of layouts with the same architecture as the main layout. The interesting thing is that if the :monitor property is set, the child is created in a frame on another monitor.

Complete layouts

Example layouts:

Programming default

2 columns with the message and scratch buffers and a side window with the magit buffer and a buffer for completion or lsp-help results

(defconst pokemacs-layout-prog-default
  '((:windows
     ((column . ("*Messages*" nil 1))
      (none . ("*scratch*" nil 1)))
     :sides
     ((right . ((1 magit-status-quick t)
                (2 ("*compilation*" "*lsp-help*") t)))))))

Programming default on 2 monitors

Some columns with the current buffer and a side window with the magit buffer and a buffer for completion or lsp-help results. The number of columns is specified by pokemacs-layout-columns or with the universal argument C-u (try it with M-<n>) A second frame is created on a second monitor specified by the custom variable pokemacs-layout-second-monitor and contains the message and scratch buffers.

(defconst pokemacs-layout-prog-default-frames-custom-number
  `((:windows
     ((column . (nil nil pokemacs-layout-columns)))
     :sides
     ((right . ((1 magit-status-quick t)
                (2 ("*compilation*" "*lsp-help*") t))))
     :children
     ((:monitor ,pokemacs-layout-second-monitor
                :windows
                ((column . ("*Messages*" nil 1))
                 (none . ("*scratch*" nil 1))))))))

Customize pokemacs-layout-layouts

Wrap your newly created layouts:

(pokemacs-layout--create-layout
 "my/layout"
 my/layout
 "My layout description")

And add it to pokemacs-layout-layouts, this will make it available when calling M-x pokemacs-layout-apply.

Future plans

  • [ ] Improve this README
  • [ ] Add some pictures or gif to this README
  • [X] Add new frames to the layout choices with monitor choice

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published