Skip to content

Commit 77bcf55

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 a8ccb3d commit 77bcf55

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
@@ -400,13 +411,121 @@ Restore the help menu only if it is currently open."
400411
(resize-window--display-menu 'open)
401412
(resize-window--add-backgrounds)))))
402413

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

407501
(defun resize-window--window-pop ()
408-
"Return the first element and remove it from the stack."
409-
(pop resize-window--window-stack))
502+
"Shift to a previous window configuration.
503+
Return the configuration shifted to if any.
504+
505+
Save the current configuration to the tail of the stack.
506+
507+
Trim adjacent duplicates and old configurations when necessary.
508+
509+
See also `resize-window-stack-size'."
510+
(resize-window--window-trim)
511+
(let* ((curr-config (resize-window--window-config))
512+
(curr-member (cons curr-config (current-time)))
513+
(prev-config nil))
514+
;; trim duplicates from the tail
515+
(while (and (setq prev-config (caar (last resize-window--window-stack)))
516+
(setq prev-config (resize-window--apply-config prev-config))
517+
(compare-window-configurations curr-config prev-config)
518+
(setq resize-window--window-stack
519+
(nbutlast resize-window--window-stack))))
520+
;; trim duplicates from the head
521+
(while (and (setq prev-config (car (pop resize-window--window-stack)))
522+
(setq prev-config (resize-window--apply-config prev-config))
523+
(compare-window-configurations curr-config prev-config)))
524+
(when prev-config
525+
(setq resize-window--window-stack
526+
(append resize-window--window-stack (list curr-member)))
527+
(resize-window--restore-config prev-config)
528+
prev-config)))
410529

411530
(defun resize-window--kill-other-windows ()
412531
"Delete other windows."

0 commit comments

Comments
 (0)