Subject: bug#76261: [PATCH] Add a mentions buffer feature to rcirc

From: Tassilo Horn <[email-masked]>
Date: Thu, 13 Feb 2025 12:27:56 +0100

Tags: patch

Hi all,

rcirc-track-minor-mode is nice to navigate to mentions of your nick or
certain keywords (rcirc-keywords), however you can navigate there only
once.

The proposed feature (if enabled) collects such mentions in a separate
buffer *rcirc mentions* as clickable text, so that you can navigate to
the source of the mention as often as you like.

In its current state, the feature works fine but I guess the *rcirc
mentions* buffer should contain a bit more information, e.g., a copy of
the actual mentioning message.

I guess there's also a technical issue: right now, the linkage is to a
concrete buffer position (point value) which only works reliably if
rcirc-buffer-maximum-lines is nil and thus buffers aren't truncated.  I
guess I should switch to markers instead, right?

Anyway, I just wanted to get feedback if such a feature is acceptable?

Thanks,
Tassilo

In GNU Emacs 31.0.50 (build 7, x86_64-pc-linux-gnu, GTK+ Version
 3.24.48, cairo version 1.18.2) of 2025-02-13 built on thinkpad-t440p
Repository revision: 2e9413255fb8cbd0c8481ca6f863b37df3e9008d
Repository branch: master
System Description: Arch Linux

Configured using:
 'configure --without-native-compilation --with-modules --with-pgtk'

>From 8a39c204e8b4b2116abac7324b402e3b0c745618 Mon Sep 17 00:00:00 2001
From: Tassilo Horn <[email-masked]>
Date: Thu, 13 Feb 2025 10:39:31 +0100
Subject: [PATCH] Add a mentions buffer feature to rcirc

If the feature is enabled by setting rcirc-mentions-buffer-enabled to a
non-nil value, a buffer rcirc-mentions-buffer-name is created and used
for logging mentions of your nick or a keyword in rcirc-keywords.  The
log lines link to the original position in the actual channel buffer
where the mention occured.

* lisp/net/rcirc.el (rcirc-mentions-buffer-name): New defcustom.
(rcirc-mentions-buffer-enabled): New defcustom.
(rcirc-update-mentions-buffer): New function.
(rcirc-record-activity): Call it if rcirc-mentions-buffer-enabled is
non-nil.
---
 lisp/net/rcirc.el | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 3f81672182b..286dc4ef133 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -2466,6 +2466,56 @@ rcirc-next-active-buffer
                  ""))))
   (rcirc-update-activity-string))
 
+(defcustom rcirc-mentions-buffer-name "*rcirc mentions*"
+  "The name of the mentions buffer.
+Also see `rcirc-mentions-buffer-enabled'."
+  :type 'string
+  :version "31.1")
+
+(defcustom rcirc-mentions-buffer-enabled nil
+  "If non-nil, create a mentions buffer.
+The name of this buffer is defined by `rcirc-mentions-buffer-name'.  In
+this buffer, mentions of your nick or a keyword in `rcirc-keywords' will
+be logged linking to the original message in the respective channel
+buffer."
+  :type 'boolean
+  :version "31.1")
+
+(defun rcirc-update-mentions-buffer (type)
+  ;; Assumes being called while the current buffer is the buffer with
+  ;; the activity.
+  (let* ((activity-buffer (current-buffer))
+         (activity-point (save-excursion
+                           (forward-line -1)
+                           (point)))
+         (action (lambda (_button)
+                   (if (buffer-live-p activity-buffer)
+                       (progn
+                         (switch-to-buffer activity-buffer)
+                         (goto-char activity-point))
+                     (message "The buffer %s has disappeared."
+                              (buffer-name activity-buffer))))))
+    (with-current-buffer (get-buffer-create
+                          rcirc-mentions-buffer-name)
+      (setq-local buffer-read-only t)
+      (let ((inhibit-read-only t))
+        (save-excursion
+          (goto-char (point-max))
+          (unless (looking-back "\n")
+            (insert "\n"))
+          (insert (rcirc-facify
+                   (format-time-string rcirc-time-format (current-time))
+                   'rcirc-timestamp)
+                  "> ")
+          (insert-button (format "%s has been mentioned in buffer %s."
+                                 (if (eq type 'nick)
+                                     "Your nick"
+                                   "A keyword")
+                                 (buffer-name activity-buffer))
+                         'action action
+                         'follow-link t)
+          (insert "\n"))))))
+
 (defvar rcirc-activity-functions nil
   "Hook to be run when there is channel activity.
 
@@ -2478,6 +2528,10 @@ rcirc-record-activity
   (with-current-buffer buffer
     (let ((old-activity rcirc-activity)
           (old-types rcirc-activity-types))
+      (when (and rcirc-mentions-buffer-enabled
+                 (memq type '(nick keyword))
+                 (not (eq buffer rcirc-server-buffer)))
+        (rcirc-update-mentions-buffer type))
       (when (and (not (get-buffer-window (current-buffer) t))
                  (not (and rcirc-track-ignore-server-buffer-flag
                            (eq rcirc-server-buffer (current-buffer)))))
-- 
2.48.1