@@ -88,6 +88,11 @@ If nil do not quit and notify the unregistered key pressed."
88
88
:type 'boolean
89
89
:group 'resize-window )
90
90
91
+ (defcustom resize-window-stack-size 16
92
+ " Size of the stack for holding window configurations."
93
+ :type 'integer
94
+ :group 'resize-window )
95
+
91
96
(defcustom resize-window-swap-capital-and-lowercase-behavior nil
92
97
" Reverse default behavior of lower case and uppercase arguments."
93
98
:type 'boolean
@@ -102,7 +107,10 @@ If nil do not quit and notify the unregistered key pressed."
102
107
" List of background overlays." )
103
108
104
109
(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." )
106
114
107
115
(defface resize-window-background
108
116
'((t (:foreground " gray40" )))
@@ -247,6 +255,9 @@ If SCALED, then call action with the `resize-window-uppercase-argument'."
247
255
Press n to resize down, p to resize up, b to resize left and f
248
256
to resize right."
249
257
(interactive )
258
+ (resize-window--refresh-stack)
259
+ ; ; NOTE: Do not trim the stack here. Let stack requests to handle
260
+ ; ; window configurations in excess.
250
261
(resize-window--add-backgrounds)
251
262
(resize-window--notify " Resize mode: enter character, ? for help" )
252
263
(condition-case nil
@@ -409,13 +420,121 @@ Restore the help menu only if it is currently open."
409
420
(resize-window--display-menu 'open )
410
421
(resize-window--add-backgrounds)))))
411
422
423
+ (defun resize-window--apply-config (config )
424
+ " Return the window configuration CONFIG after applying it.
425
+ Return nil if CONFIG isn't a proper window configuration.
426
+ Do not change the current window configuration."
427
+ (when (window-configuration-p config)
428
+ (let ((curr-frame (selected-frame ))
429
+ (some-frame (window-configuration-frame config))
430
+ (some-config config))
431
+ (when (frame-live-p some-frame)
432
+ (select-frame some-frame)
433
+ (save-excursion
434
+ (save-window-excursion
435
+ (set-window-configuration config)
436
+ (setq some-config (resize-window--window-config))))
437
+ (select-frame curr-frame))
438
+ some-config)))
439
+
440
+ (defun resize-window--refresh-stack ()
441
+ " Refresh the stack and remove adjacent duplicates.
442
+ Each window configuration is restored and saved again.
443
+
444
+ The configurations saved time is not changed. Always remove the
445
+ older configuration when a duplicate is found.
446
+
447
+ A refresh reveals duplicate configurations. When a configuration
448
+ is restored that takes account of the current state of the frame.
449
+ Since killed buffers cannot be dug up, applying a state will use
450
+ what it finds, and so two configurations may end up the same."
451
+ (let (stack-buffer)
452
+ (dotimes (n (length resize-window--window-stack))
453
+ (let* ((this-member (nth n resize-window--window-stack))
454
+ (this-config (resize-window--apply-config (car this-member)))
455
+ (this-svtime (cdr this-member))
456
+ (prev-config (caar stack-buffer))
457
+ (prev-svtime (cdar stack-buffer)))
458
+ (if (and this-config prev-config
459
+ (compare-window-configurations this-config prev-config))
460
+ (when (time-less-p prev-svtime this-svtime)
461
+ (setcar stack-buffer this-member))
462
+ (when this-config
463
+ (push this-member stack-buffer)))))
464
+ (setq resize-window--window-stack (nreverse stack-buffer))))
465
+
466
+ (defun resize-window--window-trim ()
467
+ " Trim the oldest window configurations in excess from the stack.
468
+ Return the removed stack members."
469
+ (let* ((size (length resize-window--window-stack))
470
+ (trim (- size resize-window-stack-size)))
471
+ (when (> trim 0 )
472
+ (let ((oldest-members
473
+ (sort (copy-sequence resize-window--window-stack)
474
+ (lambda (a b )
475
+ (time-less-p (cdr a) (cdr b))))))
476
+ (setq oldest-members
477
+ (nbutlast oldest-members (- size trim)))
478
+ (dotimes (n (length oldest-members))
479
+ (let ((old-member (nth n oldest-members)))
480
+ (setq resize-window--window-stack
481
+ (delq old-member resize-window--window-stack))))
482
+ oldest-members))))
483
+
412
484
(defun resize-window--window-push ()
413
- " Save the current state in the stack."
414
- (push (resize-window--window-config) resize-window--window-stack))
485
+ " Save the current window configuration in the stack.
486
+ Return its stack member if the configuration is saved.
487
+
488
+ Trim adjacent duplicates and old configurations when necessary.
489
+
490
+ See also `resize-window-stack-size' ."
491
+ (let* ((curr-config (resize-window--window-config))
492
+ (curr-member (cons curr-config (current-time )))
493
+ (prev-config nil ))
494
+ ; ; trim duplicates from the tail
495
+ (while (and (setq prev-config (caar (last resize-window--window-stack)))
496
+ (setq prev-config (resize-window--apply-config prev-config))
497
+ (compare-window-configurations curr-config prev-config)
498
+ (setq resize-window--window-stack
499
+ (nbutlast resize-window--window-stack))))
500
+ ; ; trim duplicates from the head
501
+ (while (and (setq prev-config (caar resize-window--window-stack))
502
+ (setq prev-config (resize-window--apply-config prev-config))
503
+ (compare-window-configurations curr-config prev-config)
504
+ (pop resize-window--window-stack)))
505
+ (push curr-member resize-window--window-stack)
506
+ (resize-window--window-trim)
507
+ (when resize-window--window-stack
508
+ curr-member)))
415
509
416
510
(defun resize-window--window-pop ()
417
- " Return the first element and remove it from the stack."
418
- (pop resize-window--window-stack))
511
+ " Shift to a previous window configuration.
512
+ Return the configuration shifted to if any.
513
+
514
+ Save the current configuration to the tail of the stack.
515
+
516
+ Trim adjacent duplicates and old configurations when necessary.
517
+
518
+ See also `resize-window-stack-size' ."
519
+ (resize-window--window-trim)
520
+ (let* ((curr-config (resize-window--window-config))
521
+ (curr-member (cons curr-config (current-time )))
522
+ (prev-config nil ))
523
+ ; ; trim duplicates from the tail
524
+ (while (and (setq prev-config (caar (last resize-window--window-stack)))
525
+ (setq prev-config (resize-window--apply-config prev-config))
526
+ (compare-window-configurations curr-config prev-config)
527
+ (setq resize-window--window-stack
528
+ (nbutlast resize-window--window-stack))))
529
+ ; ; trim duplicates from the head
530
+ (while (and (setq prev-config (car (pop resize-window--window-stack)))
531
+ (setq prev-config (resize-window--apply-config prev-config))
532
+ (compare-window-configurations curr-config prev-config)))
533
+ (when prev-config
534
+ (setq resize-window--window-stack
535
+ (append resize-window--window-stack (list curr-member)))
536
+ (resize-window--restore-config prev-config)
537
+ prev-config)))
419
538
420
539
(defun resize-window--kill-other-windows ()
421
540
" Delete other windows."
0 commit comments