Skip to content

Commit 17486e1

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.
1 parent c2e4ba8 commit 17486e1

File tree

1 file changed

+114
-5
lines changed

1 file changed

+114
-5
lines changed

resize-window.el

Lines changed: 114 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ This is also valuable to see that you are in resize mode."
8282
:type 'boolean
8383
:group 'resize-window)
8484

85+
(defcustom resize-window-stack-size 16
86+
"Size of the stack for holding window configurations."
87+
:type 'integer
88+
:group 'resize-window)
89+
8590
(defcustom resize-window-swap-capital-and-lowercase-behavior nil
8691
"Reverse default behavior of lower case and uppercase arguments."
8792
:type 'boolean
@@ -96,7 +101,10 @@ This is also valuable to see that you are in resize mode."
96101
"List of background overlays.")
97102

98103
(defvar resize-window--window-stack ()
99-
"Stack for holding window configurations.")
104+
"Stack for holding window configurations.
105+
106+
It is an alist of format ((configuration . time)...), where time
107+
is the time when the configuration was saved/visited.")
100108

101109
(defface resize-window-background
102110
'((t (:foreground "gray40")))
@@ -241,6 +249,9 @@ If SCALED, then call action with the `resize-window-uppercase-argument'."
241249
Press n to resize down, p to resize up, b to resize left and f
242250
to resize right."
243251
(interactive)
252+
(resize-window--refresh-stack)
253+
;; NOTE: Do not trim the stack here. Let stack requests to handle
254+
;; window configurations in excess.
244255
(resize-window--add-backgrounds)
245256
(resize-window--notify "Resize mode: enter character, ? for help")
246257
(condition-case nil
@@ -391,13 +402,111 @@ Restore the help menu only if it is currently open."
391402
(resize-window--display-menu 'open)
392403
(resize-window--add-backgrounds)))))
393404

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

398483
(defun resize-window--window-pop ()
399-
"Return the first element and remove it from the stack."
400-
(pop resize-window--window-stack))
484+
"Restore a previous window configuration.
485+
Return the configuration if restored.
486+
487+
Save the current configuration to the tail of the stack.
488+
489+
Trim adjacent duplicates and old configurations when necessary.
490+
491+
See also `resize-window-stack-size'."
492+
(resize-window--window-trim)
493+
(let* ((curr-config (resize-window--window-config))
494+
(curr-member (cons curr-config (current-time)))
495+
(prev-config nil))
496+
;; trim duplicates from the tail
497+
(while (and (setq prev-config (caar (last resize-window--window-stack)))
498+
(setq prev-config (resize-window--apply-config prev-config))
499+
(compare-window-configurations curr-config prev-config)
500+
(nbutlast resize-window--window-stack)))
501+
;; trim duplicates from the head
502+
(while (and (setq prev-config (car (pop resize-window--window-stack)))
503+
(setq prev-config (resize-window--apply-config prev-config))
504+
(compare-window-configurations curr-config prev-config)))
505+
(when prev-config
506+
(setq resize-window--window-stack
507+
(append resize-window--window-stack (list curr-member)))
508+
(resize-window--restore-config prev-config)
509+
prev-config)))
401510

402511
(defun resize-window--kill-other-windows ()
403512
"Delete other windows."

0 commit comments

Comments
 (0)