;;; 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
(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
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)
--- /dev/null
+;;; 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
(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
;;; 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))
;;; 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
(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)
(load "erc-loaddefs" 'noerror 'nomessage)
+(require 'erc-networks)
+(require 'erc-goodies)
+(require 'erc-backend)
(require 'cl-lib)
(require 'format-spec)
(require 'pp)
(require 'iso8601)
(eval-when-compile (require 'subr-x))
-(require 'erc-compat)
-
(defconst erc-version "5.4.1"
"This version of ERC.")
"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
: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
'((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|))
(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'
`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.
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))))))))
-
-(define-inline erc-channel-user-admin-p (nick)
+ (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))))))
+
+(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.
(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)
(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
(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
(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."
(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: "
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.
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."
(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.
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.
(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
(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.
(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
;;; 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")))
(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 _) "")))
(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