@@ -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
@@ -408,13 +419,121 @@ Restore the help menu only if it is currently open."
408
419
(resize-window--display-menu 'open )
409
420
(resize-window--add-backgrounds)))))
410
421
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
+
411
483
(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)))
414
508
415
509
(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)))
418
537
419
538
(defun resize-window--kill-other-windows ()
420
539
" Delete other windows."
0 commit comments