From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "J.P." Newsgroups: gmane.emacs.bugs,gmane.emacs.erc.general Subject: bug#63595: 30.0.50; ERC 5.6: Add buffer-list and nick-list modules Date: Fri, 19 May 2023 12:25:29 -0700 Message-ID: <87lehkt97a.fsf@neverwas.me> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="15174"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: emacs-erc@gnu.org To: 63595@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri May 19 21:26:26 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1q05k8-0003gp-V3 for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 19 May 2023 21:26:25 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1q05jp-00041D-Nm; Fri, 19 May 2023 15:26:05 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q05jm-000412-RI; Fri, 19 May 2023 15:26:03 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1q05jm-0005bi-Jb; Fri, 19 May 2023 15:26:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1q05jl-0004LJ-W3; Fri, 19 May 2023 15:26:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "J.P." Original-Sender: "Debbugs-submit" Resent-CC: emacs-erc@gnu.org, bug-gnu-emacs@gnu.org Resent-Date: Fri, 19 May 2023 19:26:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 63595 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org X-Debbugs-Original-Xcc: emacs-erc@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.168452435416678 (code B ref -1); Fri, 19 May 2023 19:26:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 19 May 2023 19:25:54 +0000 Original-Received: from localhost ([127.0.0.1]:57435 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1q05ja-0004Kr-HF for submit@debbugs.gnu.org; Fri, 19 May 2023 15:25:53 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:54098) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1q05jV-0004Ke-Se for submit@debbugs.gnu.org; Fri, 19 May 2023 15:25:49 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q05jV-0003yx-Ey for bug-gnu-emacs@gnu.org; Fri, 19 May 2023 15:25:45 -0400 Original-Received: from mail-108-mta11.mxroute.com ([136.175.108.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1q05jO-0005YW-Nz for bug-gnu-emacs@gnu.org; Fri, 19 May 2023 15:25:45 -0400 Original-Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta11.mxroute.com (ZoneMTA) with ESMTPSA id 1883579758200074ee.001 for (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES128-GCM-SHA256); Fri, 19 May 2023 19:25:32 +0000 X-Zone-Loop: eec7dda6ba983e849cec5c7021dd9f3b963fa6e4e9fe X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=neverwas.me ; s=x; h=Content-Type:MIME-Version:Message-ID:Date:Subject:To:From:Sender: Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=reOVYRocD84tqZU6Afp4MUToMaIkxYinxEkfAKJ6TEQ=; b=JWB0abbAfp98Slzy+ZQWJUY2pv tEBXPa65Rq/NP6nB1fU6/+hHUBsUtheeb5MoQVHR40jzE+eJhe4Dmv0UOfn+m62bNxe1VW1uuUlmT XAB1AwzSXVoCNW+V9WXYxY8kGncTwAzfmF5YHkTf+Q4YjJjlLPWtT5xmDbfKULqII4R19v6/uNGB1 JA8JrJqdIuN/fGcYwR7e8K1XSdoFHWTtNhDWfEE+J47GN2USEtY43xp1QpI3Qkkt8gGB1dDlh6vYo FrMkk24HC5++Og2JpEzxk0pyTzZoghmB+FBth71ZF8qjTluwptnYhxjEHyknC0vteueMkPqXTVRaj NVDIEzCw==; X-Authenticated-Id: masked@neverwas.me Received-SPF: pass client-ip=136.175.108.11; envelope-from=jp@neverwas.me; helo=mail-108-mta11.mxroute.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:262024 gmane.emacs.erc.general:2151 Archived-At: --=-=-= Content-Type: text/plain 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)) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-5.6-Fix-buffer-mismatch-bug-in-erc-scroll-to-bottom.patch >From 4a1bd9e173d91164d5abe6f2e349a447eaf019d7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-5.6-Allow-ERC-s-module-toggles-access-to-the-prefix-.patch >From 5ae05b1ad34ce1baea149c7af1e9e9282f101725 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-5.6-Add-preset-styles-to-erc-status-sidebar.patch >From c4746e4bb3fde7670bd655ed7f17ec90435018ac Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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 + lisp/erc/erc-status-sidebar.el | 328 ++++++++++++++++-- test/lisp/erc/erc-scenarios-status-sidebar.el | 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))) diff --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) diff --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 . + +;;; 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 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-5.6-Add-erc-status-sidebar-integration-to-erc-speedb.patch >From fd2ec89c40dd52322c8196c3653e06c937176bc7 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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 ++++++++++++++++-- test/lisp/erc/erc-scenarios-status-sidebar.el | 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 ;; diff --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 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-5.6-Add-new-ERC-modules-bufbar-and-nickbar.patch >From 93f31ce4e062acd8ea6e87ea8023707b9e4b383b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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 '' 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 --=-=-=--