branch: elpa/jabber
commit c8ab7cd903282892f466576efa3464057b076b36
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    buffer: Separate chat registry
---
 lisp/jabber-buffer-registry.el  | 69 +++++++++++++++++++++++++++++++++++++++
 lisp/jabber-chat.el             |  5 +--
 lisp/jabber-chatbuffer.el       | 50 +++--------------------------
 lisp/jabber-muc.el              |  9 +++---
 tests/jabber-test-chatbuffer.el | 71 ++++++++++++++++++++---------------------
 5 files changed, 117 insertions(+), 87 deletions(-)

diff --git a/lisp/jabber-buffer-registry.el b/lisp/jabber-buffer-registry.el
new file mode 100644
index 0000000000..57c6e3c19e
--- /dev/null
+++ b/lisp/jabber-buffer-registry.el
@@ -0,0 +1,69 @@
+;;; jabber-buffer-registry.el --- Chat buffer lookup registry  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2026  Thanos Apollo
+
+;; Maintainer: Thanos Apollo <[email protected]>
+
+;; This file is a part of jabber.el.
+
+;; This program 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 2 of the License, or
+;; (at your option) any later version.
+
+;; This program 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 this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+;;; Commentary:
+
+;; Provides lookup by chat kind without depending on chat rendering modules.
+
+;;; Code:
+
+(defvar jabber-buffer-registry--buffers (make-hash-table :test #'equal)
+  "Hash table mapping chat kinds and peer keys to live buffers.")
+
+(defvar-local jabber-buffer-registry--keys nil
+  "Registry keys owned by the current buffer.")
+
+(defun jabber-buffer-registry--key (kind peer)
+  "Return the registry key for chat KIND and PEER."
+  (cons kind peer))
+
+(defun jabber-buffer-registry--remove-current ()
+  "Remove registry entries owned by the current buffer."
+  (dolist (key jabber-buffer-registry--keys)
+    (when (eq (gethash key jabber-buffer-registry--buffers)
+              (current-buffer))
+      (remhash key jabber-buffer-registry--buffers)))
+  (setq jabber-buffer-registry--keys nil))
+
+(defun jabber-buffer-registry-register (kind peer &optional buffer)
+  "Register BUFFER under chat KIND and PEER.
+BUFFER defaults to the current buffer."
+  (with-current-buffer (or buffer (current-buffer))
+    (let ((key (jabber-buffer-registry--key kind peer)))
+      (puthash key (current-buffer) jabber-buffer-registry--buffers)
+      (unless (member key jabber-buffer-registry--keys)
+        (push key jabber-buffer-registry--keys))
+      (add-hook 'kill-buffer-hook
+                #'jabber-buffer-registry--remove-current nil t)
+      (current-buffer))))
+
+(defun jabber-buffer-registry-find (kind peer)
+  "Return the live buffer registered under chat KIND and PEER."
+  (let* ((key (jabber-buffer-registry--key kind peer))
+         (buffer (gethash key jabber-buffer-registry--buffers)))
+    (if (buffer-live-p buffer)
+        buffer
+      (remhash key jabber-buffer-registry--buffers)
+      nil)))
+
+(provide 'jabber-buffer-registry)
+;;; jabber-buffer-registry.el ends here
diff --git a/lisp/jabber-chat.el b/lisp/jabber-chat.el
index ea85a0cb46..d0df6c5742 100644
--- a/lisp/jabber-chat.el
+++ b/lisp/jabber-chat.el
@@ -28,6 +28,7 @@
 
 (require 'jabber-core)
 (require 'jabber-alert)
+(require 'jabber-buffer-registry)
 (require 'jabber-chatbuffer)
 (require 'jabber-db)
 (require 'jabber-reactions)
@@ -363,7 +364,7 @@ or `get-buffer-create'."
 
 (defun jabber-chat-find-buffer (chat-with)
   "Find an existing 1:1 chat buffer for CHAT-WITH, or nil."
-  (jabber-chatbuffer--registry-get 'chat (jabber-jid-user chat-with)))
+  (jabber-buffer-registry-find 'chat (jabber-jid-user chat-with)))
 
 (defun jabber-chat-create-buffer (jc chat-with)
   "Prepare a buffer for chatting with CHAT-WITH.
@@ -374,7 +375,7 @@ JC is the Jabber connection."
       (jabber-chat-mode)
 
       (setq-local jabber-chatting-with chat-with)
-      (jabber-chatbuffer--registry-put 'chat (jabber-jid-user chat-with))
+      (jabber-buffer-registry-register 'chat (jabber-jid-user chat-with))
 
       (jabber-chat-mode-setup jc #'jabber-chat-pp)
       (setq jabber-send-function #'jabber-chat-send)
diff --git a/lisp/jabber-chatbuffer.el b/lisp/jabber-chatbuffer.el
index 7b4a0f9caa..081fa04abe 100644
--- a/lisp/jabber-chatbuffer.el
+++ b/lisp/jabber-chatbuffer.el
@@ -27,6 +27,7 @@
 ;;; Code:
 
 (require 'jabber-util)
+(require 'jabber-buffer-registry)
 (require 'jabber-input)
 (require 'jabber-core)
 (require 'jabber-db)
@@ -107,43 +108,6 @@ previous sequence detect the mismatch and stop.")
 (defvar jabber-group)                      ; jabber-muc.el
 (defvar jabber-muc-header-line-format)    ; jabber-muc.el
 
-;;; Buffer lookup registry
-
-(defvar jabber-chatbuffer--registry (make-hash-table :test #'equal)
-  "Hash table mapping (TYPE . KEY) to a live buffer.
-TYPE is `chat', `muc', or `muc-private'.
-KEY: bare JID for chat; group JID for muc; \"group/nick\" for muc-private.")
-
-(defun jabber-chatbuffer--registry-put (type key)
-  "Register current buffer under TYPE and KEY."
-  (puthash (cons type key) (current-buffer) jabber-chatbuffer--registry))
-
-(defun jabber-chatbuffer--registry-get (type key)
-  "Return the live buffer registered under TYPE and KEY, or nil."
-  (let* ((k (cons type key))
-         (buf (gethash k jabber-chatbuffer--registry)))
-    (if (buffer-live-p buf)
-        buf
-      (remhash k jabber-chatbuffer--registry)
-      nil)))
-
-(defun jabber-chatbuffer--registry-remove ()
-  "Remove current buffer from registry.  Used as `kill-buffer-hook'."
-  (cond
-   ((and (local-variable-p 'jabber-group) jabber-group)
-    (remhash (cons 'muc jabber-group) jabber-chatbuffer--registry))
-   ((and (local-variable-p 'jabber-chatting-with) jabber-chatting-with)
-    ;; MUC-private: jabber-chatting-with is "group/nick" (has resource).
-    ;; 1:1 chat: jabber-chatting-with may be full JID or bare — always
-    ;; normalise to bare JID to match the key stored at registration time.
-    (if (jabber-jid-resource jabber-chatting-with)
-        (remhash (cons 'muc-private jabber-chatting-with)
-                 jabber-chatbuffer--registry)
-      (remhash (cons 'chat (jabber-jid-user jabber-chatting-with))
-               jabber-chatbuffer--registry)))))
-
-(add-hook 'kill-buffer-hook #'jabber-chatbuffer--registry-remove)
-
 (defcustom jabber-chat-default-encryption 'omemo
   "Default encryption mode for new chat buffers."
   :type '(choice (const :tag "OMEMO" omemo)
@@ -357,8 +321,6 @@ EWOC-PP is the pretty-printer function for the message 
EWOC."
         (setq jabber-chat-encryption 'plaintext))))
   (jabber-chat-encryption--update-header))
 
-(declare-function jabber-chat-find-buffer "jabber-chat" (chat-with))
-(declare-function jabber-muc-find-buffer "jabber-muc" (group))
 (declare-function jabber-chat-insert-backlog-entry "jabber-chat"
                   (msg-plist))
 (declare-function jabber-chat--insert-backlog-chunked "jabber-chat"
@@ -676,9 +638,8 @@ reload, so a reader scrolled up in history is not yanked to 
the top."
   "Update syncing indicator for PEER's chat buffer.
 TYPE is \"groupchat\" or \"chat\".  SYNCING-P is non-nil when
 sync starts, nil when it ends."
-  (when-let* ((buffer (if (string= type "groupchat")
-                          (jabber-muc-find-buffer peer)
-                        (jabber-chat-find-buffer peer)))
+  (when-let* ((kind (if (string= type "groupchat") 'muc 'chat))
+              (buffer (jabber-buffer-registry-find kind peer))
               ((buffer-live-p buffer)))
     (with-current-buffer buffer
       (setq jabber-chat-mam-syncing syncing-p)
@@ -692,9 +653,8 @@ PEERS is a list of (PEER . TYPE) pairs."
   (dolist (entry peers)
     (let* ((peer (car entry))
            (type (cdr entry))
-           (buffer (if (string= type "groupchat")
-                       (jabber-muc-find-buffer peer)
-                     (jabber-chat-find-buffer peer))))
+           (kind (if (string= type "groupchat") 'muc 'chat))
+           (buffer (jabber-buffer-registry-find kind peer)))
       (when (and buffer (buffer-live-p buffer))
         (with-current-buffer buffer
           (jabber-chat-buffer-refresh))))))
diff --git a/lisp/jabber-muc.el b/lisp/jabber-muc.el
index b032a58df2..7677ae8e86 100644
--- a/lisp/jabber-muc.el
+++ b/lisp/jabber-muc.el
@@ -31,6 +31,7 @@
 (require 'cl-lib)
 (require 'ewoc)
 (require 'jabber-widget)
+(require 'jabber-buffer-registry)
 (require 'jabber-disco)
 (require 'jabber-muc-protocol)
 (require 'jabber-muc-state)
@@ -280,7 +281,7 @@ or `get-buffer-create'."
 
 (defun jabber-muc-find-buffer (group)
   "Find an existing MUC buffer for GROUP, or nil."
-  (jabber-chatbuffer--registry-get 'muc group))
+  (jabber-buffer-registry-find 'muc group))
 
 (defun jabber-muc-create-buffer (jc group)
   "Prepare a buffer for chatroom GROUP.
@@ -319,7 +320,7 @@ JC is the Jabber connection."
 
     ;; Make sure the connection variable is up to date.
     (setq jabber-buffer-connection jc)
-    (jabber-chatbuffer--registry-put 'muc group)
+    (jabber-buffer-registry-register 'muc group)
 
     (current-buffer)))
 
@@ -339,7 +340,7 @@ or `get-buffer-create'."
 
 (defun jabber-muc-private-find-buffer (group nickname)
   "Find an existing MUC private buffer for GROUP/NICKNAME, or nil."
-  (jabber-chatbuffer--registry-get 'muc-private (format "%s/%s" group 
nickname)))
+  (jabber-buffer-registry-find 'muc-private (format "%s/%s" group nickname)))
 
 (defun jabber-muc-private-create-buffer (jc group nickname)
   "Prepare a buffer for chatting with NICKNAME in GROUP.
@@ -363,7 +364,7 @@ JC is the Jabber connection."
         (jabber-chat-encryption--update-header)))
 
     (setq-local jabber-chatting-with (concat group "/" nickname))
-    (jabber-chatbuffer--registry-put 'muc-private (format "%s/%s" group 
nickname))
+    (jabber-buffer-registry-register 'muc-private (format "%s/%s" group 
nickname))
     (setq jabber-send-function #'jabber-chat-send)
     (setq header-line-format jabber-muc-private-header-line-format)
 
diff --git a/tests/jabber-test-chatbuffer.el b/tests/jabber-test-chatbuffer.el
index 6d60851173..0ace6e08fb 100644
--- a/tests/jabber-test-chatbuffer.el
+++ b/tests/jabber-test-chatbuffer.el
@@ -441,75 +441,74 @@
 ;;; Group 8: Buffer lookup registry
 
 (ert-deftest jabber-test-chatbuffer-registry-chat-find ()
-  "Register a temp buffer as a chat buffer; registry-get returns it."
-  (let ((jabber-chatbuffer--registry (make-hash-table :test #'equal)))
+  "Register a temp buffer as a chat buffer and find it."
+  (let ((jabber-buffer-registry--buffers (make-hash-table :test #'equal)))
     (with-temp-buffer
-      (setq-local jabber-chatting-with "[email protected]")
-      (jabber-chatbuffer--registry-put 'chat "[email protected]")
+      (jabber-buffer-registry-register 'chat "[email protected]")
       (should (eq (current-buffer)
-                  (jabber-chatbuffer--registry-get 'chat 
"[email protected]"))))))
+                  (jabber-buffer-registry-find 'chat "[email protected]"))))))
 
 (ert-deftest jabber-test-chatbuffer-registry-kill-removes-entry ()
   "Killing the buffer removes its registry entry."
-  (let ((jabber-chatbuffer--registry (make-hash-table :test #'equal)))
+  (let ((jabber-buffer-registry--buffers (make-hash-table :test #'equal)))
     (let ((buf (generate-new-buffer " *test-chat-registry*")))
       (with-current-buffer buf
-        (setq-local jabber-chatting-with "[email protected]")
-        (jabber-chatbuffer--registry-put 'chat "[email protected]"))
-      (should (eq buf (jabber-chatbuffer--registry-get 'chat 
"[email protected]")))
+        (jabber-buffer-registry-register 'chat "[email protected]"))
+      (should (eq buf (jabber-buffer-registry-find 'chat "[email protected]")))
       (kill-buffer buf)
-      ;; The kill-buffer-hook removed it; get now returns nil.
-      (should-not (jabber-chatbuffer--registry-get 'chat 
"[email protected]")))))
+      (should-not (jabber-buffer-registry-find 'chat "[email protected]")))))
 
 (ert-deftest jabber-test-chatbuffer-registry-no-collision ()
   "MUC and chat buffers with the same bare JID do not collide."
-  (let ((jabber-chatbuffer--registry (make-hash-table :test #'equal)))
+  (let ((jabber-buffer-registry--buffers (make-hash-table :test #'equal)))
     (let ((chat-buf (generate-new-buffer " *test-chat*"))
           (muc-buf  (generate-new-buffer " *test-muc*")))
       (unwind-protect
           (progn
             (with-current-buffer chat-buf
-              (setq-local jabber-chatting-with "[email protected]")
-              (jabber-chatbuffer--registry-put 'chat "[email protected]"))
+              (jabber-buffer-registry-register 'chat "[email protected]"))
             (with-current-buffer muc-buf
-              (setq-local jabber-group "[email protected]")
-              (jabber-chatbuffer--registry-put 'muc "[email protected]"))
+              (jabber-buffer-registry-register 'muc "[email protected]"))
             (should (eq chat-buf
-                        (jabber-chatbuffer--registry-get 'chat 
"[email protected]")))
+                        (jabber-buffer-registry-find
+                         'chat "[email protected]")))
             (should (eq muc-buf
-                        (jabber-chatbuffer--registry-get 'muc 
"[email protected]"))))
+                        (jabber-buffer-registry-find
+                         'muc "[email protected]"))))
         (kill-buffer chat-buf)
         (kill-buffer muc-buf)))))
 
 (ert-deftest jabber-test-chatbuffer-registry-muc-private ()
   "MUC-private lookup by group+nick returns correct buffer."
-  (let ((jabber-chatbuffer--registry (make-hash-table :test #'equal)))
+  (let ((jabber-buffer-registry--buffers (make-hash-table :test #'equal)))
     (let ((buf (generate-new-buffer " *test-muc-private*")))
       (unwind-protect
           (progn
             (with-current-buffer buf
-              (setq-local jabber-chatting-with "[email protected]/alice")
-              (jabber-chatbuffer--registry-put
+              (jabber-buffer-registry-register
                'muc-private "[email protected]/alice"))
             (should (eq buf
-                        (jabber-chatbuffer--registry-get
+                        (jabber-buffer-registry-find
                          'muc-private "[email protected]/alice"))))
         (kill-buffer buf)))))
 
-(ert-deftest jabber-test-chatbuffer-registry-kill-full-jid-removes-bare-key ()
-  "kill-buffer-hook cleans up bare-JID key when chatting-with is a full JID."
-  (let ((jabber-chatbuffer--registry (make-hash-table :test #'equal)))
-    (let ((buf (generate-new-buffer " *test-chat-full-jid*")))
-      (with-current-buffer buf
-        ;; Registered with bare JID (as jabber-chat-create-buffer does).
-        (setq-local jabber-chatting-with "[email protected]/phone")
-        (jabber-chatbuffer--registry-put 'chat "[email protected]"))
-      ;; At this point the registry holds bare key.
-      (should (eq buf (jabber-chatbuffer--registry-get 'chat 
"[email protected]")))
-      ;; jabber-chatting-with has a resource — kill-hook should still remove
-      ;; the bare-JID key because it normalises via jabber-jid-user.
-      (kill-buffer buf)
-      (should-not (jabber-chatbuffer--registry-get 'chat 
"[email protected]")))))
+(ert-deftest jabber-test-chatbuffer-registry-replacement-survives-old-kill ()
+  "Killing a replaced buffer does not remove the current registration."
+  (let ((jabber-buffer-registry--buffers (make-hash-table :test #'equal))
+        (old (generate-new-buffer " *test-chat-old*"))
+        (new (generate-new-buffer " *test-chat-new*")))
+    (unwind-protect
+        (progn
+          (jabber-buffer-registry-register 'chat "[email protected]" old)
+          (jabber-buffer-registry-register 'chat "[email protected]" new)
+          (kill-buffer old)
+          (should (eq new
+                      (jabber-buffer-registry-find
+                       'chat "[email protected]"))))
+      (when (buffer-live-p old)
+        (kill-buffer old))
+      (when (buffer-live-p new)
+        (kill-buffer new)))))
 
 ;;; Group 9: OMEMO immediate display status transitions
 

Reply via email to