From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "J.P." Newsgroups: gmane.emacs.bugs Subject: bug#51753: ERC switches to channel buffer on reconnect Date: Mon, 23 May 2022 00:48:57 -0700 Message-ID: <87fsl0zo2e.fsf__8809.52264867432$1653293929$gmane$org@neverwas.me> References: <878rqwjqua.fsf@codeisgreat.org> <87a6b92ers.fsf@neverwas.me> <875ylxm07b.fsf@codeisgreat.org> 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="6648"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) Cc: emacs-erc@gnu.org To: 51753@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon May 23 10:18:42 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1nt3Gy-0001UG-1a for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 23 May 2022 10:18:40 +0200 Original-Received: from localhost ([::1]:44782 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nt3Gw-0001Z0-QJ for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 23 May 2022 04:18:38 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:46330) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nt2pG-000448-Va for bug-gnu-emacs@gnu.org; Mon, 23 May 2022 03:50:03 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:53291) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nt2pG-0007Ue-L5 for bug-gnu-emacs@gnu.org; Mon, 23 May 2022 03:50:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nt2pG-0002XN-I4 for bug-gnu-emacs@gnu.org; Mon, 23 May 2022 03:50:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 23 May 2022 07:50:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51753 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 51753-submit@debbugs.gnu.org id=B51753.16532921559685 (code B ref 51753); Mon, 23 May 2022 07:50:02 +0000 Original-Received: (at 51753) by debbugs.gnu.org; 23 May 2022 07:49:15 +0000 Original-Received: from localhost ([127.0.0.1]:47188 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nt2oU-0002W8-Ek for submit@debbugs.gnu.org; Mon, 23 May 2022 03:49:15 -0400 Original-Received: from mail-108-mta169.mxroute.com ([136.175.108.169]:38791) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nt2oS-0002Vq-4S for 51753@debbugs.gnu.org; Mon, 23 May 2022 03:49:13 -0400 Original-Received: from filter006.mxroute.com ([140.82.40.27] 140.82.40.27.vultrusercontent.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta169.mxroute.com (ZoneMTA) with ESMTPSA id 180efe409cd000c327.001 for <51753@debbugs.gnu.org> (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Mon, 23 May 2022 07:49:01 +0000 X-Zone-Loop: 17aff427bfd381026be68b2db7e8941a02350bff10eb X-Originating-IP: [140.82.40.27] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=neverwas.me ; s=x; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date:References: Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=Rd12fv+wInqTgqP80gGA7TaFH3gDhMrfQFF65Kiwd2Y=; b=KP70VvZP8UWPb9DG/ivxVEDvC7 WtQSebAll7ZS/0icuGTLguRiRRORzrpPTKMabP2/pZlcGZ1w8qI4zeSrCzxfx/puPgV/A1v3I0Sfd QJvo0BoYYEi2cX+YwwyiD56Kjglqpv77vmACfVK36l0jITMGQ+lOw6Qk9P+3R7bHRNxukWV7HZDNL AhgDgigVeD95qzZag2bEIitiiHki3EMVfHqvskSMCMLZevnqviQqTXA/5NsM6w8dgExtzPGye1+iC H1yGlnQ0cc2qN6a+HpnjCplDLifn0dBC4Whn6DBGXPk6RxwOBCZXhY6oUlir02ZFig9XC0VLW1W7y tXXAfhWA==; In-Reply-To: <875ylxm07b.fsf@codeisgreat.org> (Pankaj Jangid's message of "Mon, 23 May 2022 08:20:32 +0530") X-AuthUser: masked@neverwas.me X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:232936 Archived-At: --=-=-= Content-Type: text/plain Pankaj Jangid writes: > "J.P." writes: > >> Are you saying ERC ought to remember the frame in which an entry-point >> command, like `erc-tls', was originally invoked? Or might it be enough >> to make a best effort attempt at finding such a "dedicated" frame? > > I have tried the #2 as specified below. I kind of agree that #1 will > result in the desired behaviour. Thanks for trying out that patch. Basically, I bungled a few things that prevented it from faithfully representing #2, even though I claimed otherwise (sorry). IOW, I'm saying the approach may be salvageable and only the implementation flawed. > I tried this and here is what is happening. > > I launched emacs then I launched another frame and M-x erc-tls and come > back to the 1st frame for other work. "erc-tls" running fine in the > other frame but when it starts to join autojoin channels after > connecting, it creates one more frame for each channel instead of > reusing the 2nd frame. Right, it seems I blindly fixated on the segregation aspect of your description (again, apologies) and glossed over the obvious fact that you don't want ERC creating frames, period. I've adapted the existing patch with this in mind in hopes you're willing to try again. One thing to be aware of is that even if we pivot to #1, the connection-detection and buffer-association stuff will still be unreliable in many cases. However, that should change after bug#48598 lands. That said, if you still feel strongly about #1, then please say so (others following along as well). And likewise if you have suggestions on the implementation or would like to try taking the wheel. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff >From 7155fbd9f4afe9c9fd9dd2c89e28830a9d6612d7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Mon, 23 May 2022 00:15:18 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): Allow erc-reuse-frames to favor connections lisp/erc/erc.el | 52 +++++++++++++--- test/lisp/erc/erc-tests.el | 119 +++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 8 deletions(-) Interdiff: diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f82fb07a66..13ac0ec979 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1538,11 +1538,12 @@ erc-frame-dedicated-flag (defcustom erc-reuse-frames t "Non-nil means only create a frame for undisplayed buffers. For new target buffers, a value of 'displayed' extends this to mean use -the frame of any buffer from the same server connection, visible or not. -When this option is nil, a new frame is always created. Regardless of -its value, this option is ignored unless `erc-join-buffer' is set to -`frame'. Note that like most options in the `erc-buffer' customize -group, this has no effect on server buffers while reconnecting." +the frame of any buffer from the same server connection, visible or not, +or, as a last resort, a frame showing any ERC buffer. When this option +is nil, a new frame is always created. Regardless of its value, this +option is ignored unless `erc-join-buffer' is set to `frame'. Note that +like most options in the `erc-buffer' customize group, this has no +effect on server buffers while reconnecting." :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA :group 'erc-buffers :type '(choice boolean @@ -1948,18 +1949,30 @@ erc-update-modules (funcall sym 1) (error "`%s' is not a known ERC module" mod)))))) -(defun erc--setup-buffer-frame-displayed (buffer) +(defun erc--setup-buffer-first-win (frame a b) + (catch 'found + (walk-window-tree + (lambda (w) + (when (eq (buffer-local-value a (window-buffer w)) b) + (throw 'found t))) + frame nil 0))) + +(defun erc--display-buffer-use-some-frame (buffer alist) "Maybe display BUFFER in an existing frame for the same connection. -If performed, return window used; otherwise, return nil." +If performed, return window used; otherwise, return nil. Forward ALIST +to display-buffer machinery." (when-let* - ((bs (erc-buffer-list nil erc-server-process)) - (visit (lambda (w) (when (memq (window-buffer w) bs) (throw 'found t)))) - (test (lambda (fr) (catch 'found (walk-windows visit 0 fr)))) - ((or (cdr (frame-list)) (funcall test (selected-frame))))) - (display-buffer buffer `((display-buffer-use-some-frame) - (inhibit-switch-frame . t) - (inhibit-same-window . t) - (frame-predicate . ,test))))) + ((same-proc-p (lambda (fr) + (erc--setup-buffer-first-win fr 'erc-server-process + erc-server-process))) + (same-mode-p (lambda (fr) + (erc--setup-buffer-first-win fr 'major-mode 'erc-mode))) + ((or (cdr (frame-list)) (funcall same-mode-p (selected-frame)))) + (frame (car (or (filtered-frame-list same-proc-p) + (filtered-frame-list same-mode-p)))) + (window (get-lru-window frame nil t))) + ;; FIXME don't rely on internal window.el function (tab-bar also does it) + (window--display-buffer buffer window 'reuse alist))) (defun erc-setup-buffer (buffer) "Consults `erc-join-buffer' to find out how to display `BUFFER'." @@ -1975,9 +1988,9 @@ erc-setup-buffer ('frame (cond ((and (eq erc-reuse-frames 'displayed) - erc-default-recipients ; change this to `erc--target' after bug#48598 - (not (get-buffer-window buffer t)) - (erc--setup-buffer-frame-displayed buffer))) + (not (get-buffer-window buffer t))) + (display-buffer buffer `((erc--display-buffer-use-some-frame) + (inhibit-same-window . t)))) ((or (not erc-reuse-frames) (not (get-buffer-window buffer t))) (let ((frame (make-frame (or erc-frame-alist diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 1eac6b22c9..686db3bb2e 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -173,6 +173,10 @@ erc--switch-to-buffer (ert-deftest erc-reuse-frames () ;; TODO run this in a pseudo terminal subprocess for EMBA + ;; + ;; TODO case that simulates automatic reconnecting, with an + ;; existing, unselected frame containing two windows, one with a + ;; dead ERC buffer and the other a non-ERC buffer (skip-unless (not noninteractive)) (should-not erc-frame-dedicated-flag) (let ((erc-join-buffer 'frame) -- 2.36.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Allow-erc-reuse-frames-to-favor-connections.patch >From 7155fbd9f4afe9c9fd9dd2c89e28830a9d6612d7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sat, 21 May 2022 00:04:04 -0700 Subject: [PATCH 1/1] Allow erc-reuse-frames to favor connections * lisp/erc/erc.el (erc-reuse-frames): Add alternate value to favor existing frames already displaying other buffers from the same connection. (erc-setup-buffer): Add case for "displayed" variant of `erc-reuse-frames'. --- lisp/erc/erc.el | 52 +++++++++++++--- test/lisp/erc/erc-tests.el | 119 +++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 8 deletions(-) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index ff482d4933..13ac0ec979 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1536,12 +1536,18 @@ erc-frame-dedicated-flag :type 'boolean) (defcustom erc-reuse-frames t - "Determines whether new frames are always created. -Non-nil means that a new frame is not created to display an ERC -buffer if there is already a window displaying it. This only has -effect when `erc-join-buffer' is set to `frame'." + "Non-nil means only create a frame for undisplayed buffers. +For new target buffers, a value of 'displayed' extends this to mean use +the frame of any buffer from the same server connection, visible or not, +or, as a last resort, a frame showing any ERC buffer. When this option +is nil, a new frame is always created. Regardless of its value, this +option is ignored unless `erc-join-buffer' is set to `frame'. Note that +like most options in the `erc-buffer' customize group, this has no +effect on server buffers while reconnecting." + :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA :group 'erc-buffers - :type 'boolean) + :type '(choice boolean + (const displayed))) (defun erc-channel-p (channel) "Return non-nil if CHANNEL seems to be an IRC channel name." @@ -1943,6 +1949,31 @@ erc-update-modules (funcall sym 1) (error "`%s' is not a known ERC module" mod)))))) +(defun erc--setup-buffer-first-win (frame a b) + (catch 'found + (walk-window-tree + (lambda (w) + (when (eq (buffer-local-value a (window-buffer w)) b) + (throw 'found t))) + frame nil 0))) + +(defun erc--display-buffer-use-some-frame (buffer alist) + "Maybe display BUFFER in an existing frame for the same connection. +If performed, return window used; otherwise, return nil. Forward ALIST +to display-buffer machinery." + (when-let* + ((same-proc-p (lambda (fr) + (erc--setup-buffer-first-win fr 'erc-server-process + erc-server-process))) + (same-mode-p (lambda (fr) + (erc--setup-buffer-first-win fr 'major-mode 'erc-mode))) + ((or (cdr (frame-list)) (funcall same-mode-p (selected-frame)))) + (frame (car (or (filtered-frame-list same-proc-p) + (filtered-frame-list same-mode-p)))) + (window (get-lru-window frame nil t))) + ;; FIXME don't rely on internal window.el function (tab-bar also does it) + (window--display-buffer buffer window 'reuse alist))) + (defun erc-setup-buffer (buffer) "Consults `erc-join-buffer' to find out how to display `BUFFER'." (pcase erc-join-buffer @@ -1955,15 +1986,20 @@ erc-setup-buffer ('bury nil) ('frame - (when (or (not erc-reuse-frames) - (not (get-buffer-window buffer t))) + (cond + ((and (eq erc-reuse-frames 'displayed) + (not (get-buffer-window buffer t))) + (display-buffer buffer `((erc--display-buffer-use-some-frame) + (inhibit-same-window . t)))) + ((or (not erc-reuse-frames) + (not (get-buffer-window buffer t))) (let ((frame (make-frame (or erc-frame-alist default-frame-alist)))) (raise-frame frame) (select-frame frame)) (switch-to-buffer buffer) (when erc-frame-dedicated-flag - (set-window-dedicated-p (selected-window) t)))) + (set-window-dedicated-p (selected-window) t))))) (_ (if (active-minibuffer-window) (display-buffer buffer) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 520f10dd4e..686db3bb2e 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -171,6 +171,125 @@ erc--switch-to-buffer (dolist (b '("server" "other" "#chan" "#foo" "#fake")) (kill-buffer b)))) +(ert-deftest erc-reuse-frames () + ;; TODO run this in a pseudo terminal subprocess for EMBA + ;; + ;; TODO case that simulates automatic reconnecting, with an + ;; existing, unselected frame containing two windows, one with a + ;; dead ERC buffer and the other a non-ERC buffer + (skip-unless (not noninteractive)) + (should-not erc-frame-dedicated-flag) + (let ((erc-join-buffer 'frame) + (erc-reuse-frames t) + (orig-frame (selected-frame)) + erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) + + (ert-info ("Value: t") + (with-current-buffer (generate-new-buffer "server") + (erc-mode) + (setq erc-server-process (start-process "server" (current-buffer) + "sleep" "1") + erc-frame-alist (cons '(name . "server") default-frame-alist)) + (set-process-query-on-exit-flag erc-server-process nil) + (should-not (get-buffer-window (current-buffer) t)) + (erc-setup-buffer (current-buffer)) + ;; New frame created and raised + (should (equal "server" (frame-parameter (window-frame) 'name))) + (should (get-buffer-window (current-buffer) t)) + + (with-current-buffer (generate-new-buffer "#chan") + (erc-mode) + (setq erc-server-process erc-server-process + erc-frame-alist (cons '(name . "#chan") default-frame-alist) + erc-default-recipients '("#chan")) + (should-not (get-buffer-window (current-buffer) t)) + (erc-setup-buffer (current-buffer)) + ;; Another frame was created just for #chan + (should (equal "#chan" (frame-parameter (window-frame) 'name))) + (should (get-buffer-window (current-buffer) t)) + (delete-frame)) + + (select-frame-by-name "server") + (pop-to-buffer "#chan") + ;; The server frame contains two vertical windows + (let ((tree (window-tree))) + (should (memq (get-buffer-window "server" t) (car tree))) + (should (memq (get-buffer-window "#chan" t) (car tree)))) + (should (eq (get-buffer "#chan") (window-buffer (selected-window)))) + (should (eq (get-buffer "server") (window-buffer (next-window)))))) + + (ert-info ("Value: displayed, scratch frame selected") + (select-frame orig-frame) + (with-current-buffer "*scratch*" + (with-current-buffer (generate-new-buffer "#spam") + (erc-mode) + (setq erc-server-process (buffer-local-value 'erc-server-process + (get-buffer "server")) + erc-reuse-frames 'displayed + erc-frame-alist (cons '(name . "#spam") default-frame-alist) + erc-default-recipients '("#spam")) + (should-not (get-buffer-window (current-buffer) t)) + (erc-setup-buffer (current-buffer)) + ;; Window shows up in other frame + (should (eq (selected-frame) orig-frame)) + (let ((fr (window-frame (get-buffer-window (current-buffer) t)))) + (should (equal "server" (frame-parameter fr 'name))) + (with-selected-frame fr + (should (memq (get-buffer-window "#spam" t) + (car (window-tree)))))))) + + (with-current-buffer "server" + (ert-info ("Value: displayed, server frame selected") + (select-frame-by-name "server") + (select-window (get-buffer-window "#spam")) + (with-current-buffer (generate-new-buffer "bob") + (erc-mode) + (setq erc-server-process (buffer-local-value 'erc-server-process + (get-buffer "server")) + erc-frame-alist (cons '(name . "bob") default-frame-alist) + erc-default-recipients '("bob")) + (should-not (get-buffer-window (current-buffer) t)) + (erc-setup-buffer (current-buffer)) + ;; Window shows up in this frame + (let ((fr (window-frame (get-buffer-window (current-buffer) t)))) + (should (eq fr (selected-frame))) + (should (equal "server" (frame-parameter fr 'name))) + (with-selected-frame fr + (should (memq (get-buffer-window "bob" t) + (car (window-tree))))) + ;; `inhibit-same-window' respected + (should-not (eq (get-buffer-window "bob") (selected-window)))))) + + (ert-info ("Value: displayed, other frames deleted") + (with-selected-frame orig-frame + (delete-frame)) + (should-not (cdr (frame-list))) + (select-window (get-buffer-window "bob")) + (with-current-buffer (generate-new-buffer "alice") + (erc-mode) + (setq erc-server-process (buffer-local-value 'erc-server-process + (get-buffer "server")) + erc-frame-alist (cons '(name . "alice") default-frame-alist) + erc-default-recipients '("alice")) + (should-not (get-buffer-window (current-buffer) t)) + (erc-setup-buffer (current-buffer)) + (let ((fr (window-frame (get-buffer-window (current-buffer) t)))) + (should (eq fr (selected-frame))) + (should (equal "server" (frame-parameter fr 'name))) + (with-selected-frame fr + (should (memq (get-buffer-window "alice" t) + (car (window-tree))))) + (should-not (eq (get-buffer-window "alice") + (selected-window))))))))) + + (should-not (cdr (frame-list))) + (delete-other-windows) + (kill-buffer "server") + (kill-buffer "bob") + (kill-buffer "alice") + (kill-buffer "#spam") + (kill-buffer "#chan")) + (ert-deftest erc-lurker-maybe-trim () (let (erc-lurker-trim-nicks (erc-lurker-ignore-chars "_`")) -- 2.36.1 --=-=-=--