[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 5f84213c980 6/8: Retain client's own user in erc-server-users
From: |
F. Jason Park |
Subject: |
master 5f84213c980 6/8: Retain client's own user in erc-server-users |
Date: |
Mon, 27 May 2024 19:52:40 -0400 (EDT) |
branch: master
commit 5f84213c9802181b4d800615915e3c8dded7b94f
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>
Retain client's own user in erc-server-users
* lisp/erc/erc-backend.el (erc-server-KICK, erc-server-PART): Use new
function `erc--remove-channel-user-but' instead of
`erc-remove-channel-users'. In `erc-server-KICK', remove sender's
channel membership data after displaying the message so that nicks are
buttonized. Return nil. In `erc-server-PART', don't run
`erc-remove-channel-member' when the client itself has parted.
* lisp/erc/erc-common.el (erc--remove-user-from-targets): New
function.
* lisp/erc/erc.el (erc-remove-server-user): Redo doc string.
(erc--forget-server-user-function): New variable.
(erc--forget-server-user): New function.
(erc--forget-server-user-ignoring-queries): New function, the default
value of `erc--forget-server-user-function'.
(erc-remove-channel-user): Defer to `erc--forget-server-user-function'
to do the actual removal.
(erc-remove-user): Defer to `erc--remove-user-from-targets'.
(erc-remove-channel-users): Redo doc
(erc--remove-channel-users-but): New function. The only use case thus
far is for protecting the client's own `erc-server-users' entry from
removal when draining `erc-channel-members' tables after the client
leaves a target buffer or quits.
(erc-kill-buffer-function): Don't remove own user from
`erc-server-users'.
* test/lisp/erc/erc-scenarios-base-renick.el
(erc-scenarios-base-renick-queries-solo): Assert own client parting
its only channel doesn't remove own user from server. Also assert
that another user parting their only channel removes them from all
queries. (Bug#70928)
---
lisp/erc/erc-backend.el | 22 ++++----
lisp/erc/erc-common.el | 12 +++++
lisp/erc/erc.el | 80 +++++++++++++++++-------------
test/lisp/erc/erc-scenarios-base-renick.el | 24 ++++++++-
4 files changed, 93 insertions(+), 45 deletions(-)
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index a26cdd50dd7..a1f84ee5165 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -124,6 +124,7 @@
(declare-function erc--open-target "erc" (target))
(declare-function erc--parse-nuh "erc" (string))
(declare-function erc--query-list "erc" ())
+(declare-function erc--remove-channel-users-but "erc" (nick))
(declare-function erc--target-from-string "erc" (string))
(declare-function erc--update-modes "erc" (raw-args))
(declare-function erc-active-buffer "erc" nil)
@@ -1797,7 +1798,6 @@ add things to `%s' instead."
(buffer (erc-get-buffer ch proc)))
(pcase-let ((`(,nick ,login ,host)
(erc-parse-user (erc-response.sender parsed))))
- (erc-remove-channel-member buffer tgt)
(cond
((string= tgt (erc-current-nick))
(erc-display-message
@@ -1806,17 +1806,20 @@ add things to `%s' instead."
(run-hook-with-args 'erc-kick-hook buffer)
(erc-with-buffer
(buffer)
- (erc-remove-channel-users))
+ (erc--remove-channel-users-but tgt))
(with-suppressed-warnings ((obsolete erc-delete-default-channel))
(erc-delete-default-channel ch buffer))
(erc-update-mode-line buffer))
((string= nick (erc-current-nick))
(erc-display-message
parsed 'notice buffer
- 'KICK-by-you ?k tgt ?c ch ?r reason))
+ 'KICK-by-you ?k tgt ?c ch ?r reason)
+ (erc-remove-channel-member buffer tgt))
(t (erc-display-message
- parsed 'notice buffer
- 'KICK ?k tgt ?n nick ?u login ?h host ?c ch ?r reason))))))
+ parsed 'notice buffer
+ 'KICK ?k tgt ?n nick ?u login ?h host ?c ch ?r reason)
+ (erc-remove-channel-member buffer tgt)))))
+ nil)
(define-erc-response-handler (MODE)
"Handle server mode changes." nil
@@ -1926,15 +1929,15 @@ Return a list of buffers in which to announce the
change."
;; When `buffer' is nil, `erc-remove-channel-member' and
;; `erc-remove-channel-users' do almost nothing, and the message
;; is displayed in the server buffer.
- (erc-remove-channel-member buffer nick)
(erc-display-message parsed 'notice buffer
'PART ?n nick ?u login
?h host ?c chnl ?r (or reason ""))
- (when (string= nick (erc-current-nick))
+ (cond
+ ((string= nick (erc-current-nick))
(run-hook-with-args 'erc-part-hook buffer)
(erc-with-buffer
(buffer)
- (erc-remove-channel-users))
+ (erc--remove-channel-users-but nick))
(with-suppressed-warnings ((obsolete erc-delete-default-channel))
(erc-delete-default-channel chnl buffer))
(erc-update-mode-line buffer)
@@ -1942,7 +1945,8 @@ Return a list of buffers in which to announce the change."
(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))))))
+ (kill-buffer buffer))))
+ (t (erc-remove-channel-member buffer nick)))))
nil)
(define-erc-response-handler (PING)
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index c01ee6546cb..4ba7990ab98 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -560,6 +560,18 @@ Use the CASEMAPPING ISUPPORT parameter to determine the
style."
(defun erc--get-server-user (nick)
(erc-get-server-user nick))
+(define-inline erc--remove-user-from-targets (downcased-nick buffers)
+ "Remove DOWNCASED-NICK from `erc-channel-members' in BUFFERS."
+ (inline-quote
+ (progn
+ (defvar erc-channel-members-changed-hook)
+ (dolist (buffer ,buffers)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (remhash ,downcased-nick erc-channel-users)
+ (when erc-channel-members-changed-hook
+ (run-hooks 'erc-channel-members-changed-hook))))))))
+
(defmacro erc--with-dependent-type-match (type &rest features)
"Massage Custom :type TYPE with :match function that pre-loads FEATURES."
`(backquote-list* ',(car type)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 5be557dee4a..565f18163df 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -581,13 +581,7 @@ Ensure targets with an entry in `erc-server-users' are
present in
erc-server-process))
(defun erc-remove-server-user (nick)
- "This function is for internal use only.
-
-Removes the user with nickname NICK from the `erc-server-users'
-hash table. This user is not removed from the
-`erc-channel-users' lists of other buffers.
-
-See also: `erc-remove-user'."
+ "Remove NICK from the session's `erc-server-users' table."
(erc-with-server-buffer
(remhash (erc-downcase nick) erc-server-users)))
@@ -610,15 +604,29 @@ other buffers are also changed."
(puthash (erc-downcase new-nick) cdata
erc-channel-users)))))))
-(defun erc-remove-channel-user (nick)
- "This function is for internal use only.
-
-Removes the user with nickname NICK from the `erc-channel-users'
-list for this channel. If this user is not in the
-`erc-channel-users' list of any other buffers, the user is also
-removed from the server's `erc-server-users' list.
+(defvar erc--forget-server-user-function
+ #'erc--forget-server-user-ignoring-queries
+ "Function to conditionally remove a user from `erc-server-users'.
+Called with a nick and its `erc-server-user' object.")
+
+(defun erc--forget-server-user (nick user)
+ "Remove NICK's USER from server table if they're not in any target buffers."
+ (unless (erc-server-user-buffers user)
+ (erc-remove-server-user nick)))
+
+(defun erc--forget-server-user-ignoring-queries (nick user)
+ "Remove NICK's USER from `erc-server-users' if they've parted all channels."
+ (let ((buffers (erc-server-user-buffers user)))
+ (when (or (null buffers)
+ (and (not erc--decouple-query-and-channel-membership-p)
+ (cl-every #'erc-query-buffer-p buffers)))
+ (when buffers
+ (erc--remove-user-from-targets (erc-downcase nick) buffers))
+ (erc-remove-server-user nick))))
-See also: `erc-remove-server-user' and `erc-remove-user'."
+(defun erc-remove-channel-user (nick)
+ "Remove NICK from the current target buffer's `erc-channel-members'.
+If this was their only target, also remove them from `erc-server-users'."
(let ((channel-data (erc-get-channel-user nick)))
(when channel-data
(let ((user (car channel-data)))
@@ -626,32 +634,19 @@ See also: `erc-remove-server-user' and `erc-remove-user'."
(delq (current-buffer)
(erc-server-user-buffers user)))
(remhash (erc-downcase nick) erc-channel-users)
- (if (null (erc-server-user-buffers user))
- (erc-remove-server-user nick))))))
+ (funcall erc--forget-server-user-function nick user)))))
(defun erc-remove-user (nick)
- "This function is for internal use only.
-
-Removes the user with nickname NICK from the `erc-server-users'
-list as well as from all `erc-channel-users' lists.
-
-See also: `erc-remove-server-user' and
-`erc-remove-channel-user'."
+ "Remove NICK from the server and all relevant channels tables."
(let ((user (erc-get-server-user nick)))
(when user
- (let ((buffers (erc-server-user-buffers user)))
- (dolist (buf buffers)
- (if (buffer-live-p buf)
- (with-current-buffer buf
- (remhash (erc-downcase nick) erc-channel-users)
- (run-hooks 'erc-channel-members-changed-hook)))))
+ (erc--remove-user-from-targets (erc-downcase nick)
+ (erc-server-user-buffers user))
(erc-remove-server-user nick))))
(defun erc-remove-channel-users ()
- "This function is for internal use only.
-
-Removes all users in the current channel. This is called by
-`erc-server-PART' and `erc-server-QUIT'."
+ "Drain current buffer's `erc-channel-members' table.
+Also remove members from the server table if this was their only buffer."
(when (erc--target-channel-p erc--target)
(setf (erc--target-channel-joined-p erc--target) nil))
(when (and erc-server-connected
@@ -662,6 +657,19 @@ Removes all users in the current channel. This is called
by
erc-channel-users)
(clrhash erc-channel-users)))
+(defun erc--remove-channel-users-but (nick)
+ "Drain channel users and remove from server, sparing NICK."
+ (when-let ((users (erc-with-server-buffer erc-server-users))
+ (my-user (gethash (erc-downcase nick) users))
+ (original-function erc--forget-server-user-function)
+ (erc--forget-server-user-function
+ (if erc--decouple-query-and-channel-membership-p
+ erc--forget-server-user-function
+ (lambda (nick user)
+ (unless (eq user my-user)
+ (funcall original-function nick user))))))
+ (erc-remove-channel-users)))
+
(defmacro erc--define-channel-user-status-compat-getter (name c d)
"Define a gv getter for historical `erc-channel-user' status slot NAME.
Expect NAME to be a string, C to be its traditionally associated
@@ -9691,7 +9699,9 @@ one of the following hooks:
`erc-kill-channel-hook' if a channel buffer was killed,
or `erc-kill-buffer-hook' if any other buffer."
(when (eq major-mode 'erc-mode)
- (erc-remove-channel-users)
+ (when-let ((erc--target)
+ (nick (erc-current-nick)))
+ (erc--remove-channel-users-but nick))
(cond
((eq (erc-server-buffer) (current-buffer))
(run-hooks 'erc-kill-server-hook))
diff --git a/test/lisp/erc/erc-scenarios-base-renick.el
b/test/lisp/erc/erc-scenarios-base-renick.el
index 19cb1ecde1d..c96b0353e55 100644
--- a/test/lisp/erc/erc-scenarios-base-renick.el
+++ b/test/lisp/erc/erc-scenarios-base-renick.el
@@ -185,21 +185,43 @@
(with-current-buffer (erc-d-t-wait-for 10 (get-buffer "Lal"))
(funcall expect 10 "<Lal> hello")
(erc-scenarios-common-say "hi")
+ (should-not (erc-get-channel-member "tester"))
(funcall expect 10 "is now known as Linguo")
;; No duplicate message.
(funcall expect -0.1 "is now known as Linguo")
;; No duplicate buffer.
(erc-d-t-wait-for 1 (equal (buffer-name) "Linguo"))
(should-not (get-buffer "Lal"))
+ ;; Channel member has been updated
+ (should-not (erc-get-channel-member "Lal"))
+ (should-not (erc-get-server-user "Lal"))
+ (should (erc-get-channel-member "Linguo"))
(erc-scenarios-common-say "howdy Linguo")))
(with-current-buffer "#foo"
(funcall expect 10 "is now known as Linguo")
(funcall expect -0.1 "is now known as Linguo")
+ (funcall expect 10 "has left"))
+
+ ;; User parting a common channel removes them from queries.
+ (with-current-buffer "Linguo"
+ (should-not (erc-get-channel-member "tester"))
+ (erc-d-t-wait-for 10 (null (erc-get-channel-member "Linguo")))
+ (should-not (erc-get-server-user "Linguo")))
+
+ ;; Leaving the client's only channel doesn't remove its user data
+ ;; from the server table (see below, after "get along ...").
+ (with-current-buffer "#foo"
(erc-scenarios-common-say "/part"))
+ ;; Server and "channel" user are *not* (re)created upon receiving
+ ;; a direct message for a user we already have an open query with
+ ;; but with whom we no longer share a channel.
(with-current-buffer "Linguo"
- (funcall expect 10 "get along"))))
+ (funcall expect 10 "get along")
+ (should-not (erc-get-channel-member "Linguo"))
+ (should-not (erc-get-channel-member "tester"))
+ (should (erc-get-server-user "tester")))))
;; Someone you have a query with disconnects and reconnects under a
;; new nick (perhaps due to their client appending a backtick or
- master updated (1a9128e0208 -> 7aa91b299e9), F. Jason Park, 2024/05/27
- master 8c54a79ec10 1/8: Return nil from more ERC response handlers, F. Jason Park, 2024/05/27
- master ab78cbfabc8 3/8: Mention if an ERC module is local in its doc string, F. Jason Park, 2024/05/27
- master 75aefe65148 4/8: Reuse old query buffers for reassumed nicks in ERC, F. Jason Park, 2024/05/27
- master 6888bbbe832 7/8: Add ERC module querypoll as monitor placeholder, F. Jason Park, 2024/05/27
- master 5f84213c980 6/8: Retain client's own user in erc-server-users,
F. Jason Park <=
- master 1b633ea59ad 2/8: Delete original speedbar frame in erc-nickbar-mode, F. Jason Park, 2024/05/27
- master 04477cf97be 5/8: Tether query rolls to channel membership in ERC, F. Jason Park, 2024/05/27
- master 7aa91b299e9 8/8: Fix date-stamp regression in erc-fill-wrap, F. Jason Park, 2024/05/27