@@ -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
@@ -400,13 +411,121 @@ Restore the help menu only if it is currently open."
400
411
(resize-window--display-menu 'open )
401
412
(resize-window--add-backgrounds)))))
402
413
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
+
403
475
(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)))
406
500
407
501
(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)))
410
529
411
530
(defun resize-window--kill-other-windows ()
412
531
" Delete other windows."
0 commit comments