unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Add function to rotate/transpose all windows
@ 2024-09-24 13:45 pranshu sharma
  2024-09-24 13:53 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-24 13:45 UTC (permalink / raw)
  To: emacs-devel


An useful for function for C-x w map is to add a function to rotate
windows.

What I mean by this is basiclly rebuilt the window tree, but do vertical
split where a horizonal, and vice versa.

For example if we rotate the the frame with the windows A B C:
- | A | B |       | A |   |
- |-------|   - > |---| C |
- |   C   |       | B |   |

I think this is extremly useful, as sometimes for example I open a
window with a horizontal split, and the lines are rather long, then I
have to manually toggle the window split to vertical.

An example of this:
https://www.emacswiki.org/emacs/TransposeFrame
The code in this has the following limitations:
- Does not work in emacs 29.1
- No good way to transpose only specific parts of window tree



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 13:45 Add function to rotate/transpose all windows pranshu sharma
@ 2024-09-24 13:53 ` Eli Zaretskii
  2024-09-25  8:05   ` martin rudalics
  2024-09-24 17:40 ` Petteri Hintsanen
  2024-09-24 19:34 ` Charles Choi
  2 siblings, 1 reply; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-24 13:53 UTC (permalink / raw)
  To: pranshu sharma, martin rudalics; +Cc: emacs-devel

> From: pranshu sharma <pranshusharma366@gmail.com>
> Date: Tue, 24 Sep 2024 23:45:42 +1000
> 
> 
> An useful for function for C-x w map is to add a function to rotate
> windows.
> 
> What I mean by this is basiclly rebuilt the window tree, but do vertical
> split where a horizonal, and vice versa.
> 
> For example if we rotate the the frame with the windows A B C:
> - | A | B |       | A |   |
> - |-------|   - > |---| C |
> - |   C   |       | B |   |
> 
> I think this is extremly useful, as sometimes for example I open a
> window with a horizontal split, and the lines are rather long, then I
> have to manually toggle the window split to vertical.
> 
> An example of this:
> https://www.emacswiki.org/emacs/TransposeFrame
> The code in this has the following limitations:
> - Does not work in emacs 29.1
> - No good way to transpose only specific parts of window tree

Thanks.

Martin, any comments or suggestions?



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 13:45 Add function to rotate/transpose all windows pranshu sharma
  2024-09-24 13:53 ` Eli Zaretskii
@ 2024-09-24 17:40 ` Petteri Hintsanen
  2024-09-24 19:34 ` Charles Choi
  2 siblings, 0 replies; 65+ messages in thread
From: Petteri Hintsanen @ 2024-09-24 17:40 UTC (permalink / raw)
  To: pranshu sharma; +Cc: emacs-devel

pranshu sharma <pranshusharma366@gmail.com> writes:

> An useful for function for C-x w map is to add a function to rotate
> windows.
>
> What I mean by this is basiclly rebuilt the window tree, but do vertical
> split where a horizonal, and vice versa.
>
> For example if we rotate the the frame with the windows A B C:
> - | A | B |       | A |   |
> - |-------|   - > |---| C |
> - |   C   |       | B |   |

I agree, this would be a useful feature.

Despite a hint of self-promotion I'd like to point out a minor mode I
wrote a long time ago: http://iki.fi/petterih/cwm-mode.html
It can do something like that, though not exactly.
Having a general facility built into Emacs would be better.

-- 
Petteri



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 13:45 Add function to rotate/transpose all windows pranshu sharma
  2024-09-24 13:53 ` Eli Zaretskii
  2024-09-24 17:40 ` Petteri Hintsanen
@ 2024-09-24 19:34 ` Charles Choi
  2024-09-25  2:00   ` Emanuel Berg
  2024-09-25  7:00   ` pranshu sharma
  2 siblings, 2 replies; 65+ messages in thread
From: Charles Choi @ 2024-09-24 19:34 UTC (permalink / raw)
  To: emacs-devel; +Cc: pranshu sharma

Hi folks!

As a side note, I received an issue that a package that I had recently published on MELPA required a dependency on transpose-frame. Investigating further, it seems that transpose-frame was ad-hoc packaged and it is unclear who actually maintains this code.

https://github.com/emacsorphanage/transpose-frame/blob/master/transpose-frame.el

My observation is that what transpose-frame is trying to do is so useful, that it would nice to have such behavior be “built-in” to Emacs core. I am not saying that this package should be included “as-is” though. I leave it to the core team to determine how to best implement this behavior.


All my best - 
Charles

—
Charles Y. Choi, Ph.D.
kickingvegas@gmail.com





^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 19:34 ` Charles Choi
@ 2024-09-25  2:00   ` Emanuel Berg
  2024-09-25  7:00   ` pranshu sharma
  1 sibling, 0 replies; 65+ messages in thread
From: Emanuel Berg @ 2024-09-25  2:00 UTC (permalink / raw)
  To: emacs-devel

Charles Choi wrote:

> As a side note, I received an issue that a package that
> I had recently published on MELPA required a dependency on
> transpose-frame. Investigating further, it seems that
> transpose-frame was ad-hoc packaged and it is unclear who
> actually maintains this code.
>
> https://github.com/emacsorphanage/transpose-frame/blob/master/transpose-frame.el
>
> My observation is that what transpose-frame is trying to do
> is so useful, that it would nice to have such behavior be
> "built-in" to Emacs core. I am not saying that this package
> should be included "as-is" though. I leave it to the core
> team to determine how to best implement this behavior.

There is a lot of transpose already in core Emacs:

  transpose-chars
  transpose-lines
  transpose-paragraphs
  transpose-regions
  transpose-sentences
  transpose-sexps
  transpose-sexps-default-function
  transpose-subr
  transpose-subr-1
  transpose-words

Slime has a general list transposer:

(defun slime-transpose-lists (list-of-lists)
  (let ((ncols (length (car list-of-lists))))
    (cl-loop for col-index below ncols
             collect (cl-loop for row in list-of-lists
                              collect (elt row col-index)))))

And I have a transposer that works for nested elements, here:
  https://dataswamp.org/~incal/bad/class/elem/bad-rotate.el

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 19:34 ` Charles Choi
  2024-09-25  2:00   ` Emanuel Berg
@ 2024-09-25  7:00   ` pranshu sharma
  1 sibling, 0 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-25  7:00 UTC (permalink / raw)
  To: Charles Choi; +Cc: emacs-devel

Charles Choi <kickingvegas@gmail.com> writes:

> Hi folks!
>
> As a side note, I received an issue that a package that I had recently
> published on MELPA required a dependency on
> transpose-frame. Investigating further, it seems that transpose-frame
> was ad-hoc packaged and it is unclear who actually maintains this
> code.
>

I managed to get the name of the author, Irie Shinsuke, from:
https://code.launchpad.net/~irie/+junk/transpose-frame.el

However I could not find the email.

The last comit was in early 2011.

> https://github.com/emacsorphanage/transpose-frame/blob/master/transpose-frame.el
>
> My observation is that what transpose-frame is trying to do is so
> useful, that it would nice to have such behavior be “built-in” to
> Emacs core. I am not saying that this package should be included
> “as-is” though. I leave it to the core team to determine how to best
> implement this behavior.
>
>
> All my best - 
> Charles
>
> —
> Charles Y. Choi, Ph.D.
> kickingvegas@gmail.com



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-24 13:53 ` Eli Zaretskii
@ 2024-09-25  8:05   ` martin rudalics
  2024-09-25  8:34     ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-25  8:05 UTC (permalink / raw)
  To: Eli Zaretskii, pranshu sharma; +Cc: emacs-devel

 >> https://www.emacswiki.org/emacs/TransposeFrame
 >> The code in this has the following limitations:
 >> - Does not work in emacs 29.1

It works here when I remove the

(window-redisplay-end-trigger tree)

(set-window-redisplay-end-trigger window (pop config))

lines in such versions.

 >> - No good way to transpose only specific parts of window tree

Then the FRAME arguments should probably become WINDOW-OR-FRAME and
accept arbitrary internal windows as value.

 > Thanks.
 >
 > Martin, any comments or suggestions?

The problem of any such package is that Emacs never provided a suitable
balance between explicit management of objects like buffers or windows
(via 'kill-buffer' and 'delete-window') and the subsequent internal
handling of these objects.

