emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Add function to rotate/transpose all windows


From: martin rudalics
Subject: Re: Add function to rotate/transpose all windows
Date: Sun, 20 Oct 2024 19:37:00 +0200
User-agent: Mozilla Thunderbird

> Or do you mean it automaticlly makes the window-parameters the same?, as
> in I won't have to modify anything?

It should work automatically in the sense that the parent windows get
reused too.  But it doesn't work reliably for a couple of reasons:

With emacs -Q do

(let ((window (split-window)))
  (set-window-buffer window (get-buffer-create "*foo*"))
  (setq window (split-window nil nil t))
  (set-window-buffer window "*Messages*"))

so you have an arrangement with *scratch* and *Messages* at the top and
*foo* at the bottom.  Now rotate windows clockwise with the *Messages*
window selected.  Here this first deletes the remaining windows and
starts with *scratch* as the root window's buffer.  Now the very first
you ask is to split the *scratch* window with REFER set to the *foo*
window.

This is a bad idea because *foo* is _not_ *scratch*'s sibling in the
initial configuration - *Messages* is.  It can break my approach which
reuses the old parent of REFER which, however, is _not_ the old parent
of the *scratch* window.  In the next call to 'split-window' you again
ask to split the *scratch* window but set REFER to the *Messages* window.
All goes miraculously well.

Repeat the call.  Now *foo* with REFER *scratch* reuses the parent of
*scratch*.  Next *scratch* with REFER *Messages* reuses the parent of
*Messages*.  Probably due to the fact in which order you earlier deleted
windows, this changes the parent windows from (the car of each cons is
the buffer window the cdr the parent window)

((#<window 9 on *Messages*> . #<window 8>)
 (#<window 7 on *foo*> . #<window 6>)
 (#<window 3 on *scratch*> . #<window 8>))

before the call to

((#<window 9 on *Messages*> . #<window 6>)
 (#<window 7 on *foo*> . #<window 8>)
 (#<window 3 on *scratch*> . #<window 6>))

after the call. So the parent windows were interchanged.  Looks like a
minor annoyance.  But with a more complex layout things fail.  Try with

(let ((window (split-window)))
  (set-window-buffer window (get-buffer-create "*foo1*"))
  (setq window (split-window nil nil t))
  (set-window-buffer window (get-buffer-create "*foo2*"))
  (setq window (split-window window))
  (set-window-buffer window (get-buffer-create "*foo3*")))

and repeat the scenario.  Here, in the second call, when it tries to
split the window on *foo3* with REFER set to the window of *foo2*,
'split-window' finds out that the parent of *foo2* has been already
reused and allocates a new parent window.

I think you have to change two things:

(1) Instead of

      ;; All child windows need to be recursively deleted.
      (mapc (lambda (win)
              (when (and (windowp win)
                         (not (eq win fwin)))
                (delete-window win)))
            ;; We know for sure that first 2 in the list are not
            ;; windows.
            (cddr (flatten-list win-tree)))

use

      (delete-other-windows fwin)

Your strategy of deleting windows piecemeal destroys the original window
structure in a quite chaotic way.

(2) Whenever you split a leaf window (like *scratch* in the first
scenario), make sure that REFER gets always set to the window's
'window-next-sibling' (*Messages* in the first scenario) and never to
some window further up or down in the hierarchy (like *foo* in the first
scenario).  Which means that in the first scenario you have two possible
strategies:

- Split *scratch* first with REFER *Messages* and then its parent with
  REFER *foo*.

- Split *foo* first with REFER *scratch* and then *scratch* with REFER
  *Messages*.

You should try both in case we later find out that the one we did choose
fails.

martin



reply via email to

[Prev in Thread] Current Thread [Next in Thread]