emacs-devel
[Top][All Lists]
Advanced

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

Re: Add function to rotate/transpose all windows


From: pranshu sharma
Subject: Re: Add function to rotate/transpose all windows
Date: Tue, 01 Oct 2024 19:17:01 +1000
User-agent: Gnus/5.13 (Gnus v5.13)

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))))



reply via email to

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