[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Functions transpose/rotate/flip windows
From: |
Pranshu |
Subject: |
Re: Functions transpose/rotate/flip windows |
Date: |
Sat, 11 Jan 2025 20:12:35 +0530 |
User-agent: |
K-9 Mail for Android |
On 11 January 2025 7:08:19 pm GMT+05:30, Eshel Yaron <me@eshelyaron.com> wrote:
>Hi all,
>
>martin rudalics <rudalics@gmx.at> writes:
>
>>> Ok, I fixed them now. A new diff is attached.
>>
>> I pushed window-x.el to master now without any further testing or
>> looking into it. I plan to fix a few things in it but maybe Eli wants
>> to make some major corrections first.
>
>Thanks for working on these additions, the new commands seem neat.
>
>The only functional issue I ran into is that rotate-windows and
>rotate-windows-back seem to leave the wrong window selected (the
>selection does not follow the rotation).
>
>Other than that, here are some clean up suggestions from a quick pass:
>
>diff --git a/lisp/window-x.el b/lisp/window-x.el
>index d6c1851ddeb..e207c13374c 100644
>--- a/lisp/window-x.el
>+++ b/lisp/window-x.el
>@@ -1,4 +1,4 @@
>-;;; window-x.el --- extended window commands -*- lexical-binding: t; -*-
>+;;; window-x.el --- Extra window organization commands -*- lexical-binding:
>t; -*-
>
> ;; Copyright (C) 2025 Free Software Foundation, Inc.
>
>@@ -25,19 +25,21 @@
>
> ;;; Commentary:
>
>-;; This file defines additional infrequently used window commands that
>-;; should not be in window.el to not make the dumped image bigger.
>+;; This file defines less frequently used window organization commands.
>
> ;;; Code:
>
> (defun window-tree-normal-sizes (window &optional next)
> "Return normal sizes of all windows rooted at WINDOW.
>-A list of the form (SPLIT-TYPE PARENT-WIN PARENT-WIN-HEIGHT
>-PARENT-WIN-WIDTH W1 W2 ...) is returned. SPLIT-TYPE is non-nil if
>-PARENT-WIN is split horizontally. PARENT-WIN is the internal window.
>-PARENT-WIN-HEIGHT and PARENT-WIN-WIDTH are the normal heights of
>-PARENT-WIN. Wn is a list of the form (WINDOW HEIGHT WIDTH) where HEIGHT
>-and WIDTH are the normal height and width of the window."
>+
>+The return value is a list of the form (SPLIT-TYPE PARENT-WIN
>+PARENT-WIN-HEIGHT PARENT-WIN-WIDTH W1 W2 ...), where SPLIT-TYPE is
>+non-nil if PARENT-WIN is split horizontally; PARENT-WIN is the internal
>+window; PARENT-WIN-HEIGHT and PARENT-WIN-WIDTH are the normal heights
>+of PARENT-WIN; and Wn is a list of the form (WINDOW HEIGHT WIDTH) where
>+HEIGHT and WIDTH are the normal height and width of the window.
>+
>+(fn WINDOW)"
> (let (list)
> (while window
> (setq list
>@@ -62,192 +64,156 @@ window-tree-normal-sizes
> (setq window (when next (window-next-sibling window))))
> (nreverse list)))
>
>-(defun window--window-to-transpose (frame-or-window)
>- "Return the window to be acted upon by `window--transpose'.
>-If FRAME-OR-WINDOW is a window return FRAME-OR-WINDOW. If
>-FRAME-OR-WINDOW is a frame, return FRAME-OR-WINDOW's main window. If
>-FRAME-OR-WINDOW is nil, than the frames main window wil be returned. If
>-FRAME-OR-WINDOW is non-nil, and not a frame or a window or a number,
>-than the return value will be the parent window of the selected window."
>- (cond
>- ((windowp frame-or-window)
>- frame-or-window)
>- ((or (framep frame-or-window) (not frame-or-window))
>- (window-main-window frame-or-window))
>- (frame-or-window
>- (window-parent))))
>-
>-(defun rotate-window-layout-anticlockwise (&optional frame-or-window)
>- "Rotate windows of FRAME-OR-WINDOW anticlockwise by 90 degrees.
>-Transform the layout of windows such that a window on top becomes a
>-window on the right, a window on the right moves to the bottom, a window
>-on the bottom moves to the left and a window on the left becomes one on
>-the top.
>-
>-If FRAME-OR-WINDOW is nil, rotate the main window of the selected
>-frame. If FRAME-OR-WINDOW specifies a live frame, rotate the main
>-window of that frame. If FRAME-OR-WINDOW specifies a parent window,
>-rotate that window. In any other case and interactively with a prefix
>-argument rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (window--transpose window '(right . above) nil)))
>-
>-(defun rotate-window-layout-clockwise (&optional frame-or-window)
>- "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees.
>-Transform the layout of windows such that a window on top becomes a
>-window on the right, a window on the right moves to the bottom, a
>-window on the bottom moves to the left and a window on the left becomes
>-one on the top.
>-
>-If FRAME-OR-WINDOW is nil, rotate the main window of the selected frame.
>-If FRAME-OR-WINDOW specifies a live frame, rotate the main window of
>-that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that
>-window. In any other case and interactively with a prefix argument
>-rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (window--transpose window '(left . below) nil)))
>-
>-(defun flip-window-layout-horizontally (&optional frame-or-window)
>- "Horizontally flip windows of FRAME-OR-WINDOW.
>+(defsubst window--rotate-interactive-arg ()
>+ "Return interative window argument for window rotation commands."
>+ (if current-prefix-arg (window-parent) (window-main-window)))
>+
>+;;;###autoload
>+(defun rotate-window-layout-counterclockwise (&optional window)
>+ "Rotate windows under WINDOW counterclockwise by 90 degrees.
>+
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (window--transpose window '(right . above) nil))
>+
>+;;;###autoload
>+(defun rotate-window-layout-clockwise (&optional window)
>+ "Rotate windows under WINDOW clockwise by 90 degrees.
>+
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (window--transpose window '(left . below) nil))
>+
>+;;;###autoload
>+(defun flip-window-layout-horizontally (&optional window)
>+ "Horizontally flip windows under WINDOW.
>+
> Flip the window layout so that the window on the right becomes the
> window on the left, and vice-versa.
>
>-If FRAME-OR-WINDOW is nil, flip the main window of the selected frame.
>-If FRAME-OR-WINDOW specifies a live frame, rotate the main window of
>-that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that
>-window. In any other case and interactively with a prefix argument
>-rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (window--transpose window '(below . left) t)))
>-
>-(defun flip-window-layout-vertically (&optional frame-or-window)
>- "Verticlly flip windows of FRAME-OR-WINDOW.
>-Flip the window layout so that the top window becomes the bottom window
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (window--transpose window '(below . left) t))
>+
>+;;;###autoload
>+(defun flip-window-layout-vertically (&optional window)
>+ "Horizontally flip windows under WINDOW.
>+
>+Flip the window layout so that the top window becomes the bottom window,
> and vice-versa.
>
>-If FRAME-OR-WINDOW is nil, flip the main window of the selected frame.
>-If FRAME-OR-WINDOW specifies a live frame, rotate the main window of
>-that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that
>-window. In any other case and interactively with a prefix argument
>-rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (window--transpose window '(above . right) t)))
>-
>-(defun transpose-window-layout (&optional frame-or-window)
>- "Transpose windows of FRAME-OR-WINDOW.
>-Make the windows on FRAME-OR-WINDOW so that every horizontal split
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (window--transpose window '(above . right) t))
>+
>+;;;###autoload
>+(defun transpose-window-layout (&optional window)
>+ "Transpose windows under WINDOW.
>+
>+Reorganize the windows under WINDOW so that every horizontal split
> becomes a vertical split, and vice versa. This is equivalent to
> diagonally flipping.
>
>-If FRAME-OR-WINDOW is nil, transpose the main window of the selected frame.
>-If FRAME-OR-WINDOW specifies a live frame, rotate the main window of
>-that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that
>-window. In any other case and interactively with a prefix argument
>-rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (window--transpose window '(right . below) nil)))
>-
>-(defun window--depmap(fun ls)
>- "Map FUN across all nodes of list LS."
>- (if (consp ls)
>- (cons
>- (if (consp (car ls))
>- (window--depmap fun (car ls))
>- (funcall fun (car ls)))
>- (window--depmap fun (cdr ls)))
>- (funcall fun ls)))
>-
>-(defun rotate-windows-back(&optional frame-or-window)
>- "Move windows into locations of their predecessors in cyclic ordering.
>-
>-If FRAME-OR-WINDOW is nil, rotate the main window of the selected frame.
>-If FRAME-OR-WINDOW specifies a live frame, rotate the main window of
>-that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that
>-window. In any other case and interactively with a prefix argument
>-rotate the parent window of the selected window."
>- (interactive "P")
>- (rotate-windows frame-or-window t))
>-
>-(defun rotate-windows (&optional frame-or-window reverse)
>- "Move windows into locations of their forerunners in cyclic ordering.
>-
>-Else if FRAME-OR-WINDOW is nil, rotate the main window of the
>-selected frame. If FRAME-OR-WINDOW specifies a live frame, rotate the
>-main window of that frame. If FRAME-OR-WINDOW specifies a parent
>-window, rotate that window. In any other case and interactively with a
>-prefix argument rotate the parent window of the selected window."
>- (interactive "P")
>- (let ((window (window--window-to-transpose frame-or-window)))
>- (if (or (not window)
>- (window-live-p window))
>- (message "No windows to transpose")
>- (let* ((frame (window-frame window))
>- (selected-window (frame-selected-window window))
>- (win-tree (car (window-tree-normal-sizes window)))
>- (winls (seq-filter 'window-live-p (flatten-list win-tree)))
>- (rotated-ls (if reverse
>- (append (cdr winls) (list (car winls)))
>- (append (last winls) winls)))
>- (other-window-arg (if reverse 1 -1))
>- (first-window (car rotated-ls))
>- (new-win-tree (window--depmap
>- (lambda (x)
>- (if (window-live-p x)
>- (pop rotated-ls)
>- x))
>- win-tree)))
>- (if (or (seq-some 'window-atom-root winls)
>- (seq-some 'window-fixed-size-p winls))
>- (message "This does not work with fixed size or atom windows.")
>- (progn
>- ;; All child windows need to be recursively deleted.
>- (delete-other-windows-internal first-window window)
>- ;; (delete-dups atom-windows)
>- (window--transpose-1 new-win-tree first-window '(below . right) t
>nil)
>- (set-frame-selected-window frame selected-window)
>- (other-window other-window-arg)
>- (while (not (memq (selected-window) winls))
>- (other-window other-window-arg))))))))
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (window--transpose window '(right . below) nil))
>+
>+;;;###autoload
>+(defun rotate-windows-back (&optional window)
>+ "Rotate windows under WINDOW backward in cyclic ordering.
>+
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (rotate-windows window t))
>+
>+;;;###autoload
>+(defun rotate-windows (&optional window reverse)
>+ "Rotate windows under WINDOW in cyclic ordering.
>+
>+Optional argument REVERSE says to rotate windows backward, in reverse
>+cyclic order.
>+
>+If WINDOW is nil, it defaults to the root window of the selected frame.
>+
>+Interactively, a prefix argument says to rotate the parent window of the
>+selected window."
>+ (interactive (list (window--rotate-interactive-arg)))
>+ (when (or (not window) (window-live-p window))
>+ (user-error "No windows to transpose"))
>+ (let* ((frame (window-frame window))
>+ (selected-window (frame-selected-window window))
>+ (win-tree (car (window-tree-normal-sizes window)))
>+ (winls (seq-filter #'window-live-p (flatten-list win-tree)))
>+ (rotated-ls (if reverse
>+ (append (cdr winls) (list (car winls)))
>+ (append (last winls) winls)))
>+ (other-window-arg (if reverse 1 -1))
>+ (first-window (car rotated-ls))
>+ (new-win-tree (named-let rec ((ls win-tree))
>+ (cond
>+ ((consp ls) (cons (rec (car ls)) (rec (cdr ls))))
>+ ((window-live-p ls) (pop rotated-ls))
>+ (t ls)))))
>+ (when (or (seq-some #'window-atom-root winls)
>+ (seq-some #'window-fixed-size-p winls))
>+ (user-error "Cannot rotate windows due to fixed size or atom windows"))
>+ ;; All child windows need to be recursively deleted.
>+ (delete-other-windows-internal first-window window)
>+ ;; (delete-dups atom-windows)
>+ (window--transpose-1 new-win-tree first-window '(below . right) t nil)
>+ (set-frame-selected-window frame selected-window)
>+ (other-window other-window-arg)
>+ (while (not (memq (selected-window) winls))
>+ (other-window other-window-arg))))
>
> (defun window--transpose (window conf no-resize)
>- "Rearrange windows of WINDOW recursively.
>-CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where
>+ "Rearrange windows under 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 NO-RESIZE is nil, the SIDE argument of
> the window-split is converted from vertical to horizontal or vice versa,
> with the same proportion of the total split."
>- (if (or (not window)
>- (window-live-p window))
>- (message "No windows to transpose")
>- (let* ((frame (window-frame window))
>- (first-window window)
>- (selected-window (frame-selected-window window))
>- (win-tree (car (window-tree-normal-sizes window)))
>- (win-list (seq-filter 'window-live-p (flatten-list win-tree)))
>- (atom-windows
>- (remq nil (mapcar 'window-atom-root
>- win-list))))
>- (if (and (not (eq (car atom-windows) window))
>- (or no-resize
>- (and (not atom-windows)
>- (not (seq-some 'window-fixed-size-p win-list)))))
>- (progn
>- (delete-dups atom-windows)
>- (while (not (window-live-p first-window))
>- (setq first-window (window-child first-window)))
>- (delete-other-windows-internal first-window window)
>- (window--transpose-1 win-tree first-window conf no-resize
>atom-windows)
>- ;; Go back to previously selected window.
>- (set-frame-selected-window frame selected-window)
>- (mapc 'window-make-atom atom-windows))
>- (message "This does not work with fixed size or atom windows.")))))
>+ (when (or (not window) (window-live-p window))
>+ (user-error "No windows to transpose"))
>+ (let* ((frame (window-frame window))
>+ (first-window window)
>+ (selected-window (frame-selected-window window))
>+ (win-tree (car (window-tree-normal-sizes window)))
>+ (win-list (seq-filter #'window-live-p (flatten-list win-tree)))
>+ (atom-windows (seq-keep #'window-atom-root win-list)))
>+ (unless (and (not (eq (car atom-windows) window))
>+ (or no-resize
>+ (and (not atom-windows)
>+ (not (seq-some #'window-fixed-size-p win-list)))))
>+ (user-error "Cannot rotate windows due to fixed size or atom windows"))
>+ (delete-dups atom-windows)
>+ (while (not (window-live-p first-window))
>+ (setq first-window (window-child first-window)))
>+ (delete-other-windows-internal first-window window)
>+ (window--transpose-1 win-tree first-window conf no-resize atom-windows)
>+ ;; Go back to previously selected window.
>+ (set-frame-selected-window frame selected-window)
>+ (mapc #'window-make-atom atom-windows)))
>
> (defun window--transpose-1 (subtree cwin conf no-resize atom-windows)
> "Subroutine of `window--transpose'.
>@@ -259,8 +225,7 @@ window--transpose-1
> ;; `flen' is max size the window could be converted to the opposite
> ;; of the given split type.
> (let ((parent-window-is-set t)
>- (flen (if (funcall (if no-resize 'not 'identity)
>- (car subtree))
>+ (flen (if (xor no-resize (car subtree))
> (float (window-pixel-width cwin))
> (float (window-pixel-height cwin)))))
> (mapc
>@@ -268,7 +233,7 @@ window--transpose-1
> (prog1
> (let* ((split-size (- (round (* flen size))))
> (split-type
>- (funcall (if (car subtree) 'car 'cdr) conf))
>+ (funcall (if (car subtree) #'car #'cdr) conf))
> (return-win
> (if (listp window)
> ;; `window' is a window subtree.
>@@ -293,9 +258,7 @@ window--transpose-1
> (if window-combination-limit
> (cons (caar (cddddr first-child)) (cadr
> subtree))
> (caar (cddddr first-child)))))
>- (if is-atom
>- '(nil . t)
>- conf)
>+ (if is-atom '(nil . t) conf)
> no-resize
> atom-windows))
> ;; `window' is a window.
>@@ -323,14 +286,16 @@ window--transpose-1
> (if (car subtree)
> (cadr window-size-info)
> (caddr window-size-info)))))
>- ;; We need to ingore first 5 elements of window list, we ignore
>+ ;; We need to ignore first 5 elements of window list, we ignore
> ;; window split type, sizes and the first window (it's
> ;; implicitly created). We just have a list of windows.
> (nreverse (cdr (cddddr subtree)))))
> ;; (caar (cddddr subtree)) is the first child window of subtree.
> (unless (windowp (caar (cddddr subtree)))
> (let ((is-atom (memq (cadr (cadr (cddddr subtree))) atom-windows)))
>- (window--transpose-1 (car (cddddr subtree)) cwin (if is-atom '(nil . t)
>conf)
>+ (window--transpose-1 (car (cddddr subtree)) cwin
>+ (if is-atom '(nil . t) conf)
> no-resize atom-windows)))))
>
>+(provide 'window-x)
> ;;; window-x.el ends here
>
Thanks for the code review I will look at it soon.
Selecting the rotated window is intended behaviour, as if means you can use the
function as a practical alternative or 'other-window'. I don't see the
advantages of surfing the current window (other than getting sandy).
- Functions transpose/rotate/flip windows, Pranshu Sharma, 2025/01/01
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/10
- Re: Functions transpose/rotate/flip windows, Pranshu Sharma, 2025/01/10
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/10
- Re: Functions transpose/rotate/flip windows, Eshel Yaron, 2025/01/11
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/11
- Re: Functions transpose/rotate/flip windows, Eshel Yaron, 2025/01/11
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/11
- Re: Functions transpose/rotate/flip windows, Juri Linkov, 2025/01/11
- Re: Functions transpose/rotate/flip windows,
Pranshu <=
- Re: Functions transpose/rotate/flip windows, Eshel Yaron, 2025/01/11
- Re: Functions transpose/rotate/flip windows, Pranshu Sharma, 2025/01/11
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/12
- Re: Functions transpose/rotate/flip windows, Eshel Yaron, 2025/01/12
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/14
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/12
- Re: Functions transpose/rotate/flip windows, Pranshu Sharma, 2025/01/14
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/14
- Re: Functions transpose/rotate/flip windows, Pranshu Sharma, 2025/01/14
- Re: Functions transpose/rotate/flip windows, martin rudalics, 2025/01/17