Move ERC's core dependencies to separate file

Asking people to order require's is about as effective
as asking kids to keep off the grass.

* lisp/erc/erc-backend.el (erc--target, erc-auto-query,
erc-channel-list, erc-channel-users, erc-default-nicks,
erc-default-recipients, erc-format-nick-function,
erc-format-query-as-channel-p, erc-hide-prompt, erc-input-marker,
erc-insert-marker, erc-invitation, erc-join-buffer,
erc-kill-buffer-on-part, erc-kill-server-buffer-on-quit, erc-log-p,
erc-minibuffer-ignored, erc-networks--id, erc-nick,
erc-nick-change-attempt-count, erc-prompt-for-channel-key,
erc-prompt-hidden, erc-reuse-buffers, erc-verbose-server-ping,
erc-whowas-on-nosuchnick): Forward-declare variables.
(erc--open-target, erc--target-from-string, erc-active-buffer,
erc-add-default-channel, erc-banlist-update, erc-buffer-filter,
erc-buffer-list-with-nick, erc-channel-begin-receiving-names,
erc-channel-end-receiving-names, erc-channel-p,
erc-channel-receive-names, erc-cmd-JOIN, erc-connection-established,
erc-current-nick, erc-current-nick-p, erc-current-time,
erc-default-target, erc-delete-default-channel,
erc-display-error-notice, erc-display-server-message,
erc-emacs-time-to-erc-time, erc-format-message,
erc-format-privmessage, erc-get-buffer, erc-handle-login,
erc-handle-user-status-change, erc-ignored-reply-p,
erc-ignored-user-p, erc-is-message-ctcp-and-not-action-p,
erc-is-message-ctcp-p, erc-log-irc-protocol, erc-login,
erc-make-notice, erc-network, erc-networks--id-given,
erc-networks--id-reload, erc-nickname-in-use, erc-parse-user,
erc-process-away, erc-process-ctcp-query, erc-query-buffer-p,
erc-remove-channel-member, erc-remove-channel-users, erc-remove-user,
erc-sec-to-time, erc-server-buffer, erc-set-active-buffer,
erc-set-current-nick, erc-set-modes, erc-time-diff, erc-trim-string,
erc-update-mode-line, erc-update-mode-line-buffer,
erc-wash-quit-reason, erc-display-message, erc-get-buffer-create,
erc-process-ctcp-reply, erc-update-channel-topic, erc-update-modes,
erc-update-user-nick, erc-open, erc-update-channel-member):
Forward-declare functions.
(erc-response): Move to lisp/erc/erc-common.el.
(erc-compat--with-memoization): Use "erc-compat-" prefixed macro.

* lisp/erc/erc-common.el: New file.  Change indentation for
`erc-with-all-buffers-of-server' from 1 to 2.

* lisp/erc/erc-compat.el (erc-compat--with-memoization): Migrate macro
from `erc-backend' and rename.

* lisp/erc/erc-goodies.el: Require `erc-common' instead of `erc'.
(erc-controls-highlight-regexp, erc-controls-remove-regexp,
erc-input-marker, erc-insert-marker, erc-server-process, erc-modules,
erc-log-p): Forward declare variables.
(erc-buffer-list, erc-error, erc-extract-command-from-line):
Forward-declare functions.

* lisp/erc/erc-networks.el (erc--target, erc-insert-marker,
erc-kill-buffer-hook, erc-kill-server-hook, erc-modules,
erc-rename-buffers, erc-reuse-buffers, erc-server-announced-name,
erc-server-connected, erc-server-parameters, erc-server-process,
erc-session-server): Forward declare variables.
(erc--default-target, erc--get-isupport-entry, erc-buffer-filter,
erc-current-nick, erc-display-error-notice, erc-error, erc-get-buffer,
erc-server-buffer, erc-server-process-alive): Forward-declare
functions.
(erc-obsolete-var): Also suppress free-variable warnings.

* lisp/erc/erc.el: Require `erc-networks', `erc-goodies', and
`erc-backend' at top of file.  Don't require `erc-compat'.
(erc--server-last-reconnect-count, erc--server-reconnecting,
erc-channel-members-changed-hook, erc-network, erc-networks--id,
erc-server-367-functions, erc-server-announced-name,
erc-server-connect-function, erc-server-connected,
erc-server-current-nick, erc-server-lag, erc-server-last-sent-time,
erc-server-process, erc-server-quitting, erc-server-reconnect-count,
erc-server-reconnecting, erc-session-client-certificate,
erc-session-connector, erc-session-port, erc-session-server,
erc-session-user-full-name) Remove superfluous forward declarations.
(erc-message-parsed, tabbar--local-hlf, motif-version-string):
Relocate forward declares to central location.
(erc-session-password): Move to `erc-backend'.
(erc-downcase, erc-with-server-buffer, erc-server-user,
erc-channel-user, erc-get-channel-user, erc-get-server-user): Move to
lisp/erc/erc-common.el.
(erc-add-server-user, erc-remove-server-user,
erc-channel-user-owner-p, erc-channel-user-admin-p,
erc-channel-user-op-p, erc-channel-user-halfop-p,
erc-channel-user-voice-p): Convert from inline functions to normal
functions.
(define-erc-module, erc--target, erc--target-channel,
erc--target-channel-local, erc-log, erc-log-aux, erc-with-buffer,
erc-with-all-buffers-of-server): Move to lisp/erc/erc-common.el.
(erc-channel-members-changed-hook): Relocate option to avoid compiler
warning.
(erc-input, erc--input-split): Move to lisp/erc/erc-common.el.
(erc-controls-strip): Remove forward declaration temporarily until
this file stops requiring `erc-goodies'.