In particular, the 'delete-window'/'split-window' paradigm may fail when
window objects have been stored in variables.  Take this excerpt from
TransposeFrame

                            (if (eq (overlay-get ol 'window) orig-window)
                                (overlay-put ol 'window window))))

If this gets called within a 'save-window-excursion', then the 'window'
property of overlays may change from 'orig-window' to 'window'.  When
'save-window-excursion' exits and restores 'orig-window' and deletes
'window', these overlays will now reference a dead window.  This problem
could be partially fixed by using the 'clone-of' parameter of the
window.  But that would fail when windows are rotated a second time.

Such problems could be fixed if we were able to reference windows by
their number (or an arbitrary name) and have Lisp references to a window
use that number instead of the object.  It might, however, take
considerable time to have such a concept enter the minds of people used
to storing window identities as Lisp objects.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25  8:05   ` martin rudalics
@ 2024-09-25  8:34     ` pranshu sharma
  2024-09-25  9:31       ` martin rudalics
  2024-09-26 14:10       ` martin rudalics
  0 siblings, 2 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-25  8:34 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>> https://www.emacswiki.org/emacs/TransposeFrame
>>> The code in this has the following limitations:
>>> - Does not work in emacs 29.1
>
> It works here when I remove the
>
> (window-redisplay-end-trigger tree)
>
> (set-window-redisplay-end-trigger window (pop config))
>
> lines in such versions.
>
>>> - No good way to transpose only specific parts of window tree
>
> Then the FRAME arguments should probably become WINDOW-OR-FRAME and
> accept arbitrary internal windows as value.
>
>> Thanks.
>>
>> Martin, any comments or suggestions?
>
> The problem of any such package is that Emacs never provided a suitable
> balance between explicit management of objects like buffers or windows
> (via 'kill-buffer' and 'delete-window') and the subsequent internal
> handling of these objects.
>
> In particular, the 'delete-window'/'split-window' paradigm may fail when
> window objects have been stored in variables.  Take this excerpt from
> TransposeFrame
>
>                            (if (eq (overlay-get ol 'window) orig-window)
>                                (overlay-put ol 'window window))))
>
> If this gets called within a 'save-window-excursion', then the 'window'
> property of overlays may change from 'orig-window' to 'window'.  When
> 'save-window-excursion' exits and restores 'orig-window' and deletes
> 'window', these overlays will now reference a dead window.  This problem
> could be partially fixed by using the 'clone-of' parameter of the
> window.  But that would fail when windows are rotated a second time.

From what I understand, the main problems are happening when destroying
and recreating the window arragnment.  How about adding a function that
toggles or changes the window arrangment non recursivly, which will deal
with all the backend details, and the main rotate function can just
recursivly call that on all windows.

>
> Such problems could be fixed if we were able to reference windows by
> their number (or an arbitrary name) and have Lisp references to a window
> use that number instead of the object.  It might, however, take
> considerable time to have such a concept enter the minds of people used
> to storing window identities as Lisp objects.
>
> martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25  8:34     ` pranshu sharma
@ 2024-09-25  9:31       ` martin rudalics
  2024-09-25 10:50         ` pranshu sharma
  2024-09-26 14:10       ` martin rudalics
  1 sibling, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-25  9:31 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >>From what I understand, the main problems are happening when destroying
 > and recreating the window arragnment.

Right.

 > How about adding a function that
 > toggles or changes the window arrangment non recursivly, which will deal
 > with all the backend details, and the main rotate function can just
 > recursivly call that on all windows.

How would you "deal with all the backend details"?  How would you
convince Emacs that the windows B and C in the right configuration
below

- | A | B |       | A |   |
- |-------|   - > |---| C |
- |   C   |       | B |   |

are the windows B and C from the left configuration (albeit with
different parents and sizes)?

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25  9:31       ` martin rudalics
@ 2024-09-25 10:50         ` pranshu sharma
  2024-09-25 13:53           ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-25 10:50 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>>From what I understand, the main problems are happening when destroying
>> and recreating the window arragnment.
>
> Right.
>
>> How about adding a function that
>> toggles or changes the window arrangment non recursivly, which will deal
>> with all the backend details, and the main rotate function can just
>> recursivly call that on all windows.
>
> How would you "deal with all the backend details"?  How would you
> convince Emacs that the windows B and C in the right configuration
> below
>
> - | A | B |       | A |   |
> - |-------|   - > |---| C |
> - |   C   |       | B |   |
>
> are the windows B and C from the left configuration (albeit with
> different parents and sizes)?

I thought you would know.

If it's not possible, then what's wrong with rebuilding the trees from
scratch and clearly documenting that it's being done.  I mean users will
still have to do the same thing manually, which will also destroy change
the window tree.

>
> martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25 10:50         ` pranshu sharma
@ 2024-09-25 13:53           ` martin rudalics
  2024-09-25 15:31             ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-25 13:53 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > I thought you would know.

In that case I would have told you before.

 > If it's not possible, then what's wrong with rebuilding the trees from
 > scratch and clearly documenting that it's being done.  I mean users will
 > still have to do the same thing manually, which will also destroy change
 > the window tree.

I don't think that anything would be wrong with such an approach.  So if
you intend to rewrite transpose-frame.el, I can tell you what's needed
to get that done properly within the current limitations.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25 13:53           ` martin rudalics
@ 2024-09-25 15:31             ` pranshu sharma
  0 siblings, 0 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-25 15:31 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:


> I don't think that anything would be wrong with such an approach.  So if
> you intend to rewrite transpose-frame.el, I can tell you what's needed
> to get that done properly within the current limitations.

Yeah, if you think that this is the only practical way without having to
do some big rewrite, then I'm willing to rewrite tranpose-frame.el.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-25  8:34     ` pranshu sharma
  2024-09-25  9:31       ` martin rudalics
@ 2024-09-26 14:10       ` martin rudalics
  2024-09-26 14:22         ` Eli Zaretskii
  2024-09-27 10:06         ` pranshu sharma
  1 sibling, 2 replies; 65+ messages in thread
From: martin rudalics @ 2024-09-26 14:10 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 759 bytes --]

 >>From what I understand, the main problems are happening when destroying
 > and recreating the window arragnment.  How about adding a function that
 > toggles or changes the window arrangment non recursivly, which will deal
 > with all the backend details, and the main rotate function can just
 > recursivly call that on all windows.

I attach a function 'resurrect-window' that rotate/transpose/flip
functions can call to resurrect the previous windows after having
deleted them.  Tested with:

(let ((dead (split-window nil nil t)))
   (set-window-buffer dead "*Messages*")
   (message "%s" (next-window))
   (sit-for 2)
   (delete-window dead)
   (let ((live (split-window)))
     (resurrect-window dead live)
     (message "%s" (next-window))))

martin

[-- Attachment #2: resurrect.diff --]
[-- Type: text/x-patch, Size: 5812 bytes --]

diff --git a/src/window.c b/src/window.c
index 34968ac824f..312619737f3 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5368,10 +5368,14 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna
 	}
       else
 	{
+	  w->del_pointm = marker_position (w->pointm);
+	  w->del_start = marker_position (w->start);
+
 	  unshow_buffer (w);
 	  unchain_marker (XMARKER (w->pointm));
 	  unchain_marker (XMARKER (w->old_pointm));
 	  unchain_marker (XMARKER (w->start));
+	  wset_old_buffer (w, w->contents);
 	  wset_buffer (w, Qnil);
 	  /* Add WINDOW to table of dead windows so when killing a buffer
 	     WINDOW mentions, all references to that buffer can be removed
@@ -5437,6 +5441,97 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna
 
   return Qnil;
 }
+
+
+DEFUN ("resurrect-window", Fresurrect_window, Sresurrect_window, 2, 2, 0,
+       doc: /* Resurrect dead window DEAD in lieu of live window LIVE.
+DEAD must denote a dead window that was a live window before it was
+deleted.  LIVE must denote a live window.  Put the window object of DEAD
+in the place of LIVE such that the resulting window inherits LIVE's
+geometric properties and its position within the window tree while all
+other properties including the buffer and its positions, decorations and
+parameters are inherited from DEAD.
+
+DEAD must have been on the same frame as LIVE and its old buffer must be
+still live.  If LIVE was selected or its frame's selected window, select
+DEAD or make it its frame's selected window instead.  */)
+  (Lisp_Object dead, Lisp_Object live)
+{
+  struct window *l = decode_live_window (live);
+  struct window *d = decode_any_window (dead);
+  Lisp_Object frame = WINDOW_FRAME (l);
+  struct frame *f = XFRAME (frame);
+  Lisp_Object tem;
+  bool selected = EQ (live, selected_window);
+  bool frame_selected = EQ (live, f->selected_window);
+
+  if (!NILP (d->contents))
+    error ("Attempt to resurrect undead window");
+  else if (!BUFFERP (d->old_buffer))
+    error ("Dead window has no old buffer");
+  else if (!BUFFER_LIVE_P (XBUFFER (d->old_buffer)))
+    error ("Dead window's old buffer is dead");
+  else if (!EQ (l->frame, d->frame))
+    error ("Live and dead widows must be on same frame");
+
+  block_input ();
+
+  /* Copy links and geometry of LIVE into DEAD.  */
+  memcpy (&d->next, &l->next,
+	  offsetof (struct window, contents)
+	  - offsetof (struct window, next));
+  memcpy (&d->pixel_left, &l->pixel_left,
+	  offsetof (struct window, hscroll)
+	  - offsetof (struct window, pixel_left));
+
+  /* Replace LIVE in window tree with DEAD.  */
+  if (!NILP (d->next))
+    wset_prev (XWINDOW (d->next), dead);
+
+  if (!NILP (d->prev))
+    wset_next (XWINDOW (d->prev), dead);
+
+  tem = d->parent;
+  if (!NILP (tem) && EQ (XWINDOW (tem)->contents, live))
+    wset_combination (XWINDOW (tem), XWINDOW (tem)->horizontal, dead);
+
+  /* Get DEAD back its old buffer and markers.  */
+  wset_buffer (d, d->old_buffer);
+  Fset_marker (d->start, make_fixnum (d->del_start), d->contents);
+  Fset_marker (d->pointm, make_fixnum (d->del_pointm), d->contents);
+
+  /* Deal with LIVE.  */
+  wset_next (l, Qnil);  /* Don't delete l->next too.  */
+  free_window_matrices (l);
+  l->del_pointm = marker_position (l->pointm);
+  l->del_start = marker_position (l->start);
+  unshow_buffer (l);
+  unchain_marker (XMARKER (l->pointm));
+  unchain_marker (XMARKER (l->old_pointm));
+  unchain_marker (XMARKER (l->start));
+  wset_old_buffer (l, l->contents);
+  wset_buffer (l, Qnil);
+  /* Add WINDOW to table of dead windows so when killing a buffer WINDOW
+     mentions, all references to that buffer can be removed and the
+     buffer be collected.  */
+  Fputhash (make_fixnum (l->sequence_number),
+	    live, window_dead_windows_table);
+
+  /* Selection status.  */
+  if (selected)
+    Fselect_window (dead, Qt);
+  else if (frame_selected)
+    fset_selected_window (f, dead);
+
+  /* Tell redisplay.  */
+  fset_redisplay (f);
+  Vwindow_list = Qnil;
+  adjust_frame_glyphs (f);
+  unblock_input ();
+  FRAME_WINDOW_CHANGE (f) = true;
+
+  return Qnil;
+}
 \f
 /***********************************************************************
 			Resizing Mini-Windows
@@ -7712,6 +7807,9 @@ delete_all_child_windows (Lisp_Object window)
     }
   else if (BUFFERP (w->contents))
     {
+      w->del_pointm = marker_position (w->pointm);
+      w->del_start = marker_position (w->start);
+
       unshow_buffer (w);
       unchain_marker (XMARKER (w->pointm));
       unchain_marker (XMARKER (w->old_pointm));
@@ -7720,6 +7818,7 @@ delete_all_child_windows (Lisp_Object window)
 	 only, we use this slot to save the buffer for the sake of
 	 possible resurrection in Fset_window_configuration.  */
       wset_combination_limit (w, w->contents);
+      wset_old_buffer (w, w->contents);
       wset_buffer (w, Qnil);
       /* Add WINDOW to table of dead windows so when killing a buffer
 	 WINDOW mentions, all references to that buffer can be removed
@@ -9146,6 +9245,7 @@ syms_of_window (void)
   defsubr (&Sget_buffer_window);
   defsubr (&Sdelete_other_windows_internal);
   defsubr (&Sdelete_window_internal);
+  defsubr (&Sresurrect_window);
   defsubr (&Sresize_mini_window_internal);
   defsubr (&Sset_window_buffer);
   defsubr (&Srun_window_configuration_change_hook);
diff --git a/src/window.h b/src/window.h
index 335e0a3453e..41ee7f6dc18 100644
--- a/src/window.h
+++ b/src/window.h
@@ -264,6 +264,10 @@ #define WINDOW_H_INCLUDED
     int total_cols;
     int total_lines;
 
+    /* Positions of pointm and start when window was deleted.  */
+    ptrdiff_t del_pointm;
+    ptrdiff_t del_start;
+
     /* Number of columns display within the window is scrolled to the left.  */
     ptrdiff_t hscroll;
 

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-26 14:10       ` martin rudalics
@ 2024-09-26 14:22         ` Eli Zaretskii
  2024-09-27 17:29           ` martin rudalics
  2024-09-27 10:06         ` pranshu sharma
  1 sibling, 1 reply; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-26 14:22 UTC (permalink / raw)
  To: martin rudalics; +Cc: pranshusharma366, emacs-devel

> Date: Thu, 26 Sep 2024 16:10:48 +0200
> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> 
> I attach a function 'resurrect-window' that rotate/transpose/flip
> functions can call to resurrect the previous windows after having
> deleted them.  Tested with:
> 
> (let ((dead (split-window nil nil t)))
>    (set-window-buffer dead "*Messages*")
>    (message "%s" (next-window))
>    (sit-for 2)
>    (delete-window dead)
>    (let ((live (split-window)))
>      (resurrect-window dead live)
>      (message "%s" (next-window))))

Thanks.

> +DEFUN ("resurrect-window", Fresurrect_window, Sresurrect_window, 2, 2, 0,
> +       doc: /* Resurrect dead window DEAD in lieu of live window LIVE.
> +DEAD must denote a dead window that was a live window before it was
> +deleted.  LIVE must denote a live window.  Put the window object of DEAD
> +in the place of LIVE such that the resulting window inherits LIVE's
> +geometric properties and its position within the window tree while all
> +other properties including the buffer and its positions, decorations and
> +parameters are inherited from DEAD.
> +
> +DEAD must have been on the same frame as LIVE and its old buffer must be
> +still live.  If LIVE was selected or its frame's selected window, select
> +DEAD or make it its frame's selected window instead.  */)

This doc string needs to be more detailed in what it means to "put the
window object of DEAD in the place of LIVE".  For example, it
currently keeps silent about what happens to LIVE after the call.

> +  /* Add WINDOW to table of dead windows so when killing a buffer WINDOW
> +     mentions, all references to that buffer can be removed and the
> +     buffer be collected.  */

There's no WINDOW argument.  I think you meant LIVE instead.

Finally, this needs to be documented in the ELisp manual and called
out in NEWS.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-26 14:10       ` martin rudalics
  2024-09-26 14:22         ` Eli Zaretskii
@ 2024-09-27 10:06         ` pranshu sharma
  2024-09-27 17:29           ` martin rudalics
  1 sibling, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-27 10:06 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>>From what I understand, the main problems are happening when destroying
>> and recreating the window arragnment.  How about adding a function that
>> toggles or changes the window arrangment non recursivly, which will deal
>> with all the backend details, and the main rotate function can just
>> recursivly call that on all windows.
>
> I attach a function 'resurrect-window' that rotate/transpose/flip
> functions can call to resurrect the previous windows after having
> deleted them.

Thanks, I tested it and it works.

I'll get back when I've rewrote transpose frame



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-26 14:22         ` Eli Zaretskii
@ 2024-09-27 17:29           ` martin rudalics
  2024-09-28  7:52             ` pranshu sharma
                               ` (2 more replies)
  0 siblings, 3 replies; 65+ messages in thread
From: martin rudalics @ 2024-09-27 17:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pranshusharma366, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 831 bytes --]

 > This doc string needs to be more detailed in what it means to "put the
 > window object of DEAD in the place of LIVE".  For example, it
 > currently keeps silent about what happens to LIVE after the call.

The fact that LIVE existed at all was a misfeature.  I now put the dead
window right into the new window created by 'split-window' with the help
of a new argument.  Patch attached.  Tested with

(let ((dead (split-window nil nil t)))
   (set-window-buffer dead "*Messages*")
   (message "%s" (next-window))
   (sit-for 2)
   (delete-window dead)
   (let ((live (split-window nil nil nil nil dead)))
     (message "%s" (next-window))))

 > Finally, this needs to be documented in the ELisp manual and called
 > out in NEWS.

Sure.  I'll wait until the OP approves the concept and was able to make
use of it.

Thanks, martin

[-- Attachment #2: resurrect.diff --]
[-- Type: text/x-patch, Size: 12834 bytes --]

diff --git a/lisp/window.el b/lisp/window.el
index 07ea9584908..b96a7863a72 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5509,7 +5509,7 @@ window--combination-resizable
       (setq sibling (window-next-sibling sibling)))
     (/ size (1+ number))))
 
-(defun split-window (&optional window size side pixelwise)
+(defun split-window (&optional window size side pixelwise refer)
   "Make a new window adjacent to WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 Return the new window which is always a live window.
@@ -5552,11 +5552,21 @@ split-window
 root of that atomic window.  The new window does not become a
 member of that atomic window.
 
-If WINDOW is live, properties of the new window like margins and
-scrollbars are inherited from WINDOW.  If WINDOW is an internal
-window, these properties as well as the buffer displayed in the
-new window are inherited from the window selected on WINDOW's
-frame.  The selected window is not changed by this function."
+If the optional fifth argument REFER is non-nil, it has to denote a
+dead, former live window on the same frame as OLD or an arbitrary live
+window.  In the first case, REFER will become the new window with
+properties like buffer, start and point, decorations and parameters as
+to the last time when it was live.  In the latter case the new window
+will inherit properties like buffer, start and point, decorations and
+parameters from REFER.
+
+If REFER is nil or omitted, then if WINDOW is live, any such properties
+are inherited from WINDOW.  If, however, WINDOW is an internal window,
+the new window will inherit these properties from the window selected on
+WINDOW's frame.
+
+The selected window and the selected window on WINDOW's frame are
+not changed by this function."
   (setq window (window-normalize-window window))
   (let* ((side (cond
 		((not side) 'below)
@@ -5596,7 +5606,7 @@ split-window
        ((and (window-parameter window 'window-atom)
 	     (setq atom-root (window-atom-root window))
 	     (not (eq atom-root window)))
-	(throw 'done (split-window atom-root size side pixelwise)))
+	(throw 'done (split-window atom-root size side pixelwise refer)))
        ;; If WINDOW is a side window or its first or last child is a
        ;; side window, throw an error unless `window-combination-resize'
        ;; equals 'side.
@@ -5635,8 +5645,8 @@ split-window
 		   (window-combined-p window horizontal)))
 	     ;; 'old-pixel-size' is the current pixel size of WINDOW.
 	     (old-pixel-size (window-size window horizontal t))
-	     ;; 'new-size' is the specified or calculated size of the
-	     ;; new window.
+	     ;; 'new-pixel-size' is the specified or calculated size
+	     ;; of the new window.
 	     new-pixel-size new-parent new-normal)
 	(cond
 	 ((not pixel-size)
@@ -5757,8 +5767,9 @@ split-window
 	   window (- (if new-parent 1.0 (window-normal-size window horizontal))
 		     new-normal)))
 
-	(let* ((new (split-window-internal window new-pixel-size side new-normal)))
-	  (window--pixel-to-total frame horizontal)
+	(let ((new (split-window-internal
+		    window new-pixel-size side new-normal refer)))
+          (window--pixel-to-total frame horizontal)
 	  ;; Assign window-side parameters, if any.
 	  (cond
 	   ((eq window-combination-resize 'side)
diff --git a/src/window.c b/src/window.c
index 34968ac824f..402bb0459e3 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5073,7 +5073,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
 }
 
 
-DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0,
+DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0,
        doc: /* Split window OLD.
 Second argument PIXEL-SIZE specifies the number of pixels of the
 new window.  It must be a positive integer.
@@ -5088,32 +5088,30 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
 the right side of WINDOW.  SIDE `left' means the new window shall be
 located on the left of WINDOW.  In both cases PIXEL-SIZE specifies the
 width of the new window including space reserved for fringes and the
-scrollbar or a divider column.
+scroll bar or a divider column.
 
 Fourth argument NORMAL-SIZE specifies the normal size of the new window
-according to the SIDE argument.
+according to the SIDE argument.  Optional fifth argument REFER is as for
+'split-window'.
 
 The new pixel and normal sizes of all involved windows must have been
 set correctly.  See the code of `split-window' for how this is done.  */)
-  (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size)
+  (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size,
+   Lisp_Object refer)
 {
   /* OLD (*o) is the window we have to split.  (*p) is either OLD's
      parent window or an internal window we have to install as OLD's new
-     parent.  REFERENCE (*r) must denote a live window, or is set to OLD
-     provided OLD is a leaf window, or to the frame's selected window.
-     NEW (*n) is the new window created with some parameters taken from
-     REFERENCE (*r).  */
-  Lisp_Object new, frame, reference;
-  struct window *o, *p, *n, *r, *c;
-  struct frame *f;
+     parent.  NEW (*n) is the new window created or adopted with
+     properties from REFER (*r), if specified.  */
+  struct window *o = decode_valid_window (old);
+  Lisp_Object frame = WINDOW_FRAME (o);
+  struct frame *f = XFRAME (frame);
+  struct window *p, *n, *r, *c;
   bool horflag
     /* HORFLAG is true when we split side-by-side, false otherwise.  */
     = EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright);
-
-  CHECK_WINDOW (old);
-  o = XWINDOW (old);
-  frame = WINDOW_FRAME (o);
-  f = XFRAME (frame);
+  Lisp_Object new;
+  bool dead = false;
 
   CHECK_FIXNUM (pixel_size);
   EMACS_INT total_size
@@ -5131,14 +5129,38 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
 	   ? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent))
 	   : WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent))));
 
-  /* We need a live reference window to initialize some parameters.  */
-  if (WINDOW_LIVE_P (old))
-    /* OLD is live, use it as reference window.  */
-    reference = old;
+  /* Set up reference window.  */
+  if (NILP (refer))
+    {
+      if (WINDOW_LIVE_P (old))
+	/* OLD is live, use it as reference window.  */
+	refer = old;
+      else
+	/* Use the frame's selected window as reference window.  */
+	refer = FRAME_SELECTED_WINDOW (f);
+
+      r = XWINDOW (refer);
+    }
   else
-    /* Use the frame's selected window as reference window.  */
-    reference = FRAME_SELECTED_WINDOW (f);
-  r = XWINDOW (reference);
+    {
+      r = decode_any_window (refer);
+
+      if (NILP (r->contents))
+	/* Presumably a dead, former live window.  Check whether its
+	   content can be used.  */
+	{
+	  if (!BUFFERP (r->old_buffer))
+	    error ("Dead reference window was not a live window");
+	  else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
+	    error ("Dead reference window's old buffer is dead");
+	  else if (!EQ (r->frame, frame))
+	    error ("Dead referenec window was on other frame");
+
+	  dead = true;
+	}
+      else if (!WINDOW_LIVE_P (refer))
+	error ("Reference window must not be internal");
+    }
 
   /* The following bugs are caught by `split-window'.  */
   if (MINI_WINDOW_P (o))
@@ -5195,7 +5217,12 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
     p = XWINDOW (o->parent);
 
   fset_redisplay (f);
-  new = make_window ();
+
+  if (dead)
+    new = refer;
+  else
+    new = make_window ();
+
   n = XWINDOW (new);
   wset_frame (n, frame);
   wset_parent (n, o->parent);
@@ -5219,19 +5246,22 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
       wset_next (o, new);
     }
 
-  n->window_end_valid = false;
-  n->last_cursor_vpos = 0;
+  if (!dead)
+    {
+      n->window_end_valid = false;
+      n->last_cursor_vpos = 0;
 
-  /* Get special geometry settings from reference window.  */
-  n->left_margin_cols = r->left_margin_cols;
-  n->right_margin_cols = r->right_margin_cols;
-  n->left_fringe_width = r->left_fringe_width;
-  n->right_fringe_width = r->right_fringe_width;
-  n->fringes_outside_margins = r->fringes_outside_margins;
-  n->scroll_bar_width = r->scroll_bar_width;
-  n->scroll_bar_height = r->scroll_bar_height;
-  wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
-  wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
+      /* Get special geometry settings from reference window.  */
+      n->left_margin_cols = r->left_margin_cols;
+      n->right_margin_cols = r->right_margin_cols;
+      n->left_fringe_width = r->left_fringe_width;
+      n->right_fringe_width = r->right_fringe_width;
+      n->fringes_outside_margins = r->fringes_outside_margins;
+      n->scroll_bar_width = r->scroll_bar_width;
+      n->scroll_bar_height = r->scroll_bar_height;
+      wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
+      wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
+    }
 
   /* Directly assign orthogonal coordinates and sizes.  */
   if (horflag)
@@ -5267,10 +5297,44 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
   wset_new_normal (n, normal_size);
 
   block_input ();
+
+  if (dead)
+    {
+      /* Get dead window back its old buffer and markers.  */
+      wset_buffer (n, n->old_buffer);
+      Fset_marker (n->start, make_fixnum (n->del_start), n->contents);
+      Fset_marker (n->pointm, make_fixnum (n->del_pointm), n->contents);
+      Vwindow_list = Qnil;
+    }
+  else
+    {
+      /* Note: n->contents is Qnil throughout this call, so n will be
+	 neither considered a leaf nor an internal window.  */
+      Lisp_Object buffer = r->contents;
+      struct buffer *b = XBUFFER (buffer);
+
+      /* Provisorially set new's buffer to that of the reference window,
+	 resize the parent, reset new's buffer to nil and do the real
+	 set_window_buffer.  */
+      wset_buffer (n, buffer);
+      set_marker_both (n->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
+      set_marker_restricted
+	(n->start, make_fixnum (b->last_window_start), buffer);
+    }
+
   window_resize_apply (p, horflag);
+
+  if (!dead)
+    {
+      /* Set buffer of NEW to buffer of reference window.  We have to do it
+	 here so the sizes of NEW are in place.  But be sure to do it before
+	 adjusting the frame glyphs - otherwise Emacs may inexplicably loop
+	 forever.  */
+      wset_buffer (n, Qnil);
+      set_window_buffer (new, r->contents, true, true);
+    }
+
   adjust_frame_glyphs (f);
-  /* Set buffer of NEW to buffer of reference window.  */
-  set_window_buffer (new, r->contents, true, true);
   FRAME_WINDOW_CHANGE (f) = true;
   unblock_input ();
 
@@ -5368,10 +5432,16 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna
 	}
       else
 	{
+	  if (MARKERP (w->pointm))
+	    w->del_pointm = marker_position (w->pointm);
+	  if (MARKERP (w->start))
+	    w->del_start = marker_position (w->start);
+
 	  unshow_buffer (w);
 	  unchain_marker (XMARKER (w->pointm));
 	  unchain_marker (XMARKER (w->old_pointm));
 	  unchain_marker (XMARKER (w->start));
+	  wset_old_buffer (w, w->contents);
 	  wset_buffer (w, Qnil);
 	  /* Add WINDOW to table of dead windows so when killing a buffer
 	     WINDOW mentions, all references to that buffer can be removed
@@ -7712,6 +7782,11 @@ delete_all_child_windows (Lisp_Object window)
     }
   else if (BUFFERP (w->contents))
     {
+      if (MARKERP (w->pointm))
+	w->del_pointm = marker_position (w->pointm);
+      if (MARKERP (w->start))
+	w->del_start = marker_position (w->start);
+
       unshow_buffer (w);
       unchain_marker (XMARKER (w->pointm));
       unchain_marker (XMARKER (w->old_pointm));
@@ -7720,6 +7795,7 @@ delete_all_child_windows (Lisp_Object window)
 	 only, we use this slot to save the buffer for the sake of
 	 possible resurrection in Fset_window_configuration.  */
       wset_combination_limit (w, w->contents);
+      wset_old_buffer (w, w->contents);
       wset_buffer (w, Qnil);
       /* Add WINDOW to table of dead windows so when killing a buffer
 	 WINDOW mentions, all references to that buffer can be removed
diff --git a/src/window.h b/src/window.h
index 335e0a3453e..41ee7f6dc18 100644
--- a/src/window.h
+++ b/src/window.h
@@ -264,6 +264,10 @@ #define WINDOW_H_INCLUDED
     int total_cols;
     int total_lines;
 
+    /* Positions of pointm and start when window was deleted.  */
+    ptrdiff_t del_pointm;
+    ptrdiff_t del_start;
+
     /* Number of columns display within the window is scrolled to the left.  */
     ptrdiff_t hscroll;
 

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-27 10:06         ` pranshu sharma
@ 2024-09-27 17:29           ` martin rudalics
  0 siblings, 0 replies; 65+ messages in thread
From: martin rudalics @ 2024-09-27 17:29 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > Thanks, I tested it and it works.

I have rewritten this by giving 'split-window' a new argument.  See the
patch I attached to my other mail.

 > I'll get back when I've rewrote transpose frame

You might want to write your own variant of 'window--subtree' where you
would record the normal sizes of windows instead of their edges.  This
would be more accurate and give you immediately a factor to apply when
splitting a window.  And for rotating you might want to start with
'frame-first-window' as the sole window and then use 'above' and 'left'
as SIDE arguments of 'split-window' as you see fit.

Good luck, martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-27 17:29           ` martin rudalics
@ 2024-09-28  7:52             ` pranshu sharma
  2024-09-28  9:26               ` martin rudalics
  2024-09-28  7:58             ` pranshu sharma
  2024-09-28  8:18             ` Eli Zaretskii
  2 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-28  7:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:


> Sure.  I'll wait until the OP approves the concept and was able to make
> use of it.

Hello Martin,

I managed to make remake the transpose frame function without using
reseruct window, and instead used swap-window-states.  I still have to
do some cleaning up and error handling tho, eg is still returns error
when you only have one window.

However one thing I'm stuck with it getting it to work with root C-x 2
C-x 3 kinda splits (basiclly where (listp (caddar (window-tree))) is
true).  However if you start with no windows, split window once, go to
split window, they you can go crazy with splitting in any direction
(even the C-x 2 C-x 3) and it will work when you call transpose-frame.

This also different from the transpose-windows.el in that it does not
start on a blank slate(transpose-windows.el calls delete-other-windows
in the transpose-frame-set-arrangement), so transposing partial window
trees much easier but I haven't implimented it yet.

---------------------------
;; is there already another inbuilt funcion like this?
(defun deepmap(func ls)
  (if (null ls)
      ()
    (cons (if (listp (car ls))
	      (deepmap func (car ls))
	    (funcall func (car ls)))
	  (deepmap func (cdr ls)))))

(defun transpose-frame ()
    (interactive)
    (let ((fwin (car (window-tree))))
      (toggle-window-split
       ;; We gotta get sizes now, cuz if not then window split mess em
       ;; up
       (deepmap (lambda (e) (if (windowp e)
				(cons
				 e (window-edges e))
			      e))
		(car (window-tree)))
       fwin
       t)
      ))

(defun toggle-window-split (subtree cwin &optional nokill)
  (pcase-let* ((`(,eee . ,flen) (if (car subtree)
			(cons 1 (window-width cwin))
		      (cons 0 (window-height cwin))))
	       (ilen (float (- (nth (+ 2 eee) (cadr subtree))
			       (nth (+ eee 0) (cadr subtree))))))
    (mapcar
     (pcase-lambda (`(,win . ,size))
       (if (listp win)
	   (progn
	     (toggle-window-split win (split-window cwin
						    (- (round (* flen  (/ size ilen))))
						    (car subtree))))
	 (progn
	   (let ((newwin (split-window cwin
				       (- (round (* flen (/ size ilen))))
				       (car subtree))))
	     (window-swap-states newwin win nil)
	     (delete-window win)))))
     (mapcar
      (lambda (e)
	(pcase-let ((`(,edges ,window?)
		     (if (windowp (car e))
			 (list (cdr e) (car e))
		       (list (cadr e) e))))
	  (cons window? (- (nth (+ 2 eee) edges)
			   (nth eee edges)))))
      (nreverse (cdddr subtree))))
    (unless nokill
      (if (windowp (caaddr subtree))
	  (delete-window (caaddr subtree))
	(toggle-window-split (caddr subtree) cwin)))))

---------------------------



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-27 17:29           ` martin rudalics
  2024-09-28  7:52             ` pranshu sharma
@ 2024-09-28  7:58             ` pranshu sharma
  2024-09-28  8:18             ` Eli Zaretskii
  2 siblings, 0 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-28  7:58 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel


Accidently sent wrong definition of transpose-frame.  The other
functions still fine.

The correct one is:
--------------------------
(defun transpose-frame ()
    (interactive)
    (let ((fwin (car (window-tree))))
      (while (not (windowp fwin))
	 (setq fwin (caddr fwin)))
      (toggle-window-split
       ;; We gotta get sizes now, cuz if not then window split mess em
       ;; up
       (deepmap (lambda (e) (if (windowp e)
				(cons
				 e (window-edges e))
			      e))
		(car (window-tree)))
       fwin
       t)
      ))
--------------------------



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-27 17:29           ` martin rudalics
  2024-09-28  7:52             ` pranshu sharma
  2024-09-28  7:58             ` pranshu sharma
@ 2024-09-28  8:18             ` Eli Zaretskii
  2024-09-28  9:40               ` martin rudalics
  2 siblings, 1 reply; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-28  8:18 UTC (permalink / raw)
  To: martin rudalics; +Cc: pranshusharma366, emacs-devel

> Date: Fri, 27 Sep 2024 19:29:21 +0200
> Cc: pranshusharma366@gmail.com, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> 
>  > This doc string needs to be more detailed in what it means to "put the
>  > window object of DEAD in the place of LIVE".  For example, it
>  > currently keeps silent about what happens to LIVE after the call.
> 
> The fact that LIVE existed at all was a misfeature.  I now put the dead
> window right into the new window created by 'split-window' with the help
> of a new argument.  Patch attached.

Thanks, but does it really make a lot of sense to make this a
side-effect of splitting a window?  (If it makes sense due to
technical reasons, such as commonality of code of the implementation,
we could have a common internal subroutine with 2 separate APIs
exposed to Lisp.)

Or maybe it _will_ make a lot of sense if you reword the doc string so
that it explains why what we do with REFER is a variant of splitting a
window.  Something like

  Instead of making a new window, this function can reuse an existing
  dead window...

Btw, "dead window" is mentioned only once in the ELisp manual, and
even that in passing, so it is not a very clear terminology, and might
need clarifications in this case.

> +If the optional fifth argument REFER is non-nil, it has to denote a
> +dead, former live window on the same frame as OLD or an arbitrary live
> +window.                                       ^^^

What is "OLD" here?  More generally, I don't think I understand what
you wanted to say by "or an arbitrary live window".

> In the first case, REFER will become the new window with
> +properties like buffer, start and point, decorations and parameters as
> +to the last time when it was live.  In the latter case the new window
> +will inherit properties like buffer, start and point, decorations and
> +parameters from REFER.

I suggest to describe each case separately, i.e. split the previous
sentence ("it has to denote ... or ...") into two, and explain
separately what happens in each case, instead of complicating with the
former and the latter.  Especially as there are additional cases (nil
or omitted), which add to the confusion:

> +If REFER is nil or omitted, then if WINDOW is live, any such properties
> +are inherited from WINDOW.  If, however, WINDOW is an internal window,
> +the new window will inherit these properties from the window selected on
> +WINDOW's frame.

> +	  if (!BUFFERP (r->old_buffer))
> +	    error ("Dead reference window was not a live window");
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This seems to imply that the function expects a dead window to be a
live window(??).

> +	  else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
> +	    error ("Dead reference window's old buffer is dead");

Will users understand what is "old buffer" of a window?

> +	  else if (!EQ (r->frame, frame))
> +	    error ("Dead referenec window was on other frame");
                         ^^^^^^^^^
Typo.  Also, I'd say "was on a frame other that that of window being
split" or something like that.

> +	  dead = true;
> +	}
> +      else if (!WINDOW_LIVE_P (refer))
> +	error ("Reference window must not be internal");

Are we sure "internal" here will be understood?  How about using "leaf
window" instead?

More generally, the text of these error messages is not easily
correlated to the problematic argument, because it neither mentions
the argument by its exact name, nor mentions the problematic window by
any other specific reference.

> +      /* Provisorially set new's buffer to that of the reference window,
            ^^^^^^^^^^^^^
Did you mean "provisionally"? or maybe "temporarily"?

Also, "new" should be up-cased.

> +	 resize the parent, reset new's buffer to nil and do the real
> +	 set_window_buffer.  */

Likewise.

> +      /* Set buffer of NEW to buffer of reference window.  We have to do it
> +	 here so the sizes of NEW are in place.  But be sure to do it before
> +	 adjusting the frame glyphs - otherwise Emacs may inexplicably loop
> +	 forever.  */

This should be more explicit what code below adjusts the frame's
glyphs, because without that this very good comment is less useful
than it could be.

>  	  unchain_marker (XMARKER (w->start));
> +	  wset_old_buffer (w, w->contents);

What is this about?

> @@ -7720,6 +7795,7 @@ delete_all_child_windows (Lisp_Object window)
>  	 only, we use this slot to save the buffer for the sake of
>  	 possible resurrection in Fset_window_configuration.  */
>        wset_combination_limit (w, w->contents);
> +      wset_old_buffer (w, w->contents);

And this?



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28  7:52             ` pranshu sharma
@ 2024-09-28  9:26               ` martin rudalics
  2024-09-28 10:53                 ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-28  9:26 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > I managed to make remake the transpose frame function without using
 > reseruct window, and instead used swap-window-states.

I don't know 'swap-window-states' but if it uses 'window-state-get' and
'window-state-put' (which I happen to know quite intimately) the result
won't be any better than with the concept you cited earlier.

 > However one thing I'm stuck with it getting it to work with root C-x 2
 > C-x 3 kinda splits (basiclly where (listp (caddar (window-tree))) is
 > true).  However if you start with no windows, split window once, go to
 > split window, they you can go crazy with splitting in any direction
 > (even the C-x 2 C-x 3) and it will work when you call transpose-frame.

I don't understand what you mean here.

 > This also different from the transpose-windows.el in that it does not
 > start on a blank slate(transpose-windows.el calls delete-other-windows
 > in the transpose-frame-set-arrangement), so transposing partial window
 > trees much easier but I haven't implimented it yet.

Whatever you do someone has to delete all "other" windows and start with
one specific live window that you subsequently split.

Try with the 'split-window' I posted earlier so you don't have to care
about buffers, decorations and the rest and can concentrate on geometry.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28  8:18             ` Eli Zaretskii
@ 2024-09-28  9:40               ` martin rudalics
  2024-09-28 11:35                 ` Eli Zaretskii
  2024-09-28 13:22                 ` pranshu sharma
  0 siblings, 2 replies; 65+ messages in thread
From: martin rudalics @ 2024-09-28  9:40 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pranshusharma366, emacs-devel

 > Thanks, but does it really make a lot of sense to make this a
 > side-effect of splitting a window?

It makes sense because (1) we do not have to make a new window that gets
deleted right away and (2) the geometry of the new window will be
handled by 'split-window' directly and not by some obscure copying
routine (I only later noted that 'resurrect-window' got me warnings
about memcpy combined with offsetof writing beyond the bounds of window
structures).

 > (If it makes sense due to
 > technical reasons, such as commonality of code of the implementation,
 > we could have a common internal subroutine with 2 separate APIs
 > exposed to Lisp.)

We can write a separate 'split-window-reuse-existing' function and have
it call a 'split-window-reuse-existing-internal' routine so we don't
compromise the present 'split-window' at all.  It's up to you what you
like more.

 > Or maybe it _will_ make a lot of sense if you reword the doc string so
 > that it explains why what we do with REFER is a variant of splitting a
 > window.  Something like
 >
 >    Instead of making a new window, this function can reuse an existing
 >    dead window...

OK.

 > Btw, "dead window" is mentioned only once in the ELisp manual, and
 > even that in passing, so it is not a very clear terminology, and might
 > need clarifications in this case.

The problem is that in Emacs a live window is a window that shows a
buffer.  Which implies that internal windows are dead.  I once tried to
convince Chong that this terminology is misleading but he didn't allow
me to change it.

 >> +If the optional fifth argument REFER is non-nil, it has to denote a
 >> +dead, former live window on the same frame as OLD or an arbitrary live
 >> +window.                                       ^^^
 >
 > What is "OLD" here?

It should be WINDOW.  OLD is the term used by 'split-window-internal'.

 > More generally, I don't think I understand what
 > you wanted to say by "or an arbitrary live window".

That's a separate functionality to give users more control of the window
the new window inherits properties from.  It's useful when splitting an
internal window and the _new_ window should get its initial buffer and
other properties from any but the frame's selected window.

 >> In the first case, REFER will become the new window with
 >> +properties like buffer, start and point, decorations and parameters as
 >> +to the last time when it was live.  In the latter case the new window
 >> +will inherit properties like buffer, start and point, decorations and
 >> +parameters from REFER.
 >
 > I suggest to describe each case separately, i.e. split the previous
 > sentence ("it has to denote ... or ...") into two, and explain
 > separately what happens in each case, instead of complicating with the
 > former and the latter.  Especially as there are additional cases (nil
 > or omitted), which add to the confusion:

I'll try to do that.

 >> +If REFER is nil or omitted, then if WINDOW is live, any such properties
 >> +are inherited from WINDOW.  If, however, WINDOW is an internal window,
 >> +the new window will inherit these properties from the window selected on
 >> +WINDOW's frame.
 >
 >> +	  if (!BUFFERP (r->old_buffer))
 >> +	    error ("Dead reference window was not a live window");
 >                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 > This seems to imply that the function expects a dead window to be a
 > live window(??).

In our misleading terminology a dead window can be either (i) a former
live window or (ii) an internal or former internal window.  I have to
exclude (ii) because an internal window should never become a leaf
window and vice-versa.

 >> +	  else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
 >> +	    error ("Dead reference window's old buffer is dead");
 >
 > Will users understand what is "old buffer" of a window?

It's the buffer returned by 'window-old-buffer'.  I will have to explain
this in more detail.

 >> +	  else if (!EQ (r->frame, frame))
 >> +	    error ("Dead referenec window was on other frame");
 >                           ^^^^^^^^^
 > Typo.  Also, I'd say "was on a frame other that that of window being
 > split" or something like that.

OK.

 >> +	  dead = true;
 >> +	}
 >> +      else if (!WINDOW_LIVE_P (refer))
 >> +	error ("Reference window must not be internal");
 >
 > Are we sure "internal" here will be understood?  How about using "leaf
 > window" instead?

But it's the opposite - a "non-leaf window".  If you (or anyone else)
have any proposals on how to improve the nomenclature in this area, I'll
be all ears.

 > More generally, the text of these error messages is not easily
 > correlated to the problematic argument, because it neither mentions
 > the argument by its exact name, nor mentions the problematic window by
 > any other specific reference.

So the error messages should explain in more detail what when wrong.

 >> +      /* Provisorially set new's buffer to that of the reference window,
 >              ^^^^^^^^^^^^^
 > Did you mean "provisionally"? or maybe "temporarily"?

Both would fit the bill.  But this is code that I didn't intend to
submit is part of a completely different changeset where the sizes
of an individual window would be needed to set up the size hints of
frames correctly in set_window_buffer.

 >> +      /* Set buffer of NEW to buffer of reference window.  We have to do it
 >> +	 here so the sizes of NEW are in place.  But be sure to do it before
 >> +	 adjusting the frame glyphs - otherwise Emacs may inexplicably loop
 >> +	 forever.  */
 >
 > This should be more explicit what code below adjusts the frame's
 > glyphs, because without that this very good comment is less useful
 > than it could be.

Again part of that other changeset.

 >>   	  unchain_marker (XMARKER (w->start));
 >> +	  wset_old_buffer (w, w->contents);
 >
 > What is this about?

When we make a new window and delete it before redisplay runs
window_change_functions for the first time, the old buffer of the window
is nil.  But that would have caused the "Dead reference window's old
buffer is dead" error with the earlier proposed 'resurrect-window' while
in fact the window (made by 'split-window' right before) did have an old
buffer.  It has no significance for the new 'split-window'.

 >> @@ -7720,6 +7795,7 @@ delete_all_child_windows (Lisp_Object window)
 >>   	 only, we use this slot to save the buffer for the sake of
 >>   	 possible resurrection in Fset_window_configuration.  */
 >>         wset_combination_limit (w, w->contents);
 >> +      wset_old_buffer (w, w->contents);
 >
 > And this?

Same explanation.  The code for Fdelete_window_internal and
delete_all_child_windows should be refactored so that they would call a
common delete_leaf_window.

Thanks for the careful reading, martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28  9:26               ` martin rudalics
@ 2024-09-28 10:53                 ` pranshu sharma
  2024-09-28 14:48                   ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-28 10:53 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

> I don't know 'swap-window-states' but if it uses 'window-state-get' and
> 'window-state-put' (which I happen to know quite intimately) the result
> won't be any better than with the concept you cited earlier.
>

I meant window-swap-states, and it does use window-state-get and put.


>> However one thing I'm stuck with it getting it to work with root C-x 2
>> C-x 3 kinda splits (basiclly where (listp (caddar (window-tree))) is
>> true).  However if you start with no windows, split window once, go to
>> split window, they you can go crazy with splitting in any direction
>> (even the C-x 2 C-x 3) and it will work when you call transpose-frame.
>
> I don't understand what you mean here.

Say you save window layout:
- +----+--+
- | A  |C |
- |____|__|
- |  B    |
- +-------+

(car (window-tree)) returns:


(t (0 0 137 30)
   ;; Following sexp is returned by (caddar (window-tree))
   (nil (0 0 137 15)
	#<window A>
	#<window C>)
   #<window B>)

In a scinario like this, where (caddar (window-tree)) is a list, the
function does not work as it will not have any anchor point.

However transpose-frame will work on the following layout, as it can
anchor of A

- +------+----+--+
- |      | B  |C |
- |  A   |____|__|
- |      |  C    |
- +------+-------+


>> This also different from the transpose-windows.el in that it does not
>> start on a blank slate(transpose-windows.el calls delete-other-windows
>> in the transpose-frame-set-arrangement), so transposing partial window
>> trees much easier but I haven't implimented it yet.
>
> Whatever you do someone has to delete all "other" windows and start with
> one specific live window that you subsequently split.

wdym?

> Try with the 'split-window' I posted earlier so you don't have to care
> about buffers, decorations and the rest and can concentrate on geometry.

just compiled emacs an tested it works, I'll do that



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28  9:40               ` martin rudalics
@ 2024-09-28 11:35                 ` Eli Zaretskii
  2024-09-28 14:58                   ` martin rudalics
  2024-09-28 13:22                 ` pranshu sharma
  1 sibling, 1 reply; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-28 11:35 UTC (permalink / raw)
  To: martin rudalics; +Cc: pranshusharma366, emacs-devel

> Date: Sat, 28 Sep 2024 11:40:27 +0200
> Cc: pranshusharma366@gmail.com, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> 
>  >> +	  if (!BUFFERP (r->old_buffer))
>  >> +	    error ("Dead reference window was not a live window");
>  >                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  > This seems to imply that the function expects a dead window to be a
>  > live window(??).
> 
> In our misleading terminology a dead window can be either (i) a former
> live window or (ii) an internal or former internal window.  I have to
> exclude (ii) because an internal window should never become a leaf
> window and vice-versa.

So maybe this is better:

   Dead REFER window was not a leaf window"

>  >> +      else if (!WINDOW_LIVE_P (refer))
>  >> +	error ("Reference window must not be internal");
>  >
>  > Are we sure "internal" here will be understood?  How about using "leaf
>  > window" instead?
> 
> But it's the opposite - a "non-leaf window".

Yes, so I suggested replacing "must not be internal" with "must be a
leaf window".  Is that wrong?

>  >>   	  unchain_marker (XMARKER (w->start));
>  >> +	  wset_old_buffer (w, w->contents);
>  >
>  > What is this about?
> 
> When we make a new window and delete it before redisplay runs
> window_change_functions for the first time, the old buffer of the window
> is nil.  But that would have caused the "Dead reference window's old
> buffer is dead" error with the earlier proposed 'resurrect-window' while
> in fact the window (made by 'split-window' right before) did have an old
> buffer.  It has no significance for the new 'split-window'.

So this fixes a related but different bug?



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28  9:40               ` martin rudalics
  2024-09-28 11:35                 ` Eli Zaretskii
@ 2024-09-28 13:22                 ` pranshu sharma
  2024-09-28 14:21                   ` Eli Zaretskii
  2024-09-28 14:49                   ` martin rudalics
  1 sibling, 2 replies; 65+ messages in thread
From: pranshu sharma @ 2024-09-28 13:22 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:
>
> It makes sense because (1) we do not have to make a new window that gets
> deleted right away and (2) the geometry of the new window will be
> handled by 'split-window' directly and not by some obscure copying
> routine (I only later noted that 'resurrect-window' got me warnings
> about memcpy combined with offsetof writing beyond the bounds of window
> structures).

Is there a technical reason for the `refer' argument to neccasarily be
_dead_ window, it would be very helpful if you could pass a living
window.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 13:22                 ` pranshu sharma
@ 2024-09-28 14:21                   ` Eli Zaretskii
  2024-09-28 14:49                   ` martin rudalics
  1 sibling, 0 replies; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-28 14:21 UTC (permalink / raw)
  To: pranshu sharma; +Cc: rudalics, emacs-devel

> From: pranshu sharma <pranshusharma366@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> Date: Sat, 28 Sep 2024 23:22:47 +1000
> 
> Is there a technical reason for the `refer' argument to neccasarily be
> _dead_ window, it would be very helpful if you could pass a living
> window.

My reading of the latest version of the patch posted by Martin is that
this is indeed possible.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 10:53                 ` pranshu sharma
@ 2024-09-28 14:48                   ` martin rudalics
  2024-09-29  7:36                     ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-28 14:48 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > Say you save window layout:
 > - +----+--+
 > - | A  |C |
 > - |____|__|
 > - |  B    |
 > - +-------+
 >
 > (car (window-tree)) returns:
 >
 >
 > (t (0 0 137 30)
 >     ;; Following sexp is returned by (caddar (window-tree))
 >     (nil (0 0 137 15)
 > 	#<window A>
 > 	#<window C>)
 >     #<window B>)
 >
 > In a scinario like this, where (caddar (window-tree)) is a list, the
 > function does not work as it will not have any anchor point.

Do you mean that your function doesn't work because A has to be split
twice - once to produce B and then to produce C?

 > However transpose-frame will work on the following layout, as it can
 > anchor of A
 >
 > - +------+----+--+
 > - |      | B  |C |
 > - |  A   |____|__|
 > - |      |  C    |
 > - +------+-------+

What is the anchor point here?  Does it work because you have to split A
once only and then deal with the split off window only?  I don't know
how to help you but I suppose your function should work by extracting
from the window tree all windows on the same level and recursively apply
itself on the respective tails of the window tree at that level.

 >> Whatever you do someone has to delete all "other" windows and start with
 >> one specific live window that you subsequently split.
 >
 > wdym?

The standard case is where you rotate the entire window tree of a frame.
In that case you would call 'delete-other-windows' and start splitting.
But in your initial posting you said that TransposeFrame has "No good
way to transpose only specific parts of window tree".  Suppose you have
the configuration you just mentioned

  +------+----+--+
  |      | B  |C |
  |  A   |____|__|
  |      |  D    |
  +------+-------+

and want to leave A in place.  So you have to delete the other windows C
and D first and then start splitting B (alternatively, you could
temporarily bind the 'no-delete-other-windows' parameter of A to t and
reset it after calling 'delete-other-windows' on B).

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 13:22                 ` pranshu sharma
  2024-09-28 14:21                   ` Eli Zaretskii
@ 2024-09-28 14:49                   ` martin rudalics
  1 sibling, 0 replies; 65+ messages in thread
From: martin rudalics @ 2024-09-28 14:49 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > Is there a technical reason for the `refer' argument to neccasarily be
 > _dead_ window, it would be very helpful if you could pass a living
 > window.

You can pass a live window to it.  But in that case it will only use
that window's properties for the new window 'split-window' made.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 11:35                 ` Eli Zaretskii
@ 2024-09-28 14:58                   ` martin rudalics
  2024-09-28 15:28                     ` Eli Zaretskii
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-28 14:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pranshusharma366, emacs-devel

 > So maybe this is better:
 >
 >     Dead REFER window was not a leaf window"

OK.

 >>   >> +      else if (!WINDOW_LIVE_P (refer))
 >>   >> +	error ("Reference window must not be internal");
 >>   >
 >>   > Are we sure "internal" here will be understood?  How about using "leaf
 >>   > window" instead?
 >>
 >> But it's the opposite - a "non-leaf window".
 >
 > Yes, so I suggested replacing "must not be internal" with "must be a
 > leaf window".  Is that wrong?

No.  We could also say "must display a buffer".

 >
 >>   >>   	  unchain_marker (XMARKER (w->start));
 >>   >> +	  wset_old_buffer (w, w->contents);
 >>   >
 >>   > What is this about?
 >>
 >> When we make a new window and delete it before redisplay runs
 >> window_change_functions for the first time, the old buffer of the window
 >> is nil.  But that would have caused the "Dead reference window's old
 >> buffer is dead" error with the earlier proposed 'resurrect-window' while
 >> in fact the window (made by 'split-window' right before) did have an old
 >> buffer.  It has no significance for the new 'split-window'.
 >
 > So this fixes a related but different bug?

It wasn't a bug so far because the "old buffer" was not defined for dead
windows.  'window-old-buffer' is described as

   Return the old buffer displayed by WINDOW.
   WINDOW must be a live window and defaults to the selected one.

   The return value is the buffer shown in WINDOW at the last time window
   change functions were run.  It is nil if WINDOW was created after
   that.  It is t if WINDOW has been restored from a window configuration
   after that.

What the patch does is to now make it work for dead windows in the sense
that its value is that of the buffer shown in the window at the time the
window was deleted.  In general, this _is_ the buffer stored in the
old_buffer slot.  But if we manage to delete a window whose old buffer
is nil or t _before_ running window change functions on it for the first
time, it isn't.

But I just noticed that even 'window-old-buffer' can be affected by the
patch if we (i) make a window (ii) delete it before it's seen by the
change functions and (iii) resurrect it.  In that (unlikely) scenario
the next change functions will consider the window as one seen by the
last change functions although these have never seen it.  I have to add
another slot del_buffer to the window structure.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 14:58                   ` martin rudalics
@ 2024-09-28 15:28                     ` Eli Zaretskii
  2024-10-07  8:33                       ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: Eli Zaretskii @ 2024-09-28 15:28 UTC (permalink / raw)
  To: martin rudalics; +Cc: pranshusharma366, emacs-devel

> Date: Sat, 28 Sep 2024 16:58:24 +0200
> Cc: pranshusharma366@gmail.com, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> 
>  >>   >> +      else if (!WINDOW_LIVE_P (refer))
>  >>   >> +	error ("Reference window must not be internal");
>  >>   >
>  >>   > Are we sure "internal" here will be understood?  How about using "leaf
>  >>   > window" instead?
>  >>
>  >> But it's the opposite - a "non-leaf window".
>  >
>  > Yes, so I suggested replacing "must not be internal" with "must be a
>  > leaf window".  Is that wrong?
> 
> No.  We could also say "must display a buffer".

I think we should say both, to be very clear.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 14:48                   ` martin rudalics
@ 2024-09-29  7:36                     ` pranshu sharma
  2024-09-29  8:40                       ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-29  7:36 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel


>> In a scinario like this, where (caddar (window-tree)) is a list, the
>> function does not work as it will not have any anchor point.
>
> Do you mean that your function doesn't work because A has to be split
> twice - once to produce B and then to produce C?

Something like that, but I fixed now, see code below

> What is the anchor point here?  Does it work because you have to split A
> once only and then deal with the split off window only?  I don't know
> how to help you but I suppose your function should work by extracting
> from the window tree all windows on the same level and recursively apply
> itself on the respective tails of the window tree at that level.

The problem was that I was splitting off another window as I was not
already desyroying the whole tree.

Thanks for your explenation, I found out I was only over complicating it
by not destroying windows, so I gave up that approach.

This time instead of calling delete-other-windows, I recusivly walked
window subtree and deleted them.


The following code implements transpose-frame and which works fine, I
tested with some random window layouts and it worked for all.  It uses
the split-window refer argument.

The code:
-----------------------------------------
(defun transpose-frame (arg)
  "Transpose frame, or if arg is non-nil, selected window."
  (interactive "P")
  (when-let* ((win-tree (car (window--subtree
			      (if arg
				  (window-parent (selected-window))
				(frame-root-window)))))
	      (fwin (if arg
			(selected-window)
		      (let ((win (window-child (frame-root-window))))
			(while (not (window-live-p win))
			  (setq win (window-child win)))
			win)))
	      (_ (not (windowp win-tree))))
      (toggle-window-split
       (let* (delist
	     (res (deepmap (lambda (e) (if (windowp e)
					    (prog1 (cons e (window-edges e))
					      (unless (equal fwin e)
						(push e delist)))
					  e))
			    win-tree)))
         (mapc 'delete-window delist)
	 res)
       fwin)))


;; Is there already another inbuilt funcion like this?
(defun deepmap(func ls)
  (if (null ls)
      ()
    (cons (if (listp (car ls))
	      (deepmap func (car ls))
	    (funcall func (car ls)))
	  (deepmap func (cdr ls)))))


(defun toggle-window-split (subtree cwin)
  (pcase-let* ((`(,eee . ,flen) (if (car subtree)
				    (cons 1 (window-width cwin))
				  (cons 0 (window-height cwin))))
	       (ilen (float (- (nth (+ 2 eee) (cadr subtree))
			       (nth (+ eee 0) (cadr subtree))))))
    (mapc
     (pcase-lambda (`(,win . ,size))
       (if (listp win)	
	   (toggle-window-split win (split-window cwin
						  (- (round (* flen  (/ size ilen))))
						  (car subtree)
						  nil
						  (seq-some
						   (lambda (x)
						     (and (windowp x) x))
						   (flatten-list win))))
	 (split-window cwin (- (round (* flen (/ size ilen))))
		       (car subtree) nil
		       win)))
     (mapcar
      (lambda (e)
	(pcase-let ((`(,edges ,window?)
		     (if (windowp (car e))
			 (list (cdr e) (car e))
		       (list (cadr e) e))))
	  (cons window? (- (nth (+ 2 eee) edges)
			   (nth eee edges)))))
      (nreverse (cdddr subtree))))
    (unless (windowp (caaddr subtree))
      (toggle-window-split (caddr subtree) cwin))))
-----------------------------------------



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-29  7:36                     ` pranshu sharma
@ 2024-09-29  8:40                       ` martin rudalics
  2024-09-29  9:23                         ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-29  8:40 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > The following code implements transpose-frame and which works fine, I
 > tested with some random window layouts and it worked for all.  It uses
 > the split-window refer argument.

Thank you.

 > (defun transpose-frame (arg)
 >   "Transpose frame, or if arg is non-nil, selected window."

ARG (upper case please) should be renamed to make it more descriptive
and you should explain what transposing the selected window means.

 > 	     (res (deepmap (lambda (e) (if (windowp e)
 > 					    (prog1 (cons e (window-edges e))
 > 					      (unless (equal fwin e)
 > 						(push e delist)))

IIUC here you "flatten" the return value of 'window-tree'.  Why do you
do that?  Can't 'transpose-frame' work directly on the return value of a
(possibly modified) 'window-tree'?

 >					    (prog1 (cons e (window-edges e))

On my maximized frame calling 'transpose-frame' repeatedly shrinks the
right/bottom windows until they cannot be shrunk any more.  I wouldn't
use 'window-edges' here.  Make your own version of 'window-tree' (or
give that an optional argument) so it returns the normal sizes of
windows instead of the edges and use the normal sizes as factor for the
SIZE argument of ‘split-window’ and make the PIXELWISE argument non-nil.

Rounding window sizes can be awfully tricky and we should try to avoid
its effects as good as we can.  When transposing windows on a GUI you
will always have to take into account that the width of a window
includes things like fringes and scroll bars (where the size of the
latter is toolkit dependent) which often make the width not an integral
multiple of the frame's character width.  A similar argument goes for
window heights, for example, if a mode or tab line is displayed with a
different font or some sort of box around it.

Also I expected your functions to run on subwindows of a frame's windows
and permit to rotate configurations clockwise or counter clockwise as
the version from 2011 did?  Do you intend to provide those?

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-29  8:40                       ` martin rudalics
@ 2024-09-29  9:23                         ` pranshu sharma
  2024-09-29 14:48                           ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-29  9:23 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> The following code implements transpose-frame and which works fine, I
>> tested with some random window layouts and it worked for all.  It uses
>> the split-window refer argument.
>
> Thank you.
>
>> (defun transpose-frame (arg)
>>   "Transpose frame, or if arg is non-nil, selected window."
>
> ARG (upper case please) should be renamed to make it more descriptive
> and you should explain what transposing the selected window means.

Ok, will do

>
>> 	     (res (deepmap (lambda (e) (if (windowp e)
>> 					    (prog1 (cons e (window-edges e))
>> 					      (unless (equal fwin e)
>> 						(push e delist)))
>
> IIUC here you "flatten" the return value of 'window-tree'.  Why do you
> do that?  Can't 'transpose-frame' work directly on the return value of a
> (possibly modified) 'window-tree'?

This is definetly a big hack.  The reason why this is needed is
because the parent window might not actually be a window, it might also
be another split, so it would have to recursivly descent find the first
window.

The only real alternative I can see is that if toggle-window-split
returns a list of spltis to do, and then they are mapped over and done
by toggle-window-split one level higher.

I'll look into how transpose-frame.el deals with this.

>>					    (prog1 (cons e (window-edges e))
>
> On my maximized frame calling 'transpose-frame' repeatedly shrinks the
> right/bottom windows until they cannot be shrunk any more.

Hmm, show your window-tree (or the sequence of splits you did), I tested
with a lot of splits and didn't find this problem.

> I wouldn't use 'window-edges' here.  Make your own version of
> 'window-tree' (or give that an optional argument) so it returns the
> normal sizes of windows instead of the edges and use the normal sizes
> as factor for the SIZE argument of ‘split-window’ and make the
> PIXELWISE argument non-nil.

I see, this should definetly make the function better.

> Rounding window sizes can be awfully tricky and we should try to avoid
> its effects as good as we can.  When transposing windows on a GUI you
> will always have to take into account that the width of a window
> includes things like fringes and scroll bars (where the size of the
> latter is toolkit dependent) which often make the width not an integral
> multiple of the frame's character width.  A similar argument goes for
> window heights, for example, if a mode or tab line is displayed with a
> different font or some sort of box around it.
>
> Also I expected your functions to run on subwindows of a frame's windows
> and permit to rotate configurations clockwise or counter clockwise as
> the version from 2011 did?  Do you intend to provide those?

They should be very easy(just changing up the arguments of split-window
to correct combo of above, below, right, left), I'm just
trying to first get the other aspects streamlined, but yes, I do intend
on adding them.

I'll also add flip if you want.

>
> martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-29  9:23                         ` pranshu sharma
@ 2024-09-29 14:48                           ` martin rudalics
  2024-09-30  6:29                             ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-29 14:48 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]

 > This is definetly a big hack.  The reason why this is needed is
 > because the parent window might not actually be a window, it might also
 > be another split, so it would have to recursivly descent find the first
 > window.

Hmm... I seem to understand.  TransposeFrame uses the buffer of the
window it splits so there you have a lot of windows showing the frame's
selected window initially and eventually see them set to their original
buffers.  We want to set a window's final buffer immediately at the time
of splitting.

 > The only real alternative I can see is that if toggle-window-split
 > returns a list of spltis to do, and then they are mapped over and done
 > by toggle-window-split one level higher.
 >
 > I'll look into how transpose-frame.el deals with this.

Note that TransposeFrame also may revert the cdr of the list it deals
with.  Back then the 'above and 'left values for SIDE were not known
yet.

 >>> 					    (prog1 (cons e (window-edges e))
 >>
 >> On my maximized frame calling 'transpose-frame' repeatedly shrinks the
 >> right/bottom windows until they cannot be shrunk any more.
 >
 > Hmm, show your window-tree (or the sequence of splits you did), I tested
 > with a lot of splits and didn't find this problem.

I'll attach a capture of the "initial" split and the "final" split after
a couple of invocations of 'transpose-frame'.

martin

[-- Attachment #2: initial.png --]
[-- Type: image/png, Size: 84203 bytes --]

[-- Attachment #3: final.png --]
[-- Type: image/png, Size: 85594 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-29 14:48                           ` martin rudalics
@ 2024-09-30  6:29                             ` pranshu sharma
  2024-09-30  8:57                               ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-09-30  6:29 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel


Hello Martin,

After some work, the code is now complete and uses pixels instead colums
of.  It can do everything the orignal transpose frame could (flip,
transpose, rotate), and results are the same.

Some function are like opposites, eg flip-frame-horizontally and
flip-frame-verticly, I thought about merging them and using prefix arg,
but then prefix arg already in use for if or not to apply to partial
subtree instead frame.

English is not my first language, so I was unable to make the docstrings
for the more complex function, and I don't know how to explain what
transpose does.

Also I think your error was coming from scroll and tool bars(should be
fixed now cuz pixels), but since terminal does not have them I couldnt
run into too small for splitting error on terminal.

-----------------------------

(defun window--subtree-with-size (window &optional next)
  "Like `window--subtree' but each window is replaced with the
list: (WINDOW PIXEL-HEIGHT PIXEL-WIDTH), and window-edges is replaced
with the list: (PIXEL-HEIGHT PIXEL-WIDTH)."
  (let (list)
    (while window
      (setq list
	    (cons
	     (cond
	      ((window-top-child window)
	       (cons t (cons (list (window-pixel-height window) (window-pixel-width window))
			     (window--subtree-with-size (window-top-child window) t))))
	      ((window-left-child window)
	       (cons nil (cons (list (window-pixel-height window) (window-pixel-width window))
			       (window--subtree-with-size (window-left-child window) t))))
	      (t (list window (window-pixel-height window) (window-pixel-width window))))
	     list))
      (setq window (when next (window-next-sibling window))))
    (nreverse list)))


(defun rotate-frame-anticlockwise (subtree-only)
  "If SUBTREE-ONLY is nil, rotate the whole frame anti clockwise else only
apply on the subtree of selected window."
  (interactive "P")
  (apply-rearrange-frame subtree-only '(right . above) nil))

(defun rotate-frame-clockwise (subtree-only)
  "Like `rotate-frame-anticlockwise' but rotate clockwise instead."
  (interactive "P")
  (apply-rearrange-frame subtree-only '(left . below) nil))

(defun flip-frame-horizontally (subtree-only)
  "If SUBTREE-ONLY is nil, rotate the whole frame anti clockwise else only
apply on the subtree of selected window."
  (interactive "P")
  (apply-rearrange-frame subtree-only '(below . left) t))

(defun flip-frame-verticly (subtree-only)
  "Like `flip-frame-horizontally' but flip verticlly instead."
  (interactive "P")
  (apply-rearrange-frame subtree-only '(above . right) t))

(defun transpose-frame (subtree-only)
  (interactive "P")
  (apply-rearrange-frame subtree-only '(right . below) nil))


(defun apply-rearrange-frame (subtree-only conf norm-size)
  "Transpose frame, or if SUBTREE-ONLY is non-nil, selected window."
  (if (eq (next-window) (selected-window))
      (message "No windows to transpose.")
    (let* ((win-tree (car (window--subtree-with-size
			   (if subtree-only
			       (window-parent (selected-window))
			     (frame-root-window)))))
	   (fwin (if subtree-only
		     (selected-window)
		   (let ((win (window-child (frame-root-window))))
		     (while (not (window-live-p win))
		       (setq win (window-child win)))
		     win))))
      (mapc (lambda (win)
	      (when (and (windowp win)
			 (not (eq win fwin)))
		(delete-window win)))
	    (flatten-list win-tree))
      (toggle-window-split win-tree fwin conf norm-size)
      (select-window fwin))))

(defun toggle-window-split (subtree cwin conf norm-size)
  (pcase-let ((`(,ilen . ,flen) (if (car subtree)
				    (cons (float (car (cadr subtree)))
					  (float (window-pixel-width cwin)))
				  (cons (float (cadr (cadr subtree)))
					(float (window-pixel-height cwin))))))
    (mapc
     (pcase-lambda (`(,win . ,size))
       (let ((split-size (- (if norm-size
				size
			      (round (* flen  (/ size ilen))))))
	     (split-type
	      (funcall (if (car subtree) 'car 'cdr) conf)))
	 (if (listp win)	
	     (toggle-window-split win (split-window cwin
						    split-size
						    split-type
						    t
						    (seq-some
						     (lambda (x)
						       (and (windowp x) x))
						     (flatten-list win)))
				  conf norm-size)
	   (split-window cwin split-size
			 split-type t
			 win))))
     (mapcar
      (lambda (e)
	(pcase-let* ((`(,size ,window?)
		      (if (windowp (car e))
			  (list (cdr e) (car e))
			(list (cadr e) e))))
	  (cons window? (if (car subtree)
			    (car size)
			  (cadr size)))))
      (nreverse (cdddr subtree))))
    (unless (windowp (caaddr subtree))
      (toggle-window-split (caddr subtree) cwin conf norm-size))))




^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-30  6:29                             ` pranshu sharma
@ 2024-09-30  8:57                               ` martin rudalics
  2024-10-01  9:17                                 ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-09-30  8:57 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > Hello Martin,
 >
 > After some work,

... remarkable work ...

 > the code is now complete and uses pixels instead colums
 > of.  It can do everything the orignal transpose frame could (flip,
 > transpose, rotate), and results are the same.
 >
 > Some function are like opposites, eg flip-frame-horizontally and
 > flip-frame-verticly, I thought about merging them and using prefix arg,
 > but then prefix arg already in use for if or not to apply to partial
 > subtree instead frame.
 >
 > English is not my first language, so I was unable to make the docstrings
 > for the more complex function, and I don't know how to explain what
 > transpose does.

Let's hope someone will eventually proofread this as soon as we agree on
a final version.

 > Also I think your error was coming from scroll and tool bars(should be
 > fixed now cuz pixels), but since terminal does not have them I couldnt
 > run into too small for splitting error on terminal.

I rotated my windows a number of times and see no shrinking any more.
Even with pixelwise resizing it's impossible to exclude that windows
shrink over time but that's unavoidable unless one uses some heuristics.
So I think that your code handles this well now.

 > (defun window--subtree-with-size (window &optional next)
 >    "Like `window--subtree' but each window is replaced with the
 > list: (WINDOW PIXEL-HEIGHT PIXEL-WIDTH), and window-edges is replaced
 > with the list: (PIXEL-HEIGHT PIXEL-WIDTH)."

As a rule, the first line of a doc-string should be a complete sentence
and be at most 72 columns wide (see Appendix D.6 of the Elisp manual).
And you should describe all arguments like WINDOW and NEXT.

Alternatively, we could give 'window-tree' an optional PIXELWISE
argument so it returns the pixel edges of windows.

 >    (let (list)
 >      (while window
 >        (setq list
 > 	    (cons
 > 	     (cond
 > 	      ((window-top-child window)
 > 	       (cons t (cons (list (window-pixel-height window) (window-pixel-width window))

Lines should not exceed 80 characters and you probably want to use
'cons' instead of 'list' here.

 > 			     (window--subtree-with-size (window-top-child window) t))))
 > 	      ((window-left-child window)
 > 	       (cons nil (cons (list (window-pixel-height window) (window-pixel-width window))
 > 			       (window--subtree-with-size (window-left-child window) t))))
 > 	      (t (list window (window-pixel-height window) (window-pixel-width window))))
 > 	     list))
 >        (setq window (when next (window-next-sibling window))))
 >      (nreverse list)))
 >
 >
 > (defun rotate-frame-anticlockwise (subtree-only)
 >    "If SUBTREE-ONLY is nil, rotate the whole frame anti clockwise else only
 > apply on the subtree of selected window."
 >    (interactive "P")
 >    (apply-rearrange-frame subtree-only '(right . above) nil))

I think you should rename all these into something like
'rotate-windows-anticlockwise' and 'transpose-windows' (we are already
using plurals in 'transpose-lines' and 'transpose-chars').  And we do
not rotate the entire frame - the minibuffer window stays in place, for
example.  So I would try to say

   (defun rotate-windows-anticlockwise (&optional frame window)
     "Rotate windows of FRAME anticlockwise by 90 degrees.
   FRAME must be a live frame and defaults to the selected frame.  By
   default rotate the root window of FRAME (or its main window if it
   differs from the root window).  If WINDOW is non-nil ..."

Which means that we need the additional features:

(1) Rotate windows on any live frame.

(2) Run the function on 'window-main-window' of FRAME unless WINDOW is
defined and never rotate a side window.  Rotating side windows would
cause completely undefined behavior because their slots are expected to
never change.  Hence, if WINDOW is specified and is a side window, say
that you cannot rotate side windows.

(3) "subtree of selected window" is an undefined concept.  You should
say something like "to transpose all windows in the same combination as
WINDOW" instead.  But note that with a slightly more complex layout, no
average user will know what that combination is (think of C-x 2 C-x 3
C-x o C-x o C-x 3).  We could eventually try to flash all windows that
would be affected by the change but that would be non-trivial.

 > (defun apply-rearrange-frame (subtree-only conf norm-size)

I'd call this something like 'transpose-windows--rearrange' so you can
change its behavior whenever you want.

 >    "Transpose frame, or if SUBTREE-ONLY is non-nil, selected window."
 >    (if (eq (next-window) (selected-window))
 >        (message "No windows to transpose.")
 >      (let* ((win-tree (car (window--subtree-with-size
 > 			   (if subtree-only
 > 			       (window-parent (selected-window))
 > 			     (frame-root-window)))))

Is fwin not the same as what 'frame-first-window' returns?  If not,
please telly why in a comment.

 > 	   (fwin (if subtree-only
 > 		     (selected-window)
 > 		   (let ((win (window-child (frame-root-window))))
 > 		     (while (not (window-live-p win))
 > 		       (setq win (window-child win)))
 > 		     win))))
 >        (mapc (lambda (win)
 > 	      (when (and (windowp win)
 > 			 (not (eq win fwin)))
 > 		(delete-window win)))

Please tell in a comment why you flatten win-tree her.

 > 	    (flatten-list win-tree))
 >        (toggle-window-split win-tree fwin conf norm-size)
 >        (select-window fwin))))
 >
 > (defun toggle-window-split (subtree cwin conf norm-size)

Should become window--... and have its arguments described.

 >    (pcase-let ((`(,ilen . ,flen) (if (car subtree)
 > 				    (cons (float (car (cadr subtree)))
 > 					  (float (window-pixel-width cwin)))
 > 				  (cons (float (cadr (cadr subtree)))
 > 					(float (window-pixel-height cwin))))))
 >      (mapc
 >       (pcase-lambda (`(,win . ,size))
 >         (let ((split-size (- (if norm-size
 > 				size
 > 			      (round (* flen  (/ size ilen))))))
 > 	     (split-type
 > 	      (funcall (if (car subtree) 'car 'cdr) conf)))
 > 	 (if (listp win)
 > 	     (toggle-window-split win (split-window cwin
 > 						    split-size
 > 						    split-type
 > 						    t
 > 						    (seq-some
 > 						     (lambda (x)
 > 						       (and (windowp x) x))
 > 						     (flatten-list win)))
 > 				  conf norm-size)

Here I'd write

	     (let ((refer (seq-some
			   (lambda (x)
			     (and (windowp x) x))
			   (flatten-list win))))
	       (toggle-window-split
		win (split-window cwin split-size split-type t refer)
		conf norm-size))

but I won't argue about styles.

 >        (nreverse (cdddr subtree))))
 >      (unless (windowp (caaddr subtree))
 >        (toggle-window-split (caddr subtree) cwin conf norm-size))))

Whenever using things like cdddr, caaddr or caddr, please say in a
comment what these are supposed to be.  You have condensed the original
version of your code considerably so please think about people who
eventually want to understand what the code does.

Many thanks, martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-30  8:57                               ` martin rudalics
@ 2024-10-01  9:17                                 ` pranshu sharma
  2024-10-02  9:04                                   ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-01  9:17 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

> Alternatively, we could give 'window-tree' an optional PIXELWISE
> argument so it returns the pixel edges of windows.

You decide

>
> Lines should not exceed 80 characters and you probably want to use
> 'cons' instead of 'list' here.
>
Done
>
> I think you should rename all these into something like
> 'rotate-windows-anticlockwise' and 'transpose-windows' (we are already
> using plurals in 'transpose-lines' and 'transpose-chars').  And we do
> not rotate the entire frame - the minibuffer window stays in place, for
> example.  So I would try to say
>
>   (defun rotate-windows-anticlockwise (&optional frame window)
>     "Rotate windows of FRAME anticlockwise by 90 degrees.
>   FRAME must be a live frame and defaults to the selected frame.  By
>   default rotate the root window of FRAME (or its main window if it
>   differs from the root window).  If WINDOW is non-nil ..."
>
> Which means that we need the additional features:
>
> (1) Rotate windows on any live frame.
>
> (2) Run the function on 'window-main-window' of FRAME unless WINDOW is
> defined and never rotate a side window.  Rotating side windows would
> cause completely undefined behavior because their slots are expected to
> never change.  Hence, if WINDOW is specified and is a side window, say
> that you cannot rotate side windows.
>
> (3) "subtree of selected window" is an undefined concept.  You should
> say something like "to transpose all windows in the same combination as
> WINDOW" instead.  But note that with a slightly more complex layout, no
> average user will know what that combination is (think of C-x 2 C-x 3
> C-x o C-x o C-x 3).  We could eventually try to flash all windows that
> would be affected by the change but that would be non-trivial.
>

Done, I just said all 'windows of' instead.

Also instead of seperate window and frame args, I just added added one
window-or-frame arg.


> I'd call this something like 'transpose-windows--rearrange' so you can
> change its behavior whenever you want.
>

Yes, good idea

> Is fwin not the same as what 'frame-first-window' returns?  If not,
> please telly why in a comment.

It was, I just found out the function exists, thx

> Please tell in a comment why you flatten win-tree her.
>
>> 	    (flatten-list win-tree))
>>        (toggle-window-split win-tree fwin conf norm-size)
>>        (select-window fwin))))
>>
>> (defun toggle-window-split (subtree cwin conf norm-size)
>
> Should become window--... and have its arguments described.

I just did as subroutine style, same as something like
`window--atom-check-1'.

> Here I'd write
>
> 	     (let ((refer (seq-some
> 			   (lambda (x)
> 			     (and (windowp x) x))
> 			   (flatten-list win))))
> 	       (toggle-window-split
> 		win (split-window cwin split-size split-type t refer)
> 		conf norm-size))
>
> but I won't argue about styles.

Although this would be cleaner, but it means the instance of refer would
be stored in memory unnecessarily while the old toggle-window-split
would be going recursivly.

> Whenever using things like cdddr, caaddr or caddr, please say in a
> comment what these are supposed to be.  You have condensed the original
> version of your code considerably so please think about people who
> eventually want to understand what the code does.
>

Yeah I did that, after all, I found out while doing this orignally how
hard the code in in trasnpose-frame.el was to read.  Well even without
the comments(which I added now), the code is more readable now thanks
you adding refer argument to split-window.


---------------------------------------------
(defun window--subtree-with-size (window &optional next)
  "Like `window--subtree' but each window is replaced with the
list: (WINDOW (PIXEL-HEIGHT . PIXEL-WIDTH)), and window-edges is replaced
with the cons cell: (PIXEL-HEIGHT . PIXEL-WIDTH)."
  (let (list)
    (while window
      (setq list
	    (cons
	     (cond
	      ((window-top-child window)
	       (cons t (cons (cons (window-pixel-height window)
				   (window-pixel-width window))
			     (window--subtree-with-size
			      (window-top-child window) t))))
	      ((window-left-child window)
	       (cons nil (cons (cons (window-pixel-height window)
				     (window-pixel-width window))
			       (window--subtree-with-size
				(window-left-child window) t))))
	      (t (list window (cons (window-pixel-height window)
				    (window-pixel-width window)))))
	     list))
      (setq window (when next (window-next-sibling window))))
    (nreverse list)))

(defun rotate-windows-anticlockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW 90 degrees anticlockwise.
See `rotate-windows-clockwise' for more."
  (interactive `(,(and prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (frame-root-window frame-or-window))))
    (transpose-windows--rearrange window '(right . above) nil)))

(defun rotate-windows-clockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame. If FRAME-OR-WINDOW is a frame, rotate from the root
window of the frame, otherwise rotate from FRAME-OR-WINDOW."
  (interactive `(,(and prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (frame-root-window frame-or-window))))
    (transpose-windows--rearrange window '(left . below) nil)))

(defun flip-windows-horizontally (&optional frame-or-window)
  "Horizontally flip windows of FRAME-OR-WINDOW.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame. If FRAME-OR-WINDOW is a frame, flip from the root
window of the frame, otherwise flip from FRAME-OR-WINDOW."
  (interactive `(,(and prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (frame-root-window frame-or-window))))
    (transpose-windows--rearrange window '(below . left) t)))


(defun flip-windows-vertically (&optional frame-or-window)
  "Vertically flip windows of FRAME-OR-WINDOW.
See `flip-windows-horizontally' for more."
  (interactive `(,(and prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (frame-root-window frame-or-window))))
    (transpose-windows--rearrange window '(above . right) t)))

(defun transpose-windows (&optional frame-or-window)
  "Transpose windows of FRAME-OR-WINDOW.
Windows are rearanged such that where an horizontal split was used, an
vertical one is instead, and vice versa. FRAME-OR-WINDOW must be a live
frame or window and defaults to the selected frame. If FRAME-OR-WINDOW
is a frame, transpose from the root window of the frame, otherwise
transpose from FRAME-OR-WINDOW."
  (interactive `(,(and prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (frame-root-window frame-or-window))))
    (transpose-windows--rearrange window '(right . below) nil)))


(defun transpose-windows--rearrange (frame-or-window conf norm-size)
  "Rearrange windows of FRAME-OR-WINDOW recursively.
CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
horizontal split is called when splitting a window that was previously
horizontally split, and VERTICAL-SPLIT for a window that was previously
vertically split.  When is NORM-SIZE non-nil, the size argument of the
window-split is converted from vertical to horizontal or vice versa,
with the same proportion of the total split."
  (let ((rwin (if (framep frame-or-window)
		  (frame-root-window frame-root-window)
		frame-or-window)))
    (if (or (not rwin)
	    (zerop (window-child-count rwin)))
	(message "Not enough windows")
      (let* ((fwin (frame-first-window rwin))
	     (selwin (frame-selected-window frame-or-window))
	     (win-tree (car (window--subtree-with-size rwin))))
	;; 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)))
	(transpose-windows--rearrange-1 win-tree fwin conf norm-size)
	;; Go back to previously selected window.
	(select-window selwin)))))

(defun transpose-windows--rearrange-1 (subtree cwin conf norm-size)
  "Subroutine of `transpose-windows--rearrange'."
  ;; `ilen' is the max size a window could be of given the split type.
  ;; `flen' is max size the window could be converted to the opposite
  ;; of the given split type.
  (pcase-let ((`(,ilen . ,flen) (if (car subtree)
				    (cons (float (car (cadr subtree)))
					  (float (window-pixel-width cwin)))
				  (cons (float (cdr (cadr subtree)))
					(float (window-pixel-height cwin))))))
    (mapc
     (pcase-lambda (`(,win . ,size))
       (let ((split-size (- (if norm-size
				size
			      (round (* flen  (/ size ilen))))))
	     (split-type
	      (funcall (if (car subtree) 'car 'cdr) conf)))
	 (if (listp win)
	     ;; `win' is a window subtree.
	     (transpose-windows--rearrange-1 win (split-window cwin
						    split-size
						    split-type
						    t
						    (seq-some
						     (lambda (x)
						       (and (windowp x) x))
						     (flatten-list win)))
					     conf norm-size)
	   ;; `win' is a window.
	   (split-window cwin split-size
			 split-type t
			 win))))
     (mapcar
      (lambda (e)
	(let ((window? (if (windowp (car e)) (car e) e)))
	  (cons window?
		;; The relevent size of the window.
		(if (car subtree)
		    (car (cadr e))
		  (cdr (cadr e))))))
      ;; By using cdddr, we ignore over window split type, sizes and
      ;; the first window (it's implicitly created).
      (nreverse (cdddr subtree))))
    ;; (caaddr subtree) is the first window.
    (unless (windowp (caaddr subtree))
      (transpose-windows--rearrange-1 (caddr subtree) cwin conf norm-size))))



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-01  9:17                                 ` pranshu sharma
@ 2024-10-02  9:04                                   ` martin rudalics
  2024-10-03  7:06                                     ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-02  9:04 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >> Alternatively, we could give 'window-tree' an optional PIXELWISE
 >> argument so it returns the pixel edges of windows.
 >
 > You decide

Better not - the fact that 'window-tree' does not report the edges of
live windows constitutes bad design.  Let's not support it.  Rather
let's make it a normal function called 'window-tree-pixel-sizes'.  I
would write its doc string as

   (defun window-tree-pixel-sizes (window &optional next)
     "Return pixel sizes of all windows rooted at WINDOW.
   The return value is a list where each window is represented either by a
   triple whose first element is either t for an internal window that is a
   horizontal combination, nil for an internal window that is a vertical
   combination, or the window itself for a live window.  The second element
   is a cons of the pixel height and pixel width of the window.  The third
   element is specified for internal windows only and recursively lists
   that window's child windows using the same triple structure."

but you would have to check whether it really does what I wrote.

 > (defun rotate-windows-anticlockwise (&optional frame-or-window)
 >   "Rotate windows of FRAME-OR-WINDOW 90 degrees anticlockwise.
 > See `rotate-windows-clockwise' for more."

I think it's better to write out the full doc-string here first and
in a final sentence say

   See `rotate-windows-clockwise' for how to rotate windows in the
   opposite direction.

 > (defun rotate-windows-clockwise (&optional frame-or-window)
 >   "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees.
 > FRAME-OR-WINDOW must be a live frame or window and defaults to the
 > selected frame. If FRAME-OR-WINDOW is a frame, rotate from the root
 > window of the frame, otherwise rotate from FRAME-OR-WINDOW."

Please add two spaces after the end of each sentence like

   selected frame.  If FRAME-OR-WINDOW is a frame, ...

Also I would omit the "from" in "rotate from".  And I would add a cross
reference to 'rotate-windows-anticlockwise' at the end.

 > (defun flip-windows-horizontally (&optional frame-or-window)
 >   "Horizontally flip windows of FRAME-OR-WINDOW.
 > FRAME-OR-WINDOW must be a live frame or window and defaults to the
 > selected frame. If FRAME-OR-WINDOW is a frame, flip from the root
 > window of the frame, otherwise flip from FRAME-OR-WINDOW."

Here you should probably first say what "flip" means.  It's obvious when
you have a frame with two side-by-side live windows.  It's already less
obvious with three side-by-side windows and even less so with more
complex layouts.

 > (defun transpose-windows (&optional frame-or-window)
 >   "Transpose windows of FRAME-OR-WINDOW.
 > Windows are rearanged such that where an horizontal split was used, an
 > vertical one is instead, and vice versa. FRAME-OR-WINDOW must be a live
 > frame or window and defaults to the selected frame. If FRAME-OR-WINDOW
 > is a frame, transpose from the root window of the frame, otherwise
 > transpose from FRAME-OR-WINDOW."

Please us active voice like

   Rearrange windows such that where a horizontal split was used a
   vertical one is used instead, and vice versa.

and again remove the "from" in "transpose from".

 > (defun transpose-windows--rearrange (frame-or-window conf norm-size)

I'd call this just 'window--transpose'.

 > "Rearrange windows of FRAME-OR-WINDOW recursively.
 > CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
 > horizontal split is called when splitting a window that was previously
 > horizontally split, and VERTICAL-SPLIT for a window that was previously
 > vertically split.

CONF is confusing.  Why is it a cons cell in the first place?  Wouldn't
a simple boolean - t for horizontal and nil for vertical - suffice?  If
not, please explain why.

 > When is NORM-SIZE non-nil, the size argument of the

I think it's just the pixel size and not the normal size, right?  Also
you should write it as "When NORM-SIZE is non-nil ..."

 > 		  (frame-root-window frame-root-window)

This doesn't look right.

 > 	(message "Not enough windows")

Better is "No windows to transpose".

 >       (let* ((fwin (frame-first-window rwin))

Note that 'frame-first-window' returns the first live window on its
frame.  What if you want to flip some child windows only?

 > 	(select-window selwin)))))

should become (set-frame-selected-window selwin) for the case that you
rotate windows on a non-selected frame.

 > (defun transpose-windows--rearrange-1 (subtree cwin conf norm-size)

And this I'd call 'window--transpose-1'

 >   "Subroutine of `transpose-windows--rearrange'."

Again please describe all arguments in the doc-string.

And please handle the case where a frame contains side windows.  Just
replace 'frame-root-window' with 'window--main-window' everywhere and
talk about "main window" instead of "root window".

Thanks, martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-02  9:04                                   ` martin rudalics
@ 2024-10-03  7:06                                     ` pranshu sharma
  2024-10-03  8:17                                       ` martin rudalics
  2024-10-08 18:35                                       ` Juri Linkov
  0 siblings, 2 replies; 65+ messages in thread
From: pranshu sharma @ 2024-10-03  7:06 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>> Alternatively, we could give 'window-tree' an optional PIXELWISE
>>> argument so it returns the pixel edges of windows.
>>
>> You decide
>
> Better not - the fact that 'window-tree' does not report the edges of
> live windows constitutes bad design.  Let's not support it.  Rather
> let's make it a normal function called 'window-tree-pixel-sizes'.  I
> would write its doc string as
>
>   (defun window-tree-pixel-sizes (window &optional next)
>     "Return pixel sizes of all windows rooted at WINDOW.
>   The return value is a list where each window is represented either by a
>   triple whose first element is either t for an internal window that is a
>   horizontal combination, nil for an internal window that is a vertical
>   combination, or the window itself for a live window.  The second element
>   is a cons of the pixel height and pixel width of the window.  The third
>   element is specified for internal windows only and recursively lists
>   that window's child windows using the same triple structure."
>
> but you would have to check whether it really does what I wrote.

yes this does exactly that, thanks

>> (defun rotate-windows-anticlockwise (&optional frame-or-window)
>>   "Rotate windows of FRAME-OR-WINDOW 90 degrees anticlockwise.
>> See `rotate-windows-clockwise' for more."
>
> I think it's better to write out the full doc-string here first and
> in a final sentence say
>
>   See `rotate-windows-clockwise' for how to rotate windows in the
>   opposite direction.

k

>
>> (defun flip-windows-horizontally (&optional frame-or-window)
>>   "Horizontally flip windows of FRAME-OR-WINDOW.
>> FRAME-OR-WINDOW must be a live frame or window and defaults to the
>> selected frame. If FRAME-OR-WINDOW is a frame, flip from the root
>> window of the frame, otherwise flip from FRAME-OR-WINDOW."
>
> Here you should probably first say what "flip" means.  It's obvious when
> you have a frame with two side-by-side live windows.  It's already less
> obvious with three side-by-side windows and even less so with more
> complex layouts.

I explained it just using the metaphor of a reflection

>> (defun transpose-windows--rearrange (frame-or-window conf norm-size)
>
> I'd call this just 'window--transpose'.

done

>
>> "Rearrange windows of FRAME-OR-WINDOW recursively.
>> CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
>> horizontal split is called when splitting a window that was previously
>> horizontally split, and VERTICAL-SPLIT for a window that was previously
>> vertically split.
>
> CONF is confusing.  Why is it a cons cell in the first place?  Wouldn't
> a simple boolean - t for horizontal and nil for vertical - suffice?  If
> not, please explain why.

You can also have below split and abvoe split, not just nil and t

>
>> When is NORM-SIZE non-nil, the size argument of the
>
> I think it's just the pixel size and not the normal size, right?  Also
> you should write it as "When NORM-SIZE is non-nil ..."

It's a bolean that states if or not the height or width should be
converted to width or height respecitlcly. I changed the name.

> Note that 'frame-first-window' returns the first live window on its
> frame.  What if you want to flip some child windows only?

I didnt read docstring properly when I rewrote function, mb, played
cardi b bit too loud.  I kind of assumed since it accepts
frame-or-window it would return first child.  But fixed that now.

>> 	(select-window selwin)))))
>
> should become (set-frame-selected-window selwin) for the case that you
> rotate windows on a non-selected frame.

Thanks, I was looking for this function

>
>> (defun transpose-windows--rearrange-1 (subtree cwin conf norm-size)
>
> And this I'd call 'window--transpose-1'
>
> Again please describe all arguments in the doc-string.

I already explained the arguments in transpose-windows--rearrange.  As
far as I can tell most other -1 postfix don't explain their arguments eg
window--resize-reset-1.

btw, what are the plans for the keybindings? imo they should be added
top level in C-x w map, as there are lots of spots avaiable, and there
are only 5 total new functions.


(defun window-tree-pixel-sizes (window &optional next)
  "Return pixel sizes of all windows rooted at WINDOW.
The return value is a list where each window is represented either by a
triple whose first element is either t for an internal window that is a
horizontal combination, nil for an internal window that is a vertical
combination, or the window itself for a live window.  The second element
is a cons of the pixel height and pixel width of the window.  The third
element is specified for internal windows only and recursively lists
that window's child windows using the same triple structure."
  (let (list)
    (while window
      (setq list
	    (cons
	     (cond
	      ((window-top-child window)
	       (cons t (cons (cons (window-pixel-height window)
				   (window-pixel-width window))
			     (window-tree-pixel-sizes
			      (window-top-child window) t))))
	      ((window-left-child window)
	       (cons nil (cons (cons (window-pixel-height window)
				     (window-pixel-width window))
			       (window-tree-pixel-sizes
				(window-left-child window) t))))
	      (t (list window (cons (window-pixel-height window)
				    (window-pixel-width window)))))
	     list))
      (setq window (when next (window-next-sibling window))))
    (nreverse list)))

(defun rotate-windows-anticlockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW anti-clockwise by 90 degrees.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame.  If FRAME-OR-WINDOW is a frame, rotate the main window
of the frame, otherwise rotate FRAME-OR-WINDOW.  See
`rotate-windows-clockwise' for how to rotate windows in the opposite
direction"
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (transpose-windows--rearrange window '(right . above) nil)))

(defun rotate-windows-clockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame.  If FRAME-OR-WINDOW is a frame, rotate the main window
of the frame, otherwise rotate FRAME-OR-WINDOW.  See
`rotate-windows-anticlockwise' for how to rotate windows in the opposite
direction"
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (transpose-windows--rearrange window '(left . below) nil)))

(defun flip-windows-horizontally (&optional frame-or-window)
  "Horizontally flip windows of FRAME-OR-WINDOW.  When the windows are
flipped horzontally, the window layout is made to it's reflection from
the side edge.  FRAME-OR-WINDOW must be a live frame or window and
defaults to the selected frame. If FRAME-OR-WINDOW is a frame, flip from
the main window of the frame, otherwise flip from FRAME-OR-WINDOW.  See
`flip-windows-vertically' for how to flip windows vertically."
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (transpose-windows--rearrange window '(below . left) t)))


(defun flip-windows-vertically (&optional frame-or-window)
  "Horizontally flip windows of FRAME-OR-WINDOW.  When the windows are
flipped vertically, the window layout is made to it's reflection from
the top edge.  FRAME-OR-WINDOW must be a live frame or window and
defaults to the selected frame. If FRAME-OR-WINDOW is a frame, flip from
the main window of the frame, otherwise flip from FRAME-OR-WINDOW.  See
`flip-windows-horizontally' for how to flip windows horizontally."
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (transpose-windows--rearrange window '(above . right) t)))

(defun transpose-windows (&optional frame-or-window)
  "Transpose windows of FRAME-OR-WINDOW.
Rearrange windows such that where a horizontal split was used a vertical
one is used instead, and vice versa.  FRAME-OR-WINDOW must be a live
frame or window and defaults to the selected frame.  If FRAME-OR-WINDOW
is a frame, transpose the main window of the frame, otherwise
transpose FRAME-OR-WINDOW."
  (interactive `(,(and current-prefix-arg (window-parent (selected-window)))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (transpose-windows--rearrange window '(right . below) nil)))


(defun transpose-windows--rearrange (frame-or-window conf do-not-convert-size)
  "Rearrange windows of FRAME-OR-WINDOW recursively.
CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
HORIZONTAL-SPLIT will be used as the third argument of `split-window'
when splitting a window that was previously horizontally split, and
VERTICAL-SPLIT as third argument `split-window' for a window that was
previously vertically split.  When is DO-NOT-CONVERT-SIZE non-nil, the
size argument of the window-split is converted from vertical to
horizontal or vice versa, with the same proportion of the total split."
  (pcase-let ((`(,rwin . ,frame)
	       (if (framep frame-or-window)
		   (cons (window-main-window frame-or-window) frame-or-window)
		 (cons frame-or-window (window-frame frame-or-window)))))
    (if (or (not rwin)
	    (zerop (window-child-count rwin)))
	(message "No windows to transpose")
      (let* ((fwin rwin)
	     (selwin (frame-selected-window frame-or-window))
	     (win-tree (car (window-tree-pixel-sizes rwin))))
	(while (not (window-live-p fwin))
	  (setq fwin (window-child fwin)))
	;; 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)))
	(window--transpose-1 win-tree fwin conf do-not-convert-size)
	;; Go back to previously selected window.
	(set-frame-selected-window frame selwin)))))

(defun window--transpose-1 (subtree cwin conf do-not-convert-size)
  "Subroutine of `transpose-windows--rearrange'."
  ;; `ilen' is the max size a window could be of given the split type.
  ;; `flen' is max size the window could be converted to the opposite
  ;; of the given split type.
  (pcase-let ((`(,ilen . ,flen) (if (car subtree)
				    (cons (float (car (cadr subtree)))
					  (float (window-pixel-width cwin)))
				  (cons (float (cdr (cadr subtree)))
					(float (window-pixel-height cwin))))))
    (mapc
     (pcase-lambda (`(,win . ,size))
       (let ((split-size (- (if do-not-convert-size
				size
			      (round (* flen  (/ size ilen))))))
	     (split-type
	      (funcall (if (car subtree) 'car 'cdr) conf)))
	 (if (listp win)
	     ;; `win' is a window subtree.
	     (window--transpose-1 win (split-window cwin
						    split-size
						    split-type
						    t
						    (seq-some
						     (lambda (x)
						       (and (windowp x) x))
						     (flatten-list win)))
				  conf do-not-convert-size)
	   ;; `win' is a window.
	   (split-window cwin split-size
			 split-type t
			 win))))
     (mapcar
      (lambda (e)
	(let ((window? (if (windowp (car e)) (car e) e)))
	  (cons window?
		;; The relevent size of the window.
		(if (car subtree)
		    (car (cadr e))
		  (cdr (cadr e))))))
      ;; By using cdddr, we ignore over window split type, sizes and
      ;; the first window (it's implicitly created).
      (nreverse (cdddr subtree))))
    ;; (caaddr subtree) is the first window.
    (unless (windowp (caaddr subtree))
      (window--transpose-1 (caddr subtree) cwin conf do-not-convert-size))))



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03  7:06                                     ` pranshu sharma
@ 2024-10-03  8:17                                       ` martin rudalics
  2024-10-03 10:09                                         ` pranshu sharma
  2024-10-08 18:35                                       ` Juri Linkov
  1 sibling, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-03  8:17 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >>> (defun transpose-windows--rearrange (frame-or-window conf norm-size)
 >>
 >> I'd call this just 'window--transpose'.
 >
 > done

Not really IIUC.

 >> CONF is confusing.  Why is it a cons cell in the first place?  Wouldn't
 >> a simple boolean - t for horizontal and nil for vertical - suffice?  If
 >> not, please explain why.
 >
 > You can also have below split and abvoe split, not just nil and t

Aha...  So the values are the possible values of the SIDE argument of
'split-window'.

 > I already explained the arguments in transpose-windows--rearrange.  As
 > far as I can tell most other -1 postfix don't explain their arguments eg
 > window--resize-reset-1.

Then please say "the arguments are the same as for `window--transpose'".

 > btw, what are the plans for the keybindings? imo they should be added
 > top level in C-x w map, as there are lots of spots avaiable, and there
 > are only 5 total new functions.

Once we have installed it, we'll consult Juri Linkov.  He knows more
about keybindings in this area.  BTW, you could have a look at the
function 'window-swap-states'.  IIUC it should then be rewritten in
terms of the 'flip-windows-...' functions to get rid of window states
and the overlay rigmarole.

 > (defun rotate-windows-anticlockwise (&optional frame-or-window)
 >    "Rotate windows of FRAME-OR-WINDOW anti-clockwise by 90 degrees.
 > FRAME-OR-WINDOW must be a live frame or window and defaults to the
 > selected frame.  If FRAME-OR-WINDOW is a frame, rotate the main window
 > of the frame, otherwise rotate FRAME-OR-WINDOW.  See
 > `rotate-windows-clockwise' for how to rotate windows in the opposite
 > direction"
 >    (interactive `(,(and current-prefix-arg (window-parent))))

Please test what happens if you have a keybinding for this and you hit
that key in the minibuffer window, for example, after typing C-h f.

 > (defun flip-windows-horizontally (&optional frame-or-window)
 >    "Horizontally flip windows of FRAME-OR-WINDOW.  When the windows are
 > flipped horzontally, the window layout is made to it's reflection from
 > the side edge.  FRAME-OR-WINDOW must be a live frame or window and
 > defaults to the selected frame. If FRAME-OR-WINDOW is a frame, flip from

Still a space missing after the "."

 > (defun flip-windows-vertically (&optional frame-or-window)
 >    "Horizontally flip windows of FRAME-OR-WINDOW.  When the windows are

Newline missing after ".".

 > flipped vertically, the window layout is made to it's reflection from
 > the top edge.  FRAME-OR-WINDOW must be a live frame or window and
 > defaults to the selected frame. If FRAME-OR-WINDOW is a frame, flip from

Space missing after ".".

 > (defun transpose-windows--rearrange (frame-or-window conf do-not-convert-size)

Rename to 'window--transpose' as you claimed above.

 >    "Rearrange windows of FRAME-OR-WINDOW recursively.
 > CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
 > HORIZONTAL-SPLIT will be used as the third argument of `split-window'
 > when splitting a window that was previously horizontally split, and
 > VERTICAL-SPLIT as third argument `split-window' for a window that was

... third argument _of_ ...

 > previously vertically split.  When is DO-NOT-CONVERT-SIZE non-nil, the

Should become "If DO-NOT-CONVERT-SIZE is non-nil, ..."

 > size argument of the window-split is converted from vertical to
 > horizontal or vice versa, with the same proportion of the total split."
 >    (pcase-let ((`(,rwin . ,frame)
 > 	       (if (framep frame-or-window)
 > 		   (cons (window-main-window frame-or-window) frame-or-window)
 > 		 (cons frame-or-window (window-frame frame-or-window)))))
 >      (if (or (not rwin)
 > 	    (zerop (window-child-count rwin)))

Actually

(zerop (window-child-count rwin))

is equivalent to

(window-live-p rwin)

and the latter should be cheaper.

 > 		;; The relevent size of the window.

I think "respective size" is what you mean.

 >        ;; By using cdddr, we ignore over window split type, sizes and

Rather "ignore window split type" without the "over".

 >        ;; the first window (it's implicitly created).
 >        (nreverse (cdddr subtree))))
 >      ;; (caaddr subtree) is the first window.
 >      (unless (windowp (caaddr subtree))
 >        (window--transpose-1 (caddr subtree) cwin conf do-not-convert-size))))

What I forgot to ask so far: Have you completed copyright assignment
for Emacs?  I can't look into this myself.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03  8:17                                       ` martin rudalics
@ 2024-10-03 10:09                                         ` pranshu sharma
  2024-10-03 14:18                                           ` martin rudalics
  2024-10-03 15:12                                           ` Eli Zaretskii
  0 siblings, 2 replies; 65+ messages in thread
From: pranshu sharma @ 2024-10-03 10:09 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>> I'd call this just 'window--transpose'.
>>
>> done
>
> Not really IIUC.

sorry, it is done now

> Then please say "the arguments are the same as for
> `window--transpose'".

yes, done

> Once we have installed it, we'll consult Juri Linkov.  He knows more
> about keybindings in this area.  BTW, you could have a look at the
> function 'window-swap-states'.  IIUC it should then be rewritten in
> terms of the 'flip-windows-...' functions to get rid of window states
> and the overlay rigmarole.

Hmm, the only way I can imagine using the flip thing is modifying window
tree to swap 2 windows in the subtree, and then set conf to (below
. left) and do-not-convert-size to nil.  This will just rebuild the
whole window tree.

>
> Please test what happens if you have a keybinding for this and you hit
> that key in the minibuffer window, for example, after typing C-h f.
>
It just acts as if you are calling it without prefix arg, I think that
is expected behaviour imo.  It just goes back to orignal if
read-minibuffer-restore-windows is non nil.

> Still a space missing after the "."
>
>> (defun flip-windows-vertically (&optional frame-or-window)
>>    "Horizontally flip windows of FRAME-OR-WINDOW.  When the windows are
>
> Newline missing after ".".
>
>> flipped vertically, the window layout is made to it's reflection from
>> the top edge.  FRAME-OR-WINDOW must be a live frame or window and
>> defaults to the selected frame. If FRAME-OR-WINDOW is a frame, flip from
>
> Space missing after ".".
>> (defun transpose-windows--rearrange (frame-or-window conf do-not-convert-size)
> ... third argument _of_ ...
>
>> previously vertically split.  When is DO-NOT-CONVERT-SIZE non-nil, the
>

ah puncutation comments, I just failed my english writing exam on
wednesday :(

> Actually
>
> (zerop (window-child-count rwin))
>
> is equivalent to
>
> (window-live-p rwin)
>
> and the latter should be cheaper.

Thanks, I applied that change


> What I forgot to ask so far: Have you completed copyright assignment
> for Emacs?  I can't look into this myself.

I sent the form to assign@gnu.org, 15 days ago, still waiting for reply.
Does it normally take this long?

Code:
----------------------------------------

(defun window-tree-pixel-sizes (window &optional next)
  "Return pixel sizes of all windows rooted at WINDOW.
The return value is a list where each window is represented either by a
triple whose first element is either t for an internal window that is a
horizontal combination, nil for an internal window that is a vertical
combination, or the window itself for a live window.  The second element
is a cons of the pixel height and pixel width of the window.  The third
element is specified for internal windows only and recursively lists
that window's child windows using the same triple structure."
  (let (list)
    (while window
      (setq list
	    (cons
	     (cond
	      ((window-top-child window)
	       (cons t (cons (cons (window-pixel-height window)
				   (window-pixel-width window))
			     (window-tree-pixel-sizes
			      (window-top-child window) t))))
	      ((window-left-child window)
	       (cons nil (cons (cons (window-pixel-height window)
				     (window-pixel-width window))
			       (window-tree-pixel-sizes
				(window-left-child window) t))))
	      (t (list window (cons (window-pixel-height window)
				    (window-pixel-width window)))))
	     list))
      (setq window (when next (window-next-sibling window))))
    (nreverse list)))

(defun rotate-windows-anticlockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW anticlockwise by 90 degrees.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame.  If FRAME-OR-WINDOW is a frame, rotate the main window
of the frame, otherwise rotate FRAME-OR-WINDOW.  See
`rotate-windows-clockwise' for how to rotate windows in the opposite
direction"
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (window--transpose window '(right . above) nil)))

(defun rotate-windows-clockwise (&optional frame-or-window)
  "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees.
FRAME-OR-WINDOW must be a live frame or window and defaults to the
selected frame.  If FRAME-OR-WINDOW is a frame, rotate the main window
of the frame, otherwise rotate FRAME-OR-WINDOW.  See
`rotate-windows-anticlockwise' for how to rotate windows in the opposite
direction"
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (window--transpose window '(left . below) nil)))

(defun flip-windows-horizontally (&optional frame-or-window)
  "Horizontally flip windows of FRAME-OR-WINDOW.
When the windows are flipped horzontally, the window layout is made to
it's reflection from the side edge.  FRAME-OR-WINDOW must be a live
frame or window and defaults to the selected frame.  If FRAME-OR-WINDOW
is a frame, flip from the main window of the frame, otherwise flip from
FRAME-OR-WINDOW.  See `flip-windows-vertically' for how to flip windows
vertically."
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (window--transpose window '(below . left) t)))

(defun flip-windows-vertically (&optional frame-or-window)
  "Horizontally flip windows of FRAME-OR-WINDOW.
When the windows are flipped vertically, the window layout is made to
it's reflection from the top edge.  FRAME-OR-WINDOW must be a live frame
or window and defaults to the selected frame.  If FRAME-OR-WINDOW is a
frame, flip from the main window of the frame, otherwise flip from
FRAME-OR-WINDOW.  See `flip-windows-horizontally' for how to flip
windows horizontally."
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (window--transpose window '(above . right) t)))

(defun transpose-windows (&optional frame-or-window)
  "Transpose windows of FRAME-OR-WINDOW.
Rearrange windows such that where a horizontal split was used a vertical
one is used instead, and vice versa.  FRAME-OR-WINDOW must be a live
frame or window and defaults to the selected frame.  If FRAME-OR-WINDOW
is a frame, transpose the main window of the frame, otherwise
transpose FRAME-OR-WINDOW."
  (interactive `(,(and current-prefix-arg (window-parent))))
  (let ((window (if (windowp frame-or-window)
		    frame-or-window
		  (window-main-window frame-or-window))))
    (window--transpose window '(right . below) nil)))


(defun window--transpose (frame-or-window conf do-not-convert-size)
  "Rearrange windows of FRAME-OR-WINDOW recursively.
CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
HORIZONTAL-SPLIT will be used as the third argument of `split-window'
when splitting a window that was previously horizontally split, and
VERTICAL-SPLIT as third argument of `split-window' for a window that was
previously vertically split.  If DO-NOT-CONVERT-SIZE non-nil, the size
argument of the window-split is converted from vertical to horizontal or
vice versa, with the same proportion of the total split."
  (pcase-let ((`(,rwin . ,frame)
	       (if (framep frame-or-window)
		   (cons (window-main-window frame-or-window) frame-or-window)
		 (cons frame-or-window (window-frame frame-or-window)))))
    (if (or (not rwin)
	    (window-live-p rwin))
	(message "No windows to transpose")
      (let* ((fwin rwin)
	     (selwin (frame-selected-window frame-or-window))
	     (win-tree (car (window-tree-pixel-sizes rwin))))
	(while (not (window-live-p fwin))
	  (setq fwin (window-child fwin)))
	;; 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)))
	(window--transpose-1 win-tree fwin conf do-not-convert-size)
	;; Go back to previously selected window.
	(set-frame-selected-window frame selwin)))))

(defun window--transpose-1 (subtree cwin conf do-not-convert-size)
  "Subroutine of `window--transpose'.
SUBTREE must be in the format of the result of
`window-tree-pixel-sizes'.  CWIN is the current window through which the
window splits are made.  The CONF and DO-NOT-CONVERT-SIZE arguments are
the same as the ones in `window--transpose'."
  ;; `ilen' is the max size a window could be of given the split type.
  ;; `flen' is max size the window could be converted to the opposite
  ;; of the given split type.
  (pcase-let ((`(,ilen . ,flen) (if (car subtree)
				    (cons (float (car (cadr subtree)))
					  (float (window-pixel-width cwin)))
				  (cons (float (cdr (cadr subtree)))
					(float (window-pixel-height cwin))))))
    (mapc
     (pcase-lambda (`(,win . ,size))
       (let ((split-size (- (if do-not-convert-size
				size
			      (round (* flen  (/ size ilen))))))
	     (split-type
	      (funcall (if (car subtree) 'car 'cdr) conf)))
	 (if (listp win)
	     ;; `win' is a window subtree.
	     (window--transpose-1 win (split-window cwin
						    split-size
						    split-type
						    t
						    (seq-some
						     (lambda (x)
						       (and (windowp x) x))
						     (flatten-list win)))
				  conf do-not-convert-size)
	   ;; `win' is a window.
	   (split-window cwin split-size
			 split-type t
			 win))))
     (mapcar
      (lambda (e)
	(let ((window? (if (windowp (car e)) (car e) e)))
	  (cons window?
		;; The respective size of the window.
		(if (car subtree)
		    (car (cadr e))
		  (cdr (cadr e))))))
      ;; By using cdddr, we ignore window split type, sizes and the
      ;; first window (it's implicitly created).
      (nreverse (cdddr subtree))))
    ;; (caaddr subtree) is the first window.
    (unless (windowp (caaddr subtree))
      (window--transpose-1 (caddr subtree) cwin conf do-not-convert-size))))



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03 10:09                                         ` pranshu sharma
@ 2024-10-03 14:18                                           ` martin rudalics
  2024-10-04  5:50                                             ` pranshu sharma
  2024-10-03 15:12                                           ` Eli Zaretskii
  1 sibling, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-03 14:18 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >> BTW, you could have a look at the
 >> function 'window-swap-states'.  IIUC it should then be rewritten in
 >> terms of the 'flip-windows-...' functions to get rid of window states
 >> and the overlay rigmarole.
 >
 > Hmm, the only way I can imagine using the flip thing is modifying window
 > tree to swap 2 windows in the subtree, and then set conf to (below
 > . left) and do-not-convert-size to nil.  This will just rebuild the
 > whole window tree.

I thought when the two windows are neighbors (which they often enough
are) we could flip them.  But I think the solution is to (1) add for
each live window its number in 'window-state-get' (we need a function
'window-number' for that) and (2) in 'window-state-put', whenever we
split a window, try to find out whether a window with the respective
number is in 'window-dead-windows-table' and reuse it in that case.

 > I sent the form to assign@gnu.org, 15 days ago, still waiting for reply.
 > Does it normally take this long?

It can take longer.  Don't worry.  They'll reply before Emacs 31 gets
out.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03 10:09                                         ` pranshu sharma
  2024-10-03 14:18                                           ` martin rudalics
@ 2024-10-03 15:12                                           ` Eli Zaretskii
  1 sibling, 0 replies; 65+ messages in thread
From: Eli Zaretskii @ 2024-10-03 15:12 UTC (permalink / raw)
  To: pranshu sharma; +Cc: rudalics, emacs-devel

> From: pranshu sharma <pranshusharma366@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> Date: Thu, 03 Oct 2024 20:09:43 +1000
> 
> > What I forgot to ask so far: Have you completed copyright assignment
> > for Emacs?  I can't look into this myself.
> 
> I sent the form to assign@gnu.org, 15 days ago, still waiting for reply.

Please ping them and CC me.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03 14:18                                           ` martin rudalics
@ 2024-10-04  5:50                                             ` pranshu sharma
  2024-10-04  8:08                                               ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-04  5:50 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> Hmm, the only way I can imagine using the flip thing is modifying window
>> tree to swap 2 windows in the subtree, and then set conf to (below
>> . left) and do-not-convert-size to nil.  This will just rebuild the
>> whole window tree.
>
> I thought when the two windows are neighbors (which they often enough
> are) we could flip them.

Flip windows would work to swap when they are sibling windows, and
neigbor windows can sometimes not be siblings.

> But I think the solution is to (1) add for each live window its number
> in 'window-state-get' (we need a function 'window-number' for that)
> and (2) in 'window-state-put', whenever we split a window, try to find
> out whether a window with the respective number is in
> 'window-dead-windows-table' and reuse it in that case.

I can't comment much cuz I'm not really familiar with these functions,
but one thing that pops out is would maintaining a dead windows table
take up lot of resources?

Also do you think a function like 'window-rebuild-tree' would be useful,
and it accepts the a tree like the output of window-tree-pixel-sizes.
rn this is possible by using the following arguments for
window--transpose-1:
(window--transpose-1 tree-you-want (below . left) t)
However this is not really obvious.

I think it could be useful to add a wrapper with more obvious name



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-04  5:50                                             ` pranshu sharma
@ 2024-10-04  8:08                                               ` martin rudalics
  2024-10-04 15:10                                                 ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-04  8:08 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >> I thought when the two windows are neighbors (which they often enough
 >> are) we could flip them.
 >
 > Flip windows would work to swap when they are sibling windows, and
 > neigbor windows can sometimes not be siblings.

Right.  I meant siblings (it was the typical two windows frame I had in
mind).

 > I can't comment much cuz I'm not really familiar with these functions,
 > but one thing that pops out is would maintaining a dead windows table
 > take up lot of resources?

No.  It's already here via the variable 'window-dead-windows-table'.

 > Also do you think a function like 'window-rebuild-tree' would be useful,
 > and it accepts the a tree like the output of window-tree-pixel-sizes.
 > rn this is possible by using the following arguments for
 > window--transpose-1:
 > (window--transpose-1 tree-you-want (below . left) t)
 > However this is not really obvious.
 >
 > I think it could be useful to add a wrapper with more obvious name

You would have to tell me in more detail what 'window-rebuild-tree'
would do.  One thing 'window-tree-pixel-sizes' should then possibly do
is to include the identity of internal windows so 'window-rebuild-tree'
could resurrect them as well.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-04  8:08                                               ` martin rudalics
@ 2024-10-04 15:10                                                 ` pranshu sharma
  2024-10-05 14:43                                                   ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-04 15:10 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> I can't comment much cuz I'm not really familiar with these functions,
>> but one thing that pops out is would maintaining a dead windows table
>> take up lot of resources?
>
> No.  It's already here via the variable 'window-dead-windows-table'.

I see

>> Also do you think a function like 'window-rebuild-tree' would be useful,
>> and it accepts the a tree like the output of window-tree-pixel-sizes.
>> rn this is possible by using the following arguments for
>> window--transpose-1:
>> (window--transpose-1 tree-you-want (below . left) t)
>> However this is not really obvious.
>>
>> I think it could be useful to add a wrapper with more obvious name
>
> You would have to tell me in more detail what 'window-rebuild-tree'
> would do.

Say window window-tree-pixel-sizes retruns:

((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
*scratch*> (476 . 562))))

Then if you C-x 1, and then:
(window-rebuild-tree
  '((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
   *scratch*> (476 . 562)))))

It should rebuild the whole thing to the orignal

> One thing 'window-tree-pixel-sizes' should then possibly do is to
> include the identity of internal windows so 'window-rebuild-tree'
> could resurrect them as well.

idk what you mean by this, is the identity not included in window object
itself, as in does refer argument not work with it?

also I found that when using tabs from tab-bar-mode, calling functions
like flip windows 2 times in a row will fuck up the tabs.  I tested it
with orignal transpose-frame.el and it does not have this problem, mayeb
it is something to do with the C new patch refer argument code?



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-04 15:10                                                 ` pranshu sharma
@ 2024-10-05 14:43                                                   ` martin rudalics
  2024-10-06  2:54                                                     ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-05 14:43 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 >> You would have to tell me in more detail what 'window-rebuild-tree'
 >> would do.
 >
 > Say window window-tree-pixel-sizes retruns:
 >
 > ((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
 > *scratch*> (476 . 562))))
 >
 > Then if you C-x 1, and then:
 > (window-rebuild-tree
 >    '((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
 >     *scratch*> (476 . 562)))))
 >
 > It should rebuild the whole thing to the orignal

Yes.  That would be useful to (1) make a window state and store it
somewhere (2) arbitrarily alter the frame's configuration and (3) put
the state back into its frame.  It's obviously the same thing
'save-window-excursion' does but there's a twist: When a frame gets
deleted, you cannot restore the window configuration in it.
'window-build-tree' could do it and 'undelete-frame' could use it.  It
has one drawback: We can't collect the dead windows as long as the saved
state needs them.  BTW I have no idea why 'undelete-frame-mode' does not
try to resurrect a deleted frame as we do with windows.

 >> One thing 'window-tree-pixel-sizes' should then possibly do is to
 >> include the identity of internal windows so 'window-rebuild-tree'
 >> could resurrect them as well.
 >
 > idk what you mean by this, is the identity not included in window object
 > itself, as in does refer argument not work with it?

No.  Look at your your example above: All we know about the parent
window is what type of combination it is and what sizes it has.

 > also I found that when using tabs from tab-bar-mode, calling functions
 > like flip windows 2 times in a row will fuck up the tabs.

In what sense does it "fuck up the tabs"?

 > I tested it
 > with orignal transpose-frame.el and it does not have this problem, mayeb
 > it is something to do with the C new patch refer argument code?

'tab-bar-mode' uses window configurations.  Maybe that's the cause.

martin




^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-05 14:43                                                   ` martin rudalics
@ 2024-10-06  2:54                                                     ` pranshu sharma
  2024-10-06 15:02                                                       ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-06  2:54 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> Say window window-tree-pixel-sizes retruns:
>>
>> ((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
>> *scratch*> (476 . 562))))
>>
>> Then if you C-x 1, and then:
>> (window-rebuild-tree
>>    '((t (918 . 562) (#<window 7 on *scratch*> (442 . 562)) (#<window 23 on
>>     *scratch*> (476 . 562)))))
>>
>> It should rebuild the whole thing to the orignal
>
> Yes.  That would be useful to (1) make a window state and store it
> somewhere (2) arbitrarily alter the frame's configuration and (3) put
> the state back into its frame.  It's obviously the same thing
> 'save-window-excursion' does but there's a twist: When a frame gets
> deleted, you cannot restore the window configuration in it.
> 'window-build-tree' could do it and 'undelete-frame' could use it.  It
> has one drawback: We can't collect the dead windows as long as the saved
> state needs them.  BTW I have no idea why 'undelete-frame-mode' does not
> try to resurrect a deleted frame as we do with windows.

I was thinking more about making it easier to programticly change the
layout, as window-configurations are in C source, which is far from
userland.  This would make it possible to do stuff like recursivly go
through window tree and do whatver you want, eg make vertical split
windows a bit larger.


>>> One thing 'window-tree-pixel-sizes' should then possibly do is to
>>> include the identity of internal windows so 'window-rebuild-tree'
>>> could resurrect them as well.
>>
>> idk what you mean by this, is the identity not included in window object
>> itself, as in does refer argument not work with it?
>
> No.  Look at your your example above: All we know about the parent
> window is what type of combination it is and what sizes it has.

Do you mean the windows lile #<window nnn>, that are not included in
(window-tree) and return nil in window-live-p?

If so, what do we need to know about them apart from sizes,
transpose-windows and that know nothing about them and still work.

>> also I found that when using tabs from tab-bar-mode, calling functions
>> like flip windows 2 times in a row will fuck up the tabs.
>
> In what sense does it "fuck up the tabs"?
>

It just makes them dissapear in gui, and in terminal it makes them blank.

Try this:
C-x t n
C-x 2
C-x 3
M-x flip-windows
C-x z



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-06  2:54                                                     ` pranshu sharma
@ 2024-10-06 15:02                                                       ` martin rudalics
  2024-10-06 15:52                                                         ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-06 15:02 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > I was thinking more about making it easier to programticly change the
 > layout, as window-configurations are in C source, which is far from
 > userland.  This would make it possible to do stuff like recursivly go
 > through window tree and do whatver you want, eg make vertical split
 > windows a bit larger.

Hmm..  You can't do that by simply resizing windows?

 >> No.  Look at your your example above: All we know about the parent
 >> window is what type of combination it is and what sizes it has.
 >
 > Do you mean the windows lile #<window nnn>, that are not included in
 > (window-tree) and return nil in window-live-p?

Yes.

 > If so, what do we need to know about them apart from sizes,
 > transpose-windows and that know nothing about them and still work.

Because internal windows usually don't have properties.  The only
exception are window parameters.  With emacs -Q do C-x 2, then do

(set-window-parameter (window-parent) 'foo 3)

M-x transpose-windows

(window-parameter (window-parent) 'foo)

Gets me nil here so the parameter is lost.

 > It just makes them dissapear in gui, and in terminal it makes them blank.
 >
 > Try this:
 > C-x t n
 > C-x 2
 > C-x 3
 > M-x flip-windows
 > C-x z

Works here (with 'flip-windows-horizontally') as expected.  At the end
there are two tabs, one for a one window configuration and one for a
three windows one.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-06 15:02                                                       ` martin rudalics
@ 2024-10-06 15:52                                                         ` pranshu sharma
  2024-10-07  8:33                                                           ` martin rudalics
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-06 15:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1756 bytes --]

martin rudalics <rudalics@gmx.at> writes:

>> I was thinking more about making it easier to programticly change the
>> layout, as window-configurations are in C source, which is far from
>> userland.  This would make it possible to do stuff like recursivly go
>> through window tree and do whatver you want, eg make vertical split
>> windows a bit larger.
>
> Hmm..  You can't do that by simply resizing windows?
>
>>> No.  Look at your your example above: All we know about the parent
>>> window is what type of combination it is and what sizes it has.
>>
>> Do you mean the windows lile #<window nnn>, that are not included in
>> (window-tree) and return nil in window-live-p?
>
> Yes.
>
>> If so, what do we need to know about them apart from sizes,
>> transpose-windows and that know nothing about them and still work.
>
> Because internal windows usually don't have properties.  The only
> exception are window parameters.  With emacs -Q do C-x 2, then do
>
> (set-window-parameter (window-parent) 'foo 3)
>
> M-x transpose-windows
>
> (window-parameter (window-parent) 'foo)
>
> Gets me nil here so the parameter is lost.

I see, seems like this is low level, complex and will require lot of
work to do right.  I'm out.  Let just focus on getting the orignal
functions added.

>> It just makes them dissapear in gui, and in terminal it makes them blank.
>>
>> Try this:
>> C-x t n
>> C-x 2
>> C-x 3
>> M-x flip-windows
>> C-x z
>
> Works here (with 'flip-windows-horizontally') as expected.  At the end
> there are two tabs, one for a one window configuration and one for a
> three windows one.

I'm on master branch if that changes anything.  Also you have to call
flip-windows-horizontally at least twice for it to work.

I attached demo of this.


[-- Attachment #2: out.mp4 --]
[-- Type: video/mp4, Size: 738207 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-09-28 15:28                     ` Eli Zaretskii
@ 2024-10-07  8:33                       ` martin rudalics
  0 siblings, 0 replies; 65+ messages in thread
From: martin rudalics @ 2024-10-07  8:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pranshusharma366, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1321 bytes --]

I now rewrote 'split-window' and 'split-window-internal' and attach the
new versions.  I don't mention "dead windows" in docs and error messages
any more.  I can't use "leaf windows" because that is nowhere specified
(with one exception in E.9.2 the Elisp manual talks about "leaf nodes"
only).  Internal windows OTOH are mentioned because they are defined and
frequently used in the manual.  Please have a look.

ChangeLog is below, a NEWS entry will be added later.

martin

Let 'split-window' optionally reuse dead window instead of making new one

* lisp/window.el (split-window): New argument REFER to reuse dead
window instead of making a new one.
* src/window.c (Fwindow_old_buffer): Make it work for any window
including deleted ones.  In doc-string say that for a deleted
window it returns the buffer the window had at the time it was
deleted.
(make_parent_window): Reset old_buffer slot installed by memcpy.
(Fsplit_window_internal): Handle new argument REFER inherited
from 'split-window'.
(Fdelete_window_internal, delete_all_child_windows): Set
old_buffer slot of the window to delete to the window's buffer.
* doc/lispref/windows.texi (Splitting Windows): Describe new
argument REFER.
(Window Hooks): Mention that for a dead window 'window-old-buffer'
returns the buffer the window had when it was deleted.

[-- Attachment #2: split-window.diff --]
[-- Type: text/x-patch, Size: 17820 bytes --]

diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 541c91ddae2..149cc47de62 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -1354,7 +1354,7 @@ Splitting Windows
 Examples of such windows are side windows (@pxref{Side Windows}) and
 atomic windows (@pxref{Atomic Windows}).
 
-@defun split-window &optional window size side pixelwise
+@defun split-window &optional window size side pixelwise refer
 This function creates a new live window next to the window
 @var{window}.  If @var{window} is omitted or @code{nil}, it defaults
 to the selected window.  That window is split, and reduced in
@@ -1402,10 +1402,24 @@ Splitting Windows
 to interpret @var{size} in units of pixels, instead of lines and
 columns.
 
-If @var{window} is a live window, the new window inherits various
-properties from it, including margins and scroll bars.  If
-@var{window} is an internal window, the new window inherits the
-properties of the window selected within @var{window}'s frame.
+If the optional fifth argument @var{refer} is non-@code{nil}, it has to
+denote either a deleted, former live window on the same frame as
+@var{window} or an arbitrary live window.  If @var{refer} is a deleted
+window, this function does not make a new window but rather resurrects
+@var{refer} and inserts it into the window tree at the position and with
+the sizes the new window would have been given.  Buffer, start and point
+positions of @var{refer} are restored to the values they had immediately
+before @var{refer} was deleted the last time.  Decorations and
+parameters remain unaltered from their values before @var{refer} was
+deleted.  An error is thrown if @var{refer}'s buffer has been deleted
+after @var{refer} itself was deleted.
+
+If @var{refer} is a live window, the new window will inherit properties
+like buffer, start and point and some decorations from @var{refer}.  If
+@var{refer} is @code{nil} or omitted, then if @var{window} is live, any
+such properties are inherited from @var{window}.  If, however,
+@var{window} is an internal window, the new window will inherit these
+properties from the window selected on @var{window}'s frame.
 
 The behavior of this function may be altered by the window parameters
 of @var{window}, so long as the variable
@@ -7103,13 +7117,16 @@ Window Hooks
 window.
 
 @defun window-old-buffer &optional window
-This function returns the buffer shown in @var{window} at the last
-time window change functions were run for @var{window}'s frame.  If it
-returns @code{nil}, @var{window} has been created after that.  If it
-returns @code{t}, @var{window} was not shown at that time but has been
-restored from a previously saved window configuration afterwards.
-Otherwise, the return value is the buffer shown by @var{window} at
-that time.
+This function returns the buffer shown in @var{window} at the last time
+window change functions were run for @var{window}'s frame.  If it
+returns @code{nil}, @var{window} is either an internal window or has
+been created after that.  If it returns @code{t}, @var{window} was not
+shown at that time but has been restored from a previously saved window
+configuration afterwards.  Otherwise, the return value is the buffer
+shown by @var{window} at that time.  As a special case, if @var{window}
+has been deleted, this function returns the last buffer @var{window} had
+shown at that time.  @var{window} can be any window and defaults to the
+selected one.
 @end defun
 
 @defun window-old-pixel-width &optional window
diff --git a/lisp/window.el b/lisp/window.el
index 07ea9584908..52191cff1dd 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5509,7 +5509,7 @@ window--combination-resizable
       (setq sibling (window-next-sibling sibling)))
     (/ size (1+ number))))
 
-(defun split-window (&optional window size side pixelwise)
+(defun split-window (&optional window size side pixelwise refer)
   "Make a new window adjacent to WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 Return the new window which is always a live window.
@@ -5552,11 +5552,26 @@ split-window
 root of that atomic window.  The new window does not become a
 member of that atomic window.
 
-If WINDOW is live, properties of the new window like margins and
-scrollbars are inherited from WINDOW.  If WINDOW is an internal
-window, these properties as well as the buffer displayed in the
-new window are inherited from the window selected on WINDOW's
-frame.  The selected window is not changed by this function."
+If the optional fifth argument REFER is non-nil, it has to denote either
+a deleted, former live window on the same frame as WINDOW or an
+arbitrary live window.  If REFER is a deleted window, do not make a new
+window but rather make REFER live again and insert it into the window
+tree at the position and with the sizes the new window would have been
+given.  Buffer, start and point positions of REFER are set to the values
+they had immediately before REFER was deleted the last time.
+Decorations and parameters remain unaltered from their values before
+REFER was deleted.  Throw an error if REFER's buffer has been deleted
+after REFER itself was deleted.
+
+If REFER is a live window, the new window will inherit properties like
+buffer, start and point and some decorations from REFER.  If REFER is
+nil or omitted, then if WINDOW is live, any such properties are
+inherited from WINDOW.  If, however, WINDOW is an internal window, the
+new window will inherit these properties from the window selected on
+WINDOW's frame.
+
+The selected window and the selected window on WINDOW's frame are
+not changed by this function."
   (setq window (window-normalize-window window))
   (let* ((side (cond
 		((not side) 'below)
@@ -5596,7 +5611,7 @@ split-window
        ((and (window-parameter window 'window-atom)
 	     (setq atom-root (window-atom-root window))
 	     (not (eq atom-root window)))
-	(throw 'done (split-window atom-root size side pixelwise)))
+	(throw 'done (split-window atom-root size side pixelwise refer)))
        ;; If WINDOW is a side window or its first or last child is a
        ;; side window, throw an error unless `window-combination-resize'
        ;; equals 'side.
@@ -5635,8 +5650,8 @@ split-window
 		   (window-combined-p window horizontal)))
 	     ;; 'old-pixel-size' is the current pixel size of WINDOW.
 	     (old-pixel-size (window-size window horizontal t))
-	     ;; 'new-size' is the specified or calculated size of the
-	     ;; new window.
+	     ;; 'new-pixel-size' is the specified or calculated size
+	     ;; of the new window.
 	     new-pixel-size new-parent new-normal)
 	(cond
 	 ((not pixel-size)
@@ -5757,8 +5772,9 @@ split-window
 	   window (- (if new-parent 1.0 (window-normal-size window horizontal))
 		     new-normal)))
 
-	(let* ((new (split-window-internal window new-pixel-size side new-normal)))
-	  (window--pixel-to-total frame horizontal)
+	(let ((new (split-window-internal
+		    window new-pixel-size side new-normal refer)))
+          (window--pixel-to-total frame horizontal)
 	  ;; Assign window-side parameters, if any.
 	  (cond
 	   ((eq window-combination-resize 'side)
diff --git a/src/window.c b/src/window.c
index 34968ac824f..94ea3491a11 100644
--- a/src/window.c
+++ b/src/window.c
@@ -652,15 +652,16 @@ DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
 
 DEFUN ("window-old-buffer", Fwindow_old_buffer, Swindow_old_buffer, 0, 1, 0,
        doc: /* Return the old buffer displayed by WINDOW.
-WINDOW must be a live window and defaults to the selected one.
+WINDOW can be any window and defaults to the selected one.
 
 The return value is the buffer shown in WINDOW at the last time window
-change functions were run.  It is nil if WINDOW was created after
-that.  It is t if WINDOW has been restored from a window configuration
-after that.  */)
+change functions were run or WINDOW is a former live window that was
+deleted.  It is nil if WINDOW was created after that.  It is t if WINDOW
+has been restored from a window configuration after that.  It is always
+nil if WINDOW is an internal window.  */)
   (Lisp_Object window)
 {
-  struct window *w = decode_live_window (window);
+  struct window *w = decode_any_window (window);
 
   return (NILP (w->old_buffer)
 	  /* A new window.  */
@@ -668,8 +669,8 @@ DEFUN ("window-old-buffer", Fwindow_old_buffer, Swindow_old_buffer, 0, 1, 0,
 	  : (w->change_stamp != WINDOW_XFRAME (w)->change_stamp)
 	  /* A window restored from a configuration.  */
 	  ? Qt
-	  /* A window that was live the last time seen by window
-	     change functions.  */
+	  /* A window that was live the last time seen by window change
+	     functions or was deleted.  */
 	  : w->old_buffer);
 }
 
@@ -4521,6 +4522,7 @@ make_parent_window (Lisp_Object window, bool horflag)
   wset_pointm (p, Qnil);
   wset_old_pointm (p, Qnil);
   wset_buffer (p, Qnil);
+  wset_old_buffer (p, Qnil);
   wset_combination (p, horflag, window);
   wset_combination_limit (p, Qnil);
   /* Reset any previous and next buffers of p which have been installed
@@ -5073,7 +5075,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
 }
 
 
-DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0,
+DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0,
        doc: /* Split window OLD.
 Second argument PIXEL-SIZE specifies the number of pixels of the
 new window.  It must be a positive integer.
@@ -5088,32 +5090,33 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
 the right side of WINDOW.  SIDE `left' means the new window shall be
 located on the left of WINDOW.  In both cases PIXEL-SIZE specifies the
 width of the new window including space reserved for fringes and the
-scrollbar or a divider column.
+scroll bar or a divider column.
 
 Fourth argument NORMAL-SIZE specifies the normal size of the new window
-according to the SIDE argument.
+according to the SIDE argument.  Optional fifth argument REFER is as for
+'split-window'.
 
 The new pixel and normal sizes of all involved windows must have been
 set correctly.  See the code of `split-window' for how this is done.  */)
-  (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size)
-{
-  /* OLD (*o) is the window we have to split.  (*p) is either OLD's
-     parent window or an internal window we have to install as OLD's new
-     parent.  REFERENCE (*r) must denote a live window, or is set to OLD
-     provided OLD is a leaf window, or to the frame's selected window.
-     NEW (*n) is the new window created with some parameters taken from
-     REFERENCE (*r).  */
-  Lisp_Object new, frame, reference;
-  struct window *o, *p, *n, *r, *c;
-  struct frame *f;
+  (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side,
+   Lisp_Object normal_size, Lisp_Object refer)
+{
+  /* OLD (*o) is the window to split.  REFER (*r) is a reference window,
+     either an arbitrary live window or a former live, now deleted
+     window on the same frame as OLD.  NEW (*n) is the new window
+     created anew or resurrected from REFER (*r), if specified.  *p
+     refers either to OLD's parent window that will become NEW's parent
+     window too or to a new internal window that becomes OLD's and NEW's
+     new parent.  */
+  struct window *o = decode_valid_window (old);
+  Lisp_Object frame = WINDOW_FRAME (o);
+  struct frame *f = XFRAME (frame);
+  struct window *p, *n, *r, *c;
   bool horflag
     /* HORFLAG is true when we split side-by-side, false otherwise.  */
     = EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright);
-
-  CHECK_WINDOW (old);
-  o = XWINDOW (old);
-  frame = WINDOW_FRAME (o);
-  f = XFRAME (frame);
+  Lisp_Object new;
+  bool dead = false;
 
   CHECK_FIXNUM (pixel_size);
   EMACS_INT total_size
@@ -5131,14 +5134,38 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
 	   ? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent))
 	   : WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent))));
 
-  /* We need a live reference window to initialize some parameters.  */
-  if (WINDOW_LIVE_P (old))
-    /* OLD is live, use it as reference window.  */
-    reference = old;
+  /* Set up reference window.  */
+  if (NILP (refer))
+    {
+      if (WINDOW_LIVE_P (old))
+	/* OLD is live, use it as reference window.  */
+	refer = old;
+      else
+	/* Use the frame's selected window as reference window.  */
+	refer = FRAME_SELECTED_WINDOW (f);
+
+      r = XWINDOW (refer);
+    }
   else
-    /* Use the frame's selected window as reference window.  */
-    reference = FRAME_SELECTED_WINDOW (f);
-  r = XWINDOW (reference);
+    {
+      r = decode_any_window (refer);
+
+      if (NILP (r->contents))
+	/* Presumably a deleted, former live window.  Check whether its
+	   contents can be used.  */
+	{
+	  if (!BUFFERP (r->old_buffer))
+	    error ("Deleted window REFER was not a live window (did not show a buffer)");
+	  else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
+	    error ("The buffer formerly shown by deleted window REFER has been deleted");
+	  else if (!EQ (r->frame, frame))
+	    error ("Deleted window REFER was not on the same frame as the window to split");
+
+	  dead = true;
+	}
+      else if (!WINDOW_LIVE_P (refer))
+	error ("REFER is not a live window (does not show a buffer)");
+    }
 
   /* The following bugs are caught by `split-window'.  */
   if (MINI_WINDOW_P (o))
@@ -5195,7 +5222,12 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
     p = XWINDOW (o->parent);
 
   fset_redisplay (f);
-  new = make_window ();
+
+  if (dead)
+    new = refer;
+  else
+    new = make_window ();
+
   n = XWINDOW (new);
   wset_frame (n, frame);
   wset_parent (n, o->parent);
@@ -5222,16 +5254,19 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
   n->window_end_valid = false;
   n->last_cursor_vpos = 0;
 
-  /* Get special geometry settings from reference window.  */
-  n->left_margin_cols = r->left_margin_cols;
-  n->right_margin_cols = r->right_margin_cols;
-  n->left_fringe_width = r->left_fringe_width;
-  n->right_fringe_width = r->right_fringe_width;
-  n->fringes_outside_margins = r->fringes_outside_margins;
-  n->scroll_bar_width = r->scroll_bar_width;
-  n->scroll_bar_height = r->scroll_bar_height;
-  wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
-  wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
+  if (!dead)
+    {
+      /* Get special geometry settings from reference window.  */
+      n->left_margin_cols = r->left_margin_cols;
+      n->right_margin_cols = r->right_margin_cols;
+      n->left_fringe_width = r->left_fringe_width;
+      n->right_fringe_width = r->right_fringe_width;
+      n->fringes_outside_margins = r->fringes_outside_margins;
+      n->scroll_bar_width = r->scroll_bar_width;
+      n->scroll_bar_height = r->scroll_bar_height;
+      wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
+      wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
+    }
 
   /* Directly assign orthogonal coordinates and sizes.  */
   if (horflag)
@@ -5260,6 +5295,7 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
 	sum = sum + XFIXNUM (c->new_total);
       c = NILP (c->next) ? 0 : XWINDOW (c->next);
     }
+
   wset_new_total (n, make_fixnum ((horflag
 				   ? p->total_cols
 				   : p->total_lines)
@@ -5267,10 +5303,30 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal,
   wset_new_normal (n, normal_size);
 
   block_input ();
+
+  if (dead)
+    {
+      /* Get dead window back its old buffer and markers.  */
+      wset_buffer (n, n->old_buffer);
+      set_marker_restricted
+	(n->start, make_fixnum (XMARKER (n->start)->charpos), n->contents);
+      set_marker_restricted
+	(n->pointm, make_fixnum (XMARKER (n->pointm)->charpos), n->contents);
+      set_marker_restricted
+	(n->old_pointm, make_fixnum (XMARKER (n->old_pointm)->charpos),
+	 n->contents);
+
+      Vwindow_list = Qnil;
+      /* Remove window from the table of dead windows.  */
+      Fremhash (make_fixnum (n->sequence_number),
+		window_dead_windows_table);
+    }
+
   window_resize_apply (p, horflag);
   adjust_frame_glyphs (f);
-  /* Set buffer of NEW to buffer of reference window.  */
+
   set_window_buffer (new, r->contents, true, true);
+
   FRAME_WINDOW_CHANGE (f) = true;
   unblock_input ();
 
@@ -5368,6 +5424,8 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna
 	}
       else
 	{
+	  /* Store WINDOW's buffer in old_buffer.  */
+	  wset_old_buffer (w, w->contents);
 	  unshow_buffer (w);
 	  unchain_marker (XMARKER (w->pointm));
 	  unchain_marker (XMARKER (w->old_pointm));
@@ -7712,6 +7770,8 @@ delete_all_child_windows (Lisp_Object window)
     }
   else if (BUFFERP (w->contents))
     {
+      /* Store WINDOW's buffer in old_buffer.  */
+      wset_old_buffer (w, w->contents);
       unshow_buffer (w);
       unchain_marker (XMARKER (w->pointm));
       unchain_marker (XMARKER (w->old_pointm));
@@ -9064,12 +9124,9 @@ syms_of_window (void)
     doc: /* Hash table of dead windows.
 Each entry in this table maps a window number to a window object.
 Entries are added by `delete-window-internal' and are removed by the
-garbage collector.
-
-This table is maintained by code in window.c and is made visible in
-Elisp for testing purposes only.  */);
+garbage collector.  */);
   window_dead_windows_table
-    = CALLN (Fmake_hash_table, QCweakness, Qt);
+    = CALLN (Fmake_hash_table, QCweakness, Qvalue);
 
   defsubr (&Sselected_window);
   defsubr (&Sold_selected_window);

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-06 15:52                                                         ` pranshu sharma
@ 2024-10-07  8:33                                                           ` martin rudalics
  2024-10-07  9:42                                                             ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: martin rudalics @ 2024-10-07  8:33 UTC (permalink / raw)
  To: pranshu sharma; +Cc: Eli Zaretskii, emacs-devel

 > I see, seems like this is low level, complex and will require lot of
 > work to do right.  I'm out.  Let just focus on getting the orignal
 > functions added.

No sweat.  In another mail I attached a new version of 'split-window'.
Please use that from now on.

 >>> It just makes them dissapear in gui, and in terminal it makes them blank.
 >>>
 >>> Try this:
 >>> C-x t n
 >>> C-x 2
 >>> C-x 3
 >>> M-x flip-windows
 >>> C-x z
 >>
 >> Works here (with 'flip-windows-horizontally') as expected.  At the end
 >> there are two tabs, one for a one window configuration and one for a
 >> three windows one.
 >
 > I'm on master branch if that changes anything.  Also you have to call
 > flip-windows-horizontally at least twice for it to work.
 >
 > I attached demo of this.

In the demo you use C-x 3 C-x 2 C-x 3 so you make one split more.
However, even with that additional split I see no problem here.  Unless
you mean that the final C-x 1 is part of the scenario.  But even with

C-x t n C-x 3 C-x 2 C-x 3 C-x w f C-x z C-x 1

I still see two tabs here.  I'm not familiar with 'tab-bar-mode' so you
will probably have to debug it.  Otherwise, we can ask Juri whether he
sees any problems with it.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-07  8:33                                                           ` martin rudalics
@ 2024-10-07  9:42                                                             ` pranshu sharma
  0 siblings, 0 replies; 65+ messages in thread
From: pranshu sharma @ 2024-10-07  9:42 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel


> No sweat.  In another mail I attached a new version of 'split-window'.
> Please use that from now on.

Thanks, compiling emacs with the patch applied fixed the tab bug I was
having.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-03  7:06                                     ` pranshu sharma
  2024-10-03  8:17                                       ` martin rudalics
@ 2024-10-08 18:35                                       ` Juri Linkov
  2024-10-09  6:59                                         ` pranshu sharma
  1 sibling, 1 reply; 65+ messages in thread
From: Juri Linkov @ 2024-10-08 18:35 UTC (permalink / raw)
  To: pranshu sharma; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

> btw, what are the plans for the keybindings? imo they should be added
> top level in C-x w map, as there are lots of spots avaiable, and there
> are only 5 total new functions.

I recommend to put all these related transform commands on the dedicated
prefix map 'C-x w t', e.g. 'C-x w t t' for transpose-windows, etc.
because for example recently we discussed addition of new maps
'C-x w d <arrow>' to delete a window in direction, and
'C-x w s <arrow>' to split a window in direction.
But all these keys are already taken:
'C-x w d' for 'toggle-window-dedicated' and
'C-x w s' for 'window-toggle-side-windows'.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-08 18:35                                       ` Juri Linkov
@ 2024-10-09  6:59                                         ` pranshu sharma
  2024-10-09 16:21                                           ` Juri Linkov
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-09  6:59 UTC (permalink / raw)
  To: Juri Linkov; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

Juri Linkov <juri@linkov.net> writes:

> I recommend to put all these related transform commands on the dedicated
> prefix map 'C-x w t', e.g. 'C-x w t t' for transpose-windows, etc.

I see, then imo 'C-x w r' would probably be better, nemonic for
rerarrange.  I don't see any connection between rotating and flipping
windows under transposing catagory.

> because for example recently we discussed addition of new maps
> 'C-x w d <arrow>' to delete a window in direction, and
> 'C-x w s <arrow>' to split a window in direction.
> But all these keys are already taken:
> 'C-x w d' for 'toggle-window-dedicated' and
> 'C-x w s' for 'window-toggle-side-windows'.

Is there really need to be so strict, I mean, having semi-nonsencial but
useful keybindings is better than not having them in the first place.

For example the split window in direction could be 'C-x w n <arrow>',
'n' for new window in direction.  I would rather this than not having
it.  (tbh having four arrows not very useful, as C-x 2 and C-x 3 already
deal with 2 of them).



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-09  6:59                                         ` pranshu sharma
@ 2024-10-09 16:21                                           ` Juri Linkov
  2024-10-10 11:49                                             ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: Juri Linkov @ 2024-10-09 16:21 UTC (permalink / raw)
  To: pranshu sharma; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

>> I recommend to put all these related transform commands on the dedicated
>> prefix map 'C-x w t', e.g. 'C-x w t t' for transpose-windows, etc.
>
> I see, then imo 'C-x w r' would probably be better, nemonic for
> rerarrange.  I don't see any connection between rotating and flipping
> windows under transposing catagory.

Here is an existing example to get inspiration.
There are two keymaps on images:

image-map:
i r             image-rotate
i h             image-flip-horizontally
i v             image-flip-vertically

image-mode-map:
s 0             image-transform-reset-to-initial
s b             image-transform-fit-both
s f             image-mode-fit-frame
s h             image-transform-fit-to-height
s i             image-transform-fit-to-width
s m             image-transform-set-smoothing
s o             image-transform-reset-to-original
s p             image-transform-set-percent
s r             image-transform-set-rotation
s s             image-transform-set-scale
s w             image-transform-fit-to-window

>> because for example recently we discussed addition of new maps
>> 'C-x w d <arrow>' to delete a window in direction, and
>> 'C-x w s <arrow>' to split a window in direction.
>> But all these keys are already taken:
>> 'C-x w d' for 'toggle-window-dedicated' and
>> 'C-x w s' for 'window-toggle-side-windows'.
>
> Is there really need to be so strict, I mean, having semi-nonsencial but
> useful keybindings is better than not having them in the first place.
>
> For example the split window in direction could be 'C-x w n <arrow>',
> 'n' for new window in direction.  I would rather this than not having
> it.  (tbh having four arrows not very useful, as C-x 2 and C-x 3 already
> deal with 2 of them).

'n' for new is a nice mnemonics indeed.

Or maybe better to move the toggle commands to the prefix 'C-x w t':

'C-x w t d' for 'toggle-window-dedicated' and
'C-x w t s' for 'window-toggle-side-windows'.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-09 16:21                                           ` Juri Linkov
@ 2024-10-10 11:49                                             ` pranshu sharma
  2024-10-10 16:57                                               ` Juri Linkov
  0 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-10 11:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

Juri Linkov <juri@linkov.net> writes:

>>> I recommend to put all these related transform commands on the dedicated
>>> prefix map 'C-x w t', e.g. 'C-x w t t' for transpose-windows, etc.
>>
>> I see, then imo 'C-x w r' would probably be better, nemonic for
>> rerarrange.  I don't see any connection between rotating and flipping
>> windows under transposing catagory.
>
> Here is an existing example to get inspiration.
> There are two keymaps on images:
>
> image-map:
> i r             image-rotate
> i h             image-flip-horizontally
> i v             image-flip-vertically
>

Whole i map:
i +		image-increase-size
i -		image-decrease-size
i c		image-crop
i h		image-flip-horizontally
i o		image-save
i r		image-rotate
i v		image-flip-vertically
i x		image-cut

seems like the pattern here is changing how image is displayed.

What do you think about rotate/transpose/flip keybindings based of this?

>>> because for example recently we discussed addition of new maps
>>> 'C-x w d <arrow>' to delete a window in direction, and
>>> 'C-x w s <arrow>' to split a window in direction.
>>> But all these keys are already taken:
>>> 'C-x w d' for 'toggle-window-dedicated' and
>>> 'C-x w s' for 'window-toggle-side-windows'.
>>
>> Is there really need to be so strict, I mean, having semi-nonsencial but
>> useful keybindings is better than not having them in the first place.
>>
>> For example the split window in direction could be 'C-x w n <arrow>',
>> 'n' for new window in direction.  I would rather this than not having
>> it.  (tbh having four arrows not very useful, as C-x 2 and C-x 3 already
>> deal with 2 of them).
>
> 'n' for new is a nice mnemonics indeed.

Now I think about it, n is better than s, as when you are splitting
something, with an argument, it implies splitting direction (eg angle)
more than new window.  'n' would somewhat imply that a new window is
beign spawned.

> Or maybe better to move the toggle commands to the prefix 'C-x w t':
>
> 'C-x w t d' for 'toggle-window-dedicated' and
> 'C-x w t s' for 'window-toggle-side-windows'.

maybe, but my rsi says no



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-10 11:49                                             ` pranshu sharma
@ 2024-10-10 16:57                                               ` Juri Linkov
  2024-10-13  5:43                                                 ` pranshu sharma
  0 siblings, 1 reply; 65+ messages in thread
From: Juri Linkov @ 2024-10-10 16:57 UTC (permalink / raw)
  To: pranshu sharma; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

>>>> I recommend to put all these related transform commands on the dedicated
>>>> prefix map 'C-x w t', e.g. 'C-x w t t' for transpose-windows, etc.
>>>
>>> I see, then imo 'C-x w r' would probably be better, nemonic for
>>> rerarrange.  I don't see any connection between rotating and flipping
>>> windows under transposing catagory.
>>
>> Here is an existing example to get inspiration.
>> There are two keymaps on images:
>>
>> image-map:
>> i r          image-rotate
>> i h          image-flip-horizontally
>> i v          image-flip-vertically
>
> Whole i map:
> i +		image-increase-size
> i -		image-decrease-size
> i c		image-crop
> i h		image-flip-horizontally
> i o		image-save
> i r		image-rotate
> i v		image-flip-vertically
> i x		image-cut
>
> seems like the pattern here is changing how image is displayed.
>
> What do you think about rotate/transpose/flip keybindings based of this?

Then keybindings could be like these:

C-x w r a       rotate-windows-anticlockwise
C-x w r c       rotate-windows-clockwise
C-x w r h       flip-windows-horizontally
C-x w r v       flip-windows-vertically
C-x w r t       transpose-windows

>>>> because for example recently we discussed addition of new maps
>>>> 'C-x w d <arrow>' to delete a window in direction, and
>>>> 'C-x w s <arrow>' to split a window in direction.
>>>> But all these keys are already taken:
>>>> 'C-x w d' for 'toggle-window-dedicated' and
>>>> 'C-x w s' for 'window-toggle-side-windows'.
>>>
>>> Is there really need to be so strict, I mean, having semi-nonsencial but
>>> useful keybindings is better than not having them in the first place.
>>>
>>> For example the split window in direction could be 'C-x w n <arrow>',
>>> 'n' for new window in direction.  I would rather this than not having
>>> it.  (tbh having four arrows not very useful, as C-x 2 and C-x 3 already
>>> deal with 2 of them).
>>
>> 'n' for new is a nice mnemonics indeed.
>
> Now I think about it, n is better than s, as when you are splitting
> something, with an argument, it implies splitting direction (eg angle)
> more than new window.  'n' would somewhat imply that a new window is
> beign spawned.

Agreed.

Also there is 'C-x w d' bound to toggle-window-dedicated,
so the key [D] can't be used to [D]elete a window
neither to [D]isplay a window in the specified direction.

>> Or maybe better to move the toggle commands to the prefix 'C-x w t':
>>
>> 'C-x w t d' for 'toggle-window-dedicated' and
>> 'C-x w t s' for 'window-toggle-side-windows'.
>
> maybe, but my rsi says no

Depends on how often these key sequences are used.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-10 16:57                                               ` Juri Linkov
@ 2024-10-13  5:43                                                 ` pranshu sharma
  2024-10-13  8:17                                                   ` martin rudalics
  2024-10-14 17:32                                                   ` Juri Linkov
  0 siblings, 2 replies; 65+ messages in thread
From: pranshu sharma @ 2024-10-13  5:43 UTC (permalink / raw)
  To: Juri Linkov; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

Juri Linkov <juri@linkov.net> writes:

> Then keybindings could be like these:
>
> C-x w r a       rotate-windows-anticlockwise
> C-x w r c       rotate-windows-clockwise
> C-x w r h       flip-windows-horizontally
> C-x w r v       flip-windows-vertically
> C-x w r t       transpose-windows

Yeah this seems good.

Btw Martin, did you have look at the code for these functions, and think
it is ready? I am still waiting on assign@gnu.org(I sent them signed
form) but then we can add it.

>> Now I think about it, n is better than s, as when you are splitting
>> something, with an argument, it implies splitting direction (eg angle)
>> more than new window.  'n' would somewhat imply that a new window is
>> beign spawned.
>
> Agreed.
>
> Also there is 'C-x w d' bound to toggle-window-dedicated,
> so the key [D] can't be used to [D]elete a window
> neither to [D]isplay a window in the specified direction.

toggle window dedicated seems like an extremely useless command tbh,
have you should about binding it to C-x w D or C-x w C-d.  I prefer the
former, but capital keys are not really used in C-x maps, but lots of
major modes(gnus,org) use them.

Also for the delete-window, you could maybe bind it to C-x w k, for kill
window, or C-x w <DEL>, not perfect but better than nothing.  Also is
windmove not responiseble for these bindings?

>>> Or maybe better to move the toggle commands to the prefix 'C-x w t':
>>>
>>> 'C-x w t d' for 'toggle-window-dedicated' and
>>> 'C-x w t s' for 'window-toggle-side-windows'.
>>
>> maybe, but my rsi says no
>
> Depends on how often these key sequences are used.

If we are also coutning that in, do you think C-x w ^ map should be
moved to C-x w t (for tear-off) instead? I mean those keys are
frequently used if you have multitab/frame workflow, and pressing 'C-x w
^' a lot is perfect RSI fuel.

Also C-x w o for open in new frame/tab could be used.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-13  5:43                                                 ` pranshu sharma
@ 2024-10-13  8:17                                                   ` martin rudalics
  2024-10-14 17:36                                                     ` Juri Linkov
                                                                       ` (2 more replies)
  2024-10-14 17:32                                                   ` Juri Linkov
  1 sibling, 3 replies; 65+ messages in thread
From: martin rudalics @ 2024-10-13  8:17 UTC (permalink / raw)
  To: pranshu sharma, Juri Linkov; +Cc: Eli Zaretskii, emacs-devel

 >> Then keybindings could be like these:
 >>
 >> C-x w r a       rotate-windows-anticlockwise
 >> C-x w r c       rotate-windows-clockwise
 >> C-x w r h       flip-windows-horizontally
 >> C-x w r v       flip-windows-vertically
 >> C-x w r t       transpose-windows
 >
 > Yeah this seems good.

I'm not sure whether "horizontally" and "vertically" are good terms.  In
the past, people complained that for example 'split-window-horizontally'
could mean side-by-side or at some horizontal axis.  Maybe
'flip-windows-left-right' and 'flip-windows-above-below' would be better
and should be reflected in the key mnemonics somehow.

 > Btw Martin, did you have look at the code for these functions, and think
 > it is ready? I am still waiting on assign@gnu.org(I sent them signed
 > form) but then we can add it.

Yes.  Also people might still want to comment on my latest patch to
'split-window'.

 > toggle window dedicated seems like an extremely useless command tbh,
 > have you should about binding it to C-x w D or C-x w C-d.  I prefer the
 > former, but capital keys are not really used in C-x maps, but lots of
 > major modes(gnus,org) use them.

You should hurry here: IIUC 'toggle-window-dedicated' is new in the
release version and if you want to change its default binding, you'd
better do that right away there.

 > Also C-x w o for open in new frame/tab could be used.

"o" could be also used for deleting an "old" window in some direction
but I think that it has been already taken to mean "other" for too long.

But whatever you do my opinion should hardly count - I'm using my own
sets of key bindings ever since.

martin



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-13  5:43                                                 ` pranshu sharma
  2024-10-13  8:17                                                   ` martin rudalics
@ 2024-10-14 17:32                                                   ` Juri Linkov
  1 sibling, 0 replies; 65+ messages in thread
From: Juri Linkov @ 2024-10-14 17:32 UTC (permalink / raw)
  To: pranshu sharma; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

>> Also there is 'C-x w d' bound to toggle-window-dedicated,
>> so the key [D] can't be used to [D]elete a window
>> neither to [D]isplay a window in the specified direction.
>
> toggle window dedicated seems like an extremely useless command tbh,
> have you should about binding it to C-x w D or C-x w C-d.  I prefer the
> former, but capital keys are not really used in C-x maps, but lots of
> major modes(gnus,org) use them.

'C-x w D' is fine since "D" is displayed on the mode-line
for strongly dedicated windows.

> Also for the delete-window, you could maybe bind it to C-x w k, for kill
> window, or C-x w <DEL>, not perfect but better than nothing.

'C-x w k' would be more suitable for 'quit-window'
with its KILL argument set to t.

> Also is windmove not responiseble for these bindings?

windmove commands are exactly what should be bound to these keys
because there are no default short keybindings for
windmove-display-default-keybindings, windmove-delete-default-keybindings,
etc.

>>>> Or maybe better to move the toggle commands to the prefix 'C-x w t':
>>>>
>>>> 'C-x w t d' for 'toggle-window-dedicated' and
>>>> 'C-x w t s' for 'window-toggle-side-windows'.
>>>
>>> maybe, but my rsi says no
>>
>> Depends on how often these key sequences are used.
>
> If we are also coutning that in, do you think C-x w ^ map should be
> moved to C-x w t (for tear-off) instead? I mean those keys are
> frequently used if you have multitab/frame workflow, and pressing
> 'C-x w ^' a lot is perfect RSI fuel.

'^' is not easy to type indeed, so any suggestions are welcome.
Then with the prefix 'C-x w t' we could replace

  C-x w ^ f     tear-off-window

with

  C-x w t f     tear-off-window

with mnemonic 'w t f'.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-13  8:17                                                   ` martin rudalics
@ 2024-10-14 17:36                                                     ` Juri Linkov
  2024-10-15  8:34                                                     ` pranshu sharma
  2024-10-18 14:52                                                     ` pranshu sharma
  2 siblings, 0 replies; 65+ messages in thread
From: Juri Linkov @ 2024-10-14 17:36 UTC (permalink / raw)
  To: martin rudalics; +Cc: pranshu sharma, Eli Zaretskii, emacs-devel

>> Btw Martin, did you have look at the code for these functions, and think
>> it is ready? I am still waiting on assign@gnu.org(I sent them signed
>> form) but then we can add it.
>
> Yes.  Also people might still want to comment on my latest patch to
> 'split-window'.

I already tested your latest patch together with Pranshu's implementation
of new commands, and everything works nicely.

>> toggle window dedicated seems like an extremely useless command tbh,
>> have you should about binding it to C-x w D or C-x w C-d.  I prefer the
>> former, but capital keys are not really used in C-x maps, but lots of
>> major modes(gnus,org) use them.
>
> You should hurry here: IIUC 'toggle-window-dedicated' is new in the
> release version and if you want to change its default binding, you'd
> better do that right away there.

Agreed.

>> Also C-x w o for open in new frame/tab could be used.
>
> "o" could be also used for deleting an "old" window in some direction
> but I think that it has been already taken to mean "other" for too long.

Or 'C-x w C-o' like 'C-o' in 'open-line'.  Or 'C-x w c' ([c]reate).



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-13  8:17                                                   ` martin rudalics
  2024-10-14 17:36                                                     ` Juri Linkov
@ 2024-10-15  8:34                                                     ` pranshu sharma
  2024-10-15 16:16                                                       ` Juri Linkov
  2024-10-18 14:52                                                     ` pranshu sharma
  2 siblings, 1 reply; 65+ messages in thread
From: pranshu sharma @ 2024-10-15  8:34 UTC (permalink / raw)
  To: martin rudalics; +Cc: Juri Linkov, Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>>> Then keybindings could be like these:
>>>
>>> C-x w r a       rotate-windows-anticlockwise
>>> C-x w r c       rotate-windows-clockwise
>>> C-x w r h       flip-windows-horizontally
>>> C-x w r v       flip-windows-vertically
>>> C-x w r t       transpose-windows
>>
>> Yeah this seems good.
>
> I'm not sure whether "horizontally" and "vertically" are good terms.  In
> the past, people complained that for example 'split-window-horizontally'
> could mean side-by-side or at some horizontal axis.  Maybe
> 'flip-windows-left-right' and 'flip-windows-above-below' would be better
> and should be reflected in the key mnemonics somehow.

I think in terms of flipping the window, horizontal/vertical don't
really leave that much room for interpretatin as
split-window-horizontally.  flip-windows-left-right above-below seem
kind of clunky tbh, imo we should just go with horizontal/vertical, I
mean, worst case users will learn it by using it, or reading the
doctring. 99% of users should already know from
split-window-horizotnally and it's counter part what horizontal and
vertical means in the context of window.  But I'm also fine with
left-right, only problem is that it will make searching through C-h f
and 'C-h m' a little bit weird



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-15  8:34                                                     ` pranshu sharma
@ 2024-10-15 16:16                                                       ` Juri Linkov
  0 siblings, 0 replies; 65+ messages in thread
From: Juri Linkov @ 2024-10-15 16:16 UTC (permalink / raw)
  To: pranshu sharma; +Cc: martin rudalics, Eli Zaretskii, emacs-devel

>>>> Then keybindings could be like these:
>>>>
>>>> C-x w r a       rotate-windows-anticlockwise
>>>> C-x w r c       rotate-windows-clockwise
>>>> C-x w r h       flip-windows-horizontally
>>>> C-x w r v       flip-windows-vertically
>>>> C-x w r t       transpose-windows
>>>
>>> Yeah this seems good.
>>
>> I'm not sure whether "horizontally" and "vertically" are good terms.  In
>> the past, people complained that for example 'split-window-horizontally'
>> could mean side-by-side or at some horizontal axis.  Maybe
>> 'flip-windows-left-right' and 'flip-windows-above-below' would be better
>> and should be reflected in the key mnemonics somehow.
>
> I think in terms of flipping the window, horizontal/vertical don't
> really leave that much room for interpretatin as
> split-window-horizontally.  flip-windows-left-right above-below seem
> kind of clunky tbh, imo we should just go with horizontal/vertical, I
> mean, worst case users will learn it by using it, or reading the
> doctring. 99% of users should already know from
> split-window-horizotnally and it's counter part what horizontal and
> vertical means in the context of window.  But I'm also fine with
> left-right, only problem is that it will make searching through C-h f
> and 'C-h m' a little bit weird

Agreed, let's stick to the established terminology.



^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: Add function to rotate/transpose all windows
  2024-10-13  8:17                                                   ` martin rudalics
  2024-10-14 17:36                                                     ` Juri Linkov
  2024-10-15  8:34                                                     ` pranshu sharma
@ 2024-10-18 14:52                                                     ` pranshu sharma
  2 siblings, 0 replies; 65+ messages in thread
From: pranshu sharma @ 2024-10-18 14:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: Juri Linkov, Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1226 bytes --]

martin rudalics <rudalics@gmx.at> writes:

>> Btw Martin, did you have look at the code for these functions, and think
>> it is ready? I am still waiting on assign@gnu.org(I sent them signed
>> form) but then we can add it.
>
> Yes.  Also people might still want to comment on my latest patch to
> 'split-window'.
>

Ok, so today I made major changes to the interactive side of the
functions(new file attached), mostly because the function would error if
you call iti with prefix arg, and the press C-x z, as it would use the
last used argument of frame-or-window which is now dead.

The problem was that C-x z sends with same arguments, so using code in
the (interactive (HERE)) would be repeated, which means same argument
would be used in `repeat'.

I added subtree speicfic options to the docstring(before they were not
there), and made changes to window--transpose.  However it is weird if
you C-u M-x transpose-windows C-x z multiple times, you get weired
result since the parent window changes, nothing I can do about that,
just how windows work.

Also I'm finally done with the bureaucracy, I got the copyright
assignment done.

I'm ready to send final patch now, do you want it to be added to
window.el or new file?


[-- Attachment #2: new file --]
[-- Type: application/emacs-lisp, Size: 8509 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2024-10-18 14:52 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-24 13:45 Add function to rotate/transpose all windows pranshu sharma
2024-09-24 13:53 ` Eli Zaretskii
2024-09-25  8:05   ` martin rudalics
2024-09-25  8:34     ` pranshu sharma
2024-09-25  9:31       ` martin rudalics
2024-09-25 10:50         ` pranshu sharma
2024-09-25 13:53           ` martin rudalics
2024-09-25 15:31             ` pranshu sharma
2024-09-26 14:10       ` martin rudalics
2024-09-26 14:22         ` Eli Zaretskii
2024-09-27 17:29           ` martin rudalics
2024-09-28  7:52             ` pranshu sharma
2024-09-28  9:26               ` martin rudalics
2024-09-28 10:53                 ` pranshu sharma
2024-09-28 14:48                   ` martin rudalics
2024-09-29  7:36                     ` pranshu sharma
2024-09-29  8:40                       ` martin rudalics
2024-09-29  9:23                         ` pranshu sharma
2024-09-29 14:48                           ` martin rudalics
2024-09-30  6:29                             ` pranshu sharma
2024-09-30  8:57                               ` martin rudalics
2024-10-01  9:17                                 ` pranshu sharma
2024-10-02  9:04                                   ` martin rudalics
2024-10-03  7:06                                     ` pranshu sharma
2024-10-03  8:17                                       ` martin rudalics
2024-10-03 10:09                                         ` pranshu sharma
2024-10-03 14:18                                           ` martin rudalics
2024-10-04  5:50                                             ` pranshu sharma
2024-10-04  8:08                                               ` martin rudalics
2024-10-04 15:10                                                 ` pranshu sharma
2024-10-05 14:43                                                   ` martin rudalics
2024-10-06  2:54                                                     ` pranshu sharma
2024-10-06 15:02                                                       ` martin rudalics
2024-10-06 15:52                                                         ` pranshu sharma
2024-10-07  8:33                                                           ` martin rudalics
2024-10-07  9:42                                                             ` pranshu sharma
2024-10-03 15:12                                           ` Eli Zaretskii
2024-10-08 18:35                                       ` Juri Linkov
2024-10-09  6:59                                         ` pranshu sharma
2024-10-09 16:21                                           ` Juri Linkov
2024-10-10 11:49                                             ` pranshu sharma
2024-10-10 16:57                                               ` Juri Linkov
2024-10-13  5:43                                                 ` pranshu sharma
2024-10-13  8:17                                                   ` martin rudalics
2024-10-14 17:36                                                     ` Juri Linkov
2024-10-15  8:34                                                     ` pranshu sharma
2024-10-15 16:16                                                       ` Juri Linkov
2024-10-18 14:52                                                     ` pranshu sharma
2024-10-14 17:32                                                   ` Juri Linkov
2024-09-28  7:58             ` pranshu sharma
2024-09-28  8:18             ` Eli Zaretskii
2024-09-28  9:40               ` martin rudalics
2024-09-28 11:35                 ` Eli Zaretskii
2024-09-28 14:58                   ` martin rudalics
2024-09-28 15:28                     ` Eli Zaretskii
2024-10-07  8:33                       ` martin rudalics
2024-09-28 13:22                 ` pranshu sharma
2024-09-28 14:21                   ` Eli Zaretskii
2024-09-28 14:49                   ` martin rudalics
2024-09-27 10:06         ` pranshu sharma
2024-09-27 17:29           ` martin rudalics
2024-09-24 17:40 ` Petteri Hintsanen
2024-09-24 19:34 ` Charles Choi
2024-09-25  2:00   ` Emanuel Berg
2024-09-25  7:00   ` pranshu sharma

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).