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: Sat, 26 Oct 2024 00:24:33 +1000 Message-ID: <87zfms6z1a.fsf@gmail.com> References: <87setpdv21.fsf@gmail.com> <87ikudk62k.fsf@gmail.com> <0d879e95-c37e-416d-b439-daa6384c4f30@gmx.at> <878qv8kws2.fsf@gmail.com> <87ed4xvf60.fsf@gmail.com> <861q0qfnhr.fsf@mail.linkov.net> <878quxdant.fsf@gmail.com> <86zfndi6wh.fsf@mail.linkov.net> <87zfncuqhu.fsf@gmail.com> <86v7y00w68.fsf@mail.linkov.net> <87y12smubh.fsf@gmail.com> <96ea5140-9043-4c1b-97f3-4c534296355e@gmx.at> <87frotqx90.fsf@gmail.com> <87y12iyidd.fsf@gmail.com> <87iktld1bd.fsf@gmail.com> <87r085r2gl.fsf@gmail.com> 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="20711"; 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 Fri Oct 25 16:25:37 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 1t4LFw-0005Ey-K3 for ged-emacs-devel@m.gmane-mx.org; Fri, 25 Oct 2024 16:25:36 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t4LFB-0005YH-22; Fri, 25 Oct 2024 10:24:49 -0400 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 1t4LF1-00053W-4L for emacs-devel@gnu.org; Fri, 25 Oct 2024 10:24:39 -0400 Original-Received: from mail-pf1-x433.google.com ([2607:f8b0:4864:20::433]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1t4LEz-0000yZ-AU; Fri, 25 Oct 2024 10:24:38 -0400 Original-Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-71e467c3996so1546083b3a.2; Fri, 25 Oct 2024 07:24:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1729866275; x=1730471075; 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=oBUGf5K9jqyh1m/2utZLEKeRQBTVhw6d/X2U8szlBdQ=; b=F8kGIBvAHjzNBxihIeNGDDvTyMERcTixtMuQUQ8P0kt2tmbzx7CASher4FRloOA29V fXe/XhnS1qGch0/pPOH96D8bUol712Ig9SaQy0Kwg9QN0m9q486JOOmQBlotok5q1JG5 d455ifpVU6yzuuTtWeocc0JU2etn4k6ydvIPB+n/TW4T0lBJybPzu1M9duQxTXonjKzw 4LgmIqVNP7mrJMhDHgwRz0zo1P9I/u9hXy5KGgYwMz7XI7jNnaNml/bUipFiS4qW9bXr lL76az2SZ38CIEvP/Z4BvE/c1YKPaQBolDMBrbv3+7S3XqdpmCI4H0z/7snHKnoZGnNY mSew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729866275; x=1730471075; 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=oBUGf5K9jqyh1m/2utZLEKeRQBTVhw6d/X2U8szlBdQ=; b=bLkfQr/H197KszUA7Q7Ckqu7Me12s3cz+pikvJeYCH92JG/gZQbNgAwRhET/ZCVTz2 oMwkr+uNCe95HTJglsJhLkkbc/LTR5KwaoroQl+ExBASHj4Ln7FZUuWPV9gEt/O5qhwR ctojud5hIzbaILXRitxTkVWYFQDE8IzhCvk+a/Vh8eAoZEQnwJUXHoBAM5RlcM8c7Lip ulMvj7WiH8hY85lJinJZ7+Hx+Mu80ny34AFIqz58HIwpqZwX0D+f/POqr0bDe09yuhee v31PASxJon7XjulKGmj18VpQj02YEc0EkN9F56gsuo4aHUnNkMufMcYngZo83d/Gpg/0 O6EQ== X-Forwarded-Encrypted: i=1; AJvYcCVX++8CxoL7M3bMi7cKHSLcoURQhirI3pRz2q/HrP2mqWM1Su9u0M9K1bh2iAoQQNBzfPFKC0mTUywCNJw=@gnu.org, AJvYcCXJusyu9HJLQNMRuinbQx+fmpzY8z7vPD+vdeuCcFleQW2PODHbrM+GWnHSH2CCltvHpf3W@gnu.org X-Gm-Message-State: AOJu0YwxRII98n8tfI5HSmEAEl5GTEtPXT1JYjcVywI6hqvmg4Ysn62I 87KT3JnLrrq3cA1wFysXMdXmqqmFyJalM9pD1jqDd60yecVWoXRROgVNipt6 X-Google-Smtp-Source: AGHT+IHBQ2JmqUOYdKvAxMI+3QdNDOvca92uPp9e4oUYtcCf/G2Yn8NRplqrDODcZxRXKn8+y/ssuQ== X-Received: by 2002:a05:6a00:3d43:b0:71e:7a19:7d64 with SMTP id d2e1a72fcca58-72045e254c7mr6960526b3a.5.1729866274972; Fri, 25 Oct 2024 07:24:34 -0700 (PDT) Original-Received: from pranshu-ThinkPad-E560 ([2001:8003:7816:8300:637e:fa26:2e48:d8d3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-720579326e3sm1109119b3a.71.2024.10.25.07.24.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Oct 2024 07:24:34 -0700 (PDT) In-Reply-To: (martin rudalics's message of "Thu, 24 Oct 2024 20:39:17 +0200") Received-SPF: pass client-ip=2607:f8b0:4864:20::433; envelope-from=pranshusharma366@gmail.com; helo=mail-pf1-x433.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: Fri, 25 Oct 2024 10:24:47 -0400 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:324839 Archived-At: --=-=-= Content-Type: text/plain martin rudalics writes: > > since you don't want to split parent windows. I decided to do this, since I also don't want my brain to start bleeding > I attach a file called window-rotate.el which handles the above > scenario. In contrast with a window tree it simply operates on the old > window structure of the frame directly which I store as an association > list. Note two aspects: > > (1) It always tries to find a leftmost live window to start operating > on. I think you do the same but I've never been able to understand how. >From looking at the code, same reason as you. The leftmost top window is first window in a flattened window tree, then the recurisve descent started from there. The new function also does ame, but perfoms recursive ascent asc > (2) It binds 'window-combination-limit' to make a parent window within > something like the first combination you sketched above so this becomes > > |-------------| > | A | > |-------------| > | ----------- | > || B || > ||-----------|| > || C || > | ----------- | > |-------------| Wow! this is best thing since flush toilets, I was able to make the function work with this. Also, I plan on working on a cycle-windows function which will basiclly change window-tree so that that the layout isn't changed, but the windows are thing is. This will be able to be properly done using window--transpose-1, instead of window swap state which you said didn't work. > Half of the code is debugging code that is not commented. Note that the > code handles rotations only, rotates only the entire frame, does not set > sizes and probably misses other things. But it seems to work so please > test it and maybe try to use as much of it as possible. I looked at it, and could not really understnad it fully due to some low level stuff, but I got the idea and incoroperated some logic of windows-rotate. It seems like window-configurations are kind of being reinvented except in elisp, which is good. The function I made, I feel like my approach is higher level then yours cause I can't quite fully wrap my head around window management in emacs. So a lot of stuff, I don't know you can do. But on other hand, I feel the logic is also quite simpler, you can judge that. --=-=-= Content-Type: application/emacs-lisp Content-Disposition: inline; filename=window-transpose.el Content-Transfer-Encoding: quoted-printable (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 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 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 (current-prefix-arg (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 (current-prefix-arg (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 (current-prefix-arg (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 (current-prefix-arg (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 (current-prefix-arg (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)) (window-combination-limit t) (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--transpose-1 win-tree fwin conf do-not-convert-size nil) ;; Go back to previously selected window. (set-frame-selected-window frame selwin)))) (defun window--transpose-1 (subtree cwin conf do-not-convert-size &optional o-size o-split) "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))))) (split-type (funcall (if (car subtree) 'car 'cdr) conf)) (deepest-window (seq-reduce (pcase-lambda (parent-win `(,win . ,size)) (if (eq fwin win) ;; We are at root win parent-win (let ((split-size (and size (if do-not-convert-size size (round (* flen (/ size ilen))))))) (if (listp win) ;; win is a subtree instead of a window (if (and (not size) o-size) ;; We need to keep going down the ;; identity of correct window. (window--transpose-1 (cons (car win) (cdr win)) parent-win conf do-not-convert-size (progn (when (eq o-split split-type) (setq flen (- flen o-size))) o-size) o-split) (window--transpose-1 win parent-win conf do-not-convert-size split-= size split-type)) (if (and (not size) o-size) (prog1 (split-window parent-win o-size o-split t win) (when (eq o-split split-type) (setq flen (- flen o-size)))) (split-window parent-win split-size split-type t win)))))) (let ((ls (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 first window (irelevnt unless tree) (cddr subtree)))) ;; I add lookahead in size. The size of first win is lost, ;; but it is irelevent as it is total size minus size of rest ;; of windows (seq-mapn 'cons (mapcar 'car ls) (cons nil (mapcar 'cdr ls))) ) cwin))) ;; Perfoming recursive ascent (dotimes (_ (- (length subtree) 3)) (setq deepest-window (window-parent deepest-window))) deepest-window)) --=-=-=--