* test/lisp/erc/erc-networks-tests.el: Require `erc' instead of
`erc-networks'.
* test/lisp/erc/erc.el (erc--meta--backend-dependencies): Remove
obsolete test.  Don't require `erc-networks'. Bug#56340.
This commit is contained in:
dickmao 2022-07-01 11:06:51 -04:00 committed by F. Jason Park
parent ae0642f859
commit c2d657e7c4
8 changed files with 475 additions and 367 deletions

View file

@ -99,24 +99,117 @@
;;; Code:
(eval-when-compile (require 'cl-lib))
;; There's a fairly strong mutual dependency between erc.el and erc-backend.el.
;; Luckily, erc.el does not need erc-backend.el for macroexpansion whereas the
;; reverse is true:
(require 'erc)
(require 'erc-common)
(defvar erc--target)
(defvar erc-auto-query)
(defvar erc-channel-list)
(defvar erc-channel-users)
(defvar erc-default-nicks)
(defvar erc-default-recipients)
(defvar erc-format-nick-function)
(defvar erc-format-query-as-channel-p)
(defvar erc-hide-prompt)
(defvar erc-input-marker)
(defvar erc-insert-marker)
(defvar erc-invitation)
(defvar erc-join-buffer)
(defvar erc-kill-buffer-on-part)
(defvar erc-kill-server-buffer-on-quit)
(defvar erc-log-p)
(defvar erc-minibuffer-ignored)
(defvar erc-networks--id)
(defvar erc-nick)
(defvar erc-nick-change-attempt-count)
(defvar erc-prompt-for-channel-key)
(defvar erc-prompt-hidden)
(defvar erc-reuse-buffers)
(defvar erc-verbose-server-ping)
(defvar erc-whowas-on-nosuchnick)
(declare-function erc--open-target "erc" (target))
(declare-function erc--target-from-string "erc" (string))
(declare-function erc-active-buffer "erc" nil)
(declare-function erc-add-default-channel "erc" (channel))
(declare-function erc-banlist-update "erc" (proc parsed))
(declare-function erc-buffer-filter "erc" (predicate &optional proc))
(declare-function erc-buffer-list-with-nick "erc" (nick proc))
(declare-function erc-channel-begin-receiving-names "erc" nil)
(declare-function erc-channel-end-receiving-names "erc" nil)
(declare-function erc-channel-p "erc" (channel))
(declare-function erc-channel-receive-names "erc" (names-string))
(declare-function erc-cmd-JOIN "erc" (channel &optional key))
(declare-function erc-connection-established "erc" (proc parsed))
(declare-function erc-current-nick "erc" nil)
(declare-function erc-current-nick-p "erc" (nick))
(declare-function erc-current-time "erc" (&optional specified-time))
(declare-function erc-default-target "erc" nil)
(declare-function erc-delete-default-channel "erc" (channel &optional buffer))
(declare-function erc-display-error-notice "erc" (parsed string))
(declare-function erc-display-server-message "erc" (_proc parsed))
(declare-function erc-emacs-time-to-erc-time "erc" (&optional specified-time))
(declare-function erc-format-message "erc" (msg &rest args))
(declare-function erc-format-privmessage "erc" (nick msg privp msgp))
(declare-function erc-get-buffer "erc" (target &optional proc))
(declare-function erc-handle-login "erc" nil)
(declare-function erc-handle-user-status-change "erc" (type nlh &optional l))
(declare-function erc-ignored-reply-p "erc" (msg tgt proc))
(declare-function erc-ignored-user-p "erc" (spec))
(declare-function erc-is-message-ctcp-and-not-action-p "erc" (message))
(declare-function erc-is-message-ctcp-p "erc" (message))
(declare-function erc-log-irc-protocol "erc" (string &optional outbound))
(declare-function erc-login "erc" nil)
(declare-function erc-make-notice "erc" (message))
(declare-function erc-network "erc-networks" nil)
(declare-function erc-networks--id-given "erc-networks" (arg &rest args))
(declare-function erc-networks--id-reload "erc-networks" (arg &rest args))
(declare-function erc-nickname-in-use "erc" (nick reason))
(declare-function erc-parse-user "erc" (string))
(declare-function erc-process-away "erc" (proc away-p))
(declare-function erc-process-ctcp-query "erc" (proc parsed nick login host))
(declare-function erc-query-buffer-p "erc" (&optional buffer))
(declare-function erc-remove-channel-member "erc" (channel nick))
(declare-function erc-remove-channel-users "erc" nil)
(declare-function erc-remove-user "erc" (nick))
(declare-function erc-sec-to-time "erc" (ns))
(declare-function erc-server-buffer "erc" nil)
(declare-function erc-set-active-buffer "erc" (buffer))
(declare-function erc-set-current-nick "erc" (nick))
(declare-function erc-set-modes "erc" (tgt mode-string))
(declare-function erc-time-diff "erc" (t1 t2))
(declare-function erc-trim-string "erc" (s))
(declare-function erc-update-mode-line "erc" (&optional buffer))
(declare-function erc-update-mode-line-buffer "erc" (buffer))
(declare-function erc-wash-quit-reason "erc" (reason nick login host))
(declare-function erc-display-message "erc"
(parsed type buffer msg &rest args))
(declare-function erc-get-buffer-create "erc"
(server port target &optional tgt-info id))
(declare-function erc-process-ctcp-reply "erc"
(proc parsed nick login host msg))
(declare-function erc-update-channel-topic "erc"
(channel topic &optional modify))
(declare-function erc-update-modes "erc"
(tgt mode-string &optional _nick _host _login))
(declare-function erc-update-user-nick "erc"
(nick &optional new-nick host login full-name info))
(declare-function erc-open "erc"
(&optional server port nick full-name connect passwd tgt-list
channel process client-certificate user id))
(declare-function erc-update-channel-member "erc"
(channel nick new-nick
&optional add voice halfop op admin owner host
login full-name info update-message-time))
;;;; Variables and options
(defvar-local erc-session-password nil
"The password used for the current session.")
(defvar erc-server-responses (make-hash-table :test #'equal)
"Hash table mapping server responses to their handler hooks.")
(cl-defstruct (erc-response (:conc-name erc-response.))
(unparsed "" :type string)
(sender "" :type string)
(command "" :type string)
(command-args '() :type list)
(contents "" :type string)
(tags '() :type list))
;;; User data
(defvar-local erc-server-current-nick nil
@ -1662,16 +1755,6 @@ Then display the welcome message."
(split-string value ",")
(list value)))))
(defmacro erc--with-memoization (table &rest forms)
"Adapter to be migrated to erc-compat."
(declare (indent defun))
`(cond
((fboundp 'with-memoization)
(with-memoization ,table ,@forms)) ; 29.1
((fboundp 'cl--generic-with-memoization)
(cl--generic-with-memoization ,table ,@forms))
(t ,@forms)))
(defun erc--get-isupport-entry (key &optional single)
"Return an item for \"ISUPPORT\" token KEY, a symbol.
When a lookup fails return nil. Otherwise return a list whose
@ -1681,7 +1764,7 @@ ambiguous and only useful for tokens supporting a single
primitive value."
(if-let* ((table (or erc--isupport-params
(erc-with-server-buffer erc--isupport-params)))
(value (erc--with-memoization (gethash key table)
(value (erc-compat--with-memoization (gethash key table)
(when-let ((v (assoc (symbol-name key)
erc-server-parameters)))
(if (cdr v)

271
lisp/erc/erc-common.el Normal file
View file

@ -0,0 +1,271 @@
;;; erc-common.el --- Macros and types for ERC -*- lexical-binding:t -*-
;; Copyright (C) 2022 Free Software Foundation, Inc.
;;
;; Maintainer: Amin Bandali <bandali@gnu.org>, F. Jason Park <jp@neverwas.me>
;; Keywords: comm, IRC, chat, client, internet
;;
;; 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/>.
;;; Commentary:
;;; Code:
(eval-when-compile (require 'cl-lib) (require 'subr-x))
(require 'erc-compat)
(defvar erc--casemapping-rfc1459)
(defvar erc--casemapping-rfc1459-strict)
(defvar erc-channel-users)
(defvar erc-dbuf)
(defvar erc-log-p)
(defvar erc-server-users)
(defvar erc-session-server)
(declare-function erc--get-isupport-entry "erc-backend" (key &optional single))
(declare-function erc-get-buffer "erc" (target &optional proc))
(declare-function erc-server-buffer "erc" nil)
(cl-defstruct erc-input
string insertp sendp)
(cl-defstruct (erc--input-split (:include erc-input))
lines cmdp)
(cl-defstruct (erc-server-user (:type vector) :named)
;; User data
nickname host login full-name info
;; Buffers
;;
;; This is an alist of the form (BUFFER . CHANNEL-DATA), where
;; CHANNEL-DATA is either nil or an erc-channel-user struct.
(buffers nil))
(cl-defstruct (erc-channel-user (:type vector) :named)
voice halfop op admin owner
;; Last message time (in the form of the return value of
;; (current-time)
;;
;; This is useful for ordered name completion.
(last-message-time nil))
(cl-defstruct erc--target
(string "" :type string :documentation "Received name of target.")
(symbol nil :type symbol :documentation "Case-mapped name as symbol."))
;; At some point, it may make sense to add a query type with an
;; account field, which may help support reassociation across
;; reconnects and nick changes (likely requires v3 extensions).
;;
;; These channel variants should probably take on a `joined' field to
;; track "joinedness", which `erc-server-JOIN', `erc-server-PART',
;; etc. should toggle. Functions like `erc--current-buffer-joined-p'
;; may find it useful.
(cl-defstruct (erc--target-channel (:include erc--target)))
(cl-defstruct (erc--target-channel-local (:include erc--target-channel)))
(cl-defstruct (erc-response (:conc-name erc-response.))
(unparsed "" :type string)
(sender "" :type string)
(command "" :type string)
(command-args '() :type list)
(contents "" :type string)
(tags '() :type list))
(defmacro define-erc-module (name alias doc enable-body disable-body
&optional local-p)
"Define a new minor mode using ERC conventions.
Symbol NAME is the name of the module.
Symbol ALIAS is the alias to use, or nil.
DOC is the documentation string to use for the minor mode.
ENABLE-BODY is a list of expressions used to enable the mode.
DISABLE-BODY is a list of expressions used to disable the mode.
If LOCAL-P is non-nil, the mode will be created as a buffer-local
mode, rather than a global one.
This will define a minor mode called erc-NAME-mode, possibly
an alias erc-ALIAS-mode, as well as the helper functions
erc-NAME-enable, and erc-NAME-disable.
Example:
;;;###autoload(autoload \\='erc-replace-mode \"erc-replace\")
(define-erc-module replace nil
\"This mode replaces incoming text according to `erc-replace-alist'.\"
((add-hook \\='erc-insert-modify-hook
#\\='erc-replace-insert))
((remove-hook \\='erc-insert-modify-hook
#\\='erc-replace-insert)))"
(declare (doc-string 3) (indent defun))
(let* ((sn (symbol-name name))
(mode (intern (format "erc-%s-mode" (downcase sn))))
(group (intern (format "erc-%s" (downcase sn))))
(enable (intern (format "erc-%s-enable" (downcase sn))))
(disable (intern (format "erc-%s-disable" (downcase sn)))))
`(progn
(define-minor-mode
,mode
,(format "Toggle ERC %S mode.
With a prefix argument ARG, enable %s if ARG is positive,
and disable it otherwise. If called from Lisp, enable the mode
if ARG is omitted or nil.
%s" name name doc)
;; FIXME: We don't know if this group exists, so this `:group' may
;; actually just silence a valid warning about the fact that the var
;; is not associated with any group.
:global ,(not local-p) :group (quote ,group)
(if ,mode
(,enable)
(,disable)))
(defun ,enable ()
,(format "Enable ERC %S mode."
name)
(interactive)
(add-to-list 'erc-modules (quote ,name))
(setq ,mode t)
,@enable-body)
(defun ,disable ()
,(format "Disable ERC %S mode."
name)
(interactive)
(setq erc-modules (delq (quote ,name) erc-modules))
(setq ,mode nil)
,@disable-body)
,(when (and alias (not (eq name alias)))
`(defalias
',(intern
(format "erc-%s-mode"
(downcase (symbol-name alias))))
#',mode))
;; For find-function and find-variable.
(put ',mode 'definition-name ',name)
(put ',enable 'definition-name ',name)
(put ',disable 'definition-name ',name))))
(defmacro erc-with-buffer (spec &rest body)
"Execute BODY in the buffer associated with SPEC.
SPEC should have the form
(TARGET [PROCESS])
If TARGET is a buffer, use it. Otherwise, use the buffer
matching TARGET in the process specified by PROCESS.
If PROCESS is nil, use the current `erc-server-process'.
See `erc-get-buffer' for details.
See also `with-current-buffer'.
\(fn (TARGET [PROCESS]) BODY...)"
(declare (indent 1) (debug ((form &optional form) body)))
(let ((buf (make-symbol "buf"))
(proc (make-symbol "proc"))
(target (make-symbol "target"))
(process (make-symbol "process")))
`(let* ((,target ,(car spec))
(,process ,(cadr spec))
(,buf (if (bufferp ,target)
,target
(let ((,proc (or ,process
(and (processp erc-server-process)
erc-server-process))))
(if (and ,target ,proc)
(erc-get-buffer ,target ,proc))))))
(when (buffer-live-p ,buf)
(with-current-buffer ,buf
,@body)))))
(defmacro erc-with-server-buffer (&rest body)
"Execute BODY in the current ERC server buffer.
If no server buffer exists, return nil."
(declare (indent 0) (debug (body)))
(let ((buffer (make-symbol "buffer")))
`(let ((,buffer (erc-server-buffer)))
(when (buffer-live-p ,buffer)
(with-current-buffer ,buffer
,@body)))))
(defmacro erc-with-all-buffers-of-server (process pred &rest forms)
"Execute FORMS in all buffers which have same process as this server.
FORMS will be evaluated in all buffers having the process PROCESS and
where PRED matches or in all buffers of the server process if PRED is
nil."
(declare (indent 2) (debug (form form body)))
(macroexp-let2 nil pred pred
`(erc-buffer-filter (lambda ()
(when (or (not ,pred) (funcall ,pred))
,@forms))
,process)))
(defun erc-log-aux (string)
"Do the debug logging of STRING."
(let ((cb (current-buffer))
(point 1)
(was-eob nil)
(session-buffer (erc-server-buffer)))
(if session-buffer
(progn
(set-buffer session-buffer)
(if (not (and erc-dbuf (bufferp erc-dbuf) (buffer-live-p erc-dbuf)))
(progn
(setq erc-dbuf (get-buffer-create
(concat "*ERC-DEBUG: "
erc-session-server "*")))))
(set-buffer erc-dbuf)
(setq point (point))
(setq was-eob (eobp))
(goto-char (point-max))
(insert (concat "** " string "\n"))
(if was-eob (goto-char (point-max))
(goto-char point))
(set-buffer cb))
(message "ERC: ** %s" string))))
(define-inline erc-log (string)
"Logs STRING if logging is on (see `erc-log-p')."
(inline-quote
(when erc-log-p
(erc-log-aux ,string))))
(defun erc-downcase (string)
"Return a downcased copy of STRING with properties.
Use the CASEMAPPING ISUPPORT parameter to determine the style."
(let* ((mapping (erc--get-isupport-entry 'CASEMAPPING 'single))
(inhibit-read-only t))
(if (equal mapping "ascii")
(downcase string)
(with-temp-buffer
(insert string)
(translate-region (point-min) (point-max)
(if (equal mapping "rfc1459-strict")
erc--casemapping-rfc1459-strict
erc--casemapping-rfc1459))
(buffer-string)))))
(define-inline erc-get-channel-user (nick)
"Find NICK in the current buffer's `erc-channel-users' hash table."
(inline-quote (gethash (erc-downcase ,nick) erc-channel-users)))
(define-inline erc-get-server-user (nick)
"Find NICK in the current server's `erc-server-users' hash table."
(inline-letevals (nick)
(inline-quote (erc-with-server-buffer
(gethash (erc-downcase ,nick) erc-server-users)))))
(provide 'erc-common)
;;; erc-common.el ends here

View file

@ -156,6 +156,18 @@ If START or END is negative, it counts from the end."
(setq i (1+ i) start (1+ start)))
res))))))
;;;; Misc 29.1
(defmacro erc-compat--with-memoization (table &rest forms)
(declare (indent defun))
(cond
((fboundp 'with-memoization)
`(with-memoization ,table ,@forms)) ; 29.1
((fboundp 'cl--generic-with-memoization)
`(cl--generic-with-memoization ,table ,@forms))
(t `(progn ,@forms))))
(provide 'erc-compat)
;;; erc-compat.el ends here

View file

@ -29,10 +29,23 @@
;;; Code:
(require 'erc)
;;; Imenu support
(require 'erc-common)
(defvar erc-controls-highlight-regexp)
(defvar erc-controls-remove-regexp)
(defvar erc-input-marker)
(defvar erc-insert-marker)
(defvar erc-server-process)
(defvar erc-modules)
(defvar erc-log-p)
(declare-function erc-buffer-list "erc" (&optional predicate proc))
(declare-function erc-error "erc" (&rest args))
(declare-function erc-extract-command-from-line "erc" (line))
(declare-function erc-beg-of-input-line "erc" nil)
(defun erc-imenu-setup ()
"Setup Imenu support in an ERC buffer."
(setq-local imenu-create-index-function #'erc-create-imenu-index))

View file

@ -39,8 +39,32 @@
;;; Code:
(require 'erc)
(eval-when-compile (require 'cl-lib))
(require 'erc-common)
(defvar erc--target)
(defvar erc-insert-marker)
(defvar erc-kill-buffer-hook)
(defvar erc-kill-server-hook)
(defvar erc-modules)
(defvar erc-rename-buffers)
(defvar erc-reuse-buffers)
(defvar erc-server-announced-name)
(defvar erc-server-connected)
(defvar erc-server-parameters)
(defvar erc-server-process)
(defvar erc-session-server)
(declare-function erc--default-target "erc" nil)
(declare-function erc--get-isupport-entry "erc-backend" (key &optional single))
(declare-function erc-buffer-filter "erc" (predicate &optional proc))
(declare-function erc-current-nick "erc" nil)
(declare-function erc-display-error-notice "erc" (parsed string))
(declare-function erc-error "erc" (&rest args))
(declare-function erc-get-buffer "erc" (target &optional proc))
(declare-function erc-server-buffer "erc" nil)
(declare-function erc-server-process-alive "erc-backend" (&optional buffer))
(declare-function erc-set-active-buffer "erc" (buffer))
;; Variables
@ -813,7 +837,7 @@ This may have originated from an `:id' arg to entry-point commands
(erc-networks--id-symbol nid))
(cl-generic-define-context-rewriter erc-obsolete-var (var spec)
`((with-suppressed-warnings ((obsolete ,var)) ,var) ,spec))
`((with-suppressed-warnings ((obsolete ,var) (free-vars ,var)) ,var) ,spec))
;; As a catch-all, derive the symbol from the unquoted printed repr.
(cl-defgeneric erc-networks--id-create (id)

View file

@ -60,6 +60,9 @@
(load "erc-loaddefs" 'noerror 'nomessage)
(require 'erc-networks)
(require 'erc-goodies)
(require 'erc-backend)
(require 'cl-lib)
(require 'format-spec)
(require 'pp)
@ -69,8 +72,6 @@
(require 'iso8601)
(eval-when-compile (require 'subr-x))
(require 'erc-compat)
(defconst erc-version "5.4.1"
"This version of ERC.")
@ -132,29 +133,12 @@
"Running scripts at startup and with /LOAD."
:group 'erc)
;; Defined in erc-backend
(defvar erc--server-last-reconnect-count)
(defvar erc--server-reconnecting)
(defvar erc-channel-members-changed-hook)
(defvar erc-network)
(defvar erc-networks--id)
(defvar erc-server-367-functions)
(defvar erc-server-announced-name)
(defvar erc-server-connect-function)
(defvar erc-server-connected)
(defvar erc-server-current-nick)
(defvar erc-server-lag)
(defvar erc-server-last-sent-time)
(defvar erc-server-process)
(defvar erc-server-quitting)
(defvar erc-server-reconnect-count)
(defvar erc-server-reconnecting)
(defvar erc-session-client-certificate)
(defvar erc-session-connector)
(defvar erc-session-port)
(defvar erc-session-server)
(defvar erc-session-user-full-name)
(defvar erc-session-username)
;; Forward declarations
(defvar erc-message-parsed)
(defvar tabbar--local-hlf)
(defvar motif-version-string)
(defvar gtk-version-string)
;; tunable connection and authentication parameters
@ -349,9 +333,6 @@ A typical value would be \((\"#emacs\" \"QUIT\" \"JOIN\")
:group 'erc-ignore
:type 'erc-message-type)
(defvar-local erc-session-password nil
"The password used for the current session.")
(defcustom erc-disconnected-hook nil
"Run this hook with arguments (NICK IP REASON) when disconnected.
This happens before automatic reconnection. Note, that
@ -436,69 +417,14 @@ It associates nicknames with `erc-server-user' struct instances.")
'((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|))
(mapcar (lambda (c) (cons c (+ c 32))) "ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
(defun erc-downcase (string)
"Return a downcased copy of STRING with properties.
Use the CASEMAPPING ISUPPORT parameter to determine the style."
(let* ((mapping (erc--get-isupport-entry 'CASEMAPPING 'single))
(inhibit-read-only t))
(if (equal mapping "ascii")
(downcase string)
(with-temp-buffer
(insert string)
(translate-region (point-min) (point-max)
(if (equal mapping "rfc1459-strict")
erc--casemapping-rfc1459-strict
erc--casemapping-rfc1459))
(buffer-string)))))
(defmacro erc-with-server-buffer (&rest body)
"Execute BODY in the current ERC server buffer.
If no server buffer exists, return nil."
(declare (indent 0) (debug (body)))
(let ((buffer (make-symbol "buffer")))
`(let ((,buffer (erc-server-buffer)))
(when (buffer-live-p ,buffer)
(with-current-buffer ,buffer
,@body)))))
(cl-defstruct (erc-server-user (:type vector) :named)
;; User data
nickname host login full-name info
;; Buffers
;;
;; This is an alist of the form (BUFFER . CHANNEL-DATA), where
;; CHANNEL-DATA is either nil or an erc-channel-user struct.
(buffers nil)
)
(cl-defstruct (erc-channel-user (:type vector) :named)
voice halfop op admin owner
;; Last message time (in the form of the return value of
;; (current-time)
;;
;; This is useful for ordered name completion.
(last-message-time nil))
(define-inline erc-get-channel-user (nick)
"Find NICK in the current buffer's `erc-channel-users' hash table."
(inline-quote (gethash (erc-downcase ,nick) erc-channel-users)))
(define-inline erc-get-server-user (nick)
"Find NICK in the current server's `erc-server-users' hash table."
(inline-letevals (nick)
(inline-quote (erc-with-server-buffer
(gethash (erc-downcase ,nick) erc-server-users)))))
(define-inline erc-add-server-user (nick user)
(defun erc-add-server-user (nick user)
"This function is for internal use only.
Adds USER with nickname NICK to the `erc-server-users' hash table."
(inline-letevals (nick user)
(inline-quote
(erc-with-server-buffer
(puthash (erc-downcase ,nick) ,user erc-server-users)))))
(erc-with-server-buffer
(puthash (erc-downcase nick) user erc-server-users)))
(define-inline erc-remove-server-user (nick)
(defun erc-remove-server-user (nick)
"This function is for internal use only.
Removes the user with nickname NICK from the `erc-server-users'
@ -506,10 +432,8 @@ hash table. This user is not removed from the
`erc-channel-users' lists of other buffers.
See also: `erc-remove-user'."
(inline-letevals (nick)
(inline-quote
(erc-with-server-buffer
(remhash (erc-downcase ,nick) erc-server-users)))))
(erc-with-server-buffer
(remhash (erc-downcase nick) erc-server-users)))
(defun erc-change-user-nickname (user new-nick)
"This function is for internal use only.
@ -580,55 +504,45 @@ Removes all users in the current channel. This is called by
erc-channel-users)
(clrhash erc-channel-users)))
(define-inline erc-channel-user-owner-p (nick)
(defun erc-channel-user-owner-p (nick)
"Return non-nil if NICK is an owner of the current channel."
(inline-letevals (nick)
(inline-quote
(and ,nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user ,nick)))
(and cdata (cdr cdata)
(erc-channel-user-owner (cdr cdata))))))))
(and nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user nick)))
(and cdata (cdr cdata)
(erc-channel-user-owner (cdr cdata))))))
(define-inline erc-channel-user-admin-p (nick)
(defun erc-channel-user-admin-p (nick)
"Return non-nil if NICK is an admin in the current channel."
(inline-letevals (nick)
(inline-quote
(and ,nick
(and nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user ,nick)))
(let ((cdata (erc-get-channel-user nick)))
(and cdata (cdr cdata)
(erc-channel-user-admin (cdr cdata))))))))
(erc-channel-user-admin (cdr cdata))))))
(define-inline erc-channel-user-op-p (nick)
(defun erc-channel-user-op-p (nick)
"Return non-nil if NICK is an operator in the current channel."
(inline-letevals (nick)
(inline-quote
(and ,nick
(and nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user ,nick)))
(let ((cdata (erc-get-channel-user nick)))
(and cdata (cdr cdata)
(erc-channel-user-op (cdr cdata))))))))
(erc-channel-user-op (cdr cdata))))))
(define-inline erc-channel-user-halfop-p (nick)
(defun erc-channel-user-halfop-p (nick)
"Return non-nil if NICK is a half-operator in the current channel."
(inline-letevals (nick)
(inline-quote
(and ,nick
(and nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user ,nick)))
(let ((cdata (erc-get-channel-user nick)))
(and cdata (cdr cdata)
(erc-channel-user-halfop (cdr cdata))))))))
(erc-channel-user-halfop (cdr cdata))))))
(define-inline erc-channel-user-voice-p (nick)
(defun erc-channel-user-voice-p (nick)
"Return non-nil if NICK has voice in the current channel."
(inline-letevals (nick)
(inline-quote
(and ,nick
(and nick
(hash-table-p erc-channel-users)
(let ((cdata (erc-get-channel-user ,nick)))
(let ((cdata (erc-get-channel-user nick)))
(and cdata (cdr cdata)
(erc-channel-user-voice (cdr cdata))))))))
(erc-channel-user-voice (cdr cdata))))))
(defun erc-get-channel-user-list ()
"Return a list of users in the current channel.
@ -1377,96 +1291,6 @@ See also `erc-show-my-nick'."
(defvar-local erc-dbuf nil)
(defmacro define-erc-module (name alias doc enable-body disable-body
&optional local-p)
"Define a new minor mode using ERC conventions.
Symbol NAME is the name of the module.
Symbol ALIAS is the alias to use, or nil.
DOC is the documentation string to use for the minor mode.
ENABLE-BODY is a list of expressions used to enable the mode.
DISABLE-BODY is a list of expressions used to disable the mode.
If LOCAL-P is non-nil, the mode will be created as a buffer-local
mode, rather than a global one.
This will define a minor mode called erc-NAME-mode, possibly
an alias erc-ALIAS-mode, as well as the helper functions
erc-NAME-enable, and erc-NAME-disable.
Example:
;;;###autoload(autoload \\='erc-replace-mode \"erc-replace\")
(define-erc-module replace nil
\"This mode replaces incoming text according to `erc-replace-alist'.\"
((add-hook \\='erc-insert-modify-hook
#\\='erc-replace-insert))
((remove-hook \\='erc-insert-modify-hook
#\\='erc-replace-insert)))"
(declare (doc-string 3) (indent defun))
(let* ((sn (symbol-name name))
(mode (intern (format "erc-%s-mode" (downcase sn))))
(group (intern (format "erc-%s" (downcase sn))))
(enable (intern (format "erc-%s-enable" (downcase sn))))
(disable (intern (format "erc-%s-disable" (downcase sn)))))
`(progn
(define-minor-mode
,mode
,(format "Toggle ERC %S mode.
With a prefix argument ARG, enable %s if ARG is positive,
and disable it otherwise. If called from Lisp, enable the mode
if ARG is omitted or nil.
%s" name name doc)
;; FIXME: We don't know if this group exists, so this `:group' may
;; actually just silence a valid warning about the fact that the var
;; is not associated with any group.
:global ,(not local-p) :group (quote ,group)
(if ,mode
(,enable)
(,disable)))
(defun ,enable ()
,(format "Enable ERC %S mode."
name)
(interactive)
(add-to-list 'erc-modules (quote ,name))
(setq ,mode t)
,@enable-body)
(defun ,disable ()
,(format "Disable ERC %S mode."
name)
(interactive)
(setq erc-modules (delq (quote ,name) erc-modules))
(setq ,mode nil)
,@disable-body)
,(when (and alias (not (eq name alias)))
`(defalias
',(intern
(format "erc-%s-mode"
(downcase (symbol-name alias))))
#',mode))
;; For find-function and find-variable.
(put ',mode 'definition-name ',name)
(put ',enable 'definition-name ',name)
(put ',disable 'definition-name ',name))))
;; The rationale for favoring inheritance here (nicer dispatch) is
;; kinda flimsy since there aren't yet any actual methods.
(cl-defstruct erc--target
(string "" :type string :documentation "Received name of target.")
(symbol nil :type symbol :documentation "Case-mapped name as symbol."))
;; These should probably take on a `joined' field to track joinedness,
;; which should be toggled by `erc-server-JOIN', `erc-server-PART',
;; etc. Functions like `erc--current-buffer-joined-p' (bug#48598) may
;; find it useful.
(cl-defstruct (erc--target-channel (:include erc--target)))
(cl-defstruct (erc--target-channel-local (:include erc--target-channel)))
;; At some point, it may make sense to add a query type with an
;; account field, which may help support reassociation across
;; reconnects and nick changes (likely requires v3 extensions).
(defun erc--target-from-string (string)
"Construct an `erc--target' variant from STRING."
(funcall (if (erc-channel-p string)
@ -1516,12 +1340,6 @@ capabilities."
(add-hook hook fun nil t)
fun))
(define-inline erc-log (string)
"Logs STRING if logging is on (see `erc-log-p')."
(inline-quote
(when erc-log-p
(erc-log-aux ,string))))
(defun erc-server-buffer ()
"Return the server buffer for the current buffer's process.
The buffer-local variable `erc-server-process' is used to find
@ -1577,29 +1395,7 @@ If BUFFER is nil, the current buffer is used."
(if erc-online-p "" "not "))
erc-online-p))))
(defun erc-log-aux (string)
"Do the debug logging of STRING."
(let ((cb (current-buffer))
(point 1)
(was-eob nil)
(session-buffer (erc-server-buffer)))
(if session-buffer
(progn
(set-buffer session-buffer)
(if (not (and erc-dbuf (bufferp erc-dbuf) (buffer-live-p erc-dbuf)))
(progn
(setq erc-dbuf (get-buffer-create
(concat "*ERC-DEBUG: "
erc-session-server "*")))))
(set-buffer erc-dbuf)
(setq point (point))
(setq was-eob (eobp))
(goto-char (point-max))
(insert (concat "** " string "\n"))
(if was-eob (goto-char (point-max))
(goto-char point))
(set-buffer cb))
(message "ERC: ** %s" string))))
;; Last active buffer, to print server messages in the right place
@ -1841,40 +1637,6 @@ All strings are compared according to IRC protocol case rules, see
(throw 'result list)
(setq list (cdr list))))))
(defmacro erc-with-buffer (spec &rest body)
"Execute BODY in the buffer associated with SPEC.
SPEC should have the form
(TARGET [PROCESS])
If TARGET is a buffer, use it. Otherwise, use the buffer
matching TARGET in the process specified by PROCESS.
If PROCESS is nil, use the current `erc-server-process'.
See `erc-get-buffer' for details.
See also `with-current-buffer'.
\(fn (TARGET [PROCESS]) BODY...)"
(declare (indent 1) (debug ((form &optional form) body)))
(let ((buf (make-symbol "buf"))
(proc (make-symbol "proc"))
(target (make-symbol "target"))
(process (make-symbol "process")))
`(let* ((,target ,(car spec))
(,process ,(cadr spec))
(,buf (if (bufferp ,target)
,target
(let ((,proc (or ,process
(and (processp erc-server-process)
erc-server-process))))
(if (and ,target ,proc)
(erc-get-buffer ,target ,proc))))))
(when (buffer-live-p ,buf)
(with-current-buffer ,buf
,@body)))))
(defun erc-get-buffer (target &optional proc)
"Return the buffer matching TARGET in the process PROC.
If PROC is not supplied, all processes are searched."
@ -1921,18 +1683,6 @@ needs to match PROC."
(setq predicate (lambda () t)))
(erc-buffer-filter predicate proc))
(defmacro erc-with-all-buffers-of-server (process pred &rest forms)
"Execute FORMS in all buffers which have same process as this server.
FORMS will be evaluated in all buffers having the process PROCESS and
where PRED matches or in all buffers of the server process if PRED is
nil."
(declare (indent 1) (debug (form form body)))
(macroexp-let2 nil pred pred
`(erc-buffer-filter (lambda ()
(when (or (not ,pred) (funcall ,pred))
,@forms))
,process)))
(define-obsolete-function-alias 'erc-iswitchb #'erc-switch-to-buffer "25.1")
(defun erc--switch-to-buffer (&optional arg)
(read-buffer "Switch to ERC buffer: "
@ -2877,8 +2627,6 @@ every `erc-lurker-cleanup-interval' updates to
consumption of lurker state during long Emacs sessions and/or ERC
sessions with large numbers of incoming PRIVMSGs.")
(defvar erc-message-parsed)
(defun erc-lurker-update-status (_message)
"Update `erc-lurker-state' if necessary.
@ -4090,9 +3838,6 @@ the message given by REASON."
t)
(put 'erc-cmd-SERVER 'process-not-needed t)
(defvar motif-version-string)
(defvar gtk-version-string)
(defun erc-cmd-SV ()
"Say the current ERC and Emacs version into channel."
(erc-send-message (format "I'm using ERC %s with GNU Emacs %s (%s%s)%s."
@ -5349,6 +5094,12 @@ Example: (operator) o => @, (voiced) v => +."
(setq i (1+ i)))
alist))))
(defcustom erc-channel-members-changed-hook nil
"This hook is called every time the variable `channel-members' changes.
The buffer where the change happened is current while this hook is called."
:group 'erc-hooks
:type 'hook)
(defun erc-channel-receive-names (names-string)
"This function is for internal use only.
@ -5392,13 +5143,6 @@ channel."
name name t voice halfop op admin owner)))))
(run-hooks 'erc-channel-members-changed-hook)))
(defcustom erc-channel-members-changed-hook nil
"This hook is called every time the variable `channel-members' changes.
The buffer where the change happened is current while this hook is called."
:group 'erc-hooks
:type 'hook)
(defun erc-update-user-nick (nick &optional new-nick
host login full-name info)
"Update the stored user information for the user with nickname NICK.
@ -6008,12 +5752,6 @@ When the returned value is a string, pass it to `erc-error'.")
(defvar erc-command-regexp "^/\\([A-Za-z']+\\)\\(\\s-+.*\\|\\s-*\\)$"
"Regular expression used for matching commands in ERC.")
(cl-defstruct erc-input
string insertp sendp)
(cl-defstruct (erc--input-split (:include erc-input))
lines cmdp)
(defun erc--discard-trailing-multiline-nulls (state)
"Ensure last line of STATE's string is non-null.
But only when `erc-send-whitespace-lines' is non-nil. STATE is
@ -6957,9 +6695,6 @@ shortened server name instead."
(t ""))))
;; erc-goodies is required at end of this file.
(declare-function erc-controls-strip "erc-goodies" (str))
(defvar tabbar--local-hlf)
;; FIXME when 29.1 is cut and `format-spec' is added to ELPA Compat,
;; remove the function invocations from the spec form below.
@ -7448,12 +7183,4 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL."
(provide 'erc)
(require 'erc-backend)
;; Deprecated. We might eventually stop requiring the goodies automatically.
;; IMPORTANT: This require must appear _after_ the above (provide 'erc) to
;; avoid a recursive require error when byte-compiling the entire package.
(require 'erc-goodies)
(require 'erc-networks)
;;; erc.el ends here

View file

@ -20,7 +20,7 @@
;;; Code:
(require 'ert-x) ; cl-lib
(require 'erc-networks)
(require 'erc)
(defun erc-networks-tests--create-dead-proc (&optional buf)
(let ((p (start-process "true" (or buf (current-buffer)) "true")))

View file

@ -24,7 +24,6 @@
(require 'ert-x)
(require 'erc)
(require 'erc-ring)
(require 'erc-networks)
(ert-deftest erc--read-time-period ()
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "")))
@ -48,27 +47,6 @@
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1d")))
(should (equal (erc--read-time-period "foo: ") 86400))))
(ert-deftest erc--meta--backend-dependencies ()
(with-temp-buffer
(insert-file-contents-literally
(concat (file-name-sans-extension (symbol-file 'erc)) ".el"))
(let ((beg (search-forward ";; Defined in erc-backend"))
(end (search-forward "\n\n"))
vars)
(save-excursion
(save-restriction
(narrow-to-region beg end)
(goto-char (point-min))
(with-syntax-table lisp-data-mode-syntax-table
(condition-case _
(while (push (cadr (read (current-buffer))) vars))
(end-of-file)))))
(should (= (point) end))
(dolist (var vars)
(setq var (concat "\\_<" (symbol-name var) "\\_>"))
(ert-info (var)
(should (save-excursion (search-forward-regexp var nil t))))))))
(ert-deftest erc-with-all-buffers-of-server ()
(let (proc-exnet
proc-onet