* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
@ 2023-05-19 19:25 J.P.
2023-05-19 20:47 ` J.P.
` (11 more replies)
0 siblings, 12 replies; 17+ messages in thread
From: J.P. @ 2023-05-19 19:25 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
[-- Attachment #1: Type: text/plain, Size: 8242 bytes --]
Tags: patch
Severity: wishlist
(This bug could just as well be titled "Make ERC look more like
standalone clients," although that's perhaps a bit clickbaity.)
Hi,
Newcomers to ERC are occasionally dumbfounded by the absence of a
certain pair of IRC essentials, namely, a "window list" and a "nicknames
list." But what even existing users may not know is that ERC already has
both; they just don't quite work the way folks coming from other clients
might expect. This patch aims to address that as if it were a problem.
What's being proposed here is the addition of two new modules built
entirely on functionality already offered by their host libraries,
erc-status-sidebar.el and erc-speedbar.el. What's different is these
additions flirt with something somewhat verboten in ERC, and that's
changing existing defaults for non-security reasons (in this case,
chiefly for unifying UX [1]). Beyond that, these changes also hard-wire
potentially offensive choices into some of these defaults while trying
in earnest to ensure old behavior remains accessible. For example, one
module assumes no one with a non-nil `erc-header-line-format' has any
use for modes and topics in a side window. Other baked in preferences
include the nixing of all throwback icons [2] and the showing of
disconnected buffers in a muted face. The list goes on but is open for
discussion, as always.
Another consideration here is of course naming [3]. I've gone ahead and
dubbed the speedbar module 'nickbar' as a bit of an homage to its roots.
`nicklist' wasn't available because a popular module of that name was
once part of ERC, and people still use it today. For status-sidebar, I
went with `bufbar', in part for consistency but also because the
would-be canonical "status-sidebar" is already taken by the side
window's buffer for its major mode. We might also consider going with
the slightly pedestrian `buflist', which is already used by at least one
other IRC client for referring to this feature.
Lastly, I'd like to stress that these modules (thankfully) won't be
loaded by default, which means you'll need to add `bufbar' and `nickbar'
to `erc-modules' when trying them out. Note that this patch set
currently depends on bug#63569 [3], whose changes need applying
beforehand.
Thanks!
[1] My justifications for taking such liberties are at best anecdotal,
based mostly on personal impressions of prevailing usage patterns
and the perceived motivations behind them. A few examples:
a. The relative newness of erc-status-sidebar.el, its lack of an
associated module, and its absence from ERC's Custom menu all
point to its defaults being somewhat more free for the changing.
The speedbar integration likewise lacks a module, and its
graphical-only nature means its set of users currently excludes
anyone using ERC from a terminal. (Less expected fallout from the
proposed churn, IOW.)
b. Both libraries provide an always-open side window (or, in
speedbar's case, frame), which imposes a specific layout on the
user, something that's relatively rare in Emacs outside of
IDE-style modes. Compare this to something like ibuffer for
listing buffers or a hypothetical /NAMES buffer, which, if based
on `tabulated-list-mode', would make for a more familiar means of
reviewing channel members. The point here is that devoted users
likely aren't messing with erc-status-sidebar or erc-speedbar in
droves, preferring more Emacsy alternatives instead.
c. Newcomers can't be bothered with an overly involved setup if it
requires carefully exploring options before trying. But they're
perfectly willing to copy/paste gobs of configuration or even
mindlessly follow a minutes long Customize itinerary, so long as
the promise of emerging with something resembling their present
idea of what makes an IRC client remains within reach. By
introducing these modules "preconfigured," I'm positing that
these preconceived notions typically include a reactive window
list and/or nick list. That said, my hope is that these users
will eventually gravitate toward the more Emacs-native way of
doing things, at which point these modules will have served their
primary purpose (of acting as bait).
[2] My reason for 86'ing the icons outright in the speedbar's new
"window mode" is consistency. I figure anyone who wants the vanilla
experience wants it in full and thus also wants a separate frame.
That said, I suppose we could add a knob for tweaking this (or any
of the other hard-coded choices mentioned), but IMO doing that
unprovoked just contributes to "options sprawl."
[3] FWIW, all module names in contention flout our supposed policy of
preferring those that align with host libraries and the features
they `provide'.
In GNU Emacs 30.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version
3.24.37, cairo version 1.17.6) of 2023-05-13 built on localhost
Repository revision: 867b104010760c4b7cd700078884cc774a01860a
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12014000
System Description: Fedora Linux 37 (Workstation Edition)
Configured using:
'configure --enable-check-lisp-object-type --enable-checking=yes,glyphs
'CFLAGS=-O0 -g3'
PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'
Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB
Important settings:
value of $LANG: en_US.UTF-8
value of $XMODIFIERS: @im=ibus
locale-coding-system: utf-8-unix
Major mode: Lisp Interaction
Minor modes in effect:
tooltip-mode: t
global-eldoc-mode: t
eldoc-mode: t
show-paren-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tool-bar-mode: t
menu-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
blink-cursor-mode: t
line-number-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
None found.
Features:
(shadow sort mail-extr emacsbug message mailcap yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config
gnus-util text-property-search time-date mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047
rfc2045 ietf-drums mm-util mail-prsvr mail-utils erc auth-source cl-seq
eieio eieio-core cl-macs password-cache json subr-x map format-spec
cl-loaddefs cl-lib erc-backend erc-networks byte-opt gv bytecomp
byte-compile erc-common erc-compat erc-loaddefs rmc iso-transl tooltip
cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd
fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow
isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo
move-toolbar gtk x-toolkit xinput2 x multi-tty make-network-process
emacs)
Memory information:
((conses 16 64236 9476)
(symbols 48 8573 0)
(strings 32 23246 1709)
(string-bytes 1 674076)
(vectors 16 15015)
(vector-slots 8 207266 8159)
(floats 8 24 33)
(intervals 56 229 0)
(buffers 976 10))
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-5.6-Fix-buffer-mismatch-bug-in-erc-scroll-to-bottom.patch --]
[-- Type: text/x-patch, Size: 1019 bytes --]
From 4a1bd9e173d91164d5abe6f2e349a447eaf019d7 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 17 May 2023 19:48:02 -0700
Subject: [PATCH 1/5] [5.6] Fix buffer-mismatch bug in erc-scroll-to-bottom
* lisp/erc/erc-goodies.el (erc-scroll-to-bottom): Only `recenter' when
the selected window's buffer is current. Previously, the module
`scrolltobottom' signaled an "Error in `post-command-hook'" when a
user clicked a channel indicator in the mode line from a window
showing another ERC buffer.
---
lisp/erc/erc-goodies.el | 1 +
1 file changed, 1 insertion(+)
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index 01eae4b63c5..87c95778523 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -92,6 +92,7 @@ erc-scroll-to-bottom
(save-restriction
(widen)
(when (and erc-insert-marker
+ (eq (current-buffer) (window-buffer))
;; we're editing a line. Scroll.
(> (point) erc-insert-marker))
(save-excursion
--
2.40.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-5.6-Allow-ERC-s-module-toggles-access-to-the-prefix-.patch --]
[-- Type: text/x-patch, Size: 3981 bytes --]
From 5ae05b1ad34ce1baea149c7af1e9e9282f101725 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 15 May 2023 00:16:00 -0700
Subject: [PATCH 2/5] [5.6] Allow ERC's module toggles access to the prefix arg
* lisp/erc/erc-common.el (erc--module-toggle-prefix-arg): Add internal
variable for preserving the `arg' passed to a module's minor-mode
toggle, which was previously discarded. Doing this lets modules that
are more interactive in nature overload their mode toggles with
alternate behaviors.
(define-erc-module): Bind `erc--module-toggle-prefix-arg' to the `arg'
parameter, which is normally defined inside a `define-minor-mode' body
form.
* test/lisp/erc/erc-tests.el (define-erc-module--global,
define-erc-module--local): Expect activation body to be wrapped by a
let form binding `erc--module-toggle-prefix-arg'.
---
lisp/erc/erc-common.el | 14 +++++++++++---
test/lisp/erc/erc-tests.el | 14 ++++++++------
2 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index f152a1a32d9..dd39b30c4db 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -289,6 +289,15 @@ erc--find-feature
(intern (file-name-base file))))
(v v)))
+(defvar erc--module-toggle-prefix-arg nil
+ "The interpreted prefix arg of the minor-mode toggle.
+Non-nil inside an ERC module's activation (or deactivation)
+command, such as `erc-spelling-enable', when it's been called
+indirectly via the module's minor-mode toggle, i.e.,
+`erc-spelling-mode'. Nil otherwise. Its value is either the
+symbol `toggle' or an integer produced by `prefix-numeric-value'.
+See Info node `(elisp) Defining Minor Modes' for more.")
+
(defmacro define-erc-module (name alias doc enable-body disable-body
&optional local-p)
"Define a new minor mode using ERC conventions.
@@ -337,9 +346,8 @@ define-erc-module
:group (erc--find-group ',name ,(and alias (list 'quote alias)))
,@(unless local-p `(:require ',(erc--find-feature name alias)))
,@(unless local-p `(:type ,(erc--prepare-custom-module-type name)))
- (if ,mode
- (,enable)
- (,disable)))
+ (let ((erc--module-toggle-prefix-arg arg))
+ (if ,mode (,enable) (,disable))))
,(erc--assemble-toggle local-p name enable mode t enable-body)
,(erc--assemble-toggle local-p name disable mode nil disable-body)
,@(and-let* ((alias)
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 991bfa3b082..de472527bde 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -2175,9 +2175,10 @@ define-erc-module--global
:group (erc--find-group 'mname 'malias)
:require 'nil
:type "mname"
- (if erc-mname-mode
- (erc-mname-enable)
- (erc-mname-disable)))
+ (let ((erc--module-toggle-prefix-arg arg))
+ (if erc-mname-mode
+ (erc-mname-enable)
+ (erc-mname-disable))))
(defun erc-mname-enable ()
"Enable ERC mname mode."
@@ -2230,9 +2231,10 @@ define-erc-module--local
Some docstring."
:global nil
:group (erc--find-group 'mname nil)
- (if erc-mname-mode
- (erc-mname-enable)
- (erc-mname-disable)))
+ (let ((erc--module-toggle-prefix-arg arg))
+ (if erc-mname-mode
+ (erc-mname-enable)
+ (erc-mname-disable))))
(defun erc-mname-enable (&optional ,arg-en)
"Enable ERC mname mode.
--
2.40.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-5.6-Add-preset-styles-to-erc-status-sidebar.patch --]
[-- Type: text/x-patch, Size: 29702 bytes --]
From c4746e4bb3fde7670bd655ed7f17ec90435018ac Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Thu, 4 May 2023 00:01:11 -0700
Subject: [PATCH 3/5] [5.6] Add preset styles to erc-status-sidebar
* lisp/erc/erc-networks.el (erc-networks--rename-server-buffer): Store
`erc-networks--id' in process object's plist.
* lisp/erc/erc-status-sidebar.el (erc-status-sidebar): Change parent
from `convenience' to `erc'.
(erc-status-sidebar-channel-format):
Mention in doc string that it depends on new option
`erc-status-sidebar-style'.
(erc-status-sidebar-highlight-active-buffer): New option to control
whether the current window's target is highlighted in the status bar.
(erc-status-sidebar-style): New option to determine whether servers
and queries also appear in the sidebar.
(erc-status-sidebar-click-display-action,
erc-status-sidebar-singular): New options.
(erc-status-sidebar-get-window): Consider
`erc-status-sidebar-singular'.
(erc-status-sidebar-open): Fix toggle functionality that somehow fell
through the cracks after the adoption of the package into ERC proper.
(erc-buflist-mode, erc-buflist-enable, erc-buflist-disable): New
module named `buflist' instead of `sidebar', which is more easily
confusable with `speedbar'. The preferred name, `status-sidebar' was
unavailable because its minor-mode would have been
`erc-status-sidebar-mode', which is already taken by the major mode
used for status-bar buffers themselves.
(erc-status-sidebar-toggle): Ignore `erc-status-sidebar-singular'.
(erc-status-sidebar--trimpat, erc-status-sidebar--prechan): Add helper
vars for new sorting function, allowing it to honor the existing
interface, which only expects one argument.
(erc-status-sidebar-prefer-target-as-name): New function for
determining buffer name, preferring targets for target buffers.
(erc-status-sidebar-get-channame): Use internal API to help determine
name of buffer in sidebar.
(erc-status-sidebar-prefer-target-as-name,
erc-status-sidebar--show-disconnected,
erc-status-sidebar-all-target-buffers,
erc-status-sidebar-default-allsort): Add new naming and sorting
functions and associated helper functions and variables.
(erc-status-sidebar--active-marker,
erc-status-sidebar--set-active-line): New variable and function for
highlighting the active target in the status bar.
(erc-status-sidebar-default-insert,
erc-status-sidebar-pad-hierarchy): New functions for visiting various
stages of buffer modification when rendering sidebar.
(erc-status-sidebar-click): Appeal to option
`erc-status-sidebar-display-action' for `pop-to-buffer' action.
(erc-status-sidebar-scroll-up, erc-status-sidebar-scroll-down,
erc-status-sidebar-recenter): Add commands to scroll and
recenter sidebar from a target buffer's window.
(erc-status-sidebar-refresh): Consider presets and new options when
rendering sidebar. Disable `erc-buflist-mode' when active.
(erc-status-sidebar-set-window-preserve-size): Ignore
`erc-status-sidebar-singular'.
(erc-status-sidebar-mode): Make non-interactive to avoid confusion
when folks run "M-x erc-status-sidebar-mode" expecting a module
toggle.
* test/lisp/erc/erc-scenarios-status-sidebar.el: New file.
* test/lisp/erc/resources/base/gapless-connect/foonet.eld: Fix wrong
manifest for channel and extend PASS timeout.
---
lisp/erc/erc-networks.el | 1 +
| 328 ++++++++++++++++--
| 93 +++++
.../resources/base/gapless-connect/foonet.eld | 8 +-
4 files changed, 400 insertions(+), 30 deletions(-)
create mode 100644 test/lisp/erc/erc-scenarios-status-sidebar.el
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index dd481032e7e..60d76d059da 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -1459,6 +1459,7 @@ erc-networks--rename-server-buffer
;; When this ends up being the current buffer, either we have
;; a "given" ID or the buffer was reused on reconnecting.
(existing (get-buffer name)))
+ (process-put new-proc 'erc-networks--id erc-networks--id)
(cond ((or (not existing)
(erc-networks--id-given erc-networks--id)
(eq existing (current-buffer)))
--git a/lisp/erc/erc-status-sidebar.el b/lisp/erc/erc-status-sidebar.el
index f11faa3db10..c06ba53f3ae 100644
--- a/lisp/erc/erc-status-sidebar.el
+++ b/lisp/erc/erc-status-sidebar.el
@@ -45,6 +45,13 @@
;; Use M-x erc-status-sidebar-kill RET to kill the sidebar buffer and
;; close the sidebar on all frames.
+;; In addition to the commands above, you can also try the all-in-one,
+;; "DWIM" command, `erc-bufbar-mode'. See its doc string for usage.
+
+;; If you want the status sidebar enabled whenever you use ERC, add
+;; `bufbar' to `erc-modules'. Note that this library also has a major
+;; mode, `erc-status-sidebar-mode', which is for internal use.
+
;;; Code:
(require 'erc)
@@ -53,8 +60,15 @@
(require 'seq)
(defgroup erc-status-sidebar nil
- "A sidebar for ERC channel status."
- :group 'convenience)
+ "A responsive side window listing all connected ERC buffers.
+More commonly known as a window list or \"buflist\", this side
+panel displays clickable buffer names for switching to with the
+mouse. By default, ERC highlights the name corresponding to the
+selected window's buffer, if any. Here, \"connected buffer\"
+means one belonging to a session context for a server that ERC is
+currently communicating with. For information on how the window
+itself works, see Info node `(elisp) Side Windows'."
+ :group 'erc)
(defcustom erc-status-sidebar-buffer-name "*ERC Status*"
"Name of the sidebar buffer."
@@ -80,9 +94,78 @@ erc-status-sidebar-channel-sort
(defcustom erc-status-sidebar-channel-format
'erc-status-sidebar-default-chan-format
- "Function used to format channel names for display in the sidebar."
+ "Function used to format channel names for display in the sidebar.
+Only consulted for certain values of `erc-status-sidebar-style'."
:type 'function)
+(defcustom erc-status-sidebar-highlight-active-buffer t
+ "Whether to highlight the selected window's buffer in the sidebar.
+ERC uses the same instance across all frames. May not be
+compatible with all values of `erc-status-sidebar-style'."
+ :package-version '(ERC . "5.6") ; FIXME sync on release
+ :type 'boolean)
+
+(defcustom erc-status-sidebar-style 'all-queries-first
+ "Preset style for rendering the sidebar.
+
+When set to `channels-only', ERC limits the items in the
+status bar to uniquified channels. It uses the options
+and functions
+
+ `erc-channel-list',
+ `erc-status-sidebar-channel-sort',
+ `erc-status-sidebar-get-channame',
+ `erc-status-sidebar-channel-format'
+ `erc-status-sidebar-default-insert'
+
+for selecting, formatting, naming, and inserting entries. When
+set to one of the various \\=`all-*' values, such as `all-mixed',
+ERC shows channels and queries under their respective server
+buffers, using the functions
+
+ `erc-status-sidebar-all-target-buffers',
+ `erc-status-sidebar-default-allsort',
+ `erc-status-sidebar-prefer-target-as-name',
+ `erc-status-sidebar-default-chan-format',
+ `erc-status-sidebar-pad-hierarchy'
+
+for the above-mentioned purposes. ERC also accepts a list of
+functions to preform these roles a la carte. See doc strings for
+a description of their expected arguments and return values."
+ :package-version '(ERC . "5.6") ; FIXME sync on release
+ :type '(choice (const channels-only)
+ (const all-mixed)
+ (const all-queries-first)
+ (const all-channels-first)
+ (list (function :tag "Buffer lister")
+ (function :tag "Buffer sorter")
+ (function :tag "Name extractor")
+ (function :tag "Name formatter")
+ (function :tag "Name inserter"))))
+
+(defcustom erc-status-sidebar-click-display-action t
+ "How to display a buffer when clicked.
+Values can be anything recognized by `display-buffer' for its
+ACTION parameter."
+ :package-version '(ERC . "5.6") ; FIXME sync on release
+ :type '(choice (const :tag "Always use/create other window" t)
+ (const :tag "Let `display-buffer' decide" nil)
+ (const :tag "Same window" (display-buffer-same-window
+ (inhibit-same-window . nil)))
+ (cons :tag "Action"
+ (choice function (repeat function))
+ (alist :tag "Action arguments"
+ :key-type symbol
+ :value-type (sexp :tag "Value")))))
+
+(defcustom erc-status-sidebar-singular t
+ "Whether to show the sidebar on all frames or just one (default)."
+ :package-version '(ERC . "5.6") ; FIXME sync on release
+ :type 'boolean)
+
+(defvar hl-line-mode)
+(declare-function hl-line-highlight "hl-line" nil)
+
(defun erc-status-sidebar-display-window ()
"Display the status buffer in a side window. Return the new window."
(display-buffer
@@ -94,7 +177,8 @@ erc-status-sidebar-get-window
"Return the created/existing window displaying the status buffer.
If NO-CREATION is non-nil, the window is not created."
- (let ((sidebar-window (get-buffer-window erc-status-sidebar-buffer-name)))
+ (let ((sidebar-window (get-buffer-window erc-status-sidebar-buffer-name
+ erc-status-sidebar-singular)))
(unless (or sidebar-window no-creation)
(with-current-buffer (erc-status-sidebar-get-buffer)
(setq-local vertical-scroll-bar nil))
@@ -144,22 +228,50 @@ erc-status-sidebar-open
"Open or create a sidebar."
(interactive)
(save-excursion
- (let ((sidebar-exists (erc-status-sidebar-buffer-exists-p))
- (sidebar-buffer (erc-status-sidebar-get-buffer))
- ;; (sidebar-window (erc-status-sidebar-get-window))
- )
- (unless sidebar-exists
- (with-current-buffer sidebar-buffer
- (erc-status-sidebar-mode)
- (erc-status-sidebar-refresh))))))
+ (if (erc-status-sidebar-buffer-exists-p)
+ (erc-status-sidebar-get-window)
+ (with-current-buffer (erc-status-sidebar-get-buffer)
+ (erc-status-sidebar-mode)
+ (erc-status-sidebar-refresh)))))
+
+;;;###autoload(autoload 'erc-bufbar-mode "erc-status-sidebar" nil t)
+(define-erc-module bufbar nil
+ "Show `erc-track'-like activity in a side window.
+When enabling, show the sidebar immediately if called from a
+connected ERC buffer. Otherwise, arrange for doing so on connect
+or whenever next displaying a new ERC buffer. When disabling,
+hide the status window if it's showing. With a negative prefix
+arg, also shutdown the session."
+ ((unless erc-track-mode
+ (unless (memq 'track erc-modules)
+ (erc--warn-once-before-connect 'erc-bufbar-mode
+ "Module `bufbar' needs global module `track'. Enabling now."
+ " This will affect \C-]all\C-] ERC sessions."
+ " Add `track' to `erc-modules' to silence this message."))
+ (erc-track-mode +1))
+ (add-hook 'erc--setup-buffer-hook #'erc-status-sidebar-open)
+ (unless erc--updating-modules-p
+ (if (erc-with-server-buffer erc-server-connected)
+ (erc-status-sidebar-open)
+ (setq erc-bufbar-mode nil)
+ (user-error "`%s' not called from a connected ERC buffer."
+ 'erc-bufbar-mode))))
+ ((remove-hook 'erc--setup-buffer-hook #'erc-status-sidebar-open)
+ (erc-status-sidebar-close erc-status-sidebar-singular)
+ (when-let* ((arg erc--module-toggle-prefix-arg)
+ ((numberp arg))
+ ((< arg 0)))
+ (erc-status-sidebar-kill))))
;;;###autoload
(defun erc-status-sidebar-toggle ()
- "Toggle the sidebar open/closed on the current frame."
+ "Toggle the sidebar open/closed on the current frame.
+Do this regardless of `erc-status-sidebar-singular'."
(interactive)
(if (get-buffer-window erc-status-sidebar-buffer-name nil)
(erc-status-sidebar-close)
- (erc-status-sidebar-open)))
+ (let (erc-status-sidebar-singular)
+ (erc-status-sidebar-open))))
(defun erc-status-sidebar-get-channame (buffer)
"Return name of BUFFER with all leading \"#\" characters removed."
@@ -174,6 +286,98 @@ erc-status-sidebar-default-chansort
(string< (erc-status-sidebar-get-channame x)
(erc-status-sidebar-get-channame y)))))
+(defvar erc-status-sidebar--trimpat nil)
+(defvar erc-status-sidebar--prechan nil)
+
+(defun erc-status-sidebar-prefer-target-as-name (buffer)
+ "Return some name to represent buffer in the sidebar."
+ (if-let ((target (buffer-local-value 'erc--target buffer)))
+ (cond ((and erc-status-sidebar--trimpat (erc--target-channel-p target))
+ (string-trim-left (erc--target-string target)
+ erc-status-sidebar--trimpat))
+ ((and erc-status-sidebar--prechan (erc--target-channel-p target))
+ (concat erc-status-sidebar--prechan
+ (erc--target-string target)))
+ (t (erc--target-string target)))
+ (buffer-name buffer)))
+
+;; This could be converted into an option if people want.
+(defvar erc-status-sidebar--show-disconnected t)
+
+(defun erc-status-sidebar-all-target-buffers (process)
+ (erc-buffer-filter (lambda ()
+ (and erc--target
+ (or erc-status-sidebar--show-disconnected
+ (erc-server-process-alive))))
+ process))
+
+;; FIXME profile this. Rebuilding the graph every time track updates
+;; seems wasteful for occasions where server messages are processed
+;; unthrottled, such as during history playback. If it's a problem,
+;; we should look into rewriting this using `ewoc' or some other
+;; solution that maintains a persistent model.
+(defun erc-status-sidebar-default-allsort (target-buffers)
+ "Return a list of servers interspersed with their targets."
+ (mapcan (pcase-lambda (`(,proc . ,chans))
+ (cons (process-buffer proc)
+ (let ((erc-status-sidebar--trimpat
+ (and (eq erc-status-sidebar-style 'all-mixed)
+ (with-current-buffer (process-buffer proc)
+ (when-let ((ch-pfxs (erc--get-isupport-entry
+ 'CHANTYPES 'single)))
+ (regexp-quote ch-pfxs)))))
+ (erc-status-sidebar--prechan
+ (and (eq erc-status-sidebar-style
+ 'all-queries-first)
+ "\C-?")))
+ (sort chans
+ (lambda (x y)
+ (string<
+ (erc-status-sidebar-prefer-target-as-name x)
+ (erc-status-sidebar-prefer-target-as-name y)))))))
+ (sort (seq-group-by (lambda (b)
+ (buffer-local-value 'erc-server-process b))
+ target-buffers)
+ (lambda (a b)
+ (string< (buffer-name (process-buffer (car a)))
+ (buffer-name (process-buffer (car b))))))))
+
+(defvar-local erc-status-sidebar--active-marker nil
+ "Marker indicating currently active buffer.")
+
+(defun erc-status-sidebar--set-active-line (erc-buffer)
+ (when (and erc-status-sidebar-highlight-active-buffer
+ (eq (window-buffer (and (minibuffer-window-active-p
+ (selected-window))
+ (minibuffer-selected-window)))
+ erc-buffer))
+ (set-marker erc-status-sidebar--active-marker (point))))
+
+(defun erc-status-sidebar-default-insert (channame chanbuf _chanlist)
+ "Insert CHANNAME followed by a newline.
+Maybe arrange to highlight line if CHANBUF is showing in the
+focused window."
+ (erc-status-sidebar--set-active-line chanbuf)
+ (insert channame "\n"))
+
+(defun erc-status-sidebar-pad-hierarchy (bufname buffer buflist)
+ "Prefix BUFNAME to emphasize BUFFER's role in BUFLIST."
+ (if (and (buffer-live-p buffer) (buffer-local-value 'erc--target buffer))
+ (insert " ")
+ (unless (eq buffer (car buflist))
+ (insert "\n"))) ; ^L
+ (when bufname
+ (erc-status-sidebar--set-active-line buffer))
+ (insert (or bufname
+ (and-let* (((not (buffer-live-p buffer)))
+ (next (cadr (member buffer buflist)))
+ ((buffer-live-p next))
+ (proc (buffer-local-value 'erc-server-process next))
+ (id (process-get proc 'erc-networks--id)))
+ (symbol-name (erc-networks--id-symbol id)))
+ "???")
+ "\n"))
+
(defun erc-status-sidebar-default-chan-format (channame
&optional num-messages erc-face)
"Format CHANNAME for display in the sidebar.
@@ -193,43 +397,111 @@ erc-status-sidebar-default-chan-format
(defun erc-status-sidebar-refresh ()
"Update the content of the sidebar."
(interactive)
- (let ((chanlist (apply erc-status-sidebar-channel-sort
- (erc-channel-list nil) nil)))
+ (pcase-let* ((`(,list-fn ,sort-fn ,name-fn ,fmt-fn ,insert-fn)
+ (pcase erc-status-sidebar-style
+ ('channels-only (list #'erc-channel-list
+ erc-status-sidebar-channel-sort
+ #'erc-status-sidebar-get-channame
+ erc-status-sidebar-channel-format
+ #'erc-status-sidebar-default-insert))
+ ((or 'all-mixed 'all-queries-first 'all-channels-first)
+ '(erc-status-sidebar-all-target-buffers
+ erc-status-sidebar-default-allsort
+ erc-status-sidebar-prefer-target-as-name
+ erc-status-sidebar-default-chan-format
+ erc-status-sidebar-pad-hierarchy))
+ (v v)))
+ (chanlist (apply sort-fn (funcall list-fn nil) nil))
+ (window nil)
+ (winstart nil))
(with-current-buffer (erc-status-sidebar-get-buffer)
+ (setq window (get-buffer-window nil erc-status-sidebar-singular)
+ winstart (and window (window-start window)))
(erc-status-sidebar-writable
(delete-region (point-min) (point-max))
(goto-char (point-min))
+ (if erc-status-sidebar--active-marker
+ (set-marker erc-status-sidebar--active-marker nil)
+ (setq erc-status-sidebar--active-marker (make-marker)))
(dolist (chanbuf chanlist)
(let* ((tup (seq-find (lambda (tup) (eq (car tup) chanbuf))
erc-modified-channels-alist))
(count (if tup (cadr tup)))
(face (if tup (cddr tup)))
- (channame (apply erc-status-sidebar-channel-format
- (buffer-name chanbuf) count face nil))
+ (face (if (or (not (buffer-live-p chanbuf))
+ (not (erc-server-process-alive chanbuf)))
+ `(shadow ,face)
+ face))
+ (channame (apply fmt-fn
+ (copy-sequence (funcall name-fn chanbuf))
+ count face nil))
(cnlen (length channame)))
(put-text-property 0 cnlen 'erc-buf chanbuf channame)
(put-text-property 0 cnlen 'mouse-face 'highlight channame)
(put-text-property
0 cnlen 'help-echo
"mouse-1: switch to buffer in other window" channame)
- (insert channame "\n")))))))
+ (funcall insert-fn channame chanbuf chanlist)))
+ (when winstart
+ (set-window-point window winstart)
+ (with-selected-window window (recenter 0)))
+ (when (and erc-status-sidebar-highlight-active-buffer
+ (marker-buffer erc-status-sidebar--active-marker))
+ (goto-char erc-status-sidebar--active-marker)
+ (require 'hl-line)
+ (unless hl-line-mode (hl-line-mode +1))
+ (hl-line-highlight))))))
(defun erc-status-sidebar-kill ()
"Close the ERC status sidebar and its buffer."
(interactive)
+ (when (and erc-bufbar-mode (not erc--module-toggle-prefix-arg))
+ (erc-bufbar-mode -1))
(ignore-errors (kill-buffer erc-status-sidebar-buffer-name)))
(defun erc-status-sidebar-click (event)
"Handle click EVENT in `erc-status-sidebar-mode-map'."
(interactive "e")
(save-excursion
- (let ((window (posn-window (event-end event)))
+ (let ((window (posn-window (event-start event)))
(pos (posn-point (event-end event))))
- (set-buffer (window-buffer window))
- (let ((buf (get-text-property pos 'erc-buf)))
- (when buf
- (select-window window)
- (switch-to-buffer-other-window buf))))))
+ ;; Current buffer is "ERC Status" and its window is selected
+ (cl-assert (eq major-mode 'erc-status-sidebar-mode))
+ (cl-assert (eq (selected-window) window))
+ (cl-assert (eq (window-buffer window) (current-buffer)))
+ (when-let ((buf (get-text-property pos 'erc-buf)))
+ ;; Option operates relative to last selected window
+ (select-window (get-mru-window nil nil 'not-selected))
+ (pop-to-buffer buf erc-status-sidebar-click-display-action)))))
+
+(defun erc-status-sidebar-scroll-up (lines)
+ "Scroll sidebar buffer's content LINES linse upward.
+If LINES is nil, scroll up a full screen's worth."
+ (interactive "P")
+ (let ((other-window-scroll-buffer (erc-status-sidebar-get-buffer)))
+ (scroll-other-window lines)))
+
+(defun erc-status-sidebar-scroll-down (lines)
+ "Scroll sidebar buffer's content LINES lines downward.
+If LINES is nil, scroll down a full screen's worth."
+ (interactive "P")
+ (let ((other-window-scroll-buffer (erc-status-sidebar-get-buffer)))
+ (scroll-other-window-down lines)))
+
+(defun erc-status-sidebar-recenter (arg)
+ "Recenter the status sidebar.
+Expect `erc-status-sidebar-highlight-active-buffer' to be non-nil
+and to be invoked in a buffer matching the line currently
+highlighted."
+ (interactive "P")
+ (let* ((buf (erc-status-sidebar-get-buffer))
+ (win (get-buffer-window buf)))
+ (with-current-buffer buf
+ (when (and erc-status-sidebar--active-marker
+ (marker-position erc-status-sidebar--active-marker))
+ (with-selected-window win
+ (goto-char erc-status-sidebar--active-marker)
+ (recenter arg t))))))
(defvar erc-status-sidebar-mode-map
(let ((map (make-sparse-keymap)))
@@ -268,13 +540,17 @@ erc-status-sidebar-set-window-preserve-size
Note that preserve status needs to be reset when the window is
manually resized, so `erc-status-sidebar-mode' adds this function
to the `window-configuration-change-hook'."
- (when (and (eq (selected-window) (erc-status-sidebar-get-window))
+ (when (and (eq (selected-window) (let (erc-status-sidebar-singular)
+ (erc-status-sidebar-get-window)))
(fboundp 'window-preserve-size))
(unless (eq (window-total-width) (window-min-size nil t))
(apply #'window-preserve-size (selected-window) t t nil))))
(define-derived-mode erc-status-sidebar-mode special-mode "ERC Sidebar"
"Major mode for ERC status sidebar."
+ ;; Users invoking M-x erc-status-sidebar-mode most likely expect to
+ ;; summon the module's minor-mode, `erc-bufbar-mode'.
+ :interactive nil
;; Don't scroll the buffer horizontally, if a channel name is
;; obscured then the window can be resized.
(setq-local auto-hscroll-mode nil)
--git a/test/lisp/erc/erc-scenarios-status-sidebar.el b/test/lisp/erc/erc-scenarios-status-sidebar.el
new file mode 100644
index 00000000000..aec61333e0b
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-status-sidebar.el
@@ -0,0 +1,93 @@
+;;; erc-scenarios-status-sidebar.el --- sidebar/speedbar -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022-2023 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 <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-scenarios-common)))
+
+(require 'erc-status-sidebar)
+
+
+(ert-deftest erc-scenarios-status-sidebar--bufbar ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/gapless-connect")
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-penalty erc-server-flood-penalty)
+ (erc-modules `(bufbar ,@erc-modules))
+ (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter)))
+
+ (ert-info ("Connect to two different endpoints")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester")
+ (funcall expect 10 "MOTD File is missing"))
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester")
+ (funcall expect 10 "marked as being away")))
+
+
+ (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#bar"))
+ (funcall expect 10 "was created on")
+ (funcall expect 2 "his second fit"))
+
+ (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#foo"))
+ (funcall expect 10 "was created on")
+ (funcall expect 2 "no use of him")
+ (ert-info ("Activity marker is in the right spot")
+ (let ((obuf (window-buffer))) ; *scratch*
+ (set-window-buffer (selected-window) "#foo")
+ (erc-d-t-wait-for 5
+ (when noninteractive
+ (erc-status-sidebar-refresh))
+ (with-current-buffer "*ERC Status*"
+ (and (marker-position erc-status-sidebar--active-marker)
+ (goto-char erc-status-sidebar--active-marker)
+ ;; The " [N]" suffix disappears because it's selected
+ (search-forward "#foo" (pos-eol) t))))
+ (set-window-buffer (selected-window) obuf))))
+
+ (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "*ERC Status*"))
+ (ert-info ("Hierarchy printed correctly")
+ (funcall expect 10 "barnet [")
+ (funcall expect 10 "#bar [")
+ (funcall expect 10 "foonet [")
+ (funcall expect 10 "#foo")))
+
+ (with-current-buffer "#foo"
+ (ert-info ("Core toggle and kill commands work")
+ ;; Avoid using API, e.g., `erc-status-sidebar-buffer-exists-p',
+ ;; etc. for testing commands that call those same functions.
+ (should (get-buffer-window "*ERC Status*"))
+ (erc-bufbar-mode -1)
+ (should-not (get-buffer-window "*ERC Status*"))
+ (erc-status-sidebar-kill)
+ (should-not (get-buffer "*ERC Status*"))))))
+
+;;; erc-scenarios-status-sidebar.el ends here
diff --git a/test/lisp/erc/resources/base/gapless-connect/foonet.eld b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
index 4ac4a3e5968..10b742fdb34 100644
--- a/test/lisp/erc/resources/base/gapless-connect/foonet.eld
+++ b/test/lisp/erc/resources/base/gapless-connect/foonet.eld
@@ -1,7 +1,7 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :foonet:changeme"))
-((nick 1 "NICK tester"))
-((user 1 "USER user 0 * :tester")
+((pass 10 "PASS :foonet:changeme"))
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
(0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
(0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.foonet.org 003 tester :This server was created Sun, 25 Apr 2021 11:28:28 UTC")
@@ -21,7 +21,7 @@
;; No mode answer
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #foo")
- (0 ":irc.foonet.org 353 tester = #foo :joe @mike tester")
+ (0 ":irc.foonet.org 353 tester = #foo :alice @bob tester")
(0 ":irc.foonet.org 366 tester #foo :End of /NAMES list.")
(0 ":***!znc@znc.in PRIVMSG #foo :Buffer Playback...")
(0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #foo :[07:02:41] bob: To-morrow is the joyful day, Audrey; to-morrow will we be married.")
--
2.40.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-5.6-Add-erc-status-sidebar-integration-to-erc-speedb.patch --]
[-- Type: text/x-patch, Size: 22647 bytes --]
From fd2ec89c40dd52322c8196c3653e06c937176bc7 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Thu, 4 May 2023 00:01:11 -0700
Subject: [PATCH 4/5] [5.6] Add erc-status-sidebar integration to erc-speedbar
* lisp/erc/erc-speedbar.el: Require `erc-button' atop file and don't
bother loading `dframe', which `speedbar' handles for us.
(erc-speedbar-hide-mode-topic): New option determining whether to hide
the mode and topic.
(erc-speedbar-my-nick-face): New option for determining face to use
when displaying user's current nick.
(erc-speedbar-browser): Call `erc-install-speedbar-variables'
explicitly and remove top-level `with-eval-after-load'.
(erc-speedbar-insert-target): Add parenthesized channel count after
channel name in server and channel views.
(erc-speedbar-expand-channel): Hide mode and topic depending on option
`erc-speedbar-hide-mode-topic' and pass buffer to
`erc-speedbar-insert-user'.
(erc-speedbar--nick-face-function): New internal function-interface
variable.
(erc-speedbar--highlight-self-and-ops): New function to serve as
default value for `erc-speedbar--nick-face-function'.
(erc-speedbar--on-click): Dispatch `erc-nick-popup' after trimming
status chars.
(erc-speedbar-insert-user): Revise doc string. Call
`erc-speedbar--nick-face-function' to determine face. Change
token for both expansion and on-click text props. Assign
`erc-speedbar--on-click' as the mouse handler for nick items.
(erc-speedbar-emulated-sidebar-width): New option to control width
of nicknames list window.
(erc-speedbar): Mention `erc-nickbar-mode' in group doc string.
(erc-speedbar--buffer-options): Variable to override options locally
in speedbar buffer.
(erc-speedbar--hidden-speedbar-frame): Add variable to hold original
`speedbar-frame' before spoofing by setting to selected frame
containing window showing ERC buffer.
(erc-speedbar--dframe-controlled) Add function to overwrite
`speedbar-frame-mode' as `dframe-controlled' in speedbar buffer.
(erc-speedbar--emulate-sidebar-set-window-preserve-size,
erc-speedbar--status-sidebar-mode--unhook): Add function
to ensure status sidebar is showing correctly and helper to
unregister from hook on teardown.
(erc-speedbar--emulate-sidebar): Add function to
control sidebar nicknames setup.
(erc-speedbar--toggle-nicknames-sidebar): Add toggle function
for sidebar or speedbar.
(erc-speedbar--ensure): Add helper function to show speedbar if its
hidden or create one if none exists.
(erc-nickbar-mode, erc-nickbar-enable, erc-nickbar-disable):
Add new module.
(erc-speedbar-toggle-nicknames-window-lock,
erc-speedbar-close-nicknames-window): Add commands to close speedbar
window and toggle its cyclability.
(erc-speedbar--compose-nicks-face): Add helper for nicks integration.
* test/lisp/erc/erc-scenarios-status-sidebar.el
(erc-scenarios-status-sidebar--nickbar): New test, unfortunately only
runs in terminals.
---
lisp/erc/erc-speedbar.el | 284 ++++++++++++++++--
| 76 +++++
2 files changed, 342 insertions(+), 18 deletions(-)
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index a9443e0ea17..21ad4c6f97a 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -32,20 +32,31 @@
;; update-channel, update-nick, remove-nick-from-channel, ...
;; * Use indicator-strings for op/voice
;; * Extract/convert face notes field from bbdb if available
+;; * Write tests that run in a term-mode subprocess
;;
;;; Code:
(require 'erc)
(require 'erc-goodies)
+(require 'erc-button)
(require 'speedbar)
-(condition-case nil (require 'dframe) (error nil))
;;; Customization:
(defgroup erc-speedbar nil
- "Integration of ERC in the Speedbar."
+ "Speedbar integration for ERC.
+To open an ERC-flavored speedbar in a separate frame, run the
+command `erc-speedbar-browser'. To use a window-based proxy
+instead, run \\[erc-nickbar-mode] in a connected ERC buffer or
+put `nickbar' in `erc-modules' before connecting. See Info
+node `(speedbar) Top' for more about the underlying integration."
:group 'erc)
+(defcustom erc-speedbar-nicknames-window-width 18
+ "Default width of the nicknames sidebar (in columns)."
+ :package-version '(ERC . "5.7")
+ :type 'integer)
+
(defcustom erc-speedbar-sort-users-type 'activity
"How channel nicknames are sorted.
@@ -56,6 +67,23 @@ erc-speedbar-sort-users-type
(const :tag "Sort users alphabetically" alphabetical)
(const :tag "Do not sort users" nil)))
+(defcustom erc-speedbar-hide-mode-topic 'headerline
+ "Hide mode and topic lines."
+ :package-version '(ERC . "5.7") ; FIXME sync on release
+ :type '(choice (const :tag "Always show" nil)
+ (const :tag "Always hide" t)
+ (const :tag "Omit when headerline visible" headerline)))
+
+(defcustom erc-speedbar-my-nick-face t
+ "A face to use for your nickname.
+When the value is t, ERC uses `erc-current-nick-face' if
+`erc-match' has been loaded and `erc-my-nick-face' otherwise.
+When using the `nicks' module, you can see your nick as it
+appears to others by coordinating with the option
+`erc-nicks-skip-faces'."
+ :package-version '(ERC . "5.7")
+ :type '(choice face (const :tag "Match or own input face" t)))
+
(defvar erc-speedbar-key-map nil
"Keymap used when in erc display mode.")
@@ -88,10 +116,6 @@ erc-speedbar-menu-items
(looking-at "[0-9]+: *.-. "))])
"Additional menu-items to add to speedbar frame.")
-;; Make sure our special speedbar major mode is loaded
-(with-eval-after-load 'speedbar
- (erc-install-speedbar-variables))
-
;;; ERC hierarchy display method
;;;###autoload
(defun erc-speedbar-browser ()
@@ -99,6 +123,7 @@ erc-speedbar-browser
This will add a speedbar major display mode."
(interactive)
(require 'speedbar)
+ (erc-install-speedbar-variables)
;; Make sure that speedbar is active
(speedbar-frame-mode 1)
;; Now, throw us into Info mode on speedbar.
@@ -169,12 +194,18 @@ erc-speedbar-channel-buttons
t)))))
(defun erc-speedbar-insert-target (buffer depth)
- (if (with-current-buffer buffer
- (erc-channel-p (erc-default-target)))
- (speedbar-make-tag-line
- 'bracket ?+ 'erc-speedbar-expand-channel buffer
- (buffer-name buffer) 'erc-speedbar-goto-buffer buffer nil
- depth)
+ (if (erc--target-channel-p (buffer-local-value 'erc--target buffer))
+ (progn
+ (speedbar-make-tag-line
+ 'bracket ?+ 'erc-speedbar-expand-channel buffer
+ (erc--target-string (buffer-local-value 'erc--target buffer))
+ 'erc-speedbar-goto-buffer buffer nil
+ depth)
+ (save-excursion
+ (forward-line -1)
+ (let ((table (buffer-local-value 'erc-channel-users buffer)))
+ (speedbar-add-indicator (format "(%d)" (hash-table-count table)))
+ (rx "(" (+ (any "0-9")) ")"))))
;; Query target
(speedbar-make-tag-line
nil nil nil nil
@@ -220,6 +251,13 @@ erc-speedbar-expand-channel
'angle ?i nil nil
(concat "Topic: " topic) nil nil nil
(1+ indent)))
+ (unless (pcase erc-speedbar-hide-mode-topic
+ ('nil 'show)
+ ('headerline (null erc-header-line-format)))
+ (save-excursion
+ (goto-char (point-max))
+ (forward-line (if (string= topic "") -1 -2))
+ (put-text-property (pos-bol) (point-max) 'invisible t)))
(let ((names (cond ((eq erc-speedbar-sort-users-type 'alphabetical)
(erc-sort-channel-users-alphabetically
(with-current-buffer channel
@@ -233,17 +271,52 @@ erc-speedbar-expand-channel
(when names
(speedbar-with-writable
(dolist (entry names)
- (erc-speedbar-insert-user entry ?+ (1+ indent))))))))))
+ (erc-speedbar-insert-user entry ?+ (1+ indent) channel)))))))))
((string-search "-" text)
(speedbar-change-expand-button-char ?+)
(speedbar-delete-subblock indent))
(t (error "Ooops... not sure what to do")))
(speedbar-center-buffer-smartly))
-(defun erc-speedbar-insert-user (entry exp-char indent)
+(defvar erc-speedbar--nick-face-function #'erc-speedbar--highlight-self-and-ops
+ "Function called when finding a face for fontifying nicks.
+Called with the proposed nick, the `erc-server-user', and the
+`erc-channel-user'. Should return any valid face, possibly
+composed or anonymous, or nil.")
+
+(defun erc-speedbar--highlight-self-and-ops (buffer user cuser)
+ "Highlight own nick and op'd users in the speedbar."
+ (with-current-buffer buffer
+ (if (erc-current-nick-p (erc-server-user-nickname user))
+ (pcase erc-speedbar-my-nick-face
+ ('t (if (featurep 'erc-match)
+ 'erc-current-nick-face
+ 'erc-my-nick-face))
+ (v v))
+ ;; FIXME overload `erc-channel-user-owner-p' and friends to
+ ;; accept an `erc-channel-user' object and replace this unrolled
+ ;; stuff with a single call to `erc-get-user-mode-prefix'.
+ (and cuser (or (erc-channel-user-owner cuser)
+ (erc-channel-user-admin cuser)
+ (erc-channel-user-op cuser)
+ (erc-channel-user-halfop cuser)
+ (erc-channel-user-voice cuser))
+ erc-button-nickname-face))))
+
+(defun erc-speedbar--on-click (nick sbtoken _indent)
+ ;; 0: finger, 1: name, 2: info, 3: buffer-name
+ (with-current-buffer (nth 3 sbtoken)
+ (erc-nick-popup (string-trim-left nick "[~&@%+]+"))))
+
+(defun erc-speedbar-insert-user (entry exp-char indent &optional buffer)
"Insert one user based on the channel member list ENTRY.
-EXP-CHAR is the expansion character to use.
-INDENT is the current indentation level."
+Expect EXP-CHAR to be the expansion character to use, INDENT the
+current indentation level, and BUFFER the associated channel or
+query buffer. Set the `speedbar-function' text property to
+`erc-speedbar--on-click', which is called with the formatted
+nick, a so-called \"token\", and the indent level. The token is
+a list of four items: the userhost, the GECOS, the current
+`erc-server-user' info slot, and the associated buffer."
(let* ((user (car entry))
(cuser (cdr entry))
(nick (erc-server-user-nickname user))
@@ -255,11 +328,12 @@ erc-speedbar-insert-user
(op (and cuser (erc-channel-user-op cuser)))
(nick-str (concat (if op "@" "") (if voice "+" "") nick))
(finger (concat login (when (or login host) "@") host))
- (sbtoken (list finger name info)))
+ (sbtoken (list finger name info (buffer-name buffer))))
(if (or login host name info) ; we want to be expandable
(speedbar-make-tag-line
'bracket ?+ 'erc-speedbar-expand-user sbtoken
- nick-str nil sbtoken nil
+ nick-str #'erc-speedbar--on-click sbtoken
+ (funcall erc-speedbar--nick-face-function buffer user cuser)
indent)
(when (equal exp-char ?-)
(forward-line -1)
@@ -357,6 +431,180 @@ erc-speedbar-item-info
(t
(message "%s" txt)))))
+
+;;;; Status-sidebar integration
+
+(defvar erc-status-sidebar-buffer-name)
+(declare-function erc-status-sidebar-set-window-preserve-size
+ "erc-status-sidebar" nil)
+(declare-function erc-status-sidebar-mode--unhook "erc-status-sidebar" nil)
+
+(defvar erc-speedbar--buffer-options
+ '((speedbar-update-flag . t)
+ (speedbar-use-images . nil)
+ (speedbar-hide-button-brackets-flag . t)))
+
+(defvar erc-speedbar--hidden-speedbar-frame nil)
+
+(defun erc-speedbar--emulate-sidebar-set-window-preserve-size ()
+ (let ((erc-status-sidebar-buffer-name (buffer-name speedbar-buffer))
+ (display-buffer-overriding-action
+ `(display-buffer-in-side-window
+ . ((side . right)
+ (window-width . ,erc-speedbar-nicknames-window-width)))))
+ (erc-status-sidebar-set-window-preserve-size)
+ (when-let ((window (get-buffer-window speedbar-buffer)))
+ (set-window-parameter window 'no-other-window nil)
+ (internal-show-cursor window t))))
+
+(defun erc-speedbar--status-sidebar-mode--unhook ()
+ "Remove hooks installed by `erc-status-sidebar-mode'."
+ (remove-hook 'window-configuration-change-hook
+ #'erc-speedbar--emulate-sidebar-set-window-preserve-size))
+
+(defun erc-speedbar--emulate-sidebar ()
+ (require 'erc-status-sidebar)
+ (cl-assert speedbar-frame)
+ (cl-assert (eq speedbar-buffer (current-buffer)))
+ (cl-assert (eq speedbar-frame (selected-frame)))
+ (setq erc-speedbar--hidden-speedbar-frame speedbar-frame
+ dframe-controlled #'erc-speedbar--dframe-controlled)
+ (add-hook 'window-configuration-change-hook
+ #'erc-speedbar--emulate-sidebar-set-window-preserve-size nil t)
+ (add-hook 'kill-buffer-hook
+ #'erc-speedbar--status-sidebar-mode--unhook nil t)
+ (with-current-buffer speedbar-buffer
+ (pcase-dolist (`(,var . ,val) erc-speedbar--buffer-options)
+ (set (make-local-variable var) val)))
+ (when (memq 'nicks erc-modules)
+ (with-current-buffer speedbar-buffer
+ (add-function :around (local 'erc-speedbar--nick-face-function)
+ #'erc-speedbar--compose-nicks-face))))
+
+(defun erc-speedbar--toggle-nicknames-sidebar (arg)
+ (let ((force (numberp arg)))
+ (if speedbar-buffer
+ (progn
+ (cl-assert (buffer-live-p speedbar-buffer))
+ (if (or (and force (< arg 0))
+ (and (not force) (get-buffer-window speedbar-buffer nil)))
+ (erc-speedbar-close-nicknames-window nil)
+ (when (or (not force) (>= arg 0))
+ (with-selected-frame speedbar-frame
+ (erc-speedbar--emulate-sidebar-set-window-preserve-size)))))
+ (when (or (not force) (>= arg 0))
+ (let ((speedbar-frame-parameters (backquote-list*
+ '(visibility . nil)
+ '(no-other-frame . t)
+ speedbar-frame-parameters))
+ (speedbar-after-create-hook #'erc-speedbar--emulate-sidebar))
+ (erc-speedbar-browser)
+ ;; If we put the remaining parts in the "create hook" along
+ ;; with everything else, the frame with `window-main-window'
+ ;; gets raised and steals focus if you've switched away from
+ ;; Emacs in the meantime.
+ (make-frame-invisible speedbar-frame)
+ (select-frame (setq speedbar-frame (previous-frame)))
+ (erc-speedbar--emulate-sidebar-set-window-preserve-size))))))
+
+(defun erc-speedbar--ensure (&optional force)
+ (when (or (erc-server-buffer) force)
+ (erc-speedbar--toggle-nicknames-sidebar +1)
+ (speedbar-enable-update)))
+
+;;;###autoload(autoload 'erc-nickbar-mode "erc-speedbar" nil t)
+(define-erc-module nickbar nil
+ "Show nicknames in a side window.
+When enabling, create a speedbar session if one doesn't exist and
+show its buffer in an `erc-status-sidebar' window instead of a
+separate frame. When disabling, close the window or, with a
+negative prefix arg, destroy the session.
+
+WARNING: it's suspected that this module may perform unwanted
+side effects like raising frames and/or stealing input focus. If
+you witness such an occurrence, and can reproduce it, please file
+a bug report with \\[erc-bug]."
+ ((add-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
+ (erc-speedbar--ensure)
+ (unless (or erc--updating-modules-p
+ (and-let* ((speedbar-buffer)
+ (win (get-buffer-window speedbar-buffer 'all-frames))
+ ((eq speedbar-frame (window-frame win))))))
+ (if speedbar-buffer
+ (erc-speedbar--ensure 'force)
+ (cl-assert (not (derived-mode-p 'erc-mode)))
+ (setq erc-nickbar-mode nil)
+ (user-error "Cannot initialize `%s' in a non-ERC buffer"
+ 'erc-nickbar-mode))))
+ ((remove-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
+ (speedbar-disable-update)
+ (erc-speedbar--toggle-nicknames-sidebar -1)
+ (when-let* ((arg erc--module-toggle-prefix-arg)
+ ((numberp arg))
+ ((< arg 0)))
+ (erc-speedbar-close-nicknames-window 'kill))))
+
+(defun erc-speedbar--dframe-controlled (arg)
+ (when (and erc-speedbar--hidden-speedbar-frame (numberp arg) (< arg 0))
+ (when erc-nickbar-mode
+ (erc-nickbar-mode -1))
+ (setq speedbar-frame erc-speedbar--hidden-speedbar-frame
+ erc-speedbar--hidden-speedbar-frame nil)
+ ;; It's unknown whether leaving the frame invisible interferes
+ ;; with the upstream teardown procedure.
+ (when (display-graphic-p)
+ (make-frame-visible speedbar-frame))
+ (speedbar-frame-mode arg)
+ (when speedbar-buffer
+ (kill-buffer speedbar-buffer)
+ (setq speedbar-buffer nil))))
+
+(defun erc-speedbar-toggle-nicknames-window-lock ()
+ "Toggle whether nicknames window is selectable with \\[other-window]."
+ (interactive)
+ (unless erc-nickbar-mode
+ (user-error "`erc-nickbar-mode' inactive"))
+ (when-let* ((window (get-buffer-window speedbar-buffer)))
+ (let ((val (window-parameter window 'no-other-window)))
+ (set-window-parameter window 'no-other-window (not val))
+ (message "nick-window: %s" (if val "selectable" "protected")))))
+
+(defun erc-speedbar-close-nicknames-window (kill)
+ (interactive "P")
+ (if kill
+ (with-current-buffer speedbar-buffer
+ (dframe-close-frame)
+ (cl-assert (not erc-nickbar-mode))
+ (setq erc-speedbar--hidden-speedbar-frame nil))
+ (dolist (window (get-buffer-window-list speedbar-buffer nil t))
+ (unless (frame-root-window-p window)
+ (when erc-speedbar--hidden-speedbar-frame
+ (cl-assert (not (eq (window-frame window)
+ erc-speedbar--hidden-speedbar-frame))))
+ (delete-window window)))))
+
+
+;;;; Nicks integration
+
+(defvar erc-nicks--phony-face)
+(declare-function erc-nicks--highlight "erc-nicks" (nick-object))
+
+(defun erc-speedbar--compose-nicks-face (orig buffer user cuser)
+ (require 'erc-nicks)
+ (let ((rv (funcall orig buffer user cuser)))
+ (if-let* ((nobj (make-erc-button--nick
+ :downcased (erc-downcase (erc-server-user-nickname user))
+ :user user
+ :cuser cuser))
+ (erc-nicks--phony-face (or rv t))
+ (nobj (with-current-buffer buffer
+ (erc-nicks--highlight nobj)))
+ (face (erc-button--nick-erc-button-nickname-face nobj))
+ ((not (eq face erc-button-nickname-face))))
+ (cons face (ensure-list rv))
+ rv)))
+
+
(provide 'erc-speedbar)
;;; erc-speedbar.el ends here
;;
--git a/test/lisp/erc/erc-scenarios-status-sidebar.el b/test/lisp/erc/erc-scenarios-status-sidebar.el
index aec61333e0b..6ac1821ebb7 100644
--- a/test/lisp/erc/erc-scenarios-status-sidebar.el
+++ b/test/lisp/erc/erc-scenarios-status-sidebar.el
@@ -90,4 +90,80 @@ erc-scenarios-status-sidebar--bufbar
(erc-status-sidebar-kill)
(should-not (get-buffer "*ERC Status*"))))))
+;; No need to pollute the global obarray since we can't currently run
+;; this on EMBA (it requires a terminal). Please try running this
+;; test interactively with both graphical Emacs and non.
+(declare-function erc-nickbar-mode "erc-speedbar" (arg))
+(declare-function erc-speedbar-close-nicknames-window "erc-speedbar" (kill))
+(declare-function speedbar-timer-fn "speedbar" nil)
+(defvar erc-nickbar-mode)
+(defvar speedbar-buffer)
+
+(ert-deftest erc-scenarios-status-sidebar--nickbar ()
+ :tags '(:unstable :expensive-test)
+ (when noninteractive (ert-skip "Interactive only"))
+
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/gapless-connect")
+ (erc-server-flood-penalty 0.1)
+ (erc-server-flood-penalty erc-server-flood-penalty)
+ (erc-modules `(nickbar ,@erc-modules))
+ (dumb-server (erc-d-run "localhost" t 'foonet 'barnet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter)))
+
+ (ert-info ("Connect to two different endpoints")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "foonet:changeme"
+ :full-name "tester")
+ (funcall expect 10 "MOTD File is missing"))
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "barnet:changeme"
+ :full-name "tester")
+ (funcall expect 10 "marked as being away")))
+
+ (erc-d-t-wait-for 20 (get-buffer "#bar"))
+ (with-current-buffer (pop-to-buffer "#bar")
+ (funcall expect 10 "was created on")
+ (funcall expect 2 "his second fit")
+ (erc-d-t-wait-for 10 (and speedbar-buffer (get-buffer speedbar-buffer)))
+ (speedbar-timer-fn)
+ (with-current-buffer speedbar-buffer
+ (funcall expect 10 "#bar (3)")
+ (funcall expect 10 '(| "@mike" "joe"))
+ (funcall expect 10 '(| "@mike" "joe"))
+ (funcall expect 10 "tester")))
+
+ (erc-d-t-wait-for 20 (get-buffer "#foo"))
+ (with-current-buffer (pop-to-buffer "#foo")
+ (delete-other-windows)
+ (funcall expect 10 "was created on")
+ (funcall expect 2 "no use of him")
+ (speedbar-timer-fn)
+ (with-current-buffer speedbar-buffer
+ (funcall expect 10 "#foo (3)")
+ (funcall expect 10 '(| "alice" "@bob"))
+ (funcall expect 10 '(| "alice" "@bob"))
+ (funcall expect 10 "tester")))
+
+ (with-current-buffer "#foo"
+ (ert-info ("Core toggle and kill commands work")
+ ;; Avoid using API, e.g., `erc-status-sidebar-buffer-exists-p',
+ ;; etc. for testing commands that call those same functions.
+ (erc-nickbar-mode -1)
+ (should-not (and speedbar-buffer
+ (get-buffer-window speedbar-buffer)))
+ (erc-nickbar-mode +1)
+ (should (and speedbar-buffer
+ (get-buffer-window speedbar-buffer)))
+ (should (get-buffer " SPEEDBAR"))
+ (erc-speedbar-close-nicknames-window 'kill)
+ (should-not (get-buffer " SPEEDBAR"))
+ (should-not erc-nickbar-mode)
+ (should-not (cdr (frame-list)))))))
+
;;; erc-scenarios-status-sidebar.el ends here
--
2.40.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-5.6-Add-new-ERC-modules-bufbar-and-nickbar.patch --]
[-- Type: text/x-patch, Size: 4680 bytes --]
From 93f31ce4e062acd8ea6e87ea8023707b9e4b383b Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Thu, 4 May 2023 00:01:11 -0700
Subject: [PATCH 5/5] [5.6] Add new ERC modules bufbar and nickbar
* doc/misc/erc.texi: Add `bufbar' and `nickbar' to known modules.
* erc/ERC-NEWS: Mention erc-status-sidebar and erc-speedbar
improvements.
* lisp/erc/erc.el (erc-modules): Add `bufbar' and `nickbar' to
selection of offered modules.
* test/lisp/erc/erc-tests.el (erc-tests--modules): Add `bufbar' and
`nickbar'.
---
doc/misc/erc.texi | 9 +++++++++
etc/ERC-NEWS | 16 ++++++++++++++++
lisp/erc/erc.el | 2 ++
test/lisp/erc/erc-tests.el | 4 ++--
4 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index f7036e57638..7c625c2fd02 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -418,6 +418,10 @@ Modules
@item bbdb
Integrate with the Big Brother Database
+@cindex modules, bufbar
+@item bufbar
+List ERC buffers belonging to a live connection in a side window
+
@cindex modules, button
@item button
Buttonize URLs, nicknames, and other text
@@ -463,6 +467,11 @@ Modules
@item nicks
Automatically colorize nicks
+@cindex modules, nickbar
+@item nickbar
+List participating nicks for the current target buffer in a side
+window
+
@cindex modules, noncommands
@item noncommands
Don't display non-IRC commands after evaluation
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 41af8b88277..6922ae22482 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -72,6 +72,22 @@ widget has been an age-old annoyance for new users. Previously
ineffective, this method now actually works, but it also admonishes
users to edit the 'erc-modules' widget instead.
+** ERC's status-sidebar now has an accompanying module.
+Users can now add 'bufbar' to 'erc-modules' to achieve the same effect
+as toggling 'erc-status-sidebar-open' manually at the start of an IRC
+session. The module has also been outfitted to show channels and
+queries under their respective servers by default. To avoid
+confusion, the major mode used for the sidebar buffer itself,
+'erc-status-sidebar-mode', is no longer available interactively.
+
+** A new spin on a classic integration in erc-speedbar.
+Add 'nickbar' to 'erc-modules' to spawn a dynamically updating side
+window listing all the users in any target buffer. It's powered by
+the same speedbar.el integration you've always known, except this
+one's optionally accessible from the keyboard, just like any other
+side window. Hit '<RET>' over a nick to spawn a "/QUERY" or a
+"Lastlog" (Occur) session. See 'erc-nickbar-mode' for more.
+
** The option 'erc-timestamp-use-align-to' is more versatile.
While this option has always offered to right-align stamps via the
'display' text property, it's now more effective at doing so when set
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 5a3b312b53b..2f26985f74d 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -2006,6 +2006,7 @@ erc-modules
:greedy t
(const :tag "autoaway: Set away status automatically" autoaway)
(const :tag "autojoin: Join channels automatically" autojoin)
+ (const :tag "bufbar: Show ERC buffers in a side window" bufbar)
(const :tag "button: Buttonize URLs, nicknames, and other text" button)
(const :tag "capab: Mark unidentified users on servers supporting CAPAB"
capab-identify)
@@ -2026,6 +2027,7 @@ erc-modules
move-to-prompt)
(const :tag "netsplit: Detect netsplits" netsplit)
(const :tag "networks: Provide data about IRC networks" networks)
+ (const :tag "nickbar: Show nicknames in a dyamic side window" nickbar)
(const :tag "nicks: Uniquely colorize nicknames in target buffers" nicks)
(const :tag "noncommands: Don't display non-IRC commands after evaluation"
noncommands)
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index de472527bde..4432dc58082 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1951,9 +1951,9 @@ erc-handle-irc-url
(kill-buffer "#chan")))
(defconst erc-tests--modules
- '( autoaway autojoin button capab-identify completion dcc fill identd
+ '( autoaway autojoin bufbar button capab-identify completion dcc fill identd
imenu irccontrols keep-place list log match menu move-to-prompt netsplit
- networks nicks noncommands notifications notify page readonly
+ networks nickbar nicks noncommands notifications notify page readonly
replace ring sasl scrolltobottom services smiley sound
spelling stamp track truncate unmorse xdcc))
--
2.40.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
@ 2023-05-19 20:47 ` J.P.
2023-07-14 2:07 ` J.P.
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-05-19 20:47 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
Screenshots (modus themed but otherwise vanilla):
graphical:
https://debbugs.gnu.org/cgi/bugreport.cgi?filename=erc-sidebar-graphical.png;bug=63595;att=1;msg=6
terminal:
https://debbugs.gnu.org/cgi/bugreport.cgi?msg=6;att=2;filename=erc-sidebar-terminal.png;bug=63595
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
2023-05-19 20:47 ` J.P.
@ 2023-07-14 2:07 ` J.P.
2023-07-25 13:32 ` J.P.
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-07-14 2:07 UTC (permalink / raw)
To: 63595-done; +Cc: emacs-erc
A more refined version of these changes has been installed [1]. However,
they're more likely than most to be imperfect due to their relative
complexity and the lack of effective tests, not to mention the kludgy
nature of the new speedbar module (whose frame we're hiding in favor of
showing its buffer in a side window). Hopefully, these new features will
lead to increased use, which should help exorcise the worst of their
demons.
Closing (for now).
[1] https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=ded35c2d
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=3c70e85d
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
2023-05-19 20:47 ` J.P.
2023-07-14 2:07 ` J.P.
@ 2023-07-25 13:32 ` J.P.
[not found] ` <87o7k0yv4b.fsf@neverwas.me>
` (8 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-07-25 13:32 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
[-- Attachment #1: Type: text/plain, Size: 2237 bytes --]
This may come as a shock, but problems exist in the `bufbar' changes
recently introduced (by me) to erc-status-sidebar.el.
The first involves the new boolean option `erc-status-sidebar-singular'.
No matter what its doc string says, the purpose of this option remains
difficult to describe and its behavior hard to predict. This makes it
only really practical as an internal flag, which is what it should have
been from the get-go and how it's been repurposed in the attached patch.
Initially, this option was intended to alter the behavior of the
minor-mode toggle `erc-bufbar-mode' so that when the option is nil,
toggling the mode in a frame where the sidebar is hidden would summon
it, regardless of the value of the mode's variable. This kind of extreme
DWIM'ness may suit normal, standalone minor modes, but users likely
expect mode toggles for global ERC modules to work more or less
traditionally.
A somewhat related problem stems from my altering the original behavior
of existing status-sidebar commands, like `erc-status-sidebar-open', to
accommodate and promote `erc-bufbar-mode' as a unified entry point. In
retrospect, that probably threatens to anger the rare person who's
become accustomed to those commands over the past couple years and who
may not be interested in the new module at all (for whatever reason).
I've attempted to rectify this in the attached patch so that the newer
behavior only takes effect when `erc-bufbar-mode' is active. This means
users of the module must now issue an M-x erc-status-sidebar-open RET to
see the sidebar in (additional) frames that don't yet have one, but
non-module users will still only ever encounter a single sidebar
instance in an Emacs session.
The last issue involves the sidebar intermittently clobbering the
window's scroll position. I've tried to eradicate this while also
improving the overall responsiveness by having it refresh when users
select another window. Basically, updates were initially tethered to
mode-line changes, which often left users with the wrong buffer
highlighted whenever updates were few and far between. Although this is
now much improved, the change likely adds some overhead, so I've
included an escape hatch while we investigate further.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-5.6-Simplify-multi-frame-behavior-of-erc-bufbar-mode.patch --]
[-- Type: text/x-patch, Size: 13129 bytes --]
From 7b47f05fbc7093db798f2ee421a3082c9febc363 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Sun, 23 Jul 2023 23:09:42 -0700
Subject: [PATCH 1/2] [5.6] Simplify multi-frame behavior of erc-bufbar-mode
* lisp/erc/erc-status-sidebar.el (erc-status-sidebar-singular,
erc-status-sidebar--singular-p): Replace public option, new in ERC
5.6, with the latter, an internal state flag.
(erc-status-sidebar-get-window): Use new name for option turned
ordinary variable `erc-status-sidebar--singular-p'.
(erc-status-sidebar-close): Add comment.
(erc-status-sidebar--open): New function containing the old body of
`erc-status-sidebar-open'.
(erc-bufbar-mode, erc-bufbar-enable, erc-bufbar-disable): Update
variable names. When disabling, always close window on all frames.
Don't set mode variable to nil when enabling outside of an `erc-mode'
buffer. This may have made some practical sense but was illogical
since the `erc--setup-buffer-hook' was left as is, meaning the
activation state was still partially enabled.
(erc-status-sidebar-open): Move definition to lower down in file,
after `erc-bufbar-mode'. When `erc-bufbar-mode' is active, always
create a sidebar if needed, even when another frame is already
displaying one.
(erc-status-toggle-sidebar): When `erc-bufbar-mode' is disabled,
revert to pre-5.6 behavior, ignoring bug fixes. When the module is
enabled, adopt new behavior of always ensuring the current frame shows
a sidebar, even if another frame already has one.
(erc-status-sidebar-refresh): Save and restore window start in all
windows showing status sidebar buffer after refreshing. Update
option and variable names.
(erc-status-sidebar--refresh-unless-input): New function to run
`erc-status-sidebar-refresh' unless input is pending or the selected
window's buffer is a minibuffer.
(erc-status-sidebar--post-refresh): Call `erc-status-sidebar-refresh'
wrapper `erc-status-sidebar--refresh-unless-input' instead.
(erc-status-sidebar-refresh-triggers): Add doc string, noting that the
variable is set locally when the option
`erc-status-sidebar-highlight-active-buffer' is non-nil.
(erc-status-sidebar--highlight-refresh-triggers): New variable
containing additional triggers enabled when the option
`erc-status-highlight-active-buffer' is non-nil.
(erc-status-sidebar-set-window-preserve-size): Update var name to
`erc-status-sidebar--singular-p'.
(erc-status-sidebar-mode): Run `erc-status-sidebar--post-refresh' on
`window-selection-change-functions' globally when highlighting active
buffers. (bug#63595)
---
| 107 +++++++++++++++++++++------------
1 file changed, 70 insertions(+), 37 deletions(-)
--git a/lisp/erc/erc-status-sidebar.el b/lisp/erc/erc-status-sidebar.el
index b8bd7b0065e..a82c846ff1a 100644
--- a/lisp/erc/erc-status-sidebar.el
+++ b/lisp/erc/erc-status-sidebar.el
@@ -45,8 +45,8 @@
;; Use M-x erc-status-sidebar-kill RET to kill the sidebar buffer and
;; close the sidebar on all frames.
-;; In addition to the commands above, you can also try the all-in-one,
-;; "DWIM" command, `erc-bufbar-mode'. See its doc string for usage.
+;; In addition to the commands above, you can also try the all-in-one
+;; entry point `erc-bufbar-mode'. See its doc string for usage.
;; If you want the status sidebar enabled whenever you use ERC, add
;; `bufbar' to `erc-modules'. Note that this library also has a major
@@ -130,8 +130,11 @@ erc-status-sidebar-style
`erc-status-sidebar-pad-hierarchy'
for the above-mentioned purposes. ERC also accepts a list of
-functions to preform these roles a la carte. See doc strings for
-a description of their expected arguments and return values."
+functions to preform these roles a la carte. Since the members
+of the above sets aren't really interoperable, we don't offer
+them here as customization choices, but you can still specify
+them manually. See doc strings for a description of their
+expected arguments and return values."
:package-version '(ERC . "5.6") ; FIXME sync on release
:type '(choice (const channels-only)
(const all-mixed)
@@ -158,10 +161,12 @@ erc-status-sidebar-click-display-action
:key-type symbol
:value-type (sexp :tag "Value")))))
-(defcustom erc-status-sidebar-singular t
- "Whether to show the sidebar on all frames or just one (default)."
- :package-version '(ERC . "5.6") ; FIXME sync on release
- :type 'boolean)
+(defvar erc-status-sidebar--singular-p t
+ "Whether to restrict the sidebar to a single frame.
+This variable only affects `erc-bufbar-mode'. Disabling it does
+not arrange for automatically showing the sidebar in all frames.
+Rather, disabling it allows for displaying the sidebar in the
+selected frame even if it's already showing in some other frame.")
(defvar hl-line-mode)
(declare-function hl-line-highlight "hl-line" nil)
@@ -178,7 +183,7 @@ erc-status-sidebar-get-window
If NO-CREATION is non-nil, the window is not created."
(let ((sidebar-window (get-buffer-window erc-status-sidebar-buffer-name
- erc-status-sidebar-singular)))
+ erc-status-sidebar--singular-p)))
(unless (or sidebar-window no-creation)
(with-current-buffer (erc-status-sidebar-get-buffer)
(setq-local vertical-scroll-bar nil))
@@ -214,7 +219,7 @@ erc-status-sidebar-close
containing it on the current frame is closed. See
`erc-status-sidebar-kill'."
(interactive "P")
- (mapcar #'delete-window
+ (mapcar #'delete-window ; FIXME use `mapc'.
(get-buffer-window-list (erc-status-sidebar-get-buffer)
nil (if all-frames t))))
@@ -223,10 +228,8 @@ erc-status-sidebar-writable
`(let ((buffer-read-only nil))
,@body))
-;;;###autoload
-(defun erc-status-sidebar-open ()
- "Open or create a sidebar."
- (interactive)
+(defun erc-status-sidebar--open ()
+ "Maybe open the sidebar, respecting `erc-status-sidebar--singular-p'."
(save-excursion
(if (erc-status-sidebar-buffer-exists-p)
(erc-status-sidebar-get-window)
@@ -237,11 +240,15 @@ erc-status-sidebar-open
;;;###autoload(autoload 'erc-bufbar-mode "erc-status-sidebar" nil t)
(define-erc-module bufbar nil
"Show `erc-track'-like activity in a side window.
-When enabling, show the sidebar immediately if called from a
-connected ERC buffer. Otherwise, arrange for doing so on connect
-or whenever next displaying a new ERC buffer. When disabling,
-hide the status window if it's showing. With a negative prefix
-arg, also shutdown the session."
+When enabling, show the sidebar immediately in the current frame
+if called from a connected ERC buffer. Otherwise, arrange for
+doing so on connect or whenever next displaying a new ERC buffer.
+When disabling, hide the status window in all frames. With a
+negative prefix arg, also shutdown the session. Normally, this
+module only allows one sidebar window in an Emacs session. To
+override this, use `erc-status-sidebar-open' to force creation
+and `erc-status-sidebar-close' to hide a single instance on the
+current frame only."
((unless erc-track-mode
(unless (memq 'track erc-modules)
(erc--warn-once-before-connect 'erc-bufbar-mode
@@ -249,30 +256,38 @@ bufbar
" This will affect \C-]all\C-] ERC sessions."
" Add `track' to `erc-modules' to silence this message."))
(erc-track-mode +1))
- (add-hook 'erc--setup-buffer-hook #'erc-status-sidebar-open)
+ (add-hook 'erc--setup-buffer-hook #'erc-status-sidebar--open)
(unless erc--updating-modules-p
(if (erc-with-server-buffer erc-server-connected)
- (erc-status-sidebar-open)
- (setq erc-bufbar-mode nil)
+ (erc-status-sidebar--open)
(when (derived-mode-p 'erc-mode)
(erc-error "Not initializing `erc-bufbar-mode' in %s"
(current-buffer))))))
- ((remove-hook 'erc--setup-buffer-hook #'erc-status-sidebar-open)
- (erc-status-sidebar-close erc-status-sidebar-singular)
+ ((remove-hook 'erc--setup-buffer-hook #'erc-status-sidebar--open)
+ (erc-status-sidebar-close 'all-frames)
(when-let ((arg erc--module-toggle-prefix-arg)
((numberp arg))
((< arg 0)))
(erc-status-sidebar-kill))))
+;;;###autoload
+(defun erc-status-sidebar-open ()
+ "Open or create a sidebar window in the current frame.
+When `erc-bufbar-mode' is active, do this even if one already
+exists in another frame."
+ (interactive)
+ (let ((erc-status-sidebar--singular-p (not erc-bufbar-mode)))
+ (erc-status-sidebar--open)))
+
;;;###autoload
(defun erc-status-sidebar-toggle ()
"Toggle the sidebar open/closed on the current frame.
-Do this regardless of `erc-status-sidebar-singular'."
+When opening and `erc-bufbar-mode' is active, create a sidebar
+even if one already exists in another frame."
(interactive)
(if (get-buffer-window erc-status-sidebar-buffer-name nil)
(erc-status-sidebar-close)
- (let (erc-status-sidebar-singular)
- (erc-status-sidebar-open))))
+ (erc-status-sidebar-open)))
(defun erc-status-sidebar-get-channame (buffer)
"Return name of BUFFER with all leading \"#\" characters removed."
@@ -413,11 +428,10 @@ erc-status-sidebar-refresh
erc-status-sidebar-pad-hierarchy))
(v v)))
(chanlist (apply sort-fn (funcall list-fn nil) nil))
- (window nil)
- (winstart nil))
+ (windows nil))
(with-current-buffer (erc-status-sidebar-get-buffer)
- (setq window (get-buffer-window nil erc-status-sidebar-singular)
- winstart (and window (window-start window)))
+ (dolist (window (get-buffer-window-list nil nil t))
+ (push (cons window (window-start window)) windows))
(erc-status-sidebar-writable
(delete-region (point-min) (point-max))
(goto-char (point-min))
@@ -443,9 +457,10 @@ erc-status-sidebar-refresh
0 cnlen 'help-echo
"mouse-1: switch to buffer in other window" channame)
(funcall insert-fn channame chanbuf chanlist)))
- (when winstart
- (set-window-point window winstart)
- (with-selected-window window (recenter 0)))
+ (when windows
+ (pcase-dolist (`(,window . ,winstart) windows)
+ (set-window-point window winstart)
+ (with-selected-window window (recenter 0))))
(when (and erc-status-sidebar-highlight-active-buffer
(marker-buffer erc-status-sidebar--active-marker))
(goto-char erc-status-sidebar--active-marker)
@@ -519,14 +534,28 @@ erc-status-sidebar-refresh-triggers
erc-kill-server-hook
erc-kick-hook
erc-disconnected-hook
- erc-quit-hook))
+ erc-quit-hook)
+ "Hooks to refresh the sidebar on.
+This may be set locally in the status-sidebar buffer under
+various conditions, like when the option
+`erc-status-sidebar-highlight-active-buffer' is non-nil.")
+
+(defvar erc-status-sidebar--highlight-refresh-triggers
+ '(window-selection-change-functions)
+ "Triggers enabled with `erc-status-sidebar-highlight-active-buffer'.")
+
+(defun erc-status-sidebar--refresh-unless-input ()
+ "Run `erc-status-sidebar-refresh' unless there are unread commands.
+Also abstain when the user is interacting with the minibuffer."
+ (unless (or (input-pending-p) (minibuffer-window-active-p (selected-window)))
+ (erc-status-sidebar-refresh)))
(defun erc-status-sidebar--post-refresh (&rest _ignore)
"Schedule sidebar refresh for execution after command stack is cleared.
Ignore arguments in IGNORE, allowing this function to be added to
hooks that invoke it with arguments."
- (run-at-time 0 nil #'erc-status-sidebar-refresh))
+ (run-at-time 0 nil #'erc-status-sidebar--refresh-unless-input))
(defun erc-status-sidebar-mode--unhook ()
"Remove hooks installed by `erc-status-sidebar-mode'."
@@ -541,7 +570,7 @@ erc-status-sidebar-set-window-preserve-size
Note that preserve status needs to be reset when the window is
manually resized, so `erc-status-sidebar-mode' adds this function
to the `window-configuration-change-hook'."
- (when (and (eq (selected-window) (let (erc-status-sidebar-singular)
+ (when (and (eq (selected-window) (let (erc-status-sidebar--singular-p)
(erc-status-sidebar-get-window)))
(fboundp 'window-preserve-size))
(unless (eq (window-total-width) (window-min-size nil t))
@@ -563,6 +592,10 @@ erc-status-sidebar-mode
(add-hook 'window-configuration-change-hook
#'erc-status-sidebar-set-window-preserve-size nil t)
+ (when erc-status-sidebar-highlight-active-buffer
+ (setq-local erc-status-sidebar-refresh-triggers
+ `(,@erc-status-sidebar--highlight-refresh-triggers
+ ,@erc-status-sidebar-refresh-triggers)))
(dolist (hk erc-status-sidebar-refresh-triggers)
(add-hook hk #'erc-status-sidebar--post-refresh))
--
2.41.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <87o7k0yv4b.fsf@neverwas.me>
@ 2023-07-29 0:00 ` J.P.
0 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-07-29 0:00 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
"J.P." <jp@neverwas.me> writes:
> This may come as a shock, but problems exist in the `bufbar' changes
> recently introduced (by me) to erc-status-sidebar.el.
I've attempted to address these issues in
deb74de4 Simplify multi-frame behavior in erc-bufbar-mode
Thanks.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
` (3 preceding siblings ...)
[not found] ` <87o7k0yv4b.fsf@neverwas.me>
@ 2023-08-16 14:04 ` J.P.
[not found] ` <87jztvdqxh.fsf@neverwas.me>
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-08-16 14:04 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
[-- Attachment #1: Type: text/plain, Size: 665 bytes --]
Some issues with the `nickbar' module have surfaced that may be related
to another issue involving unexpected connection loss. Thanks to Corwin
for reporting this.
It appears that the teardown logic in `erc-nickbar-disable' was calling
`dframe-close-frame', `speedbar-set-timer', and `speedbar-timer-fn'
repeatedly and unnecessarily, which resulted in redundant scheduling of
the same update timer (there should only be one per speedbar instance).
Other problems involving the variable `speedbar-update-flag' were also
discovered, as well as a possible bug in `dframe-set-timer', which I'll
leave for future people familiar with dframe to deal with if necessary.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-5.6-Prevent-unwanted-recursion-in-erc-nickbar-disabl.patch --]
[-- Type: text/x-patch, Size: 13057 bytes --]
From 645af24230bdf9032f1f0d79ff7e62f5ecf7b72a Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Tue, 15 Aug 2023 21:14:07 -0700
Subject: [PATCH] [5.6] Prevent unwanted recursion in erc-nickbar-disable
* lisp/erc/erc-speedbar.el (erc-status-sidebar-mode--unhook): Remove
forward declaration.
(erc-speedbar--toggle-nicknames-sidebar): Inline
`erc-speedbar-close-nicknames-window'. Don't call
`erc-speedbar-browser' to avoid excess timers being added.
(erc-speedbar--ensure): Inline `speedbar-enable-update' to avoid
unneeded call to `speedbar-set-timer', and ensure it runs in
`speedbar-buffer'.
(erc-speedbar--shutting-down-p): New flag variable to avoid recursive
calls to `dframe-close-frame' and friends.
(erc-nickbar-mode, erc-nickbar-enable, erc-nickbar-disable): Move
logic formerly performed by `speedbar-disable-update' to
`erc-speedbar--toggle-nicknames-sidebar'. When disabling, guard
against recursive calls to `dframe-close-frame' and friends.
(erc-speedbar--get-timers): New helper function.
(erc-speedbar--dframe-controlled): Bind
`erc-speedbar--shutting-down-p' flag non-nil around call to
`erc-nickbar-mode'. Remove excess timer left behind due to
incompatible behavior from `dframe-close-frame'. Let caller kill
buffer.
(erc-speedbar-close-nicknames-window): Remove unused command, new in
ERC 5.6 and Emacs 30.
(erc-speedbar--destroy-nicknames-frame): New function to perform
common teardown.
* test/lisp/erc/erc-scenarios-status-sidebar.el
(erc-speedbar-close-nicknames-window): Remove forward declaration.
(erc-speedbar--get-timers): Add forward declaration.
(erc-scenarios-status-sidebar--nickbar): Fix faulty expectations of
desired behavior when disabling module. Ensure timers canceled.
* test/lisp/erc/resources/erc-scenarios-common.el
(erc-scenarios-common--make-bindings): Shadow `timer-idle-list' to
avoid polluting global test environment with stray timers.
(Bug#63595)
---
lisp/erc/erc-speedbar.el | 112 +++++++++++-------
| 13 +-
.../erc/resources/erc-scenarios-common.el | 1 +
3 files changed, 79 insertions(+), 47 deletions(-)
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index f5fbaac767d..88400f034ba 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -439,7 +439,6 @@ erc-track--switch-fallback-blockers
(defvar erc-status-sidebar-buffer-name)
(declare-function erc-status-sidebar-set-window-preserve-size
"erc-status-sidebar" nil)
-(declare-function erc-status-sidebar-mode--unhook "erc-status-sidebar" nil)
(defvar erc-speedbar--buffer-options
'((speedbar-update-flag . t)
@@ -490,36 +489,64 @@ erc-speedbar--toggle-nicknames-sidebar
(cl-assert (buffer-live-p speedbar-buffer))
(if (or (and force (< arg 0))
(and (not force) (get-buffer-window speedbar-buffer nil)))
- (erc-speedbar-close-nicknames-window nil)
+ ;; Close associated windows and stop updating but leave timer.
+ (progn
+ (dolist (window (get-buffer-window-list speedbar-buffer nil t))
+ (unless (frame-root-window-p window)
+ (when erc-speedbar--hidden-speedbar-frame
+ (cl-assert
+ (not (eq (window-frame window)
+ erc-speedbar--hidden-speedbar-frame))))
+ (delete-window window)))
+ (with-current-buffer speedbar-buffer
+ (setq speedbar-update-flag nil)
+ (speedbar-set-mode-line-format)))
(when (or (not force) (>= arg 0))
(with-selected-frame speedbar-frame
(erc-speedbar--emulate-sidebar-set-window-preserve-size)))))
- (when (or (not force) (>= arg 0))
- (let ((speedbar-frame-parameters (backquote-list*
- '(visibility . nil)
- '(no-other-frame . t)
- speedbar-frame-parameters))
- (speedbar-after-create-hook #'erc-speedbar--emulate-sidebar))
- (erc-speedbar-browser)
- ;; If we put the remaining parts in the "create hook" along
- ;; with everything else, the frame with `window-main-window'
- ;; gets raised and steals focus if you've switched away from
- ;; Emacs in the meantime.
- (make-frame-invisible speedbar-frame)
- (select-frame (setq speedbar-frame (previous-frame)))
- (erc-speedbar--emulate-sidebar-set-window-preserve-size))))))
+ (when-let (((or (not force) (>= arg 0)))
+ (speedbar-frame-parameters (backquote-list*
+ '(visibility . nil)
+ '(no-other-frame . t)
+ speedbar-frame-parameters))
+ (speedbar-after-create-hook #'erc-speedbar--emulate-sidebar))
+ (erc-install-speedbar-variables)
+ ;; Run before toggling mode to prevent timer from being
+ ;; created twice.
+ (speedbar-change-initial-expansion-list "ERC")
+ (speedbar-frame-mode 1)
+ ;; If we put the remaining parts in the "create hook" along
+ ;; with everything else, the frame with `window-main-window'
+ ;; gets raised and steals focus if you've switched away from
+ ;; Emacs in the meantime.
+ (make-frame-invisible speedbar-frame)
+ (select-frame (setq speedbar-frame (previous-frame)))
+ (erc-speedbar--emulate-sidebar-set-window-preserve-size))))
+ (cl-assert (not (cdr (erc-speedbar--get-timers))) t))
(defun erc-speedbar--ensure (&optional force)
(when (or (erc-server-buffer) force)
(when erc-track-mode
(cl-pushnew '(derived-mode . speedbar-mode)
erc-track--switch-fallback-blockers :test #'equal))
+ (unless (display-graphic-p)
+ (unless speedbar-update-flag
+ (erc-button--display-error-notice-with-keys
+ (erc-server-buffer)
+ "Module `nickbar' needs `speedbar-update-flag' to be non-nil"
+ " in non-graphic terminals. Setting to t for the current"
+ " Emacs session. Customize it to avoid this message."))
+ (setq speedbar-update-flag t))
(erc-speedbar--toggle-nicknames-sidebar +1)
- (speedbar-enable-update)))
+ (with-current-buffer speedbar-buffer
+ (setq speedbar-update-flag t)
+ (speedbar-set-mode-line-format))))
+
+(defvar erc-speedbar--shutting-down-p nil)
;;;###autoload(autoload 'erc-nickbar-mode "erc-speedbar" nil t)
(define-erc-module nickbar nil
- "Show nicknames in a side window.
+ "Show nicknames for current target buffer in a side window.
When enabling, create a speedbar session if one doesn't exist and
show its buffer in an `erc-status-sidebar' window instead of a
separate frame. When disabling, close the window or, with a
@@ -527,8 +554,8 @@ nickbar
WARNING: this module may produce unwanted side effects, like the
raising of frames or the stealing of input focus. If you witness
-such an occurrence, and can reproduce it, please file a bug
-report with \\[erc-bug]."
+such a thing and can reproduce it, please file a bug report with
+\\[erc-bug]."
((add-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
(erc-speedbar--ensure)
(unless (or erc--updating-modules-p
@@ -542,31 +569,44 @@ nickbar
(erc-error "Not initializing `erc-nickbar-mode' in %s"
(current-buffer))))))
((remove-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
- (speedbar-disable-update)
(when erc-track-mode
(setq erc-track--switch-fallback-blockers
(remove '(derived-mode . speedbar-mode)
erc-track--switch-fallback-blockers)))
(erc-speedbar--toggle-nicknames-sidebar -1)
- (when-let ((arg erc--module-toggle-prefix-arg)
+ (when-let (((not erc-speedbar--shutting-down-p))
+ (arg erc--module-toggle-prefix-arg)
((numberp arg))
((< arg 0)))
- (erc-speedbar-close-nicknames-window 'kill))))
+ (with-current-buffer speedbar-buffer
+ (dframe-close-frame)
+ (setq erc-speedbar--hidden-speedbar-frame nil)))))
+
+(defun erc-speedbar--get-timers ()
+ (cl-remove #'dframe-timer-fn timer-idle-list
+ :key #'timer--function
+ :test-not #'eq))
(defun erc-speedbar--dframe-controlled (arg)
+ (when speedbar-buffer
+ (cl-assert (eq speedbar-buffer (current-buffer))))
(when (and erc-speedbar--hidden-speedbar-frame (numberp arg) (< arg 0))
(when erc-nickbar-mode
- (erc-nickbar-mode -1))
+ (let ((erc-speedbar--shutting-down-p t))
+ (erc-nickbar-mode -1)))
(setq speedbar-frame erc-speedbar--hidden-speedbar-frame
erc-speedbar--hidden-speedbar-frame nil)
;; It's unknown whether leaving the frame invisible interferes
- ;; with the upstream teardown procedure.
+ ;; with the upstream teardown sequence.
(when (display-graphic-p)
(make-frame-visible speedbar-frame))
- (speedbar-frame-mode arg)
- (when speedbar-buffer
- (kill-buffer speedbar-buffer)
- (setq speedbar-buffer nil))))
+ (speedbar-frame-mode arg) ; -1
+ ;; As of Emacs 29, `dframe-set-timer' can't remove `dframe-timer'.
+ (cl-assert (= 1 (length (erc-speedbar--get-timers))) t)
+ (cancel-function-timers #'dframe-timer-fn)
+ ;; `dframe-close-frame' kills the buffer but no function in
+ ;; erc-speedbar.el resets this to nil.
+ (setq speedbar-buffer nil)))
(defun erc-speedbar-toggle-nicknames-window-lock ()
"Toggle whether nicknames window is selectable with \\[other-window]."
@@ -578,20 +618,6 @@ erc-speedbar-toggle-nicknames-window-lock
(set-window-parameter window 'no-other-window (not val))
(message "nick-window: %s" (if val "selectable" "protected")))))
-(defun erc-speedbar-close-nicknames-window (kill)
- (interactive "P")
- (if kill
- (with-current-buffer speedbar-buffer
- (dframe-close-frame)
- (cl-assert (not erc-nickbar-mode))
- (setq erc-speedbar--hidden-speedbar-frame nil))
- (dolist (window (get-buffer-window-list speedbar-buffer nil t))
- (unless (frame-root-window-p window)
- (when erc-speedbar--hidden-speedbar-frame
- (cl-assert (not (eq (window-frame window)
- erc-speedbar--hidden-speedbar-frame))))
- (delete-window window)))))
-
;;;; Nicks integration
--git a/test/lisp/erc/erc-scenarios-status-sidebar.el b/test/lisp/erc/erc-scenarios-status-sidebar.el
index 92229121c9f..3a047bf3983 100644
--- a/test/lisp/erc/erc-scenarios-status-sidebar.el
+++ b/test/lisp/erc/erc-scenarios-status-sidebar.el
@@ -94,7 +94,7 @@ erc-scenarios-status-sidebar--bufbar
;; terminal, and we lack a fixture for that. Please try running this
;; test interactively with both graphical Emacs and non.
(declare-function erc-nickbar-mode "erc-speedbar" (arg))
-(declare-function erc-speedbar-close-nicknames-window "erc-speedbar" (kill))
+(declare-function erc-speedbar--get-timers "erc-speedbar" nil)
(declare-function speedbar-timer-fn "speedbar" nil)
(defvar erc-nickbar-mode)
(defvar speedbar-buffer)
@@ -154,16 +154,21 @@ erc-scenarios-status-sidebar--nickbar
(ert-info ("Core toggle and kill commands work")
;; Avoid using API, e.g., `erc-status-sidebar-buffer-exists-p',
;; etc. for testing commands that call those same functions.
- (erc-nickbar-mode -1)
+ (call-interactively #'erc-nickbar-mode)
+ (should-not erc-nickbar-mode)
(should-not (and speedbar-buffer
(get-buffer-window speedbar-buffer)))
+ (should speedbar-buffer)
+
(erc-nickbar-mode +1)
(should (and speedbar-buffer
(get-buffer-window speedbar-buffer)))
(should (get-buffer " SPEEDBAR"))
- (erc-speedbar-close-nicknames-window 'kill)
+ (erc-nickbar-mode -1)
(should-not (get-buffer " SPEEDBAR"))
(should-not erc-nickbar-mode)
- (should-not (cdr (frame-list)))))))
+ (should-not (cdr (frame-list)))))
+
+ (should-not (erc-speedbar--get-timers))))
;;; erc-scenarios-status-sidebar.el ends here
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el
index 972faa5c73f..2eb040d28d9 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -122,6 +122,7 @@ erc-scenarios-common--print-trace
(inhibit-interaction t)
(auth-source-do-cache nil)
(timer-list (copy-sequence timer-list))
+ (timer-idle-list (copy-sequence timer-idle-list))
(erc-auth-source-parameters-join-function nil)
(erc-autojoin-channels-alist nil)
(erc-server-auto-reconnect nil)
--
2.41.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <87jztvdqxh.fsf@neverwas.me>
@ 2023-08-20 17:23 ` Corwin Brust
[not found] ` <CAJf-WoRybO12qgFH7Hd1AZA4jKAeGTLuHdzcQisceLOrPwBd-w@mail.gmail.com>
1 sibling, 0 replies; 17+ messages in thread
From: Corwin Brust @ 2023-08-20 17:23 UTC (permalink / raw)
To: J.P.; +Cc: 63595, emacs-erc
TL;DR: Couldn't apply; can you double check?
detail below and thanks for the insta-response!
On Wed, Aug 16, 2023 at 9:04 AM J.P. <jp@neverwas.me> wrote:
>
> Some issues with the `nickbar' module have surfaced that may be related
> to another issue involving unexpected connection loss. Thanks to Corwin
> for reporting this.
>
corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
$ git apply /c/Users/corwi/Downloads/0001-5.6-Prevent-unwanted-recursion-in-erc-nickbar-disabl.patch
error: patch failed: lisp/erc/erc-speedbar.el:439
error: lisp/erc/erc-speedbar.el: patch does not apply
error: patch failed: test/lisp/erc/erc-scenarios-status-sidebar.el:94
error: test/lisp/erc/erc-scenarios-status-sidebar.el: patch does not apply
error: patch failed: test/lisp/erc/resources/erc-scenarios-common.el:122
error: test/lisp/erc/resources/erc-scenarios-common.el: patch does not apply
corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
$
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <CAJf-WoRybO12qgFH7Hd1AZA4jKAeGTLuHdzcQisceLOrPwBd-w@mail.gmail.com>
@ 2023-08-20 19:56 ` J.P.
[not found] ` <87350da3o1.fsf@neverwas.me>
1 sibling, 0 replies; 17+ messages in thread
From: J.P. @ 2023-08-20 19:56 UTC (permalink / raw)
To: Corwin Brust; +Cc: 63595, emacs-erc
Corwin Brust <corwin@bru.st> writes:
> TL;DR: Couldn't apply; can you double check?
Hm, I'm able to apply that patch atop a563ea8 [1].
$ cd /tmp
$ git clone --depth 1 https://git.savannah.gnu.org/git/emacs.git
$ cd emacs
$ curl -L "$url [2]" | git am
Applying: Prevent unwanted recursion in erc-nickbar-disable
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
$ git log -n2 --oneline
5104bc0 Prevent unwanted recursion in erc-nickbar-disable
a563ea8 * lisp/isearch.el (isearch-resume): Add isearch-push-state (bug#65379).
However, as I type this, I'm thinking I should have also tried it with a
minimal ~/.gitconfig as well as after running ./autogen.sh. That said, I
do both in CI (with a slightly updated patch), and it works fine.
> detail below and thanks for the insta-response!
>
> corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
> $ git status
> On branch master
> Your branch is up to date with 'origin/master'.
>
> nothing to commit, working tree clean
>
> corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
> $ git apply /c/Users/corwi/Downloads/0001-5.6-Prevent-unwanted-recursion-in-erc-nickbar-disabl.patch
> error: patch failed: lisp/erc/erc-speedbar.el:439
> error: lisp/erc/erc-speedbar.el: patch does not apply
> error: patch failed: test/lisp/erc/erc-scenarios-status-sidebar.el:94
> error: test/lisp/erc/erc-scenarios-status-sidebar.el: patch does not apply
> error: patch failed: test/lisp/erc/resources/erc-scenarios-common.el:122
> error: test/lisp/erc/resources/erc-scenarios-common.el: patch does not apply
>
> corwi@Avalon MINGW64 /h/emacs-dev/emacs-nt
> $
I find it unlikely that none of the hunks apply cleanly. Perhaps this
has something to do with white space/line endings? Maybe you need to
change core.autocrlf or similar?
[1] https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=a563ea89633963fb20c4159bd5e8da825ffc2248
[2] https://debbugs.gnu.org/cgi/bugreport.cgi?filename=0001-5.6-Prevent-unwanted-recursion-in-erc-nickbar-disabl.patch;msg=23;bug=63595;att=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <87350da3o1.fsf@neverwas.me>
@ 2023-08-21 13:55 ` Corwin Brust
[not found] ` <CAJf-WoSXYGWpM0_x_KbAJ+8VbKzwy4UPvNAy2gTt3ZP2vxh5DA@mail.gmail.com>
1 sibling, 0 replies; 17+ messages in thread
From: Corwin Brust @ 2023-08-21 13:55 UTC (permalink / raw)
To: J.P.; +Cc: emacs-erc, 63595
Thank you; I think this fixes things and should be applied.
On Sun, Aug 20, 2023 at 2:56 PM J.P. <jp@neverwas.me> wrote:
>
> Corwin Brust <corwin@bru.st> writes:
>
> > TL;DR: Couldn't apply; can you double check?
>
> $ curl -L "$url [2]" | git am
>
> I find it unlikely that none of the hunks apply cleanly. Perhaps this
>
> [2] https://debbugs.gnu.org/cgi/bugreport.cgi?filename=0001-5.6-Prevent-unwanted-recursion-in-erc-nickbar-disabl.patch;msg=23;bug=63595;att=1
>
Quite right; thanks for pointing out the improbability of no hunks
applying; the command you suggested worked fine.
Moreover, I believe this patch solves the issue (or helps enough I
can't notice it). Since applying I see no difference in how often I'm
disconnected between patched ERC, ERC without nickbar, and hexchat,
all running on the same system connected to the same bouncer. (Prior
to the patch ERC with nickbar running was disconnected much more often
than hexchat).
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
` (5 preceding siblings ...)
[not found] ` <87jztvdqxh.fsf@neverwas.me>
@ 2023-08-31 13:30 ` J.P.
2023-12-07 7:26 ` J.P.
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-08-31 13:30 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
This feature introduced a couple auxiliary modules to serve as higher
level wrappers around newer functionality that was awkwardly bolted onto
the existing libraries erc-status-sidebar and erc-speedbar. One of the
stated aims of this bug's initial proposal was to unify the UI for this
flavor of transitory, command-focused module [1]. However, anyone paying
close enough attention will have noticed I've already faltered in this
regard.
Look at the minor-mode toggle `erc-bufbar-mode' and notice that, when
disabling, it tears down the mode completely, destroying all assets. To
make it easy to show and hide its window without alternately shutting
down and starting anew with every other toggle, I turned to contextually
overloading the existing commands `erc-status-sidebar-toggle' and
friends to behave specially when `erc-bufbar-mode' is active [2].
Contrast this with the approach taken for `erc-nickbar-mode', whose
namesake command is of the all-in-one, kitchen-sink variety. Toggling
off merely hides its window and preserves the speedbar session (its
hidden frame, buffer, etc.). To actually kill it off completely, you
invoke the toggle with a negative prefix argument.
Obviously, these must be reconciled somehow, or one must be made to
mimic the other. I'm leaning toward changing `nickbar' by adding a
second command to toggle it without shutting it down, and then having
the main minor-mode toggle always do a full shutdown. This probably
aligns more with prevailing expectations and traditional Emacs semantics
that assume a nil `erc-nickbar-mode' variable indicates not only a
logical disabled activation state but that the mode is completely
destroyed.
Therefore, unless anyone has any better ideas, I'll provide a patch
shortly that does something to this effect.
Thanks.
[1] To recap, the trend in recent years has been to downplay the use of
a module's minor-mode toggle as a viable entry point for enabling
its functionality. Rather, there's been a focus on emphasizing
membership in `erc-modules' as the preferred means of doing so. The
reasons are manifold but ultimately rooted in attaining more
predictable behavior and tighter inter-module interop across the
board. However, this paradigm necessarily couples a module's
activation state to the lifetime of an IRC session, which doesn't
always make sense. Some modules, by their very nature, are
intrinsically interactive and ephemeral. IOW, they're minor-modes
first and modules second.
[2] Note the traditional library namespace prefix, which probably
hampers discoverability for users of the module. We could alias the
transitory toggles (at least) to reflect the new module names, but
that may just confuse things further because the new options would
all continue to sport library prefixes.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <CAJf-WoSXYGWpM0_x_KbAJ+8VbKzwy4UPvNAy2gTt3ZP2vxh5DA@mail.gmail.com>
@ 2023-08-31 13:33 ` J.P.
0 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-08-31 13:33 UTC (permalink / raw)
To: 63595; +Cc: Corwin Brust, emacs-erc
Corwin Brust <corwin@bru.st> writes:
> Moreover, I believe this patch solves the issue (or helps enough I
> can't notice it). Since applying I see no difference in how often I'm
> disconnected between patched ERC, ERC without nickbar, and hexchat,
> all running on the same system connected to the same bouncer. (Prior
> to the patch ERC with nickbar running was disconnected much more often
> than hexchat).
FTR, this was applied as:
commit f8b710e54fb8b29f39bf021ccfb993f881b0134a
Author: F. Jason Park <jp@neverwas.me>
Date: Tue Aug 15 21:14:07 2023 -0700
Prevent unwanted recursion in erc-nickbar-disable
lisp/erc/erc-speedbar.el | 112 +++++++++++++++---------
test/lisp/erc/erc-scenarios-status-sidebar.el | 13 ++-
test/lisp/erc/resources/erc-scenarios-common.el | 1 +
3 files changed, 79 insertions(+), 47 deletions(-)
Thanks.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
` (6 preceding siblings ...)
2023-08-31 13:30 ` J.P.
@ 2023-12-07 7:26 ` J.P.
2024-01-19 2:42 ` J.P.
` (3 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2023-12-07 7:26 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
[-- Attachment #1: Type: text/plain, Size: 325 bytes --]
One thing this feature left unaddressed was the inclusion of all
available channel-membership prefixes in the "nickbar" (speedbar).
Currently, only members with a "+" or "@" have their nicks augmented.
Given the recent improvements to channel-mode parsing, it's now easier
to offer the full slate of prefixes. See attached.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0009-5.6-Make-erc-get-user-mode-prefix-more-flexible.patch --]
[-- Type: text/x-patch, Size: 5964 bytes --]
From 401bc01ace91aac6f3423fc8a04fe7a95b67987c Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 27 Nov 2023 22:53:00 -0800
Subject: [PATCH 09/11] [5.6] Make erc-get-user-mode-prefix more flexible
* lisp/erc/erc-speedbar.el (erc-speedbar-insert-user): Use
`erc-get-channel-membership-prefix' so that nicks in the nickbar can
have prefixes beyond just voice and op.
* lisp/erc/erc.el (erc-get-user-mode-prefix,
erc-get-channel-membership-prefix): Rename former to latter because
"user-mode" suggests the function somehow involves user modes, but it
exclusively concerns channel modes. Also, overload the only parameter
in order to avoid redundantly looking up `erc-channel-user' object
with every predicate call. In the near future, ERC will likely need
to offer an alternate version of this function that returns multiple
prefixes instead of just one.
(erc-format-@nick): Use `channel-data' parameter.
(erc-format-my-nick, erc--format-channel-status-prefix): Use new name
for function `erc-get-user-mode-prefix'. (Bug#63595)
---
etc/ERC-NEWS | 7 +++++++
lisp/erc/erc-speedbar.el | 4 +---
lisp/erc/erc.el | 30 ++++++++++++++++++++----------
3 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 540d9e98751..4fdfe7a9dcb 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -433,6 +433,13 @@ The 'fill' module is now defined by 'define-erc-module'. The same
goes for ERC's imenu integration, which has 'imenu' now appearing in
the default value of 'erc-modules'.
+*** Function 'erc-get-user-mode-prefix' renamed.
+This utility has been renamed to 'erc-get-channel-membership-prefix'
+to better reflect its role of delivering a formatted "status prefix",
+like "+" (for "voice"), and to avoid confusion with user modes, like
+"+i" (for "invisible"). Additionally, its lone parameter is now
+overloaded to accept an 'erc-channel-user' object as well as a string.
+
*** Hidden messages contain a preceding rather than trailing newline.
ERC has traditionally only offered to hide messages involving fools,
but plans are to make hiding more powerful. Anyone depending on the
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index 93be7b9f074..90d7376fc0c 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -319,9 +319,7 @@ erc-speedbar-insert-user
(info (erc-server-user-info user))
(login (erc-server-user-login user))
(name (erc-server-user-full-name user))
- (voice (and cuser (erc-channel-user-voice cuser)))
- (op (and cuser (erc-channel-user-op cuser)))
- (nick-str (concat (if op "@" "") (if voice "+" "") nick))
+ (nick-str (concat (erc-get-channel-membership-prefix cuser) nick))
(finger (concat login (when (or login host) "@") host))
(sbtoken (list finger name info (buffer-name buffer))))
(if (or login host name info) ; we want to be expandable
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 98621302abd..8e7162fec89 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -5815,21 +5815,31 @@ erc-format-nick
See also `erc-format-nick-function'."
(when user (erc-server-user-nickname user)))
-(defun erc-get-user-mode-prefix (user)
+(define-obsolete-function-alias 'erc-get-user-mode-prefix
+ #'erc-get-channel-membership-prefix "30.1")
+(defun erc-get-channel-membership-prefix (user)
+ "Return channel membership prefix for USER as a string.
+Ensure returned string has a `help-echo' text property with the
+corresponding verbose membership type, like \"voice\", as its
+value. Expect USER to be an `erc-channel-user' object or a
+string nickname, not necessarily downcased."
(when user
- (cond ((erc-channel-user-owner-p user)
+ (when (stringp user)
+ (setq user (and erc-channel-users (cdr (erc-get-channel-user user)))))
+ (cond ((null user) "")
+ ((erc-channel-user-owner user)
(propertize "~" 'help-echo "owner"))
- ((erc-channel-user-admin-p user)
+ ((erc-channel-user-admin user)
(propertize "&" 'help-echo "admin"))
- ((erc-channel-user-op-p user)
+ ((erc-channel-user-op user)
(propertize "@" 'help-echo "operator"))
- ((erc-channel-user-halfop-p user)
+ ((erc-channel-user-halfop user)
(propertize "%" 'help-echo "half-op"))
- ((erc-channel-user-voice-p user)
+ ((erc-channel-user-voice user)
(propertize "+" 'help-echo "voice"))
(t ""))))
-(defun erc-format-@nick (&optional user _channel-data)
+(defun erc-format-@nick (&optional user channel-data)
"Format the nickname of USER showing if USER has a voice, is an
operator, half-op, admin or owner. Owners have \"~\", admins have
\"&\", operators have \"@\" and users with voice have \"+\" as a
@@ -5838,7 +5848,7 @@ erc-format-@nick
(when user
(let ((nick (erc-server-user-nickname user)))
(concat (propertize
- (erc-get-user-mode-prefix nick)
+ (erc-get-channel-membership-prefix channel-data)
'font-lock-face 'erc-nick-prefix-face)
nick))))
@@ -5848,7 +5858,7 @@ erc-format-my-nick
(let* ((open "<")
(close "> ")
(nick (erc-current-nick))
- (mode (erc-get-user-mode-prefix nick)))
+ (mode (erc-get-channel-membership-prefix nick)))
(erc--ensure-spkr-prop nick)
(concat
(propertize open 'font-lock-face 'erc-default-face)
@@ -8486,7 +8496,7 @@ erc--format-user-modes
(defun erc--format-channel-status-prefix ()
"Return the current channel membership prefix."
(and (erc--target-channel-p erc--target)
- (erc-get-user-mode-prefix (erc-current-nick))))
+ (erc-get-channel-membership-prefix (erc-current-nick))))
(defun erc--format-modes (&optional no-query-p)
"Return a string of channel modes in channels and user modes elsewhere.
--
2.42.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
` (7 preceding siblings ...)
2023-12-07 7:26 ` J.P.
@ 2024-01-19 2:42 ` J.P.
[not found] ` <875xzqqc0g.fsf@neverwas.me>
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2024-01-19 2:42 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
I'm unsure whether there's a regression present on HEAD affecting
erc-speedbar (now the `nickbar' module). I've been noticing the idle
timer only seems to run after user input has been received and dealt
with. IOW, updates don't occur if simply leaving the window open and
otherwise not interacting with Emacs. I suppose we could run the timer
function manually, like on `erc-post-insert-hook' (perhaps guarded by
some debouncing logic), but I'd only want to do so if we can confirm
this isn't a regression.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <875xzqqc0g.fsf@neverwas.me>
@ 2024-01-25 21:41 ` J.P.
0 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2024-01-25 21:41 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
"J.P." <jp@neverwas.me> writes:
> I'm unsure whether there's a regression present on HEAD affecting
> erc-speedbar (now the `nickbar' module). I've been noticing the idle
> timer only seems to run after user input has been received and dealt
> with. IOW, updates don't occur if simply leaving the window open and
> otherwise not interacting with Emacs. I suppose we could run the timer
> function manually, like on `erc-post-insert-hook' (perhaps guarded by
> some debouncing logic), but I'd only want to do so if we can confirm
> this isn't a regression.
This wasn't a regression but rather a faulty observation on account of
my ignorance regarding how idle timers work. In essence: no input, no
reset (no next run). To address this, I've implemented something like
the more robust manual trigger approach mentioned above:
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=aae131b8
This bug is already closed.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
` (9 preceding siblings ...)
[not found] ` <875xzqqc0g.fsf@neverwas.me>
@ 2024-04-01 1:42 ` J.P.
[not found] ` <87h6glg8p4.fsf@neverwas.me>
11 siblings, 0 replies; 17+ messages in thread
From: J.P. @ 2024-04-01 1:42 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
[-- Attachment #1: Type: text/plain, Size: 730 bytes --]
It's been reported that the nickbar (speedbar) window doesn't display
the cursor on at least one user's setup. I've found this to be true by
default on non-graphic displays. The attached patch should fix the
latter regression. As to whether it also fixes the reporter's issue is
TBD.
It's also been reported that the dframe timer can signal a
(wrong-type-argument window-live-p nil)
which then gets trapped by the
(with-demoted-errors "DFRAME TIMER ERROR: %S"...)
in `dframe-timer-fn'. Unfortunately, remediation is trickier here
because we've got to inspect calls to `window-live-p' stemming from
`speedbar-timer-fn', possibly via `erc-speedbar-insert-user'. (What we
really need is a backtrace from the bug reporter.)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-5.6-Fix-invisible-erc-speedbar-cursor-in-text-termin.patch --]
[-- Type: text/x-patch, Size: 4388 bytes --]
From 910b6981da743bdc661241f54e26e9b163f239d1 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Sun, 31 Mar 2024 16:32:44 -0700
Subject: [PATCH] [5.6] Fix invisible erc-speedbar cursor in text terminals
* lisp/erc/erc-speedbar.el
(erc-speedbar--reset-last-ran-on-timer): Use `with-current-buffer'
instead of `setf' and `buffer-local-value'.
(erc-nickbar-mode, erc-nickbar-enable, erc-nickbar-disable)
(erc-speedbar-toggle-nicknames-window-lock): Revise doc string.
(erc-speedbar-toggle-nicknames-window-lock): Set `cursor-type' in
speedbar buffer.
(erc-nickbar-toggle-nicknames-window-lock): New function alias. Note
that this name flouts traditional library namespacing conventions.
* lisp/erc/erc-status-sidebar.el (erc-status-sidebar-get-window): Use
`cursor-type' instead of `internal-show-cursor'.
(Bug#63595)
---
lisp/erc/erc-speedbar.el | 23 ++++++++++++++---------
| 2 +-
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index a81a3869436..b156f61d5d9 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -566,9 +566,8 @@ erc-speedbar--run-timer-on-post-insert
(defun erc-speedbar--reset-last-ran-on-timer ()
"Reset `erc-speedbar--last-ran'."
(when speedbar-buffer
- (with-suppressed-warnings ((obsolete buffer-local-value)) ; <=29
- (setf (buffer-local-value 'erc-speedbar--last-ran speedbar-buffer)
- (current-time)))))
+ (with-current-buffer speedbar-buffer
+ (setq erc-speedbar--last-ran (current-time)))))
;;;###autoload(autoload 'erc-nickbar-mode "erc-speedbar" nil t)
(define-erc-module nickbar nil
@@ -578,10 +577,12 @@ nickbar
separate frame. When disabling, close the window or, with a
negative prefix arg, destroy the session.
-WARNING: this module may produce unwanted side effects, like the
-raising of frames or the stealing of input focus. If you witness
-such a thing and can reproduce it, please file a bug report with
-\\[erc-bug]."
+For controlling whether the speedbar window is selectable with
+`other-window', see `erc-nickbar-toggle-nicknames-window-lock'.
+Note that during initialization, this module may produce unwanted
+side effects, like the raising of frames or the stealing of input
+focus. If you witness such a thing and can reproduce it, please
+file a bug report with \\[erc-bug]."
((add-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
(add-hook 'erc-insert-post-hook #'erc-speedbar--run-timer-on-post-insert)
(add-hook 'speedbar-timer-hook #'erc-speedbar--reset-last-ran-on-timer)
@@ -638,8 +639,8 @@ erc-speedbar--dframe-controlled
(defun erc-speedbar-toggle-nicknames-window-lock (arg)
"Toggle whether nicknames window is selectable with \\[other-window].
-When arg is a number, lock the window if non-negative, otherwise
-unlock."
+When ARG is a number, lock the window if non-negative. Otherwise,
+unlock the window."
(interactive "P")
(unless erc-nickbar-mode
(user-error "`erc-nickbar-mode' inactive"))
@@ -648,10 +649,14 @@ erc-speedbar-toggle-nicknames-window-lock
((integerp arg) nil)
(t (not (window-parameter window
'no-other-window))))))
+ (with-current-buffer speedbar-buffer
+ (setq cursor-type (not val)))
(set-window-parameter window 'no-other-window val)
(unless (numberp arg)
(message "nick-window: %s" (if val "protected" "selectable"))))))
+(defalias 'erc-nickbar-toggle-nicknames-window-lock
+ #'erc-speedbar-toggle-nicknames-window-lock)
;;;; Nicks integration
--git a/lisp/erc/erc-status-sidebar.el b/lisp/erc/erc-status-sidebar.el
index b7695651e4c..dcdef7cfafc 100644
--- a/lisp/erc/erc-status-sidebar.el
+++ b/lisp/erc/erc-status-sidebar.el
@@ -192,7 +192,7 @@ erc-status-sidebar-get-window
(set-window-parameter sidebar-window 'no-delete-other-windows t)
;; Don't cycle to this window with `other-window'.
(set-window-parameter sidebar-window 'no-other-window t)
- (internal-show-cursor sidebar-window nil)
+ (setq cursor-type nil)
(set-window-fringes sidebar-window 0 0)
;; Set a custom display table so the window doesn't show a
;; truncation symbol when a channel name is too big.
--
2.44.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <87h6glg8p4.fsf@neverwas.me>
@ 2024-04-01 5:58 ` J.P.
2024-04-09 18:17 ` J.P.
1 sibling, 0 replies; 17+ messages in thread
From: J.P. @ 2024-04-01 5:58 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
"J.P." <jp@neverwas.me> writes:
> It's also been reported that the dframe timer can signal a
>
> (wrong-type-argument window-live-p nil)
>
> which then gets trapped by the
>
> (with-demoted-errors "DFRAME TIMER ERROR: %S"...)
>
> in `dframe-timer-fn'. Unfortunately, remediation is trickier here
> because we've got to inspect calls to `window-live-p' stemming from
> `speedbar-timer-fn', possibly via `erc-speedbar-insert-user'. (What we
> really need is a backtrace from the bug reporter.)
Actually, I think my initial "analysis" is flawed. Of the two obvious
paths to `window-live-p' from `speedbar-timer-fn', namely
internal--after-save-selected-window
save-selected-window
speedbar-center-buffer-smartly
erc-speedbar-expand-channel
erc-speedbar-buttons
speedbar-update-special-contents
speedbar-timer-fn
dframe-timer-fn
timer-event-handler
and
window-normalize-window
unrecord-window-buffer
replace-buffer-in-windows
kill-buffer
format-spec
erc-nicks--gen-key-from-format-spec and let*
erc-nicks--highlight save-current-buffer and let* let
erc-speedbar--compose-nicks-face apply
speedbar-make-tag-line
erc-speedbar-insert-user
erc-speedbar-expand-channel
erc-speedbar-buttons
speedbar-update-special-contents
speedbar-timer-fn
dframe-timer-fn
timer-event-handler
neither seems capable of producing a `wrong-type-argument' error for
`window-live-p' (especially not directly, since that function appears to
accept any lisp object without protest).
Rather, I think the error may originate from some other function that
tests for `window-live-p' and signals a `wrong-type-argument' somehow,
possibly via something like CHECK_LIVE_WINDOW, which appears in a
handful of related definitions, such as `set-frame-selected-window'. In
any case, because this line of reasoning may also be nonsense, I think
we need a reliable repro recipe before proceeding further.
^ permalink raw reply [flat|nested] 17+ messages in thread
* bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules
[not found] ` <87h6glg8p4.fsf@neverwas.me>
2024-04-01 5:58 ` J.P.
@ 2024-04-09 18:17 ` J.P.
1 sibling, 0 replies; 17+ messages in thread
From: J.P. @ 2024-04-09 18:17 UTC (permalink / raw)
To: 63595; +Cc: emacs-erc
"J.P." <jp@neverwas.me> writes:
> It's been reported that the nickbar (speedbar) window doesn't display
> the cursor on at least one user's setup. I've found this to be true by
> default on non-graphic displays. The attached patch should fix the
> latter regression. As to whether it also fixes the reporter's issue is
> TBD.
This has been installed as
ee377aaddf9 * Fix invisible erc-speedbar cursor in text terminals
This bug is already closed.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2024-04-09 18:17 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-19 19:25 bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules J.P.
2023-05-19 20:47 ` J.P.
2023-07-14 2:07 ` J.P.
2023-07-25 13:32 ` J.P.
[not found] ` <87o7k0yv4b.fsf@neverwas.me>
2023-07-29 0:00 ` J.P.
2023-08-16 14:04 ` J.P.
[not found] ` <87jztvdqxh.fsf@neverwas.me>
2023-08-20 17:23 ` Corwin Brust
[not found] ` <CAJf-WoRybO12qgFH7Hd1AZA4jKAeGTLuHdzcQisceLOrPwBd-w@mail.gmail.com>
2023-08-20 19:56 ` J.P.
[not found] ` <87350da3o1.fsf@neverwas.me>
2023-08-21 13:55 ` Corwin Brust
[not found] ` <CAJf-WoSXYGWpM0_x_KbAJ+8VbKzwy4UPvNAy2gTt3ZP2vxh5DA@mail.gmail.com>
2023-08-31 13:33 ` J.P.
2023-08-31 13:30 ` J.P.
2023-12-07 7:26 ` J.P.
2024-01-19 2:42 ` J.P.
[not found] ` <875xzqqc0g.fsf@neverwas.me>
2024-01-25 21:41 ` J.P.
2024-04-01 1:42 ` J.P.
[not found] ` <87h6glg8p4.fsf@neverwas.me>
2024-04-01 5:58 ` J.P.
2024-04-09 18:17 ` J.P.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.