nftable-migration
1# Inspired by: https://github.com/othneildrew/Best-README-Template
2#+OPTIONS: toc:nil
3
4[[https://github.com/MArpogaus/auto-side-windows/graphs/contributors][https://img.shields.io/github/contributors/MArpogaus/auto-side-windows.svg?style=flat-square]]
5[[https://github.com/MArpogaus/auto-side-windows/network/members][https://img.shields.io/github/forks/MArpogaus/auto-side-windows.svg?style=flat-square]]
6[[https://github.com/MArpogaus/auto-side-windows/stargazers][https://img.shields.io/github/stars/MArpogaus/auto-side-windows.svg?style=flat-square]]
7[[https://github.com/MArpogaus/auto-side-windows/issues][https://img.shields.io/github/issues/MArpogaus/auto-side-windows.svg?style=flat-square]]
8[[https://github.com/MArpogaus/auto-side-windows/blob/main/LICENSE][https://img.shields.io/github/license/MArpogaus/auto-side-windows.svg?style=flat-square]]
9[[https://linkedin.com/in/MArpogaus][https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555]]
10
11* auto-side-windows :TOC_3_gh:noexport:
12 - [[#about-the-project][About The Project]]
13 - [[#motivation][Motivation]]
14 - [[#layout-concept][Layout Concept]]
15 - [[#inspirations][Inspirations]]
16 - [[#getting-started][Getting Started]]
17 - [[#prerequisites][Prerequisites]]
18 - [[#example-configuration][Example Configuration]]
19 - [[#usage][Usage]]
20 - [[#customization][Customization]]
21 - [[#commands][Commands]]
22 - [[#integration-with-other-packages][Integration with Other Packages]]
23 - [[#popper-integration][Popper Integration]]
24 - [[#ace-window-integration][Ace Window Integration]]
25 - [[#enhancing-magit-and-org-mode-compatibility][Enhancing =magit= and =org-mode= compatibility]]
26 - [[#comparison-with-other-packages][Comparison with Other Packages]]
27 - [[#shackle][Shackle]]
28 - [[#popper][Popper]]
29 - [[#core-emacs-display-buffer-alist][Core Emacs (=display-buffer-alist=)]]
30 - [[#bonus-boxes-around-top-windows][Bonus: Boxes around top windows]]
31 - [[#contributions][Contributions]]
32 - [[#license][License]]
33 - [[#contact][Contact]]
34
35** About The Project
36
37[[file:screenshot.png]]
38
39*** Motivation
40
41I found the default behavior of =display-buffer= often unpredictable, leading to new buffers appearing in unexpected windows.
42Digging into Emacs' window management led me to realize the power of =display-buffer-alist=, but configuring it directly can be complicated and confusing especially for new users.
43
44=auto-side-windows= simplifies this process.
45It provides a straightforward way to define rules based on buffer names or major modes, ensuring that specific buffers consistently open in designated side windows (top, bottom, left, or right).
46The goal is to achieve a predictable, organized workspace, similar to layouts often found in IDEs, keeping the main editing area clear while providing easy access to complementary information.
47
48*** Layout Concept
49
50The package helps achieve layouts where side windows display non-primary information, keeping the central area focused on editing. A conceptual layout might look like this:
51
52#+begin_src
53 _________________________________________________
54 | top: compilation, grep, occur |
55 |_________________________________________________|
56 | left: | | right: |
57 | - dired | | - Help |
58 | - treemacs | | - Info |
59 | - outline | Main Window Area | - Magit |
60 | | (Editing) | |
61 | | | |
62 | | | |
63 |____________|_______________________|____________|
64 | bottom: REPLs, shells |
65 |_________________________________________________|
66 | Echo Area |
67 |_________________________________________________|
68#+end_src
69
70This allows buffers like help, compilation logs, shells, or project trees to be accessible without disrupting the primary editing flow.
71
72*** Inspirations
73
74This package builds upon the excellent work and explanations of others in the Emacs community:
75- [[https://karthinks.com/software/emacs-window-management-almanac/][Emacs Window Management Almanac]] by [[https://www.reddit.com/user/karthinks/][u/karthinks]]
76- [[https://www.masteringemacs.org/article/demystifying-emacs-window-manager][Demystifying Emacs's Window Manager]] by [[https://www.reddit.com/user/mickeyp/][u/mickeyp]]
77- [[https://github.com/karthink/.emacs.d/blob/25a0aec771c38e340789d7c304f3e39ff23aee3e/lisp/setup-windows.el#L164][Karthink's setup-windows.el]] for a practical examples.
78Thank you all!
79
80** Getting Started
81
82*** Prerequisites
83
84- Emacs 30.1 or later.
85
86*** Example Configuration
87
88Here’s an example configuration using =use-package=:
89
90#+begin_src emacs-lisp
91 (use-package auto-side-windows
92 :load-path "/path/to/auto-side-windows/"
93 :custom
94 ;; Top side window configurations
95 (auto-side-windows-top-buffer-names
96 '("^\\*Backtrace\\*$" "^\\*Compile-Log\\*$" "^COMMIT_EDITMSG$"
97 "^\\*Org Src.*\\*" "^\\*Agenda Commands\\*$" "^\\*Org Agenda\\*$"
98 "^\\*Quick Help\\*$" "^\\*Multiple Choice Help\\*$" "^\\*TeX Help\\*$"
99 "^\\*TeX errors\\*$" "^\\*Warnings\\*$" "^\\*diff-hl\\*$"
100 "^\\*Process List\\*$"))
101 (auto-side-windows-top-buffer-modes
102 '(flymake-diagnostics-buffer-mode locate-mode occur-mode grep-mode
103 xref--xref-buffer-mode))
104
105 ;; Bottom side window configurations
106 (auto-side-windows-bottom-buffer-names
107 '("^\\*.*eshell.*\\*$" "^\\*.*shell.*\\*$" "^\\*.*term.*\\*$"
108 "^\\*.*vterm.*\\*$"))
109 (auto-side-windows-bottom-buffer-modes
110 '(eshell-mode shell-mode term-mode vterm-mode comint-mode debugger-mode))
111
112 ;; Right side window configurations
113 (auto-side-windows-right-buffer-names
114 '("^\\*eldoc.*\\*$" "^\\*info\\*$" "^\\*Metahelp\\*$"))
115 (auto-side-windows-right-buffer-modes
116 '(Info-mode TeX-output-mode pdf-view-mode eldoc-mode help-mode
117 helpful-mode shortdoc-mode))
118
119 ;; Example: Custom parameters for top windows (e.g., fit height to buffer)
120 ;; (auto-side-windows-top-alist '((window-height . fit-window-to-buffer)))
121 ;; (auto-side-windows-top-window-parameters '((mode-line-format . ...))) ;; Adjust mode-line
122
123 ;; Maximum number of side windows on the left, top, right and bottom
124 (window-sides-slots '(1 1 1 1)) ; Example: Allow one window per side
125
126 ;; Force left and right side windows to occupy full frame height
127 (window-sides-vertical t)
128
129 ;; Make changes to tab-/header- and mode-line-format persistent when toggleling windows visibility
130 (window-persistent-parameters
131 (append window-persistent-parameters
132 '((tab-line-format . t)
133 (header-line-format . t)
134 (mode-line-format . t))))
135 :bind ;; Example keybindings (adjust prefix as needed)
136 (:map global-map ; Or your preferred keymap prefix
137 ("C-c w t" . auto-side-windows-display-buffer-top)
138 ("C-c w b" . auto-side-windows-display-buffer-bottom)
139 ("C-c w l" . auto-side-windows-display-buffer-left)
140 ("C-c w r" . auto-side-windows-display-buffer-right)
141 ("C-c w T" . auto-side-windows-toggle-side-window)) ; Toggle current buffer in/out of side window
142 :hook
143 (after-init . auto-side-windows-mode)) ; Activate the mode
144#+end_src
145
146** Usage
147
148Once =auto-side-windows-mode= is enabled and configured, buffers matching your defined rules (by name regexp or major mode) will automatically be displayed in the specified side window.
149
150** Customization
151
152You can customize the behavior through the following variables (accessible via `M-x customize-group RET auto-side-windows RET`):
153
154| Option | Type | Description |
155|-------------------------------------------------------------+---------------+----------------------------------------------------------------------------------------|
156| =auto-side-windows-{top,bottom,left,right}-buffer-names= | list (string) | Regexps matching buffer names for each side. |
157| =auto-side-windows-{top,bottom,left,right}-buffer-modes= | list (symbol) | Major modes for buffers for each side. |
158| =auto-side-windows-{top,bottom,left,right}-extra-conditions= | list (sexp) | Additional conditions (e.g., `(category . ...)` for =display-buffer=) for matching. |
159| =auto-side-windows-{top,bottom,left,right}-window-parameters= | alist | Window parameters (see =window-parameters=) applied to windows on this side. |
160| =auto-side-windows-{top,bottom,left,right}-alist= | alist | Action alist properties (e.g., =window-height=) applied for this side. |
161| =auto-side-windows-common-window-parameters= | alist | Window parameters applied to *all* side windows created by this package. |
162| =auto-side-windows-common-alist= | alist | Action alist properties (e.g., `(dedicated . t)`) applied for *all* side windows. |
163| =auto-side-windows-reuse-mode-window= | alist | Specify sides (e.g., `((right . t))`) where windows can be reused for same major mode. |
164| =auto-side-windows-{before,after}-display-hook= | hook | Hooks run before/after displaying a buffer in a side window. |
165| =auto-side-windows-{before,after}-toggle-hook= | hook | Hooks run before/after toggling a buffer as a side window. |
166
167** Commands
168
169The package provides the following commands:
170
171- =auto-side-windows-mode=: Global minor mode. Enable this to activate the automatic side window management based on your rules.
172- =auto-side-windows-toggle-side-window=: If the current buffer is in a side window created by this package, move it to a normal window. If it was just moved out, move it back to its side window configuration. Useful for temporarily maximizing a side window buffer.
173- =auto-side-windows-display-buffer-{top,bottom,left,right}=: Manually force the current buffer to be displayed in a side window on the specified side, overriding normal rules.
174- =auto-side-windows-display-buffer-on-side=: Manually force the current buffer to be displayed in a side window on the specified side, overriding normal rules. Compared to the command above the user is prompted side in the minibuffer.
175
176** Integration with Other Packages
177
178=auto-side-windows= plays well with other common window and buffer management packages.
179
180*** Popper Integration
181
182You can configure [[https://github.com/karthink/popper][Popper]] to manage the side windows created by =auto-side-windows=. Define Popper's reference buffers using the same lists you use for =auto-side-windows=:
183
184#+begin_src emacs-lisp
185 (use-package popper
186 :after auto-side-windows ; Ensure auto-side-windows variables are defined
187 :hook (auto-side-windows-mode . popper-mode) ; Activate popper alongside
188 :custom
189 ;; Tell Popper to consider buffers matching auto-side-windows rules as popups
190 (popper-reference-buffers
191 (append auto-side-windows-top-buffer-names auto-side-windows-top-buffer-modes
192 auto-side-windows-left-buffer-names auto-side-windows-left-buffer-modes
193 auto-side-windows-right-buffer-names auto-side-windows-right-buffer-modes
194 auto-side-windows-bottom-buffer-names auto-side-windows-bottom-buffer-modes))
195 ;; Optional: Don't let Popper decide where to display, auto-side-windows handles that
196 (popper-display-control nil) ; Or 'user if you prefer popper commands for display
197 :config
198 (popper-mode +1) ; Enable popper-mode
199 (popper-echo-mode +1) ; Optional: echo area notifications
200 :bind ;; Example bindings
201 (:map your-prefix-map ;; e.g. my/toggle-map
202 ("p" . popper-toggle) ; Toggle last popup
203 ("P" . popper-toggle-type) ; Toggle popups of specific type
204 ("C-p" . popper-cycle))) ; Cycle through visible popups
205#+end_src
206
207With this setup, you can use Popper commands (like =popper-toggle= or =popper-cycle=) to quickly hide/show/cycle through the side windows managed by =auto-side-windows=.
208
209Additionally, the following custom command allows you to switch to arbitrary buried popup buffers:
210
211#+begin_src emacs-lisp
212 (defun my/popper-switch-to-buried-buffer (buffer)
213 "Switch to buried popup BUFFER."
214 (interactive
215 (list
216 (when-let ((buried-popups (progn (popper--find-buried-popups)
217 (mapcar #'cdr
218 (alist-get (funcall popper-group-function)
219 popper-buried-popup-alist nil nil 'equal))))
220 (pred (lambda (b)
221 (if (consp b) (setq b (car b)))
222 (setq b (get-buffer b))
223 (member b buried-popups))))
224 (read-buffer "Switch to popup: " nil t pred))))
225 (if buffer (display-buffer buffer)
226 (message "No buried popups.")))
227 #+end_src
228
229Just add it to the =:preface= section of the above =use-package= declaration and optionally bind it to a key.
230
231*** Ace Window Integration
232
233[[https://github.com/abo-abo/ace-window][Ace Window]] can serve as a fallback mechanism for selecting a window when =display-buffer= doesn't find a suitable existing window or rule (including those from =auto-side-windows=).
234
235Modify =display-buffer-base-action= to include =ace-display-buffer=. This tells Emacs to use Ace Window to ask you where to put a buffer if other methods fail.
236
237 #+begin_src emacs-lisp
238 (use-package ace-window
239 :custom
240 (display-buffer-base-action '(display-buffer-reuse-window
241 display-buffer-in-previous-window
242 ace-display-buffer))) ; Ask user via ace-window
243 #+end_src
244
245Now, if a command tries to display a buffer and no =auto-side-windows= rule applies and standard reuse fails, =ace-display-buffer= will trigger, letting you pick the window.
246
247*** Enhancing =magit= and =org-mode= compatibility
248
249To further enhance the Emacs experience with =auto-side-windows=, consider adding these configurations:
250
251#+begin_src emacs-lisp
252 ;; Org mode: Ensure agenda buffers open in the top side window for easy access
253 (setopt org-src-window-setup 'plain)
254 (setopt auto-side-windows-top-buffer-names '("^\\*Org Agenda\\*$"
255 "^\\*Org Src.*\\*"
256 "^\\*Org-Babel Error Output\\*"
257 ...)))
258
259 ;; Magit: Display Magit diff/status in the right side window, edit commit msg on top
260 (setopt magit-display-buffer-function #'display-buffer
261 magit-commit-diff-inhibit-same-window t)
262 (setopt auto-side-windows-right-buffer-names '("^magit-diff:.*$"
263 "^magit-process:.*$"
264 ...))
265 (setopt auto-side-windows-right-buffer-modes '(magit-status-mode
266 magit-log-mode
267 magit-diff-mode
268 magit-process-mode
269 ...))
270 (setopt auto-side-windows-top-buffer-names
271 '("^COMMIT_EDITMSG$"
272 ...))
273#+end_src
274
275These configurations integrate well with =auto-side-windows= and enhance buffer management for specific use cases in Emacs.
276
277** Comparison with Other Packages
278
279While several packages address window management, =auto-side-windows= has a specific focus:
280
281*** Shackle
282[[https://depp.brause.cc/shackle/][Shackle]] is a powerful package for finely controlling how and where popup windows appear, including options for creating new frames or specifying precise window parameters. It's very flexible and can involve more complex rule definitions.
283
284*Difference:* =auto-side-windows= focuses *specifically* on simplifying the common use case of assigning buffers to *side windows* within the *current frame* based on simple name/mode matching, acting as a high-level interface to =display-buffer-alist= for this purpose.
285
286*** Popper
287[[https://github.com/karthink/popper][Popper]] excels at *managing* buffers that are already considered "popups". It allows you to quickly toggle, cycle through, and manage the visibility of these popup windows.
288
289*Difference:* =auto-side-windows= *defines which buffers should become* side windows in the first place. Popper can then be configured to *manage* these side windows created by =auto-side-windows= rules (see [[#popper-integration][Popper Integration]]). They work well together.
290
291*** Core Emacs (=display-buffer-alist=)
292Emacs' built-in =display-buffer-alist= is the underlying mechanism for controlling buffer display. It's extremely powerful but requires writing potentially complex alist structures.
293
294*Difference:* =auto-side-windows= acts as a configuration layer *on top of* =display-buffer-alist=. It generates the necessary alist entries for side window rules based on user-friendly customization variables, reducing the need to write the raw alist entries manually for this common pattern.
295
296** Bonus: Boxes around top windows
297
298Inspired by [[https://www.reddit.com/r/emacs/comments/1hoehaa/boxes_everywhere/][u/Nicolas-Rougier's post]], you can add customized header lines to side windows for better visual distinction.
299To resemble the example shown in the screenshot add this to your configuration:
300
301#+begin_src emacs-lisp
302 (use-package auto-side-windows
303 :ensure (:host github :repo "MArpogaus/auto-side-windows")
304 :preface
305 (defun my/get-header-line-icon-for-buffer (buffer)
306 (with-current-buffer buffer
307 (unless (boundp 'header-line-icon)
308 (setq-local header-line-icon
309 (cond
310 ((buffer-match-p "Warning" buffer) '(" ! " . warning))
311 ((buffer-match-p '(or "^\\*Backtrace\\*$" ".*[Ee]rror.*") buffer) '(" ! " . error))
312 ((buffer-match-p '(or "^COMMIT_EDITMSG$" "^\\*diff-hl\\*$") buffer) '(" " . success))
313 ((buffer-match-p "^\\*Org Src.*\\*" buffer) '(" " . mode-line-emphasis))
314 ((buffer-match-p "^\\*Org Agenda\\*$" buffer) '(" " . mode-line-emphasis))
315 (t '(" ? " . mode-line-emphasis)))))
316 header-line-icon))
317 (defun my/install-top-side-window-face-remaps (buffer foreground background)
318 (with-current-buffer buffer
319 (unless (bound-and-true-p top-side-window-face-remaps-cookies)
320 (setq-local top-side-window-face-remaps-cookies
321 (list
322 (face-remap-add-relative 'header-line
323 `(:box nil :underline nil :overline ,background))
324 (face-remap-add-relative 'fringe
325 `(:background ,background))
326 (face-remap-add-relative 'mode-line-active
327 `(:overline ,background :underline nil :height 0))
328 (face-remap-add-relative 'mode-line-inactive
329 `(:overline ,background :underline nil :height 0))
330 )))))
331 (defvar my/header-line-format-top
332 '(:eval
333 (let*
334 ((buffer (current-buffer))
335 (prefix-and-face (my/get-header-line-icon-for-buffer buffer))
336 (prefix (car prefix-and-face))
337 (background (face-foreground (cdr prefix-and-face)))
338 (foreground (face-background (cdr prefix-and-face) nil 'default))
339 (prefix-face `((t :inherit bold :background ,background :foreground ,foreground)))
340 (buffer-face `((t :inherit bold :foreground ,background))))
341 (set-window-fringes nil 1 1 t)
342 ;; (set-window-margins nil 1 1)
343 (my/install-top-side-window-face-remaps buffer foreground background)
344 (list
345 (propertize prefix 'face prefix-face 'display '(space-width 0.7))
346 (propertize (format-mode-line " %b ") 'face buffer-face)
347 (propertize " " 'display `(space :align-to right))
348 (propertize " " 'face prefix-face 'display '(space-width 1))))))
349 :custom
350 ;; Draw boxes around top side windows
351 (auto-side-windows-top-window-parameters `((mode-line-format . t)
352 (header-line-format . ,my/header-line-format-top)))
353 (auto-side-windows-before-display-hook '((lambda (buffer)
354 (with-current-buffer buffer
355 (when (bound-and-true-p top-side-window-face-remaps-cookies)
356 (dolist (cookie top-side-window-face-remaps-cookies)
357 (face-remap-remove-relative cookie))
358 (kill-local-variable 'top-side-window-face-remaps-cookies))))))
359 (auto-side-windows-before-toggle-hook auto-side-windows-before-display-hook))
360#+end_src
361
362*Note:* Complex face remapping in header lines might have side effects (e.g., affecting Corfu popup fringes).
363
364** Contributions
365
366Contributions to the =auto-side-windows= package are greatly appreciated!
367Feel free to check the [[https://github.com/MArpogaus/auto-side-windows/issues][issues page]] or submit a [[https://github.com/MArpogaus/auto-side-windows/pulls][pull request]].
368
369** License
370
371Distributed under the [[file:COPYING][GPLv3]] License.
372
373** Contact
374
375[[https://github.com/MArpogaus/][Marcel Arpogaus]] - [[mailto:znepry.necbtnhf@tznvy.pbz][znepry.necbtnhf@tznvy.pbz]] (encrypted with [ROT13](https://rot13.com/))
376
377Project Link:
378[[https://github.com/MArpogaus/auto-side-windows]]