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#70840: 29.3; ERC 5.5.0.29.1: erc-kill-buffer-on-part kills server buffer Date: Thu, 16 May 2024 20:57:52 -0700 Message-ID: <87wmnt5bun.fsf__30326.6469318018$1715918366$gmane$org@neverwas.me> References: <7hseysqbu1.fsf@thibaut.dev> <8734ql9ppd.fsf@neverwas.me> <87seyj6wgh.fsf@neverwas.me> 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="32577"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org, 70840@debbugs.gnu.org To: Thibaut Meyer Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri May 17 05:59:18 2024 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 1s7okX-0008HR-TA for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 17 May 2024 05:59:18 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7okH-0001uA-K4; Thu, 16 May 2024 23:59:01 -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 1s7okG-0001u1-1s for bug-gnu-emacs@gnu.org; Thu, 16 May 2024 23:59:00 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1s7okF-0004r6-PI for bug-gnu-emacs@gnu.org; Thu, 16 May 2024 23:58:59 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1s7okI-0000Dn-6e for bug-gnu-emacs@gnu.org; Thu, 16 May 2024 23:59: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: Fri, 17 May 2024 03:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 70840 X-GNU-PR-Package: emacs Original-Received: via spool by 70840-submit@debbugs.gnu.org id=B70840.1715918290840 (code B ref 70840); Fri, 17 May 2024 03:59:02 +0000 Original-Received: (at 70840) by debbugs.gnu.org; 17 May 2024 03:58:10 +0000 Original-Received: from localhost ([127.0.0.1]:52737 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s7ojR-0000DU-6P for submit@debbugs.gnu.org; Thu, 16 May 2024 23:58:10 -0400 Original-Received: from mail-108-mta131.mxroute.com ([136.175.108.131]:42045) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s7ojL-0000DO-Km for 70840@debbugs.gnu.org; Thu, 16 May 2024 23:58:05 -0400 Original-Received: from filter006.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta131.mxroute.com (ZoneMTA) with ESMTPSA id 18f84b30d740008ca2.001 for <70840@debbugs.gnu.org> (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 17 May 2024 03:57:58 +0000 X-Zone-Loop: e931b5c3ab78f00fb20f036709c3ffa676947480b01f X-Originating-IP: [136.175.111.2] 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:Date:References:In-Reply-To: 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=lUFUH3RudT0ExTw+ZgHZfmHTzUIqwlnaR17yZA1QH/A=; b=Cx0MohmZXDF1pM70wfCJxOWz9D zy9anfKJ1SYLbe/74Suu/phyUeSdVSwEtRg5H1IMLmywEpksRqJMz1HWCZ59kBU1YK+5pjwHf5B8v p2THx8FcKpOD/+TijZLIXWjPUXwKG0aBckn7La0o7vPNqT6EZvrwrboEX4+yfpJPxUJByUNSpzWKu TpBKeqcu/+YRvK//1kTM/tiBffMmZYzEm9S9GJlI0EcsMCeJw3tKvnOmSJ31FEzHLfmGQBh/Dsq+V aDMXfAAhPe0PkINB8YvTQjgNxTxd2LKk1oH+po8Fkx0iarjQ8owB3Rg0qcLkG3OepvXVvcYYhxu6o w3CzRSWQ==; In-Reply-To: <87seyj6wgh.fsf@neverwas.me> (J. P.'s message of "Wed, 15 May 2024 06:22:54 -0700") X-Authenticated-Id: 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-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:285215 Archived-At: --=-=-= Content-Type: text/plain "J.P." writes: > "J.P." writes: > >> There may well be other issues here I've not yet considered, so if you >> can think of any, please share. Also, if you're up for taking this on >> (not necessarily in the way I've described), please feel free to send a >> patch. The same goes for anyone else out there. I can definitely help >> with the leg work and test coverage if that makes things easier. >> Otherwise, I may not be able to get to this in time for the next release >> (not that there's any rush). > > I've gone ahead with a provisional patch (attached) that incorporates > the points raised so far. Anyone interested, please take a look. After thinking a bit more on this, I've flip-flopped entirely on the notion of running `erc-part-hook' in `erc-kill-channel' and inhibiting it in `erc-server-PART' with a would-be null buffer argument. Basically, I've come to believe the current faulty behavior has been around too long to justify such a change in the name of fixing a bug that's only tangentially related. Instead, I think we should introduce a flag that `erc-kill-channel-hook' members can use to detect when `erc-server-PART' is killing a buffer on behalf of the option `erc-kill-buffer-on-part'. Updated patch attached. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0000-v1-v2.diff >From d4d766438cf2f059af20e695dd20a65dcf646c2e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 16 May 2024 20:33:06 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): [5.6] Don't kill server buffer with erc-kill-buffer-on-part etc/ERC-NEWS | 8 ++ lisp/erc/erc-backend.el | 9 +- lisp/erc/erc-log.el | 2 +- lisp/erc/erc.el | 32 ++++--- .../erc/erc-scenarios-base-kill-on-part.el | 95 +++++++++++++++++++ 5 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-kill-on-part.el Interdiff: diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 9d5a26595be..9c536636a04 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -648,15 +648,13 @@ release lacks a similar solution for detecting "joinedness" directly, but users can turn to 'xor'-ing 'erc-default-target' and 'erc-target' as a makeshift kludge. -*** The function 'erc-kill-channel' may run the hook 'erc-part-hook'. -Previously, when a user killed a channel buffer, 'erc-part-hook' would -run in the response handler upon receipt of the corresponding 'PART' -response, meaning hook members would receive a nil channel-buffer -argument. ERC now runs this hook immediately when a user kills a -channel, just before sending the 'PART' command to the server. Those -disrupted by this change should see the definition of 'erc-part-hook' -for a temporary escape hatch. Also, for clarity, the function -'erc-kill-channel' has been renamed 'erc-part-channel-on-kill'. +*** Killing on behalf of 'erc-kill-buffer-on-part' made detectable. +Members of 'erc-kill-channel-hook' can use the variable +'erc-killing-buffer-on-part-p' to detect when 'erc-server-PART' is +killing a buffer on account of the option 'erc-kill-buffer-on-part' +being non-nil. Also, for clarity, the function 'erc-kill-channel', +which normally emits a 'PART' when channel buffers are killed, has +been renamed to 'erc-part-channel-on-kill'. *** Channel-mode handling has become stricter and more predictable. ERC has always processed channel modes using "standardized" letters diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 7e8e597da46..7d6a3499d06 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1891,9 +1891,7 @@ erc--server-determine-join-display-context 'PART ?n nick ?u login ?h host ?c chnl ?r (or reason "")) (when (string= nick (erc-current-nick)) - (defvar erc--run-part-hook-with-nil-buffer-p) - (when (or buffer erc--run-part-hook-with-nil-buffer-p) - (run-hook-with-args 'erc-part-hook buffer)) + (run-hook-with-args 'erc-part-hook buffer) (erc-with-buffer (buffer) (erc-remove-channel-users)) @@ -1902,8 +1900,8 @@ erc--server-determine-join-display-context (erc-update-mode-line buffer) (defvar erc-kill-buffer-on-part) (when (and erc-kill-buffer-on-part buffer) - (defvar erc--inhibit-part-channel-on-kill-p) - (let ((erc--inhibit-part-channel-on-kill-p t)) + (defvar erc-killing-buffer-on-part-p) + (let ((erc-killing-buffer-on-part-p t)) (kill-buffer buffer))))))) (define-erc-response-handler (PING) diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index f0bd1b45e7c..019ac6c1612 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -290,10 +290,7 @@ erc-save-query-buffers (defun erc-conditional-save-buffer (buffer) "Save Query BUFFER if `erc-save-queries-on-quit' is t." - (when (and erc-save-buffer-on-part - ;; Don't run this from `erc-part-channel-on-kill' because - ;; `erc-save-buffer-in-logs' aready has it covered. - (not erc--inhibit-part-channel-on-kill-p)) + (when (and buffer erc-save-buffer-on-part) (erc-save-buffer-in-logs buffer))) (defun erc-conditional-save-queries (process) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a1c94288e8d..c174ca4b30e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -470,22 +470,21 @@ erc-quit-hook (defcustom erc-part-hook nil "Hook run when processing a PART message directed at our nick. -Called in the server buffer with one argument: the BUFFER being parted. -Also runs via `erc-part-channel-on-kill' on `erc-kill-channel-hook' if -killing BUFFER initiated the \"PART\". Note that beginning with ERC -5.6, this hook doesn't run upon receiving a \"PART\" from the server if -BUFFER has already been killed. See code near this option's definition -for a possible escape hatch." +Called in the server buffer with a single argument: the channel buffer +being parted. For historical reasons, the buffer argument may be nil if +it's been killed or otherwise no longer exists. This typically happens +when the \"PART\" response being handled comes by way of a channel +buffer being killed, which, by default, tells `erc-part-channel-on-kill' +to emit a \"PART\". Users needing to operate on a parted channel buffer +before it's killed in this fashion should use `erc-kill-channel-hook' +and condition their code on `erc-killing-buffer-on-part-p' being nil." :group 'erc-hooks :type 'hook) -(defvar erc--run-part-hook-with-nil-buffer-p nil - "When non-nil, allow running `erc-part-hook' with a nil buffer argument. -Moreover, forgo running the hook before sending a \"PART\" when the user -kills a channel buffer. This compat-oriented escape hatch exists for -third-party code that expects to run unconditionally in the default -response handler `erc-server-PART' when ERC receives a self-directed -\"PART\" from the server.") +(defvar erc-killing-buffer-on-part-p nil + "Non-nil when killing a target buffer while handling a \"PART\" response. +Useful for preventing the redundant execution of code designed to run +once when parting a channel.") (defcustom erc-kick-hook nil "Hook run when processing a KICK message directed at our nick. @@ -1124,8 +1123,7 @@ erc-last-saved-position (defcustom erc-kill-buffer-on-part nil "Kill the channel buffer on PART. -This variable should probably stay nil, as ERC can reuse buffers if -you rejoin them later." +Nil by default because ERC can reuse buffers later re-joined." :group 'erc-quit-and-part :type 'boolean) @@ -9669,18 +9667,12 @@ erc-kill-server (setq erc-server-quitting t) (erc-server-send (format "QUIT :%s" (funcall erc-quit-reason nil))))) -(defvar erc--inhibit-part-channel-on-kill-p nil) (define-obsolete-function-alias 'erc-kill-channel #'erc-part-channel-on-kill "30.1") (defun erc-part-channel-on-kill () - "Run `erc-part-hook' and send a \"PART\" when killing a channel buffer." - (when (and (erc-server-process-alive) - (not erc--inhibit-part-channel-on-kill-p)) - (unless erc--run-part-hook-with-nil-buffer-p - (let ((buffer (current-buffer)) - (erc--inhibit-part-channel-on-kill-p t)) - (erc-with-server-buffer - (run-hook-with-args 'erc-part-hook buffer)))) + "Send a \"PART\" when killing a channel buffer." + (when (and (not erc-killing-buffer-on-part-p) + (erc-server-process-alive)) (let ((tgt (erc-default-target))) (if tgt (erc-server-send (format "PART %s :%s" tgt diff --git a/test/lisp/erc/erc-scenarios-base-kill-on-part.el b/test/lisp/erc/erc-scenarios-base-kill-on-part.el index 109cf27b01a..0ca0b1ae054 100644 --- a/test/lisp/erc/erc-scenarios-base-kill-on-part.el +++ b/test/lisp/erc/erc-scenarios-base-kill-on-part.el @@ -25,7 +25,9 @@ (require 'erc-scenarios-common))) ;; Assert channel buffer is killed when `erc-kill-buffer-on-part' is -;; enabled and a user issues a /part. +;; enabled and a user issues a /part. Also assert that code in +;; `erc-kill-channel-hook' can detect when `erc-response-PART' is +;; killing a buffer on behalf of that option. (ert-deftest erc-scenarios-base-kill-on-part--enabled () :tags '(:expensive-test) (should-not erc-kill-buffer-on-part) @@ -38,6 +40,9 @@ erc-scenarios-base-kill-on-part--enabled (erc-kill-buffer-on-part t) (calls nil) (erc-part-hook (lambda (b) (push (buffer-name b) calls))) + (erc-kill-channel-hook + (cons (lambda () (push erc-killing-buffer-on-part-p calls)) + erc-kill-channel-hook)) (expect (erc-d-t-make-expecter))) (ert-info ("Connect to foonet") @@ -53,7 +58,7 @@ erc-scenarios-base-kill-on-part--enabled (erc-scenarios-common-say "/part")) (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) - (should (equal calls '("#chan"))))) + (should (equal calls '(t "#chan"))))) ;; When `erc-kill-buffer-on-part' is non-nil, and the parted buffer has ;; already been killed, don't kill the server buffer. Bug#70840 @@ -67,10 +72,8 @@ erc-scenarios-base-kill-on-part--enabled/killed (dumb-server (erc-d-run "localhost" t 'foonet)) (port (process-contact dumb-server :service)) (erc-kill-buffer-on-part t) - (killingp nil) (calls nil) - (erc-part-hook (lambda (b) (push (cons (buffer-name b) killingp) - calls))) + (erc-part-hook (lambda (b) (push b calls))) (expect (erc-d-t-make-expecter))) (ert-info ("Connect to foonet") @@ -83,50 +86,10 @@ erc-scenarios-base-kill-on-part--enabled/killed (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) (funcall expect 10 " bob: Whilst I can shake") - ;; There's a race here because the response handler may run - ;; before `killingp' is nil, but at least false negatives aren't - ;; possible. Shadowing `erc-server-send-queue' temporarily - ;; would fix it, but that's too leaky for this style of test. - (setq killingp 'kill) - (kill-buffer) - (setq killingp nil)) + (kill-buffer)) (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) - (should (equal calls '(("#chan" . kill)))) + (erc-d-t-wait-for 10 (equal calls '(nil))) (erc-d-t-ensure-for 0.1 (get-buffer "foonet")))) -(ert-deftest erc-scenarios-base-kill-on-part--enabled/killed/compat () - :tags '(:expensive-test) - (should-not erc-kill-buffer-on-part) - - (erc-scenarios-common-with-cleanup - ((erc-scenarios-common-dialog "base/reuse-buffers/channel") - (erc-server-flood-penalty 0.1) - (dumb-server (erc-d-run "localhost" t 'foonet)) - (port (process-contact dumb-server :service)) - (erc-kill-buffer-on-part t) - (erc--run-part-hook-with-nil-buffer-p t) ; option under test - (killingp nil) - (calls nil) - (erc-part-hook (lambda (b) (push (cons b killingp) calls))) - (expect (erc-d-t-make-expecter))) - - (ert-info ("Connect to foonet") - (with-current-buffer (erc :server "127.0.0.1" - :port port - :nick "tester" - :password "foonet:changeme" - :full-name "tester") - (funcall expect 10 "This server is in debug mode"))) - - (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) - (funcall expect 10 " bob: Whilst I can shake") - (setq killingp 'kill) - (kill-buffer) - (setq killingp nil)) - - (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) - (erc-d-t-wait-for 20 (equal calls '((nil . nil)))) - (should (get-buffer "foonet")))) - ;;; erc-scenarios-base-kill-on-part.el ends here -- 2.45.0 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Don-t-kill-server-buffer-with-erc-kill-buffer-on.patch >From d4d766438cf2f059af20e695dd20a65dcf646c2e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 14 May 2024 21:09:55 -0700 Subject: [PATCH 1/1] [5.6] Don't kill server buffer with erc-kill-buffer-on-part * etc/ERC-NEWS: Mention flag variable `erc-killing-buffer-on-part-p' and renaming of function `erc-kill-channel'. * lisp/erc/erc-backend.el (erc-server-PART): Only kill a buffer on behalf of `erc-kill-buffer-on-part' when the buffer hasn't already been killed, and bind `erc-killing-buffer-on-part-p' to t when doing so. * lisp/erc/erc-log.el (erc-conditional-save-buffer): Don't save logs when the buffer parameter is nil because that causes the server buffer to be saved out. * lisp/erc/erc.el (erc-part-hook): Redo doc string. (erc-killing-buffer-on-part-p): New variable, a flag to prevent redundant execution of `erc-kill-channel-hook' members concerned with parted channels. (erc-kill-buffer-on-part): Tweak doc string. (erc-kill-channel-hook): Use new name for `erc-kill-channel'. (erc-kill-channel, erc-part-channel-on-kill): Rename former to latter, and inhibit execution when `erc-killing-buffer-on-part-p' is non-nil. * test/lisp/erc/erc-scenarios-base-kill-on-part.el: New file. (Bug#70840) --- etc/ERC-NEWS | 8 ++ lisp/erc/erc-backend.el | 9 +- lisp/erc/erc-log.el | 2 +- lisp/erc/erc.el | 32 ++++--- .../erc/erc-scenarios-base-kill-on-part.el | 95 +++++++++++++++++++ 5 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-kill-on-part.el diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index b66ea6a7a02..9c536636a04 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -648,6 +648,14 @@ release lacks a similar solution for detecting "joinedness" directly, but users can turn to 'xor'-ing 'erc-default-target' and 'erc-target' as a makeshift kludge. +*** Killing on behalf of 'erc-kill-buffer-on-part' made detectable. +Members of 'erc-kill-channel-hook' can use the variable +'erc-killing-buffer-on-part-p' to detect when 'erc-server-PART' is +killing a buffer on account of the option 'erc-kill-buffer-on-part' +being non-nil. Also, for clarity, the function 'erc-kill-channel', +which normally emits a 'PART' when channel buffers are killed, has +been renamed to 'erc-part-channel-on-kill'. + *** Channel-mode handling has become stricter and more predictable. ERC has always processed channel modes using "standardized" letters and popular status prefixes. Starting with this release, ERC will diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index ab419d2b018..7d6a3499d06 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1883,6 +1883,9 @@ erc--server-determine-join-display-context (buffer (erc-get-buffer chnl proc))) (pcase-let ((`(,nick ,login ,host) (erc-parse-user (erc-response.sender parsed)))) + ;; When `buffer' is nil, `erc-remove-channel-member', + ;; `erc-remove-channel-users', and `erc-part-hook', don't run or + ;; do nothing, and the message is printed in the server buffer. (erc-remove-channel-member buffer nick) (erc-display-message parsed 'notice buffer 'PART ?n nick ?u login @@ -1896,8 +1899,10 @@ erc--server-determine-join-display-context (erc-delete-default-channel chnl buffer)) (erc-update-mode-line buffer) (defvar erc-kill-buffer-on-part) - (when erc-kill-buffer-on-part - (kill-buffer buffer)))))) + (when (and erc-kill-buffer-on-part buffer) + (defvar erc-killing-buffer-on-part-p) + (let ((erc-killing-buffer-on-part-p t)) + (kill-buffer buffer))))))) (define-erc-response-handler (PING) "Handle ping messages." nil diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index d5c56bcc2b3..019ac6c1612 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -290,7 +290,7 @@ erc-save-query-buffers (defun erc-conditional-save-buffer (buffer) "Save Query BUFFER if `erc-save-queries-on-quit' is t." - (when erc-save-buffer-on-part + (when (and buffer erc-save-buffer-on-part) (erc-save-buffer-in-logs buffer))) (defun erc-conditional-save-queries (process) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index c92fd42322a..c174ca4b30e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -470,13 +470,22 @@ erc-quit-hook (defcustom erc-part-hook nil "Hook run when processing a PART message directed at our nick. - -The hook receives one argument, the current BUFFER. -See also `erc-server-QUIT-functions', `erc-quit-hook' and -`erc-disconnected-hook'." +Called in the server buffer with a single argument: the channel buffer +being parted. For historical reasons, the buffer argument may be nil if +it's been killed or otherwise no longer exists. This typically happens +when the \"PART\" response being handled comes by way of a channel +buffer being killed, which, by default, tells `erc-part-channel-on-kill' +to emit a \"PART\". Users needing to operate on a parted channel buffer +before it's killed in this fashion should use `erc-kill-channel-hook' +and condition their code on `erc-killing-buffer-on-part-p' being nil." :group 'erc-hooks :type 'hook) +(defvar erc-killing-buffer-on-part-p nil + "Non-nil when killing a target buffer while handling a \"PART\" response. +Useful for preventing the redundant execution of code designed to run +once when parting a channel.") + (defcustom erc-kick-hook nil "Hook run when processing a KICK message directed at our nick. @@ -1114,8 +1123,7 @@ erc-last-saved-position (defcustom erc-kill-buffer-on-part nil "Kill the channel buffer on PART. -This variable should probably stay nil, as ERC can reuse buffers if -you rejoin them later." +Nil by default because ERC can reuse buffers later re-joined." :group 'erc-quit-and-part :type 'boolean) @@ -9598,7 +9606,7 @@ erc-kill-server-hook :type 'hook) (defcustom erc-kill-channel-hook - '(erc-kill-channel + '(erc-part-channel-on-kill erc-networks-shrink-ids-and-buffer-names erc-networks-rename-surviving-target-buffer) "Invoked whenever a channel-buffer is killed via `kill-buffer'." @@ -9659,10 +9667,12 @@ erc-kill-server (setq erc-server-quitting t) (erc-server-send (format "QUIT :%s" (funcall erc-quit-reason nil))))) -(defun erc-kill-channel () - "Sends a PART command to the server when the channel buffer is killed. -This function should be on `erc-kill-channel-hook'." - (when (erc-server-process-alive) +(define-obsolete-function-alias 'erc-kill-channel #'erc-part-channel-on-kill + "30.1") +(defun erc-part-channel-on-kill () + "Send a \"PART\" when killing a channel buffer." + (when (and (not erc-killing-buffer-on-part-p) + (erc-server-process-alive)) (let ((tgt (erc-default-target))) (if tgt (erc-server-send (format "PART %s :%s" tgt diff --git a/test/lisp/erc/erc-scenarios-base-kill-on-part.el b/test/lisp/erc/erc-scenarios-base-kill-on-part.el new file mode 100644 index 00000000000..0ca0b1ae054 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-kill-on-part.el @@ -0,0 +1,95 @@ +;;; erc-scenarios-base-kill-on-part.el --- killing buffers on part -*- lexical-binding: t -*- + +;; Copyright (C) 2024 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +;; Assert channel buffer is killed when `erc-kill-buffer-on-part' is +;; enabled and a user issues a /part. Also assert that code in +;; `erc-kill-channel-hook' can detect when `erc-response-PART' is +;; killing a buffer on behalf of that option. +(ert-deftest erc-scenarios-base-kill-on-part--enabled () + :tags '(:expensive-test) + (should-not erc-kill-buffer-on-part) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reuse-buffers/channel") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'foonet)) + (port (process-contact dumb-server :service)) + (erc-kill-buffer-on-part t) + (calls nil) + (erc-part-hook (lambda (b) (push (buffer-name b) calls))) + (erc-kill-channel-hook + (cons (lambda () (push erc-killing-buffer-on-part-p calls)) + erc-kill-channel-hook)) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "foonet:changeme" + :full-name "tester") + (funcall expect 10 "This server is in debug mode"))) + + (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) + (funcall expect 10 " bob: Whilst I can shake") + (erc-scenarios-common-say "/part")) + + (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) + (should (equal calls '(t "#chan"))))) + +;; When `erc-kill-buffer-on-part' is non-nil, and the parted buffer has +;; already been killed, don't kill the server buffer. Bug#70840 +(ert-deftest erc-scenarios-base-kill-on-part--enabled/killed () + :tags '(:expensive-test) + (should-not erc-kill-buffer-on-part) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reuse-buffers/channel") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'foonet)) + (port (process-contact dumb-server :service)) + (erc-kill-buffer-on-part t) + (calls nil) + (erc-part-hook (lambda (b) (push b calls))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "foonet:changeme" + :full-name "tester") + (funcall expect 10 "This server is in debug mode"))) + + (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) + (funcall expect 10 " bob: Whilst I can shake") + (kill-buffer)) + + (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) + (erc-d-t-wait-for 10 (equal calls '(nil))) + (erc-d-t-ensure-for 0.1 (get-buffer "foonet")))) + +;;; erc-scenarios-base-kill-on-part.el ends here -- 2.45.0 --=-=-=--