emacs-diffs
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]