Skip to content

Commit f37ecd9

Browse files
committed
Window configurations stack management
The stack size is now customizable. Always remove the oldest window configurations in excess to respect the stack size. Avoid stack duplicates and add the current window configuration to the tail of the stack before reverting to a previous configuration. Update: - readme.md
1 parent 622f9be commit f37ecd9

File tree

2 files changed

+125
-5
lines changed

2 files changed

+125
-5
lines changed

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ There are a few things that you can do. There are customizable variables:
6565
- resize-window-fine-argument (default: 1)
6666
- resize-window-allow-backgrounds (default: t)
6767
- resize-window-unregistered-key-quit (default: nil)
68+
- resize-window-stack-size (default: 16)
6869
- resize-window-swap-capital-and-lowercase-behavior (default: nil)
6970
- resize-window-notify-with-messages (default: t)
7071

resize-window.el

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ If nil do not quit and notify the unregistered key pressed."
8888
:type 'boolean
8989
:group 'resize-window)
9090

91+
(defcustom resize-window-stack-size 16
92+
"Size of the stack for holding window configurations."
93+
:type 'integer
94+
:group 'resize-window)
95+
9196
(defcustom resize-window-swap-capital-and-lowercase-behavior nil
9297
"Reverse default behavior of lower case and uppercase arguments."
9398
:type 'boolean
@@ -102,7 +107,10 @@ If nil do not quit and notify the unregistered key pressed."
102107
"List of background overlays.")
103108

104109
(defvar resize-window--window-stack ()
105-
"Stack for holding window configurations.")
110+
"Stack for holding window configurations.
111+
112+
It is an alist of format ((configuration . time)...), where time
113+
is the time when the configuration was saved/visited.")
106114

107115
(defface resize-window-background
108116
'((t (:foreground "gray40")))
@@ -247,6 +255,9 @@ If SCALED, then call action with the `resize-window-uppercase-argument'."
247255
Press n to resize down, p to resize up, b to resize left and f
248256
to resize right."
249257
(interactive)
258+
(resize-window--refresh-stack)
259+
;; NOTE: Do not trim the stack here. Let stack requests to handle
260+
;; window configurations in excess.
250261
(resize-window--add-backgrounds)
251262
(resize-window--notify "Resize mode: enter character, ? for help")
252263
(condition-case nil
@@ -408,13 +419,121 @@ Restore the help menu only if it is currently open."
408419
(resize-window--display-menu 'open)
409420
(resize-window--add-backgrounds)))))
410421

422+
(defun resize-window--apply-config (config)
423+
"Return the window configuration CONFIG after applying it.
424+
Return nil if CONFIG isn't a proper window configuration.
425+
Do not change the current window configuration."
426+
(when (window-configuration-p config)
427+
(let ((curr-frame (selected-frame))
428+
(some-frame (window-configuration-frame config))
429+
(some-config config))
430+
(when (frame-live-p some-frame)
431+
(select-frame some-frame)
432+
(save-excursion
433+
(save-window-excursion
434+
(set-window-configuration config)
435+
(setq some-config (resize-window--window-config))))
436+
(select-frame curr-frame))
437+
some-config)))
438+
439+
(defun resize-window--refresh-stack ()
440+
"Refresh the stack and remove adjacent duplicates.
441+
Each window configuration is restored and saved again.
442+
443+
The configurations saved time is not changed. Always remove the
444+
older configuration when a duplicate is found.
445+
446+
A refresh reveals duplicate configurations. When a configuration
447+
is restored that takes account of the current state of the frame.
448+
Since killed buffers cannot be dug up, applying a state will use
449+
what it finds, and so two configurations may end up the same."
450+
(let (stack)
451+
(dotimes (n (length resize-window--window-stack))
452+
(let* ((this-member (nth n resize-window--window-stack))
453+
(this-config (resize-window--apply-config (car this-member)))
454+
(this-svtime (cdr this-member))
455+
(prev-config (caar stack))
456+
(prev-svtime (cdar stack)))
457+
(if (and this-config prev-config
458+
(compare-window-configurations this-config prev-config))
459+
(when (time-less-p prev-svtime this-svtime)
460+
(setcar stack this-member))
461+
(when this-config
462+
(push this-member stack)))))
463+
(setq resize-window--window-stack (nreverse stack))))
464+
465+
(defun resize-window--window-trim ()
466+
"Trim the oldest window configurations in excess from the stack.
467+
Return the removed stack members."
468+
(let* ((size (length resize-window--window-stack))
469+
(trim (- size resize-window-stack-size)))
470+
(when (> trim 0)
471+
(let ((oldest-members
472+
(sort (copy-sequence resize-window--window-stack)
473+
(lambda (a b)
474+
(time-less-p (cdr a) (cdr b))))))
475+
(setq oldest-members
476+
(nbutlast oldest-members (- size trim)))
477+
(dotimes (n (length oldest-members))
478+
(let ((old-member (nth n oldest-members)))
479+
(setq resize-window--window-stack
480+
(delq old-member resize-window--window-stack))))
481+
oldest-members))))
482+
411483
(defun resize-window--window-push ()
412-
"Save the current state in the stack."
413-
(push (resize-window--window-config) resize-window--window-stack))
484+
"Save the current window configuration in the stack.
485+
Return its stack member if the configuration is saved.
486+
487+
Trim adjacent duplicates and old configurations when necessary.
488+
489+
See also `resize-window-stack-size'."
490+
(let* ((curr-config (resize-window--window-config))
491+
(curr-member (cons curr-config (current-time)))
492+
(prev-config nil))
493+
;; trim duplicates from the tail
494+
(while (and (setq prev-config (caar (last resize-window--window-stack)))
495+
(setq prev-config (resize-window--apply-config prev-config))
496+
(compare-window-configurations curr-config prev-config)
497+
(setq resize-window--window-stack
498+
(nbutlast resize-window--window-stack))))
499+
;; trim duplicates from the head
500+
(while (and (setq prev-config (caar resize-window--window-stack))
501+
(setq prev-config (resize-window--apply-config prev-config))
502+
(compare-window-configurations curr-config prev-config)
503+
(pop resize-window--window-stack)))
504+
(push curr-member resize-window--window-stack)
505+
(resize-window--window-trim)
506+
(when resize-window--window-stack
507+
curr-member)))
414508

415509
(defun resize-window--window-pop ()
416-
"Return the first element and remove it from the stack."
417-
(pop resize-window--window-stack))
510+
"Shift to a previous window configuration.
511+
Return the configuration shifted to if any.
512+
513+
Save the current configuration to the tail of the stack.
514+
515+
Trim adjacent duplicates and old configurations when necessary.
516+
517+
See also `resize-window-stack-size'."
518+
(resize-window--window-trim)
519+
(let* ((curr-config (resize-window--window-config))
520+
(curr-member (cons curr-config (current-time)))
521+
(prev-config nil))
522+
;; trim duplicates from the tail
523+
(while (and (setq prev-config (caar (last resize-window--window-stack)))
524+
(setq prev-config (resize-window--apply-config prev-config))
525+
(compare-window-configurations curr-config prev-config)
526+
(setq resize-window--window-stack
527+
(nbutlast resize-window--window-stack))))
528+
;; trim duplicates from the head
529+
(while (and (setq prev-config (car (pop resize-window--window-stack)))
530+
(setq prev-config (resize-window--apply-config prev-config))
531+
(compare-window-configurations curr-config prev-config)))
532+
(when prev-config
533+
(setq resize-window--window-stack
534+
(append resize-window--window-stack (list curr-member)))
535+
(resize-window--restore-config prev-config)
536+
prev-config)))
418537

419538
(defun resize-window--kill-other-windows ()
420539
"Delete other windows."

0 commit comments

Comments
 (0)