nftable-migration
1;;; config-windows.el --- -*- lexical-binding: t; -*-
2;; Commentary:
3;;; Windows configuration
4;; Code:
5
6(setq switch-to-buffer-obey-display-actions t)
7
8(defun vde/window-delete-popup-frame (&rest _)
9 "Kill selected selected frame if it has parameter `prot-window-popup-frame'.
10Use this function via a hook."
11 (when (frame-parameter nil 'vde/window-popup-frame)
12 (delete-frame)))
13
14(defun vde/save-desktop-no-ask ()
15 "Save the desktop without asking questions by modifying the modtime."
16 (interactive)
17 (require 'desktop)
18 (desktop--get-file-modtime)
19 (desktop-save (concat desktop-dirname)))
20(defun vde/desktop-load ()
21 "Load saved desktop"
22 (interactive)
23 (require 'desktop)
24 (desktop-read desktop-dirname))
25
26(bind-key "C-c d s" #'vde/save-desktop-no-ask)
27(bind-key "C-c d l" #'vde/desktop-load)
28
29;; Winner
30(use-package winner
31 :unless noninteractive
32 :defer 5
33 :config
34 (winner-mode 1))
35;; -UseWinner
36
37(defun toggle-maximize-buffer ()
38 "Maximize buffer"
39 (interactive)
40 (if (one-window-p)
41 (winner-undo)
42 (delete-other-windows)))
43
44;; UseAceWindow
45(use-package ace-window
46 :unless noninteractive
47 :commands (ace-window ace-swap-window)
48 :bind (("C-x o" . ace-window)
49 ("C-c w w" . ace-window)
50 ("C-c w s" . ace-swap-window))
51 :config
52 (setq-default aw-keys '(?a ?u ?i ?e ?, ?c ?t ?r ?m)
53 aw-scope 'frame
54 aw-dispatch-always t
55 aw-dispatch-alist
56 '((?s aw-swap-window "Swap Windows")
57 (?2 aw-split-window-vert "Split Window Vertically")
58 (?3 aw-split-window-horz "Split Window Horizontally")
59 (?? aw-show-dispatch-help))
60 aw-minibuffer-flag t
61 aw-ignore-current nil
62 aw-display-mode-overlay t
63 aw-background t))
64;; -UseAceWindow
65
66;; UseWindmove
67(use-package windmove
68 :unless noninteractive
69 :commands (windmove-left windmove-right windmove-down windmove-up)
70 :custom
71 (windmove-allow-all-windows t)
72 :bind (("C-M-<up>" . windmove-up)
73 ("C-M-<right>" . windmove-right)
74 ("C-M-<down>" . windmove-down)
75 ("C-M-<left>" . windmove-left)))
76;; -UseWindmove
77
78;; UseWindow
79(use-package window
80 :unless noninteractive
81 :commands (shrink-window-horizontally shrink-window enlarge-window-horizontally enlarge-window)
82 :bind (("S-C-<left>" . shrink-window-horizontally)
83 ("S-C-<right>" . enlarge-window-horizontally)
84 ("S-C-<down>" . shrink-window)
85 ("S-C-<up>" . enlarge-window)))
86;; -UseWindow
87
88;;;###autoload
89(defun prot-common-window-small-p ()
90 "Return non-nil if window is small.
91Check if the `window-width' or `window-height' is less than
92`split-width-threshold' and `split-height-threshold',
93respectively."
94 (or (and (numberp split-width-threshold)
95 (< (window-total-width) split-width-threshold))
96 (and (numberp split-height-threshold)
97 (> (window-total-height) split-height-threshold))))
98
99(defun prot-common-three-or-more-windows-p (&optional frame)
100 "Return non-nil if three or more windows occupy FRAME.
101If FRAME is non-nil, inspect the current frame."
102 (>= (length (window-list frame :no-minibuffer)) 3))
103
104(defun prot-window--get-display-buffer-below-or-pop ()
105 "Return list of functions for `prot-window-display-buffer-below-or-pop'."
106 (list
107 #'display-buffer-reuse-mode-window
108 (if (or (prot-common-window-small-p)
109 (prot-common-three-or-more-windows-p))
110 #'display-buffer-below-selected
111 #'display-buffer-pop-up-window)))
112
113(defun prot-window-display-buffer-below-or-pop (&rest args)
114 "Display buffer below current window or pop a new window.
115The criterion for choosing to display the buffer below the
116current one is a non-nil return value for
117`prot-common-window-small-p'.
118
119Apply ARGS expected by the underlying `display-buffer' functions.
120
121This as the action function in a `display-buffer-alist' entry."
122 (let ((functions (prot-window--get-display-buffer-below-or-pop)))
123 (catch 'success
124 (dolist (fn functions)
125 (when (apply fn args)
126 (throw 'success fn))))))
127
128(defvar prot-window-window-sizes
129 '( :max-height (lambda () (floor (frame-height) 3))
130 :min-height 10
131 :max-width (lambda () (floor (frame-width) 4))
132 :min-width 20)
133 "Property list of maximum and minimum window sizes.
134The property keys are `:max-height', `:min-height', `:max-width',
135and `:min-width'. They all accept a value of either a
136number (integer or floating point) or a function.")
137
138(defun prot-window--get-window-size (key)
139 "Extract the value of KEY from `prot-window-window-sizes'."
140 (when-let ((value (plist-get prot-window-window-sizes key)))
141 (cond
142 ((functionp value)
143 (funcall value))
144 ((numberp value)
145 value)
146 (t
147 (error "The value of `%s' is neither a number nor a function" key)))))
148
149(defun prot-window-select-fit-size (window &rest _)
150 "Select WINDOW and resize it.
151The resize pertains to the maximum and minimum values for height
152and width, per `prot-window-window-sizes'.
153
154Use this as the `body-function' in a `display-buffer-alist' entry."
155 (select-window window)
156 (fit-window-to-buffer
157 window
158 (prot-window--get-window-size :max-height)
159 (prot-window--get-window-size :min-height)
160 (prot-window--get-window-size :max-width)
161 (prot-window--get-window-size :min-width)))
162
163(defun prot-window-shell-or-term-p (buffer &rest _)
164 "Check if BUFFER is a shell or terminal.
165This is a predicate function for `buffer-match-p', intended for
166use in `display-buffer-alist'."
167 (when (string-match-p "\\*.*\\(e?shell\\|v?term\\).*" (buffer-name (get-buffer buffer)))
168 (with-current-buffer buffer
169 ;; REVIEW 2022-07-14: Is this robust?
170 (and (not (derived-mode-p 'message-mode 'text-mode))
171 (derived-mode-p 'eshell-mode 'shell-mode 'comint-mode 'fundamental-mode)))))
172
173;; (setq display-buffer-alist
174;; `(;; Default to no window
175;; ("\\`\\*Async Shell Command\\*\\'"
176;; (display-buffer-no-window))
177;; ("\\`\\*Warnings\\*\\'"
178;; (display-buffer-no-window)
179;; (allow-no-window . t))
180;; ("\\`\\*\\(Compile-Log\\|Org Links\\)\\*\\'"
181;; (display-buffer-no-window))
182;; ;; bottom side window
183;; ("\\*Org \\(Select\\|Note\\)\\*" ; the `org-capture' key selection and `org-add-log-note'
184;; (display-buffer-in-side-window)
185;; (dedicated . t)
186;; (side . bottom)
187;; (slot . 0)
188;; (window-parameters . ((mode-line-format . none))))
189;; ;; bottom buffer (NOT side window)
190;; ((or . ((derived-mode . flymake-diagnostics-buffer-mode)
191;; (derived-mode . flymake-project-diagnostics-mode)
192;; (derived-mode . messages-buffer-mode)
193;; (derived-mode . backtrace-mode)))
194;; (display-buffer-reuse-mode-window display-buffer-at-bottom)
195;; (window-height . 0.3)
196;; (dedicated . t)
197;; (preserve-size . (t . t)))
198;; ;; ((or . ((derived-mode . Man-mode)
199;; ;; (derived-mode . woman-mode)
200;; ;; "\\*\\(Man\\|woman\\).*"))
201;; ;; (display-buffer-reuse-mode-window display-buffer-below-selected)
202;; ;; (window-height . 0.3) ; note this is literal lines, not relative
203;; ;; (dedicated . t)
204;; ;; (preserve-size . (t . t)))
205;; ;; below current window
206;; ("\\(\\*Capture\\*\\|CAPTURE-.*\\)"
207;; (display-buffer-reuse-mode-window display-buffer-below-selected))
208;; ((derived-mode . reb-mode) ; M-x re-builder
209;; (display-buffer-reuse-mode-window display-buffer-below-selected)
210;; (window-height . 4) ; note this is literal lines, not relative
211;; (dedicated . t)
212;; (preserve-size . (t . t)))
213;; ((or . ((derived-mode . occur-mode)
214;; (derived-mode . grep-mode)
215;; (derived-mode . Buffer-menu-mode)
216;; (derived-mode . log-view-mode)
217;; (derived-mode . helpful-mode)
218;; (derived-mode . help-mode) ; See the hooks for `visual-line-mode'
219;; "\\*\\(|Buffer List\\|Occur\\|vc-change-log\\).*"
220;; prot-window-shell-or-term-p
221;; ,world-clock-buffer-name))
222;; (prot-window-display-buffer-below-or-pop)
223;; (dedicated . t)
224;; (body-function . prot-window-select-fit-size))
225;; ))
226
227(use-package auto-side-windows
228 :custom
229 ;; Top side window configurations
230 (auto-side-windows-top-buffer-names
231 '("^\\*Backtrace\\*$" "^\\*Compile-Log\\*$" "^COMMIT_EDITMSG$"
232 "^\\*Org Src.*\\*" "^\\*Agenda Commands\\*$" "^\\*Org Agenda\\*$"
233 "^\\*Quick Help\\*$" "^\\*Multiple Choice Help\\*$" "^\\*TeX Help\\*$"
234 "^\\*TeX errors\\*$" "^\\*Warnings\\*$" "^\\*diff-hl\\*$"
235 "^\\*Process List\\*$"))
236 (auto-side-windows-top-buffer-modes
237 '(flymake-diagnostics-buffer-mode locate-mode occur-mode grep-mode
238 xref--xref-buffer-mode))
239
240 ;; Bottom side window configurations
241 (auto-side-windows-bottom-buffer-names
242 '("^\\*.*eshell.*\\*$" "^\\*.*shell.*\\*$" "^\\*.*term.*\\*$"
243 "^\\*.*vterm.*\\*$" "^\\*.*eat.*\\*$"))
244 (auto-side-windows-bottom-buffer-modes
245 '(eshell-mode shell-mode term-mode vterm-mode comint-mode compilation-mode debugger-mode))
246
247 ;; Right side window configurations
248 (auto-side-windows-right-buffer-names
249 '("^\\*eldoc.*\\*$" "^\\*info\\*$" "^\\*Metahelp\\*$"))
250 (auto-side-windows-right-buffer-modes
251 '(Info-mode TeX-output-mode pdf-view-mode eldoc-mode help-mode
252 helpful-mode shortdoc-mode))
253
254 ;; Example: Custom parameters for top windows (e.g., fit height to buffer)
255 ;; (auto-side-windows-top-alist '((window-height . fit-window-to-buffer)))
256 ;; (auto-side-windows-top-window-parameters '((mode-line-format . ...))) ;; Adjust mode-line
257
258 ;; Maximum number of side windows on the left, top, right and bottom
259 (window-sides-slots '(1 1 1 1)) ; Example: Allow one window per side
260
261 ;; Force left and right side windows to occupy full frame height
262 (window-sides-vertical t)
263 (window-combination-resize t)
264
265 ;; Make changes to tab-/header- and mode-line-format persistent when toggleling windows visibility
266 (window-persistent-parameters
267 (append window-persistent-parameters
268 '((tab-line-format . t)
269 (header-line-format . t)
270 (mode-line-format . t))))
271 :bind ;; Example keybindings (adjust prefix as needed)
272 (:map global-map ; Or your preferred keymap prefix
273 ("C-c w t" . auto-side-windows-display-buffer-top)
274 ("C-c w b" . auto-side-windows-display-buffer-bottom)
275 ("C-c w l" . auto-side-windows-display-buffer-left)
276 ("C-c w r" . auto-side-windows-display-buffer-right)
277 ("C-c w T" . auto-side-windows-toggle-side-window)) ; Toggle current buffer in/out of side window
278 :hook
279 (after-init . auto-side-windows-mode)) ; Activate the mode
280
281(use-package popper
282 :after auto-side-windows ; Ensure auto-side-windows variables are defined
283 :hook (auto-side-windows-mode . popper-mode) ; Activate popper alongside
284 :custom
285 ;; Tell Popper to consider buffers matching auto-side-windows rules as popups
286 (popper-reference-buffers
287 (append auto-side-windows-top-buffer-names auto-side-windows-top-buffer-modes
288 auto-side-windows-left-buffer-names auto-side-windows-left-buffer-modes
289 auto-side-windows-right-buffer-names auto-side-windows-right-buffer-modes
290 auto-side-windows-bottom-buffer-names auto-side-windows-bottom-buffer-modes))
291 ;; Optional: Don't let Popper decide where to display, auto-side-windows handles that
292 (popper-display-control nil) ; Or 'user if you prefer popper commands for display
293 :config
294 (require 'popper-echo)
295 (popper-mode +1) ; Enable popper-mode
296 (popper-echo-mode +1) ; Optional: echo area notifications
297 :bind
298 (("C-`" . popper-toggle)
299 ("C-M-`" . popper-toggle-type)
300 ("M-`" . popper-cycle)))
301;; TODO: Move display-buffer-alist here
302
303(provide 'config-windows)
304;;; config-windows ends here