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: Tue, 19 Nov 2024 19:34:11 +1000 Message-ID: <87h683muss.fsf@gmail.com> References: <87setpdv21.fsf@gmail.com> <877c9ersei.fsf@gmail.com> <51068b75-e12d-4161-9a63-8c280e8b2668@gmx.at> <8734k1gnt9.fsf@gmail.com> <8a2007d9-d501-404b-966d-57a7a51310ef@gmx.at> <87ses0r81d.fsf@gmail.com> <69658762-5fc7-4a9d-9262-528dfd9e93cd@gmx.at> <87wmhb2yew.fsf@gmail.com> <801bbd24-8f79-48a4-9615-f5ef21b2341e@gmx.at> <87ikstsu7f.fsf@gmail.com> <68dc98d6-42c0-431a-aefe-eecb02991764@gmx.at> <875xosy316.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> 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="11947"; 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 Tue Nov 19 15:30:11 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 1tDPF4-0002rc-Cq for ged-emacs-devel@m.gmane-mx.org; Tue, 19 Nov 2024 15:30:10 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tDPED-000789-Tz; Tue, 19 Nov 2024 09:29:17 -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 1tDKcn-0008NM-0E for emacs-devel@gnu.org; Tue, 19 Nov 2024 04:34:21 -0500 Original-Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tDKcl-0002oo-Du; Tue, 19 Nov 2024 04:34:20 -0500 Original-Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-20e576dbc42so43276485ad.0; Tue, 19 Nov 2024 01:34:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732008857; x=1732613657; 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=VXitjGNsAlAn5tBGePINdzwtUwhNcJFJLK57JNKvruQ=; b=W3W5lqTANT/xX7hwIfsec9Z4FMr/DoytbYr55gc865QMc+P1M97GYc/5U8b+Vp+oPZ H8nS3T8jcybOb3YdBbN2cw7EBa8YHpCHthdJhGlG8il6fzpKxC+5FRzlcoNpCI9r3N6p KplQiHr8f6vFSrnFk9JhM1PhHIN6PWT0tD6w1uC//i2aTvKLHJ6HTeIjnxJ9EBFUXL3h U6HrMQhQ42dcm1Eo8o2wFDNX560oY6KKpBLfhdrDlvhuU07rEsCRoO9ok4QmVgVTAy9y EGnMIuaxXcekg/hBxs66rPRuaaKxvs9OZolx1jR5Mh5Yb4DsjejNCIw5kMll7zp3Mnx0 aghQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732008857; x=1732613657; 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=VXitjGNsAlAn5tBGePINdzwtUwhNcJFJLK57JNKvruQ=; b=sG82Ol/yIuoyAz9X5hwh+kHDuQ/R8T2VTDrOtOOTYw8qXgc++nG++oEUkDTHV0g8I6 XxsiWNUj7UUwT1CSEmuo7P1dLxGi8XvuXnEjNWVpc8MfI/VRqlwa+fPVC1SVQ6VEek86 z2JbRv6FgX5hEXbmFt/ZquLekMljoXKBp6MtmK0iZpgPARSdmi4dE9mabklr1fS5c72x As/fZhdS7M3tKkTlr+NLb25q6ae3JY5dgvCF9t3naqR8+ZxpDJ7A6pNw7Fm54Wo6G2lz EfSk6+wyJikAPNTE+m+X9YL6YzUxT9z5pT70NuaIAsqwoO1ARxbzujIbOzf/T2bnaWlj 4lcg== X-Forwarded-Encrypted: i=1; AJvYcCUVsgzDhieMDNok8W/9jds8YqiGKBEHSSui27KRftM3gWwWheMN21Bd4K1vaItHMePC3iHEBOEh+5lY2bs=@gnu.org, AJvYcCVNr2dhcvKPKIikOoPV5dRBmfM1CQV8VoSE47Dq2TAp8heKv+/EzhjSBCf/W79eQbCMJubp@gnu.org X-Gm-Message-State: AOJu0YzxQKc1WXhLG9XlB8VyAJjn7mWbbGZM33Mk1bjnNx81Kc5KtO4j XFR3dTfjHF6ESXq/RdZx5ZEh8jTYIBN4BtoV1Xy1sFQeYmnsmocVPQzAZE2t X-Google-Smtp-Source: AGHT+IGkau5JIKv4xB5FexuUI3qdGe+3TTJALAbNgkHIS4fIDffjFCcGTkuDCbOlG+0TTDE9X8f/Hw== X-Received: by 2002:a17:902:e745:b0:20c:e6e4:9d9f with SMTP id d9443c01a7336-211d0ebd07cmr233933455ad.40.1732008856728; Tue, 19 Nov 2024 01:34:16 -0800 (PST) Original-Received: from pebl ([2001:8003:7816:8300:ed1e:8507:1370:12ad]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-211d0ec7fffsm70612975ad.70.2024.11.19.01.34.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Nov 2024 01:34:16 -0800 (PST) In-Reply-To: <823c7cca-63d4-4568-94bc-11f5949d6c5c@gmx.at> (martin rudalics's message of "Mon, 18 Nov 2024 09:55:09 +0100") Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=pranshusharma366@gmail.com; helo=mail-pl1-x62e.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: Tue, 19 Nov 2024 09:29:16 -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:325504 Archived-At: --=-=-= Content-Type: text/plain martin rudalics writes: >> I can't quite get it to work, imagine this scinario: >> >> +-----+------+ >> | A |__B___| >> | | C | >> +-----+------+ >> >> What the above split does is that is splits A, with refer B, and these >> windows aren't really siblings. So if I do pass the refer of A and B, >> it should be from A's parent, but then when I pass B with refer (cons C >> (B and C's parent)), won't it bug out since B's parent is being set twice? > > I tell you what I'm doing here: Let's call P the original parent of A > and Q that of B and C. The first split is a "first child" below split > with A as window to split and a cons of B and P as REFER. The second > split is a "next sibling" left split with B as window to split and a > cons of C and Q as REFER. Both splits are done with combination limit > set to t. > Thanks, the whole explenation really helped me, I now fixed the thing so that it preserves parents windows as well. I tested it with the: C-x {3 2 o o 2} grid split and the parent window's were same before and after transposing. > BTW if you bind 'window-combination-limit' to t don't forget to reset > it's effect for the parent window via > > (set-window-combination-limit parent limit) > > right after the split. Otherwise the parent window cannot be recombined > later on although that would be principally possible. This means I will need this information provided at runtime of the windows--transpose-1 function, meaning it will have to go in the tree. I had a look at the window combination limit functoin, and it does not work on a dead window. The code for that function is: { struct window *w; CHECK_VALID_WINDOW (window); w = XWINDOW (window); if (WINDOW_LEAF_P (w)) error ("Combination limit is meaningful for internal windows only"); return w->combination_limit; } Now, iiuc, there is some `window' struct which has the combination limit variable. So when the window is dead, the struct still exists as long as lisp object exists, so I don't see any technical reason on not being able to get the window-combination-limit of a dead window. It would be helpful if this and alike functions would be able to work on dead windows. --=-=-= 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-pixel-height window) (window-pixel-width window)) (window-tree-pixel-sizes (window-top-child window) t)))) ((window-left-child window) (cons (cons nil window) (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 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 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)))) (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) ;; Go back to previously selected window. (set-frame-selected-window frame selwin)))) (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) (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))) ;; All child windows need to be recursively deleted. (delete-other-windows-internal fwin window) (window--transpose-1 new-win-tree fwin '(below . right) t) (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 (caar subtree) (cons (float (car (cadr subtree))) (float (window-pixel-width cwin))) (cons (float (cdr (cadr subtree))) (float (window-pixel-height cwin))))) (n-set t)) (mapc (pcase-lambda (`(,win . ,size)) (let ((split-size (- (if do-not-convert-size size (round (* flen (/ size ilen)))))) (split-type (funcall (if (caar subtree) 'car 'cdr) conf))) (if (listp win) ;; `win' is a window subtree. (let* ((d-win win) (_ (while (listp (caaddr d-win)) (setq d-win (caddr d-win)))) (window-combination-limit (and n-set (null (setq n-set nil))))) (window--transpose-1 win (prog1 (split-window cwin split-size split-type t (if window-combination-limit (cons (caaddr d-win) (cdar subtree)) (caaddr d-win)))) conf do-not-convert-size)) ;; `win' is a window. (split-window cwin split-size split-type t (if n-set (progn (setq n-set nil) (cons win (cdar subtree))) win))))) (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)) (window--transpose-1 (caddr subtree) cwin conf do-not-convert-size)))) (define-key global-map (kbd "C-x w t") 'transpose-windows) (define-key global-map (kbd "C-x w c") 'cycle-windows) --=-=-=--