From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Pranshu Sharma Newsgroups: gmane.emacs.devel Subject: Re: Add function to rotate/transpose all windows Date: Fri, 29 Nov 2024 01:18:28 +1000 Message-ID: <8734jbz8sb.fsf@gmail.com> References: <87setpdv21.fsf@gmail.com> <87bjyfcncu.fsf@gmail.com> <87cyiuefxs.fsf@gmail.com> <878qthewbq.fsf@gmail.com> <8599bc67-b05d-4afc-8e6e-1ba64a30054e@gmx.at> <87frnp2x85.fsf@gmail.com> <823c7cca-63d4-4568-94bc-11f5949d6c5c@gmx.at> <87h683muss.fsf@gmail.com> <02432e6c-6ee2-4c68-9ebb-246f6be88918@gmx.at> <877c8wadke.fsf@gmail.com> <878qt8spp2.fsf@gmail.com> <0ce35c7a-8b28-4905-a6ab-caf50f2fc750@gmx.at> <87mshl2i6h.fsf@gmail.com> <9b460366-f34e-48f6-a680-e7fa5bc7f598@gmx.at> <87bjy03fql.fsf@gmail.com> <356d63bc-818c-428c-b31b-a0eb227b3a8a@gmx.at> <87o720gjst.fsf@gmail.com> <7dfe87a0-b367-47df-86df-f8fd95163fd6@gmx.at> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19812"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Juri Linkov , Eli Zaretskii , emacs-devel@gnu.org To: martin rudalics Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Thu Nov 28 17:33:31 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1tGhSN-0004x4-L1 for ged-emacs-devel@m.gmane-mx.org; Thu, 28 Nov 2024 17:33:31 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tGhRa-0006ie-Ns; Thu, 28 Nov 2024 11:32:42 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tGgHu-0001QZ-Qc for emacs-devel@gnu.org; Thu, 28 Nov 2024 10:18:38 -0500 Original-Received: from mail-pl1-x633.google.com ([2607:f8b0:4864:20::633]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tGgHt-0004dU-6g; Thu, 28 Nov 2024 10:18:38 -0500 Original-Received: by mail-pl1-x633.google.com with SMTP id d9443c01a7336-214d1c6d724so7633515ad.3; Thu, 28 Nov 2024 07:18:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732807113; x=1733411913; darn=gnu.org; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=eUOA331ZhTDPcgvGEYMVjCGKLSZSG4IDd4l2tUI+fgc=; b=TNDe1NTzRgn1USh/yX96WxPm8R0G8EoS5cEFMIkA1QIE/z3TzOZFU/TMa7783pupOI ByRJbficjPfJTLBAy+cBYYsJXlImDWMZL0VANZhwP4ENGGlHOYXU3RNZVB2Q0k7HVmsU j9hfWMXjgMiFGxuevW9kHu5sUdfqtax8yaUz6SuL6JjprC4jeLeC+cF600zKT+dLdYu+ DV/Wr5tgsgx5JSqfG6/5UlreBcAVieM0yuxqLsIcByQ9G7AnFE1AhNXPzRhU9x1QKf75 LhRKoVQf7eBv1SO+1tO1vdCcHLxMXUgpTf+/nSI4Cnlu2/XD6o1Tsgah/aB/sFklexxt Lw0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732807113; x=1733411913; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=eUOA331ZhTDPcgvGEYMVjCGKLSZSG4IDd4l2tUI+fgc=; b=G+zJjZOIctr7IWisxTPI1ctrPK/gxiHpHc30EH85U2b4e4VXvJh/0Wi/w3u8Z3CGGX cSXz9dfLrF2GTI/EPIG1yZJ7jv98nzsgmo0GQ739YOfMoKgBt6DnTzu9b9zvHJfFt+xr JgnFNdJJpB1L71TEMUoO/HH8O1VSHoNCpNRtepFGpFLWnT0iX6Msx4VHsWnLJMJaimd6 5mF8IxNmTpRZ8CD/sFCX/qsOiFCZYQrxNOIVyjJPY8MjMvV8b+sTsSVM6BbV3NsIWxuA KHgzXfs23VP11igN0Uff4XozBXyXQOIziWUWhSdf7u9eg1WxPNa/lFpen2FBoSpuxqrX 3VGw== X-Forwarded-Encrypted: i=1; AJvYcCWYLlPQo8nycCzshKBLrU3oic8lhsLTH/eQLMW8qTPgnSWz0+60oWwpHL9ELIEQ7S1NXWZrdYT/rden20g=@gnu.org, AJvYcCXLY/7FwXH3Fmb9ck9XmQmAkuXZCD1dQ9TjhVz0o3DCPJn1lyXCgGvD3LZLysDEpBEsRyN1@gnu.org X-Gm-Message-State: AOJu0YwKOCbZvErzOlYO+oI3nE1Y1CaPiP1SFgxdXgAfqIlKMmFwvlUd m1BSGN45JImHtnmDyQan50X/d5hyrm+l0NTkW4KZTrCY3KYR3sH5jObOlOEX X-Gm-Gg: ASbGncv8+rVra0w0sIdFwrcsSEC40WzOJvfmxoZxQe5ixnA1efaGPxrT/7kISu3jY7u KpIBS/95fn5iYUsnImxcCXBIwlCX0UAmY2Sh3jWjaNakqWZTDcu+92YaDjqLbaV6IWuRlpNMzWc 8ROBlBdTfw8p2dOtec1LwuEtXJyIzytkVgSE9yGwFZNCkuXNcfQt0MCRqjKYbbfN+jJvWQT0J+N Y1LrS8QZwR7cgWCiN0r4utEm5Soawe6aJDvEbUnWpth+bRR/mNb X-Google-Smtp-Source: AGHT+IHsH7h214PTkqXsYq2Q9dCu6i1xDeiIAaTJzuwndJaGMaULHKuxEY3gU11eNzO0dLJ9DmNTeg== X-Received: by 2002:a17:903:32c5:b0:20c:7d7d:7ba8 with SMTP id d9443c01a7336-21501c5ecfbmr104424275ad.46.1732807113228; Thu, 28 Nov 2024 07:18:33 -0800 (PST) Original-Received: from pebl ([2001:8003:7816:8300:96bb:d6b7:c96:deea]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521966d45sm14261345ad.125.2024.11.28.07.18.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 07:18:32 -0800 (PST) In-Reply-To: <7dfe87a0-b367-47df-86df-f8fd95163fd6@gmx.at> (martin rudalics's message of "Thu, 28 Nov 2024 10:28:39 +0100") Received-SPF: pass client-ip=2607:f8b0:4864:20::633; envelope-from=pranshusharma366@gmail.com; helo=mail-pl1-x633.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 28 Nov 2024 11:32:42 -0500 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:325825 Archived-At: --=-=-= Content-Type: text/plain martin rudalics writes: >> Ok, so cycle-windows is like other-window, expect you stay where you >> are, and the windows move for you. > > So is it essentially 'window-swap-states' for N windows? Yeah, kinda >> So say if yuo had window A selected in the first scinario, window C >> would be selected in the second. > > Wouldn't that be confusing? I type into window A, cycle windows, and > continue typing into window C? That's the point. Imagine if buffers B and C contain long lines of code, and sometimes you need to edit them, and other times you need to look at a tiny section of theirs while editing A. With this function, instead of other-window, you bring B to the big window where A is at, for more convinent editing. >>> This is 'window--atom-check' at work while the window structure is yet >>> incomplete. An atomic window must contain at least two windows. Please >>> try with adding the below two forms >> >> I don't understand how this is going to fix it. The source of the error >> was that the window-atom parametor was not getting transferred >> proeprlty. > > The parameter was reset by 'window--atom-check' because it found only > one atomic window which doesn't make sense. Did you try what I said? > Ok, I see what happen. I found a simpler way to fix it: If we already have list of previously atomic root windows, why not just make them atomic again? I also fixed some of the cycle-windows code, when it wasn't properly working under C-u in which it only rotated subtree. Right now, I feel the code is in a pretty complete state. --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=window-transpose.el Content-Transfer-Encoding: quoted-printable ;;; -*- lexical-binding:t -*- (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 valid 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 (cons t window) (cons (cons (window-normal-size window nil) (window-normal-size window t)) (window-tree-pixel-sizes (window-top-child window) t)))) ((window-left-child window) (cons (cons nil window) (cons (cons (window-normal-size window nil) (window-normal-size window t)) (window-tree-pixel-sizes (window-left-child window) t)))) (t (list window (cons (window-normal-size window nil) (window-normal-size window t))))) list)) (setq window (when next (window-next-sibling window)))) (nreverse list))) (defun rotate-windows-anticlockwise (&optional subtree frame-or-window) "Rotate windows of FRAME-OR-WINDOW anticlockwise by 90 degrees. FRAME-OR-WINDOW must be a valid 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. If SUBTREE is non-nil, the function will act as if FRAME-OR-WINDOW is the parent window of the selected window." (interactive "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (window--transpose window '(right . above) nil))) (defun rotate-windows-clockwise (&optional subtree frame-or-window) "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees. FRAME-OR-WINDOW must be a valid 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. If SUBTREE is non-nil, the function will act as if FRAME-OR-WINDOW is the parent window of the selected window." (interactive "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (window--transpose window '(left . below) nil))) (defun flip-windows-horizontally (&optional subtree 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 valid 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. If SUBTREE is non-nil, the function will act as if FRAME-OR-WINDOW is the parent window of the selected window." (interactive "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (window--transpose window '(below . left) t))) (defun flip-windows-vertically (&optional subtree 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 valid 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 "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (window--transpose window '(above . right) t))) (defun transpose-windows (&optional subtree 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 valid 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. If SUBTREE is non-nil, the function will act as if FRAME-OR-WINDOW is the parent window of the selected window." (interactive "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (window--transpose window '(right . below) nil))) (defun deepmap(fun ls) (if (consp ls) (cons (if (consp (car ls)) (deepmap fun (car ls)) (funcall fun (car ls))) (deepmap fun (cdr ls))) (funcall fun ls))) (defun cycle-windows (&optional subtree frame-or-window) "This cycles windows basiclly so that for all windows, each window becomes it's `other-window'. +-----+ +-----+ | A | | C | |-----| -> |-----| |B | C| | A| B| +-----+ +-----+ " (interactive "P") (let ((window (cond (subtree (window-parent)) ((windowp frame-or-window) frame-or-window) (t (window-main-window frame-or-window))))) (if (or (not window) (window-live-p window)) (message "No windows to transpose") (let* ((frame (window-frame window)) (selwin (frame-selected-window window)) (win-tree (car (window-tree-pixel-sizes window))) (winls (seq-filter 'window-live-p (flatten-list win-tree))) (rotated-ls (append (last winls) winls)) (fwin (car (last winls))) (new-win-tree (deepmap (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 fwin window) ;; (delete-dups atom-windows) (window--transpose-1 new-win-tree fwin '(below . right) t nil) (set-frame-selected-window frame selwin) (other-window -1) (while (not (memq (selected-window) winls)) (other-window -1)))))))) (defun window--transpose (window conf do-not-convert-size) "Rearrange windows of 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." (if (or (not window) (window-live-p window)) (message "No windows to transpose") (let* ((frame (window-frame window)) (fwin window) (selwin (frame-selected-window window)) (win-tree (car (window-tree-pixel-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 do-not-convert-size (and (not atom-windows) (not (seq-some 'window-fixed-size-p win-list))))) (progn (when atom-windows (delete-dups atom-windows)) (while (not (window-live-p fwin)) (setq fwin (window-child fwin))) ;; All child windows need to be recursively deleted. (delete-other-windows-internal fwin window) (window--transpose-1 win-tree fwin conf do-not-convert-size atom-windo= ws) ;; Go back to previously selected window. (set-frame-selected-window frame selwin) (mapc 'window-make-atom atom-windows)) (message "This does not work with fixed size or atom windows."))))) (defun window--transpose-1 (subtree cwin conf do-not-convert-size atom-wind= ows) "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. (let ((n-set t) (flen (if (funcall (if do-not-convert-size 'not 'identity) (caar subtree)) (float (window-pixel-width cwin)) (float (window-pixel-height cwin))))) (mapc (pcase-lambda (`(,win . ,size)) (prog1 (let ((split-size (- (round (* flen size)))) (split-type (funcall (if (caar subtree) 'car 'cdr) conf))) (if (listp win) ;; `win' is a window subtree. (let* ((d-win win) (is-atom (memq (cdar d-win) atom-windows)) (_ (while (listp (caaddr d-win)) (setq d-win (caddr d-win))))) (window--transpose-1 win (let ((window-combination-limit n-set) (new-win (split-window cwin split-size split-type t (if window-combination-limit (cons (caaddr d-win) (cdar subtree)) (caaddr d-win))))) (when window-combination-limit (set-window-combination-limit (cdar subtree) nil)) new-win) (if is-atom '(nil . t) conf) do-not-convert-size atom-windows)) ;; `win' is a window. (split-window cwin split-size split-type t (if n-set (cons win (cdar subtree)) win)))) (setq n-set nil))) (mapcar (lambda (e) (let ((window? (if (windowp (car e)) (car e) e))) (cons window? ;; The respective size of the window. (if (caar 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)) (let ((is-atom (memq (cdar (caddr subtree)) atom-windows))) (window--transpose-1 (caddr subtree) cwin (if is-atom '(nil . t) conf) do-not-convert-size atom-windows))))) (define-key global-map (kbd "C-x w t") 'transpose-windows) (define-key global-map (kbd "C-x w c") 'cycle-windows) (define-key global-map (kbd "C-x w f") 'flip-windows-vertically) --=-=-=--