diff options
Diffstat (limited to 'lisp/erc')
30 files changed, 849 insertions, 490 deletions
diff --git a/lisp/erc/erc-autoaway.el b/lisp/erc/erc-autoaway.el index 1a13aa95cd2..f7de61ce797 100644 --- a/lisp/erc/erc-autoaway.el +++ b/lisp/erc/erc-autoaway.el @@ -43,8 +43,7 @@ This is only used when `erc-autoaway-idle-method' is set to `emacs'.") "The last time the user sent something.") (defvar erc-autoaway-caused-away nil - "Indicates whether this module was responsible for setting the -user's away status.") + "Non-nil if this module was responsible for setting the user's away status.") (defvar erc-autoaway-idle-seconds) @@ -183,7 +182,7 @@ See `erc-auto-discard-away'." (defcustom erc-autoaway-idle-seconds 1800 "Number of seconds after which ERC will set you automatically away. -If you are changing this variable using lisp instead of customizing it, +If you are changing this variable using Lisp instead of customizing it, you have to run `erc-autoaway-reestablish-idletimer' afterwards." :set (lambda (sym val) (set-default sym val) @@ -228,8 +227,7 @@ NONE-ALIVE-FUNC is the function to call if no ERC processes are alive." (when none-alive-func (funcall none-alive-func))))) (defun erc-autoaway-some-open-server-buffer () - "Return some ERC server buffer if its connection is alive and the -user is not away. + "Return some ERC server buffer if its connection is alive and user is not away. If none is found, return nil." (car (erc-buffer-list (lambda () (and (erc-open-server-buffer-p) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 7a17ee233fd..69f63dfbc44 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -199,6 +199,11 @@ active, use the `erc-server-process-alive' function instead.") (defvar-local erc-server-reconnecting nil "Non-nil if the user requests an explicit reconnect, and the current IRC process is still alive.") +(make-obsolete-variable 'erc-server-reconnecting + "see `erc--server-reconnecting'" "29.1") + +(defvar-local erc--server-reconnecting nil + "Non-nil when reconnecting.") (defvar-local erc-server-timed-out nil "Non-nil if the IRC server failed to respond to a ping.") @@ -233,8 +238,7 @@ This is useful for detecting hung connections.") This variable is only set in a server buffer.") (defvar-local erc-server-filter-data nil - "The data that arrived from the server -but has not been processed yet.") + "The data that arrived from the server but has not been processed yet.") (defvar-local erc-server-duplicates (make-hash-table :test 'equal) "Internal variable used to track duplicate messages.") @@ -278,16 +282,15 @@ Reconnection will happen automatically for any unexpected disconnection." :type 'boolean) (defcustom erc-server-reconnect-attempts 2 - "The number of times that ERC will attempt to reestablish a -broken connection, or t to always attempt to reconnect. + "Number of times that ERC will attempt to reestablish a broken connection. +If t, always attempt to reconnect. This only has an effect if `erc-server-auto-reconnect' is non-nil." :type '(choice (const :tag "Always reconnect" t) integer)) (defcustom erc-server-reconnect-timeout 1 - "The amount of time, in seconds, that ERC will wait between -successive reconnect attempts. + "Number of seconds to wait between successive reconnect attempts. If a key is pressed while ERC is waiting, it will stop waiting." :type 'number) @@ -446,7 +449,7 @@ Currently this is called by `erc-send-input'." (defun erc-forward-word () "Move forward one word, ignoring any subword settings. -If no subword-mode is active, then this is (forward-word)." +If no `subword-mode' is active, then this is (forward-word)." (skip-syntax-forward "^w") (> (skip-syntax-forward "w") 0)) @@ -460,7 +463,7 @@ If POS is out of range, the value is nil." (defun erc-bounds-of-word-at-point () "Return the bounds of word at point, or nil if we're not at a word. -If no subword-mode is active, then this is +If no `subword-mode' is active, then this is \(bounds-of-thing-at-point 'word)." (if (or (erc-word-at-arg-p (point)) (erc-word-at-arg-p (1- (point)))) @@ -535,7 +538,8 @@ TLS (see `erc-session-client-certificate' for more details)." (with-current-buffer buffer (setq erc-server-process process) (setq erc-server-quitting nil) - (setq erc-server-reconnecting nil) + (setq erc-server-reconnecting nil + erc--server-reconnecting nil) (setq erc-server-timed-out nil) (setq erc-server-banned nil) (setq erc-server-error-occurred nil) @@ -618,36 +622,42 @@ Make sure you are in an ERC buffer when running this." (erc-log-irc-protocol line nil) (erc-parse-server-response process line))))))) -(define-inline erc-server-reconnect-p (event) +(defun erc--server-reconnect-p (event) + "Return non-nil when ERC should attempt to reconnect. +EVENT is the message received from the closed connection process." + (and erc-server-auto-reconnect + (not erc-server-banned) + ;; make sure we don't infinitely try to reconnect, unless the + ;; user wants that + (or (eq erc-server-reconnect-attempts t) + (and (integerp erc-server-reconnect-attempts) + (< erc-server-reconnect-count + erc-server-reconnect-attempts))) + (or erc-server-timed-out + (not (string-match "^deleted" event))) + ;; open-network-stream-nowait error for connection refused + (if (string-match "^failed with code 111" event) 'nonblocking t))) + +(defun erc-server-reconnect-p (event) "Return non-nil if ERC should attempt to reconnect automatically. EVENT is the message received from the closed connection process." - (inline-letevals (event) - (inline-quote - (or erc-server-reconnecting - (and erc-server-auto-reconnect - (not erc-server-banned) - ;; make sure we don't infinitely try to reconnect, unless the - ;; user wants that - (or (eq erc-server-reconnect-attempts t) - (and (integerp erc-server-reconnect-attempts) - (< erc-server-reconnect-count - erc-server-reconnect-attempts))) - (or erc-server-timed-out - (not (string-match "^deleted" ,event))) - ;; open-network-stream-nowait error for connection refused - (if (string-match "^failed with code 111" ,event) 'nonblocking t)))))) + (declare (obsolete "see `erc--server-reconnect-p'" "29.1")) + (or (with-suppressed-warnings ((obsolete erc-server-reconnecting)) + erc-server-reconnecting) + (erc--server-reconnect-p event))) (defun erc-process-sentinel-2 (event buffer) "Called when `erc-process-sentinel-1' has detected an unexpected disconnect." (if (not (buffer-live-p buffer)) (erc-update-mode-line) (with-current-buffer buffer - (let ((reconnect-p (erc-server-reconnect-p event)) message delay) + (let ((reconnect-p (erc--server-reconnect-p event)) message delay) (setq message (if reconnect-p 'disconnected 'disconnected-noreconnect)) (erc-display-message nil 'error (current-buffer) message) (if (not reconnect-p) ;; terminate, do not reconnect (progn + (setq erc--server-reconnecting nil) (erc-display-message nil 'error (current-buffer) 'terminated ?e event) ;; Update mode line indicators @@ -656,7 +666,8 @@ EVENT is the message received from the closed connection process." ;; reconnect (condition-case nil (progn - (setq erc-server-reconnecting nil + (setq erc-server-reconnecting nil + erc--server-reconnecting t erc-server-reconnect-count (1+ erc-server-reconnect-count)) (setq delay erc-server-reconnect-timeout) (run-at-time delay nil @@ -950,15 +961,22 @@ PROCs `process-buffer' is `current-buffer' when this function is called." (unless (string= string "") ;; Ignore empty strings (save-match-data (let* ((tag-list (when (eq (aref string 0) ?@) - (substring string 1 (string-match " " string)))) + (substring string 1 + (if (>= emacs-major-version 28) + (string-search " " string) + (string-match " " string))))) (msg (make-erc-response :unparsed string :tags (when tag-list (erc-parse-tags tag-list)))) (string (if tag-list - (substring string (+ 1 (string-match " " string))) + (substring string (+ 1 (if (>= emacs-major-version 28) + (string-search " " string) + (string-match " " string)))) string)) (posn (if (eq (aref string 0) ?:) - (string-match " " string) + (if (>= emacs-major-version 28) + (string-search " " string) + (string-match " " string)) 0))) (setf (erc-response.sender msg) @@ -968,7 +986,9 @@ PROCs `process-buffer' is `current-buffer' when this function is called." (setf (erc-response.command msg) (let* ((bposn (string-match "[^ \n]" string posn)) - (eposn (string-match " " string bposn))) + (eposn (if (>= emacs-major-version 28) + (string-search " " string bposn) + (string-match " " string bposn)))) (setq posn (and eposn (string-match "[^ \n]" string eposn))) (substring string bposn eposn))) @@ -976,7 +996,9 @@ PROCs `process-buffer' is `current-buffer' when this function is called." (while (and posn (not (eq (aref string posn) ?:))) (push (let* ((bposn posn) - (eposn (string-match " " string bposn))) + (eposn (if (>= emacs-major-version 28) + (string-search " " string bposn) + (string-match " " string bposn)))) (setq posn (and eposn (string-match "[^ \n]" string eposn))) (substring string bposn eposn)) @@ -1160,7 +1182,8 @@ Would expand to: \(fn (NAME &rest ALIASES) &optional EXTRA-FN-DOC EXTRA-VAR-DOC &rest FN-BODY)" (declare (debug (&define [&name "erc-response-handler@" (symbolp &rest symbolp)] - &optional sexp sexp def-body))) + &optional sexp sexp def-body)) + (indent defun)) (if (numberp name) (setq name (intern (format "%03i" name)))) (setq aliases (mapcar (lambda (a) (if (numberp a) @@ -1523,7 +1546,8 @@ add things to `%s' instead." 'WALLOPS ?n nick ?m message)))) (define-erc-response-handler (001) - "Set `erc-server-current-nick' to reflect server settings and display the welcome message." + "Set `erc-server-current-nick' to reflect server settings. +Then display the welcome message." nil (erc-set-current-nick (car (erc-response.command-args parsed))) (erc-update-mode-line) ; needed here? diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 5953471ae8e..69972856d19 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -24,7 +24,7 @@ ;;; Commentary: -;; Heavily borrowed from gnus-art.el. Thanks to the original authors. +;; Heavily borrowed from gnus-art.el. Thanks to the original authors. ;; This buttonizes nicks and other stuff to make it all clickable. ;; To enable, add to your init file: ;; (require 'erc-button) @@ -130,7 +130,7 @@ longer than `erc-fill-column'." ("<URL: *\\([^<> ]+\\) *>" 0 t browse-url-button-open-url 1) ;;; ("(\\(\\([^~\n \t@][^\n \t@]*\\)@\\([a-zA-Z0-9.:-]+\\)\\)" 1 t finger 2 3) ;; emacs internal - ("[`]\\([a-zA-Z][-a-zA-Z_0-9!*<=>+]+\\)[']" + ("[`‘]\\([a-zA-Z][-a-zA-Z_0-9!*<=>+]+\\)['’]" 1 t erc-button-describe-symbol 1) ;; pseudo links ("\\bInfo:[\"]\\([^\"]+\\)[\"]" 0 t Info-goto-node 1) @@ -165,7 +165,7 @@ REGEXP is the string matching text around the button or a symbol BUTTON is the number of the regexp grouping actually matching the button. This is ignored if REGEXP is \\='nicknames. -FORM is a lisp expression which must eval to true for the button to +FORM is a Lisp expression which must eval to true for the button to be added. CALLBACK is the function to call when the user push this button. @@ -194,9 +194,10 @@ PAR is a number of a regexp grouping whose text will be passed to :inline t (integer :tag "Regexp section number"))))) -(defcustom erc-emacswiki-url "https://www.emacswiki.org/cgi-bin/wiki.pl?" - "URL of the EmacsWiki Homepage." - :type 'string) +(defcustom erc-emacswiki-url "https://www.emacswiki.org/emacs/" + "URL of the EmacsWiki website." + :type 'string + :version "28.1") (defcustom erc-emacswiki-lisp-url "https://www.emacswiki.org/elisp/" "URL of the EmacsWiki ELisp area." @@ -388,12 +389,11 @@ REGEXP is the regular expression which matched for this button." (mouse-set-point event) (erc-button-press-button))) -;; XEmacs calls this via widget-button-press with a bunch of arguments -;; which we don't care about. (defun erc-button-press-button (&rest _ignore) "Check text at point for a callback function. If the text at point has a `erc-callback' property, call it with the value of the `erc-data' text property." + (declare (advertised-calling-convention () "28.1")) (interactive) (let* ((data (get-text-property (point) 'erc-data)) (fun (get-text-property (point) 'erc-callback))) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el new file mode 100644 index 00000000000..9bbc1f6a0d1 --- /dev/null +++ b/lisp/erc/erc-compat.el @@ -0,0 +1,159 @@ +;;; erc-compat.el --- ERC compatibility code for older Emacsen -*- lexical-binding: t; -*- + +;; Copyright (C) 2002-2003, 2005-2021 Free Software Foundation, Inc. + +;; Author: Alex Schroeder <alex@gnu.org> +;; Maintainer: Amin Bandali <bandali@gnu.org> +;; URL: https://www.emacswiki.org/emacs/ERC + +;; 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: + +;; This mostly defines stuff that cannot be worked around easily. + +;;; Code: + +;;;###autoload(autoload 'erc-define-minor-mode "erc-compat") +(define-obsolete-function-alias 'erc-define-minor-mode + #'define-minor-mode "28.1") + +(defun erc-decode-coding-string (s coding-system) + "Decode S using CODING-SYSTEM." + (declare (obsolete decode-coding-string "28.1")) + (decode-coding-string s coding-system t)) + +(defun erc-encode-coding-string (s coding-system) + "Encode S using CODING-SYSTEM. +Return the same string, if the encoding operation is trivial. +See `erc-encoding-coding-alist'." + (declare (obsolete encode-coding-string "28.1")) + (encode-coding-string s coding-system t)) + +(define-obsolete-function-alias 'erc-propertize #'propertize "28.1") +(define-obsolete-function-alias 'erc-view-mode-enter #'view-mode-enter "28.1") +(autoload 'help-function-arglist "help-fns") +(define-obsolete-function-alias 'erc-function-arglist #'help-function-arglist "28.1") +(define-obsolete-function-alias 'erc-delete-dups #'delete-dups "28.1") +(define-obsolete-function-alias 'erc-replace-regexp-in-string #'replace-regexp-in-string "28.1") + +(defun erc-set-write-file-functions (new-val) + (declare (obsolete nil "28.1")) + (set (make-local-variable 'write-file-functions) new-val)) + +(defvar erc-emacs-build-time + (if (or (stringp emacs-build-time) (not emacs-build-time)) + emacs-build-time + (format-time-string "%Y-%m-%d" emacs-build-time)) + "Time at which Emacs was dumped out, or nil if not available.") +(make-obsolete-variable 'erc-emacs-build-time 'emacs-build-time "28.1") +(define-obsolete-variable-alias 'erc-user-emacs-directory 'user-emacs-directory "28.1") + +(defun erc-replace-match-subexpression-in-string + (newtext string _match subexp _start &optional fixedcase literal) + "Replace the subexpression SUBEXP of the last match in STRING with NEWTEXT. +MATCH is the text which matched the subexpression (see `match-string'). +START is the beginning position of the last match (see `match-beginning'). +See `replace-match' for explanations of FIXEDCASE and LITERAL." + (declare (obsolete replace-match "28.1")) + (replace-match newtext fixedcase literal string subexp)) + +(define-obsolete-function-alias 'erc-with-selected-window + #'with-selected-window "28.1") +(define-obsolete-function-alias 'erc-cancel-timer #'cancel-timer "28.1") +(define-obsolete-function-alias 'erc-make-obsolete #'make-obsolete "28.1") +(define-obsolete-function-alias 'erc-make-obsolete-variable + #'make-obsolete-variable "28.1") + +;; Provide a simpler replacement for `cl-member-if' +(defun erc-member-if (predicate list) + "Find the first item satisfying PREDICATE in LIST. +Return the sublist of LIST whose car matches." + (declare (obsolete cl-member-if "28.1")) + (let ((ptr list)) + (catch 'found + (while ptr + (when (funcall predicate (car ptr)) + (throw 'found ptr)) + (setq ptr (cdr ptr)))))) + +;; Provide a simpler replacement for `cl-delete-if' +(defun erc-delete-if (predicate seq) + "Remove all items satisfying PREDICATE in SEQ. +This is a destructive function: it reuses the storage of SEQ +whenever possible." + (declare (obsolete cl-delete-if "28.1")) + ;; remove from car + (while (when (funcall predicate (car seq)) + (setq seq (cdr seq)))) + ;; remove from cdr + (let ((ptr seq) + (next (cdr seq))) + (while next + (when (funcall predicate (car next)) + (setcdr ptr (if (consp next) + (cdr next) + nil))) + (setq ptr (cdr ptr)) + (setq next (cdr ptr)))) + seq) + +;; Provide a simpler replacement for `cl-remove-if-not' +(defun erc-remove-if-not (predicate seq) + "Remove all items not satisfying PREDICATE in SEQ. +This is a non-destructive function; it makes a copy of SEQ to +avoid corrupting the original SEQ." + (declare (obsolete cl-remove-if-not "28.1")) + (let (newseq) + (dolist (el seq) + (when (funcall predicate el) + (setq newseq (cons el newseq)))) + (nreverse newseq))) + +;; Copied from cl-extra.el +(defun erc-subseq (seq start &optional end) + "Return the subsequence of SEQ from START to END. +If END is omitted, it defaults to the length of the sequence. +If START or END is negative, it counts from the end." + (declare (obsolete cl-subseq "28.1")) + (if (stringp seq) (substring seq start end) + (let (len) + (and end (< end 0) (setq end (+ end (setq len (length seq))))) + (if (< start 0) (setq start (+ start (or len (setq len (length seq)))))) + (cond ((listp seq) + (if (> start 0) (setq seq (nthcdr start seq))) + (if end + (let ((res nil)) + (while (>= (setq end (1- end)) start) + (push (pop seq) res)) + (nreverse res)) + (copy-sequence seq))) + (t + (or end (setq end (or len (length seq)))) + (let ((res (make-vector (max (- end start) 0) nil)) + (i 0)) + (while (< start end) + (aset res i (aref seq start)) + (setq i (1+ i) start (1+ start))) + res)))))) + +(provide 'erc-compat) + +;;; erc-compat.el ends here +;; +;; Local Variables: +;; generated-autoload-file: "erc-loaddefs.el" +;; End: diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el index 219af3741fa..f27425ac8a1 100644 --- a/lisp/erc/erc-dcc.el +++ b/lisp/erc/erc-dcc.el @@ -1,7 +1,6 @@ ;;; erc-dcc.el --- CTCP DCC module for ERC -*- lexical-binding: t; -*- -;; Copyright (C) 1993-1995, 1998, 2002-2004, 2006-2021 Free Software -;; Foundation, Inc. +;; Copyright (C) 1993-2021 Free Software Foundation, Inc. ;; Author: Ben A. Mesander <ben@gnu.ai.mit.edu> ;; Noah Friedman <friedman@prep.ai.mit.edu> @@ -81,7 +80,8 @@ IRC users." All values of the list must be uppercase strings.") (defvar erc-dcc-list nil - "List of DCC connections. Looks like: + "List of DCC connections. +Looks like: ((:nick \"nick!user@host\" :type GET :peer proc :parent proc :size size :file file) (:nick \"nick!user@host\" :type CHAT :peer proc :parent proc) @@ -163,8 +163,8 @@ All values of the list must be uppercase strings.") ;;; Misc macros and utility functions (defun erc-dcc-member (&rest args) - "Return the first matching entry in `erc-dcc-list' which satisfies the -constraints given as a plist in ARGS. Returns nil on no match. + "Return first matching entry in `erc-dcc-list' satisfying constraints in ARGS. +ARGS is a plist. Return nil on no match. The property :nick is treated specially, if it contains a `!' character, it is treated as a nick!user@host string, and compared with the :nick property @@ -182,12 +182,12 @@ compared with `erc-nick-equal-p' which is IRC case-insensitive." (let ((prop (car prem)) (val (cadr prem))) (setq prem (cddr prem) - ;; plist-member is a predicate in xemacs - test (and (plist-member elt prop) - (plist-get elt prop))) + test (cadr (plist-member elt prop))) ;; if the property exists and is equal, we continue, else, try the ;; next element of the list - (or (and (eq prop :nick) (string-match "!" val) + (or (and (eq prop :nick) (if (>= emacs-major-version 28) + (string-search "!" val) + (string-match "!" val)) test (string-equal test val)) (and (eq prop :nick) test val @@ -203,8 +203,7 @@ compared with `erc-nick-equal-p' which is IRC case-insensitive." result)) (defun erc-pack-int (value) - "Convert an integer into a packed string in network byte order, -which is big-endian." + "Convert integer into a packed string in network byte order, which is big-endian." ;; make sure value is not negative (when (< value 0) (error "ERC-DCC (erc-pack-int): packet size is negative")) @@ -630,8 +629,13 @@ that subcommand." (define-inline erc-dcc-unquote-filename (filename) (inline-quote - (replace-regexp-in-string "\\\\\\\\" "\\" - (replace-regexp-in-string "\\\\\"" "\"" ,filename t t) t t))) + (if (>= emacs-major-version 28) + (string-replace + "\\\\" "\\" + (string-replace "\\\"" "\"" ,filename)) + (replace-regexp-in-string + "\\\\\\\\" "\\" + (replace-regexp-in-string "\\\\\"" "\"" ,filename t t) t t)))) (defun erc-dcc-handle-ctcp-send (proc query nick login host to) "This is called if a CTCP DCC SEND subcommand is sent to the client. @@ -753,8 +757,7 @@ the matching regexp, or nil if none found." :type 'integer) (defcustom erc-dcc-pump-bytes nil - "If set to an integer, keep sending until that number of bytes are -unconfirmed." + "If an integer, keep sending until that number of bytes are unconfirmed." :type '(choice (const nil) integer)) (define-inline erc-dcc-get-parent (proc) @@ -826,8 +829,7 @@ bytes sent." (defcustom erc-dcc-send-connect-hook '(erc-dcc-display-send erc-dcc-send-block) - "Hook run whenever the remote end of a DCC SEND offer connected to your -listening port." + "Hook run when remote end of a DCC SEND offer connected to your listening port." :type 'hook) (defun erc-dcc-nick (plist) @@ -858,7 +860,7 @@ listening port." (buffer-string))) (defun erc-dcc-send-file (nick file &optional pproc) - "Open a socket for incoming connections, and send a CTCP send request to the + "Open socket for incoming connections and send a CTCP send request to the other client." (interactive "sNick: \nfFile: ") (when (null pproc) (if (processp erc-server-process) @@ -1021,11 +1023,11 @@ transfer is complete." :type 'hook) (defcustom erc-dcc-chat-connect-hook nil - "" + "" ; FIXME :type 'hook) (defcustom erc-dcc-chat-exit-hook nil - "" + "" ; FIXME :type 'hook) (defun erc-cmd-CREQ (line &optional _force) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 41256682c00..9f29b9dad9f 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -97,15 +97,15 @@ function is called." function)) (defcustom erc-fill-static-center 27 - "Column around which all statically filled messages will be -centered. This column denotes the point where the ` ' character -between <nickname> and the entered text will be put, thus aligning -nick names right and text left." + "Column around which all statically filled messages will be centered. +This column denotes the point where the ` ' character between +<nickname> and the entered text will be put, thus aligning nick +names right and text left." :type 'integer) (defcustom erc-fill-variable-maximum-indentation 17 - "If we indent a line after a long nick, don't indent more then this -characters. Set to nil to disable." + "Don't indent a line after a long nick more than this many characters. +Set to nil to disable." :type 'integer) (defcustom erc-fill-column 78 diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index fc9a8d39ef4..683ac2d37c5 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -137,7 +137,7 @@ Put this function on `erc-insert-post-hook' and/or `erc-send-post-hook'." (goto-char (point-max)))) (defun erc-move-to-prompt-setup () - "Initialize the move-to-prompt module for XEmacs." + "Initialize the move-to-prompt module." (add-hook 'pre-command-hook #'erc-move-to-prompt nil t)) ;;; Keep place in unvisited channels diff --git a/lisp/erc/erc-ibuffer.el b/lisp/erc/erc-ibuffer.el index 22336ede219..95eab040449 100644 --- a/lisp/erc/erc-ibuffer.el +++ b/lisp/erc/erc-ibuffer.el @@ -38,17 +38,16 @@ :group 'erc) (defcustom erc-ibuffer-keyword-char ?k - "Char used to indicate a channel which had keyword traffic lately (hidden)." + "Char indicating a channel which had keyword traffic lately (hidden)." :type 'character) (defcustom erc-ibuffer-pal-char ?p - "Char used to indicate a channel which had pal traffic lately (hidden)." + "Char indicating a channel which had pal traffic lately (hidden)." :type 'character) (defcustom erc-ibuffer-fool-char ?f - "Char used to indicate a channel which had fool traffic lately (hidden)." + "Char indicating a channel which had fool traffic lately (hidden)." :type 'character) (defcustom erc-ibuffer-dangerous-host-char ?d - "Char used to indicate a channel which had dangerous-host traffic lately -\(hidden)." + "Char indicating a channel which had dangerous-host traffic lately (hidden)." :type 'character) (define-ibuffer-filter erc-server @@ -73,7 +72,7 @@ erc-track-mode) (let ((entry (assq (current-buffer) erc-modified-channels-alist))) (if entry - (if (> (length entry) 1) + (if (cdr entry) (cond ((eq 'pal (nth 1 entry)) (string erc-ibuffer-pal-char)) ((eq 'fool (nth 1 entry)) diff --git a/lisp/erc/erc-identd.el b/lisp/erc/erc-identd.el index 3821e298cda..80039005520 100644 --- a/lisp/erc/erc-identd.el +++ b/lisp/erc/erc-identd.el @@ -46,7 +46,8 @@ :group 'erc) (defcustom erc-identd-port 8113 - "Port to run the identd server on if not specified in the argument for + "Port to run the identd server on. +This can be overridden by specifying an argument for `erc-identd-start'. This can be either a string or a number." diff --git a/lisp/erc/erc-imenu.el b/lisp/erc/erc-imenu.el index dcf6db7407a..522bc805f8d 100644 --- a/lisp/erc/erc-imenu.el +++ b/lisp/erc/erc-imenu.el @@ -1,7 +1,6 @@ ;;; erc-imenu.el --- Imenu support for ERC -*- lexical-binding: t; -*- -;; Copyright (C) 2001-2002, 2004, 2006-2021 Free Software Foundation, -;; Inc. +;; Copyright (C) 2001-2021 Free Software Foundation, Inc. ;; Author: Mario Lang <mlang@delysid.org> ;; Maintainer: Amin Bandali <bandali@gnu.org> diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el index 2ad9c8bd941..2ed8622b856 100644 --- a/lisp/erc/erc-join.el +++ b/lisp/erc/erc-join.el @@ -34,6 +34,7 @@ (require 'erc) (require 'auth-source) +(require 'erc-networks) (defgroup erc-autojoin nil "Enable autojoining." @@ -54,8 +55,12 @@ (defcustom erc-autojoin-channels-alist nil "Alist of channels to autojoin on IRC networks. Every element in the alist has the form (SERVER . CHANNELS). -SERVER is a regexp matching the server, and channels is the -list of channels to join. +SERVER is a regexp matching the server, and channels is the list +of channels to join. SERVER can also be a symbol, in which case +it is matched against the value of `erc-network' instead of +`erc-server-announced-name' or `erc-session-server' (this can be +useful when connecting to an IRC proxy that relays several +networks under the same server). If the channel(s) require channel keys for joining, the passwords are found via auth-source. For instance, if you use ~/.authinfo @@ -117,6 +122,15 @@ This is called from a timer set up by `erc-autojoin-channels'." (erc-log "Delayed autojoin started (no ident success detected yet)") (erc-autojoin-channels server nick)))) +(defun erc-autojoin-server-match (candidate) + "Match the current network or server against CANDIDATE. +This should be a key from `erc-autojoin-channels-alist'." + (or (eq candidate (erc-network)) + (and (stringp candidate) + (string-match-p candidate + (or erc-server-announced-name + erc-session-server))))) + (defun erc-autojoin-after-ident (_network _nick) "Autojoin channels in `erc-autojoin-channels-alist'. This function is run from `erc-nickserv-identified-hook'." @@ -131,7 +145,7 @@ This function is run from `erc-nickserv-identified-hook'." ;; We may already be in these channels, e.g. because the ;; autojoin timer went off. (dolist (l erc-autojoin-channels-alist) - (when (string-match (car l) server) + (when (erc-autojoin-server-match (car l)) (dolist (chan (cdr l)) (unless (erc-member-ignore-case chan joined) (erc-server-join-channel server chan))))))) @@ -150,15 +164,14 @@ This function is run from `erc-nickserv-identified-hook'." ;; `erc-autojoin-timing' is `connect': (let ((server (or erc-session-server erc-server-announced-name))) (dolist (l erc-autojoin-channels-alist) - (when (string-match-p (car l) server) + (when (erc-autojoin-server-match (car l)) (dolist (chan (cdr l)) (let ((buffer (car (erc-buffer-filter (lambda () (let ((current (erc-default-target))) (and (stringp current) - (string-match-p (car l) - (or erc-session-server erc-server-announced-name)) + (erc-autojoin-server-match (car l)) (string-equal (erc-downcase chan) (erc-downcase current))))))))) (when (or (not buffer) @@ -168,20 +181,30 @@ This function is run from `erc-nickserv-identified-hook'." ;; Return nil to avoid stomping on any other hook funcs. nil) +(defun erc-autojoin-current-server () + "Compute the current server for lookup in `erc-autojoin-channels-alist'. +Respects `erc-autojoin-domain-only'." + (let ((server (or erc-server-announced-name erc-session-server))) + (if (and erc-autojoin-domain-only + (string-match "[^.\n]+\\.\\([^.\n]+\\.[^.\n]+\\)$" server)) + (match-string 1 server) + server))) + (defun erc-autojoin-add (proc parsed) "Add the channel being joined to `erc-autojoin-channels-alist'." (let* ((chnl (erc-response.contents parsed)) (nick (car (erc-parse-user (erc-response.sender parsed)))) (server (with-current-buffer (process-buffer proc) - (or erc-session-server erc-server-announced-name)))) + (erc-autojoin-current-server)))) (when (erc-current-nick-p nick) - (when (and erc-autojoin-domain-only - (string-match "[^.\n]+\\.\\([^.\n]+\\.[^.\n]+\\)$" server)) - (setq server (match-string 1 server))) - (let ((elem (assoc server erc-autojoin-channels-alist))) + (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist) + (assoc server erc-autojoin-channels-alist)))) (if elem (unless (member chnl (cdr elem)) (setcdr elem (cons chnl (cdr elem)))) + ;; This always keys on server, not network -- user can + ;; override by simply adding a network to + ;; `erc-autojoin-channels-alist' (setq erc-autojoin-channels-alist (cons (list server chnl) erc-autojoin-channels-alist)))))) @@ -196,12 +219,10 @@ This function is run from `erc-nickserv-identified-hook'." (let* ((chnl (car (erc-response.command-args parsed))) (nick (car (erc-parse-user (erc-response.sender parsed)))) (server (with-current-buffer (process-buffer proc) - (or erc-session-server erc-server-announced-name)))) + (erc-autojoin-current-server)))) (when (erc-current-nick-p nick) - (when (and erc-autojoin-domain-only - (string-match "[^.\n]+\\.\\([^.\n]+\\.[^.\n]+\\)$" server)) - (setq server (match-string 1 server))) - (let ((elem (assoc server erc-autojoin-channels-alist))) + (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist) + (assoc server erc-autojoin-channels-alist)))) (when elem (setcdr elem (delete chnl (cdr elem))) (unless (cdr elem) diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index ddd00afd73b..7c5c495f9e1 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -180,8 +180,7 @@ If you set this to nil, you may want to enable both :type 'boolean) (defcustom erc-log-write-after-insert nil - "If non-nil, write to log file when new text is added to a -logged ERC buffer. + "If non-nil, write to log file when new text is added to a logged ERC buffer. If you set this to nil, you may want to enable both `erc-save-buffer-on-part' and `erc-save-queries-on-quit'." @@ -195,8 +194,7 @@ This should ideally, be a \"catch-all\" coding system, like :type 'coding-system) (defcustom erc-log-filter-function nil - "If non-nil, pass text through the given function before writing it to -a log file. + "If non-nil, pass text to this function before writing it to a log file. The function should take one argument, which is the text to filter." :type '(choice (function "Function") @@ -361,7 +359,7 @@ function is a possible value for (concat (buffer-name buffer) ".txt")) (defun erc-generate-log-file-name-long (_buffer target nick server port) - "Generates a log-file name in the way ERC always did it. + "Generate a log-file name in the way ERC always did it. This results in a file name of the form #channel!nick@server:port.txt. This function is a possible value for `erc-generate-log-file-name-function'." (let ((file (concat @@ -375,7 +373,7 @@ This function is a possible value for `erc-generate-log-file-name-function'." (declare-function erc-network-name "erc-networks" ()) (defun erc-generate-log-file-name-network (buffer target nick server _port) - "Generates a log-file name using the network name rather than server name. + "Generate a log-file name using the network name rather than server name. This results in a file name of the form #channel!nick@network.txt. This function is a possible value for `erc-generate-log-file-name-function'." (require 'erc-networks) diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index 43fbca3e666..01d6e44d594 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -24,7 +24,7 @@ ;;; Commentary: -;; This file includes stuff to work with pattern matching in ERC. If +;; This file includes stuff to work with pattern matching in ERC. If ;; you were used to customizing erc-fools, erc-keywords, erc-pals, ;; erc-dangerous-hosts and the like, this file contains these ;; customizable variables. @@ -79,7 +79,7 @@ Useful to mark nicks from dangerous hosts." :type '(repeat regexp)) (defcustom erc-current-nick-highlight-type 'keyword - "Determines how to highlight text in which your current nickname appears + "Determine how to highlight text in which your current nickname appears \(does not apply to text sent by you). The following values are allowed: @@ -234,9 +234,9 @@ current-nick, keyword, pal, dangerous-host, fool." :type 'hook) (defcustom erc-match-exclude-server-buffer nil - "If true, don't perform match on the server buffer; this is -useful for excluding all the things like MOTDs from the server -and other miscellaneous functions." + "If true, don't perform match on the server buffer. +This is useful for excluding all the things like MOTDs from the +server and other miscellaneous functions." :version "24.3" :type 'boolean) diff --git a/lisp/erc/erc-menu.el b/lisp/erc/erc-menu.el index 1bee6ff2a67..2da1abb29a7 100644 --- a/lisp/erc/erc-menu.el +++ b/lisp/erc/erc-menu.el @@ -103,8 +103,7 @@ "ERC menu definition.") (defvar erc-menu-defined nil - "Internal variable used to keep track of whether we've defined the -ERC menu yet.") + "Internal variable used to keep track of whether we've defined the ERC menu yet.") ;;;###autoload(autoload 'erc-menu-mode "erc-menu" nil t) (define-erc-module menu nil diff --git a/lisp/erc/erc-netsplit.el b/lisp/erc/erc-netsplit.el index 9cfb947003c..994f2d07c30 100644 --- a/lisp/erc/erc-netsplit.el +++ b/lisp/erc/erc-netsplit.el @@ -52,7 +52,7 @@ netsplits, so that it can filter the JOIN messages on a netjoin too." (remove-hook 'erc-timer-hook #'erc-netsplit-timer))) (defcustom erc-netsplit-show-server-mode-changes-flag nil - "Set to t to enable display of server mode changes." + "Non-nil means to enable display of server mode changes." :type 'boolean) (defcustom erc-netsplit-debug nil @@ -61,8 +61,7 @@ netsplits, so that it can filter the JOIN messages on a netjoin too." (defcustom erc-netsplit-regexp "^[^ @!\"\n]+\\.[^ @!\n]+ [^ @!\n]+\\.[^ @!\"\n]+$" - "This regular expression should match quit reasons produced -by netsplits." + "This regular expression should match quit reasons produced by netsplits." :type 'regexp) (defcustom erc-netsplit-hook nil diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 54502b2df05..678c596760b 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -45,7 +45,7 @@ ;; Variables (defgroup erc-networks nil - "IRC Networks" + "IRC Networks." :group 'erc) (defcustom erc-server-alist @@ -720,7 +720,7 @@ NET is a symbol naming that IRC network and MATCHER is used to find a corresponding network to a server while connected to it. If it is regexp, it's used to match against `erc-server-announced-name'. It can also be a function (predicate). - Then it is executed with the server buffer as current-buffer." + Then it is executed with the server buffer as current buffer." :type '(repeat (list :tag "Network" (symbol :tag "Network name") @@ -755,15 +755,6 @@ server name and search for a match in `erc-networks-alist'." "Return the value of `erc-network' for the current server." (erc-with-server-buffer erc-network)) -(defun erc-current-network () - "Deprecated. Use `erc-network' instead. -Return the name of this server's network as a symbol." - (erc-with-server-buffer - (intern (downcase (symbol-name erc-network))))) - -(make-obsolete 'erc-current-network 'erc-network - "Obsolete since erc-networks 1.5") - (defun erc-network-name () "Return the name of the current network as a string." (erc-with-server-buffer (symbol-name erc-network))) @@ -833,7 +824,7 @@ As an example: (ports (if (listp (nth 3 srv)) (erc-ports-list (nth 3 srv)) (list (nth 3 srv)))) - (port (nth (random (length ports)) ports))) + (port (and ports (seq-random-elt ports)))) (erc :server host :port port))) ;;; The following experimental diff --git a/lisp/erc/erc-notify.el b/lisp/erc/erc-notify.el index 1ed056c277d..d4f22ca0f5a 100644 --- a/lisp/erc/erc-notify.el +++ b/lisp/erc/erc-notify.el @@ -40,13 +40,11 @@ :group 'erc) (defcustom erc-notify-list nil - "List of nicknames you want to be notified about online/offline -status change." + "List of nicknames you want to be notified about online/offline status change." :type '(repeat string)) (defcustom erc-notify-interval 60 - "Time interval (in seconds) for checking online status of notified -people." + "Time interval (in seconds) for checking online status of notified people." :type 'integer) (defcustom erc-notify-signon-hook nil diff --git a/lisp/erc/erc-pcomplete.el b/lisp/erc/erc-pcomplete.el index 8ea37c7f290..c846a1f003f 100644 --- a/lisp/erc/erc-pcomplete.el +++ b/lisp/erc/erc-pcomplete.el @@ -44,7 +44,7 @@ (require 'time-date) (defgroup erc-pcomplete nil - "Programmable completion for ERC" + "Programmable completion for ERC." :group 'erc) (defcustom erc-pcomplete-nick-postfix ":" @@ -53,8 +53,7 @@ add this string to nicks completed." :type 'string) (defcustom erc-pcomplete-order-nickname-completions t - "If t, channel nickname completions will be ordered such that -the most recent speakers are listed first." + "If t, order nickname completions with the most recent speakers first." :type 'boolean) ;;;###autoload(autoload 'erc-completion-mode "erc-pcomplete" nil t) diff --git a/lisp/erc/erc-replace.el b/lisp/erc/erc-replace.el index 3f69c4cb9cc..b2e9047ce77 100644 --- a/lisp/erc/erc-replace.el +++ b/lisp/erc/erc-replace.el @@ -1,7 +1,6 @@ ;;; erc-replace.el --- wash and massage messages inserted into the buffer -*- lexical-binding: t; -*- -;; Copyright (C) 2001-2002, 2004, 2006-2021 Free Software Foundation, -;; Inc. +;; Copyright (C) 2001-2021 Free Software Foundation, Inc. ;; Author: Andreas Fuchs <asf@void.at> ;; Maintainer: Amin Bandali <bandali@gnu.org> @@ -37,7 +36,7 @@ (require 'erc) (defgroup erc-replace nil - "Replace text from incoming messages" + "Replace text from incoming messages." :group 'erc) (defcustom erc-replace-alist nil diff --git a/lisp/erc/erc-ring.el b/lisp/erc/erc-ring.el index 666fd585926..52285a8343a 100644 --- a/lisp/erc/erc-ring.el +++ b/lisp/erc/erc-ring.el @@ -79,7 +79,7 @@ STATE-OR-STRING should be a string or an erc-input object." (setq erc-input-ring-index nil)) (defun erc-clear-input-ring () - "Remove all entries from the input ring, then call garbage-collect. + "Remove all entries from the input ring, then call `garbage-collect'. You might use this for security purposes if you have typed a command containing a password." (interactive) diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el index 61006e0c028..adb3f521cdd 100644 --- a/lisp/erc/erc-services.el +++ b/lisp/erc/erc-services.el @@ -169,9 +169,8 @@ You can also use \\[erc-nickserv-identify-mode] to change modes." (defcustom erc-use-auth-source-for-nickserv-password nil "Query auth-source for a password when identifiying to NickServ. -This option has an no effect if `erc-prompt-for-nickserv-password' -is non-nil, and passwords from `erc-nickserv-passwords' take -precedence." +Passwords from `erc-nickserv-passwords' take precedence. See +function `erc-nickserv-get-password'." :version "28.1" :type 'boolean) @@ -405,85 +404,114 @@ password for this nickname, otherwise try to send it automatically." identify-regex (string-match identify-regex msg)) (erc-log "NickServ IDENTIFY request detected") - (erc-nickserv-call-identify-function nick) + (erc-nickserv-identify nil nick) nil)))) (defun erc-nickserv-identify-on-connect (_server nick) "Identify to Nickserv after the connection to the server is established." - (unless (or (and (null erc-nickserv-passwords) - (null erc-prompt-for-nickserv-password) - (null erc-use-auth-source-for-nickserv-password)) - (and (eq erc-nickserv-identify-mode 'both) - (erc-nickserv-alist-regexp (erc-network)))) - (erc-nickserv-call-identify-function nick))) + (unless (and (eq erc-nickserv-identify-mode 'both) + (erc-nickserv-alist-regexp (erc-network))) + (erc-nickserv-identify nil nick))) (defun erc-nickserv-identify-on-nick-change (nick _old-nick) "Identify to Nickserv whenever your nick changes." - (unless (or (and (null erc-nickserv-passwords) - (null erc-prompt-for-nickserv-password) - (null erc-use-auth-source-for-nickserv-password)) - (and (eq erc-nickserv-identify-mode 'both) - (erc-nickserv-alist-regexp (erc-network)))) - (erc-nickserv-call-identify-function nick))) - -(defun erc-nickserv-get-password (nickname) - "Return the password for NICKNAME from configured sources. - -It uses `erc-nickserv-passwords' and additionally auth-source -when `erc-use-auth-source-for-nickserv-password' is not nil." - (or - (when erc-nickserv-passwords - (cdr (assoc nickname - (nth 1 (assoc (erc-network) - erc-nickserv-passwords))))) - (when erc-use-auth-source-for-nickserv-password - (let* ((secret (nth 0 (auth-source-search - :max 1 :require '(:secret) - :host (erc-with-server-buffer erc-session-server) - :port (format ; ensure we have a string - "%s" (erc-with-server-buffer erc-session-port)) - :user nickname)))) - (when secret - (let ((passwd (plist-get secret :secret))) - (if (functionp passwd) (funcall passwd) passwd))))))) - -(defun erc-nickserv-call-identify-function (nickname) - "Call `erc-nickserv-identify'. -Either call it interactively or run it with NICKNAME's password, -depending on the value of `erc-prompt-for-nickserv-password'." - (if erc-prompt-for-nickserv-password - (call-interactively 'erc-nickserv-identify) - (erc-nickserv-identify (erc-nickserv-get-password nickname)))) + (unless (and (eq erc-nickserv-identify-mode 'both) + (erc-nickserv-alist-regexp (erc-network))) + (erc-nickserv-identify nil nick))) + +(defun erc-nickserv-get-password (nick) + "Return the password for NICK from configured sources. +First, a password for NICK is looked up in +`erc-nickserv-passwords'. Then, it is looked up in auth-source +if `erc-use-auth-source-for-nickserv-password' is not nil. +Finally, interactively prompt the user, if +`erc-prompt-for-nickserv-password' is true. + +As soon as some source returns a password, the sequence of +lookups stops and this function returns it (or returns nil if it +is empty). Otherwise, no corresponding password was found, and +it returns nil." + (let (network server port) + ;; Fill in local vars, switching to the server buffer once only + (erc-with-server-buffer + (setq network erc-network + server erc-session-server + port erc-session-port)) + (let ((ret + (or + (when erc-nickserv-passwords + (cdr (assoc nick + (cl-second (assoc network + erc-nickserv-passwords))))) + (when erc-use-auth-source-for-nickserv-password + (let ((secret (cl-first (auth-source-search + :max 1 :require '(:secret) + :host server + ;; Ensure a string for :port + :port (format "%s" port) + :user nick)))) + (when secret + (let ((passwd (plist-get secret :secret))) + (if (functionp passwd) (funcall passwd) passwd))))) + (when erc-prompt-for-nickserv-password + (read-passwd + (format "NickServ password for %s on %s (RET to cancel): " + nick network)))))) + (when (and ret (not (string= ret ""))) + ret)))) (defvar erc-auto-discard-away) -;;;###autoload -(defun erc-nickserv-identify (password) +(defun erc-nickserv-send-identify (nick password) "Send an \"identify <PASSWORD>\" message to NickServ. -When called interactively, read the password using `read-passwd'." +Returns t if the message could be sent, nil otherwise." + (let* ((erc-auto-discard-away nil) + (network (erc-network)) + (nickserv-info (assoc network erc-nickserv-alist)) + (nickserv (or (erc-nickserv-alist-nickserv nil nickserv-info) + "NickServ")) + (identify-word (or (erc-nickserv-alist-ident-keyword + nil nickserv-info) + "IDENTIFY")) + (nick (if (erc-nickserv-alist-use-nick-p nil nickserv-info) + (concat nick " ") + "")) + (msgtype (or (erc-nickserv-alist-ident-command nil nickserv-info) + "PRIVMSG"))) + (erc-message msgtype + (concat nickserv " " identify-word " " nick password)))) + +(defun erc-nickserv-call-identify-function (nickname) + "Call `erc-nickserv-identify' with NICKNAME." + (declare (obsolete erc-nickserv-identify "28.1")) + (erc-nickserv-identify nil nickname)) + +;;;###autoload +(defun erc-nickserv-identify (&optional password nick) + "Identify to NickServ immediately. +Identification will either use NICK or the current nick if not +provided, and some password obtained through +`erc-nickserv-get-password' (which see). If no password can be +found, an error is reported trough `erc-error'. + +Interactively, the user will be prompted for NICK, an empty +string meaning to default to the current nick. + +Returns t if the identify message could be sent, nil otherwise." (interactive - (list (read-passwd - (format "NickServ password for %s on %s (RET to cancel): " - (erc-current-nick) - (or (and (erc-network) - (symbol-name (erc-network))) - "Unknown network"))))) - (when (and password (not (string= "" password))) - (let* ((erc-auto-discard-away nil) - (network (erc-network)) - (nickserv-info (assoc network erc-nickserv-alist)) - (nickserv (or (erc-nickserv-alist-nickserv nil nickserv-info) - "NickServ")) - (identify-word (or (erc-nickserv-alist-ident-keyword - nil nickserv-info) - "IDENTIFY")) - (nick (if (erc-nickserv-alist-use-nick-p nil nickserv-info) - (concat (erc-current-nick) " ") - "")) - (msgtype (or (erc-nickserv-alist-ident-command nil nickserv-info) - "PRIVMSG"))) - (erc-message msgtype - (concat nickserv " " identify-word " " nick password))))) + (list + nil + (read-from-minibuffer "Nickname: " nil nil nil + 'erc-nick-history-list (erc-current-nick)))) + (unless (and nick (not (string= nick ""))) + (setq nick (erc-current-nick))) + (unless password + (setq password (erc-nickserv-get-password nick))) + (if password + (erc-nickserv-send-identify nick password) + (erc-error "Cannot find a password for nickname %s" + nick) + nil)) (provide 'erc-services) diff --git a/lisp/erc/erc-sound.el b/lisp/erc/erc-sound.el index 92759d206a3..cb4c232aba8 100644 --- a/lisp/erc/erc-sound.el +++ b/lisp/erc/erc-sound.el @@ -128,8 +128,9 @@ See also `play-sound-file'." (erc-log (format "Playing sound file %S" filepath)))) (defun erc-toggle-sound (&optional arg) - "Toggles playing sounds on and off. With positive argument, - turns them on. With any other argument turns sounds off." + "Toggle playing sounds on and off. +With positive argument, turns them on. With any other argument +turns sounds off." (interactive "P") (cond ((and (numberp arg) (> arg 0)) (setq erc-play-sound t)) diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el index bb858445235..84854e3be52 100644 --- a/lisp/erc/erc-speedbar.el +++ b/lisp/erc/erc-speedbar.el @@ -139,7 +139,9 @@ This will add a speedbar major display mode." t)))) (defun erc-speedbar-expand-server (text server indent) - (cond ((string-match "\\+" text) + (cond ((if (>= emacs-major-version 28) + (string-search "+" text) + (string-match "\\+" text)) (speedbar-change-expand-button-char ?-) (if (speedbar-with-writable (save-excursion @@ -147,7 +149,10 @@ This will add a speedbar major display mode." (erc-speedbar-channel-buttons nil (1+ indent) server))) (speedbar-change-expand-button-char ?-) (speedbar-change-expand-button-char ??))) - ((string-match "-" text) ;we have to contract this node + (;; we have to contract this node + (if (>= emacs-major-version 28) + (string-search "-" text) + (string-match "-" text)) (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) (t (error "Ooops... not sure what to do"))) @@ -184,7 +189,9 @@ This will add a speedbar major display mode." "For the line matching TEXT, in CHANNEL, expand or contract a line. INDENT is the current indentation level." (cond - ((string-match "\\+" text) + ((if (>= emacs-major-version 28) + (string-search "+" text) + (string-match "\\+" text)) (speedbar-change-expand-button-char ?-) (speedbar-with-writable (save-excursion @@ -233,7 +240,9 @@ INDENT is the current indentation level." (speedbar-with-writable (dolist (entry names) (erc-speedbar-insert-user entry ?+ (1+ indent)))))))))) - ((string-match "-" text) + ((if (>= emacs-major-version 28) + (string-search "-" text) + (string-match "-" text)) (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) (t (error "Ooops... not sure what to do"))) @@ -284,7 +293,9 @@ The update is only done when the channel is actually expanded already." (erc-speedbar-expand-channel "+" buffer 1))))) (defun erc-speedbar-expand-user (text token indent) - (cond ((string-match "\\+" text) + (cond ((if (>= emacs-major-version 28) + (string-search "+" text) + (string-match "\\+" text)) (speedbar-change-expand-button-char ?-) (speedbar-with-writable (save-excursion @@ -307,7 +318,9 @@ The update is only done when the channel is actually expanded already." nil nil nil nil info nil nil nil (1+ indent))))))) - ((string-match "-" text) + ((if (>= emacs-major-version 28) + (string-search "-" text) + (string-match "-" text)) (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) (t (error "Ooops... not sure what to do"))) diff --git a/lisp/erc/erc-spelling.el b/lisp/erc/erc-spelling.el index 950a821e3c4..ddfaafb0483 100644 --- a/lisp/erc/erc-spelling.el +++ b/lisp/erc/erc-spelling.el @@ -24,7 +24,7 @@ ;;; Commentary: -;; This is an ERC module to enable flyspell mode in ERC buffers. This +;; This is an ERC module to enable flyspell mode in ERC buffers. This ;; ensures correct behavior of flyspell, and even sets up a ;; channel-local dictionary if so required. diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index 31de9e80697..7d31bc971e3 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -181,6 +181,11 @@ or `erc-send-modify-hook'." (list (lambda (_window _before dir) (erc-echo-timestamp dir ct)))))))) +(defvar-local erc-timestamp-last-window-width nil + "The width of the last window that showed the current buffer. +his is used by `erc-insert-timestamp-right' when the current +buffer is not shown in any window.") + (defvar-local erc-timestamp-last-inserted nil "Last timestamp inserted into the buffer.") @@ -195,7 +200,7 @@ This is used when `erc-insert-timestamp-function' is set to `erc-timestamp-left-and-right'") (defcustom erc-timestamp-only-if-changed-flag t - "Insert timestamp only if its value changed since last insertion. + "Non-nil means insert timestamp only if its value changed since last insertion. If `erc-insert-timestamp-function' is `erc-insert-timestamp-left', a string of spaces which is the same size as the timestamp is added to the beginning of the line in its place. If you use @@ -250,27 +255,32 @@ property to get to the POSth column." (defun erc-insert-timestamp-right (string) "Insert timestamp on the right side of the screen. -STRING is the timestamp to insert. The function is a possible value -for `erc-insert-timestamp-function'. - -If `erc-timestamp-only-if-changed-flag' is nil, a timestamp is always -printed. If this variable is non-nil, a timestamp is only printed if -it is different from the last. - -If `erc-timestamp-right-column' is set, its value will be used as the -column at which the timestamp is to be printed. If it is nil, and -`erc-fill-mode' is active, then the timestamp will be printed just -before `erc-fill-column'. Otherwise, if the current buffer is -shown in a window, that window's width is used. If the buffer is -not shown, and `fill-column' is set, then the timestamp will be -printed just `fill-column'. As a last resort, the timestamp will -be printed just before the window-width." +STRING is the timestamp to insert. This function is a possible +value for `erc-insert-timestamp-function'. + +If `erc-timestamp-only-if-changed-flag' is nil, a timestamp is +always printed. If this variable is non-nil, a timestamp is only +printed if it is different from the last. + +If `erc-timestamp-right-column' is set, its value will be used as +the column at which the timestamp is to be printed. If it is +nil, and `erc-fill-mode' is active, then the timestamp will be +printed just before `erc-fill-column'. Otherwise, if the current +buffer is shown in a window, that window's width is used as the +right boundary. In case multiple windows show the buffer, the +width of the most recently selected one is used. If the buffer +is not shown, the timestamp will be printed just before the +window width of the last window that showed it. If the buffer +was never shown, and `fill-column' is set, it will be printed +just before `fill-column'. As a last resort, timestamp will be +printed just after each line's text (no alignment)." (unless (and erc-timestamp-only-if-changed-flag (string-equal string erc-timestamp-last-inserted)) (setq erc-timestamp-last-inserted string) (goto-char (point-max)) - (forward-char -1);; before the last newline + (forward-char -1) ; before the last newline (let* ((str-width (string-width string)) + window ; used in computation of `pos' only (pos (cond (erc-timestamp-right-column erc-timestamp-right-column) ((and (boundp 'erc-fill-mode) @@ -278,10 +288,15 @@ be printed just before the window-width." (boundp 'erc-fill-column) erc-fill-column) (1+ (- erc-fill-column str-width))) + ((setq window (get-buffer-window nil t)) + (setq erc-timestamp-last-window-width + (window-width window)) + (- erc-timestamp-last-window-width str-width)) + (erc-timestamp-last-window-width + (- erc-timestamp-last-window-width str-width)) (fill-column (1+ (- fill-column str-width))) - (t - (- (window-width) str-width 1)))) + (t (current-column)))) (from (point)) (col (current-column))) ;; The following is a kludge used to calculate whether to move @@ -301,10 +316,10 @@ be printed just before the window-width." (erc-put-text-property from (1+ (point)) 'cursor-intangible t))))) (defun erc-insert-timestamp-left-and-right (_string) - "This is another function that can be assigned to -`erc-insert-timestamp-function'. If the date is changed, it will -print a blank line, the date, and another blank line. If the time is -changed, it will then print it off to the right." + "This is another function that can be used with `erc-insert-timestamp-function'. +If the date is changed, it will print a blank line, the date, and +another blank line. If the time is changed, it will then print +it off to the right." (let* ((ct (current-time)) (ts-left (erc-format-timestamp ct erc-timestamp-format-left)) (ts-right (erc-format-timestamp ct erc-timestamp-format-right))) diff --git a/lisp/erc/erc-status-sidebar.el b/lisp/erc/erc-status-sidebar.el index a75a74bb6fd..a6ad856bfd7 100644 --- a/lisp/erc/erc-status-sidebar.el +++ b/lisp/erc/erc-status-sidebar.el @@ -274,7 +274,7 @@ to the `window-configuration-change-hook'." (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" + "Major mode for ERC status sidebar." ;; 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/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index 2364d45d6f3..57553844900 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -104,14 +104,13 @@ channel (353)." :type 'erc-message-type) (defcustom erc-track-exclude-server-buffer nil - "If true, don't perform tracking on the server buffer; this is -useful for excluding all the things like MOTDs from the server and -other miscellaneous functions." + "If true, don't perform tracking on the server buffer. +This is useful for excluding all the things like MOTDs from the +server and other miscellaneous functions." :type 'boolean) (defcustom erc-track-shorten-start 1 - "This number specifies the minimum number of characters a channel name in -the mode-line should be reduced to." + "Minimum number of characters for a channel name in the mode-line." :type 'number) (defcustom erc-track-shorten-cutoff 4 @@ -149,8 +148,7 @@ If nil instead of a function, shortening is disabled." function)) (defcustom erc-track-list-changed-hook nil - "Hook that is run whenever the contents of -`erc-modified-channels-alist' changes. + "Hook run when the contents of `erc-modified-channels-alist' changes. This is useful for people that don't use the default mode-line notification but instead use a separate mechanism to provide @@ -262,14 +260,22 @@ nil - don't add to mode line." (defvar erc-modified-channels-alist nil "An ALIST used for tracking channel modification activity. -Each element looks like (BUFFER COUNT FACE) where BUFFER is a buffer -object of the channel the entry corresponds to, COUNT is a number -indicating how often activity was noticed, and FACE is the face to use -when displaying the buffer's name. See `erc-track-faces-priority-list', -and `erc-track-showcount'. - -Entries in this list should only happen for buffers where activity occurred -while the buffer was not visible.") +Each element is a list of the form (BUFFER COUNT . FACE) where +BUFFER is a buffer object of the channel the entry corresponds +to, COUNT is a number indicating how often activity was noticed, +and FACE is a face (or a list of faces, combined as usual) to use +when displaying the buffer's name in the mode line. + +Entries in this list are only added/updated for buffers that were +not visible when activity occurred in them, and are removed for +each buffer as soon as it becomes visible again (or if the server +is disconnected, provided `erc-track-remove-disconnected-buffers' +is true). + +For how the face is chosen for a buffer, see +`erc-track-select-mode-line-face' and +`erc-track-priority-faces-only'. For how buffers are then +displayed in the mode line, see `erc-modified-channels-display'.") (defcustom erc-track-showcount nil "If non-nil, count of unseen messages will be shown for each channel." @@ -538,8 +544,7 @@ keybindings will not do anything useful." (erc-track-minor-mode -1))))) (defcustom erc-track-when-inactive nil - "Enable channel tracking even for visible buffers, if you are -inactive." + "Enable channel tracking even for visible buffers, if you are inactive." :type 'boolean :set (lambda (sym val) (if erc-track-mode @@ -590,15 +595,15 @@ only consider active buffers visible.") (erc-modified-channels-update))) (defvar erc-modified-channels-update-inside nil - "Variable to prevent running `erc-modified-channels-update' multiple -times. Without it, you cannot debug `erc-modified-channels-display', -because the debugger also causes changes to the window-configuration.") + "Variable to prevent running `erc-modified-channels-update' multiple times. +Without it, you cannot debug `erc-modified-channels-display', +because the debugger also causes changes to the +window-configuration.") (defun erc-modified-channels-update (&rest _args) - "This function updates the information in `erc-modified-channels-alist' -according to buffer visibility. It calls -`erc-modified-channels-display' at the end. This should usually be -called via `window-configuration-change-hook'. + "Update `erc-modified-channels-alist' according to buffer visibility. +It calls `erc-modified-channels-display' at the end. This should +usually be called via `window-configuration-change-hook'. ARGS are ignored." (interactive) (unless erc-modified-channels-update-inside @@ -622,8 +627,14 @@ ARGS are ignored." "The face to use when mouse is over channel names in the mode line.") (defun erc-make-mode-line-buffer-name (string buffer &optional faces count) - "Return STRING as a button that switches to BUFFER when clicked. -If FACES are provided, color STRING with them." + "Return a button that switches to BUFFER when clicked. +STRING is the string in the button. It is possibly suffixed with +the number of unread messages, according to variables +`erc-track-showcount' and `erc-track-showcount-string'. + +If `erc-track-use-faces' is true and FACES are provided, format +STRING with them. When the mouse hovers above the button, STRING +is displayed according to `erc-track-mouse-face'." ;; We define a new sparse keymap every time, because 1. this data ;; structure is very small, the alternative would require us to ;; defvar a keymap, 2. the user is not interested in customizing it @@ -661,8 +672,7 @@ If FACES are provided, color STRING with them." name)) (defun erc-modified-channels-display () - "Set `erc-modified-channels-object' -according to `erc-modified-channels-alist'. + "Set `erc-modified-channels-object' according to `erc-modified-channels-alist'. Use `erc-make-mode-line-buffer-name' to create buttons." (cond ((or (eq 'mostactive erc-track-switch-direction) (eq 'leastactive erc-track-switch-direction)) @@ -720,43 +730,55 @@ Use `erc-make-mode-line-buffer-name' to create buttons." (erc-modified-channels-display))) (defun erc-track-find-face (faces) - "Return the face to use in the mode line from the faces in FACES. -If `erc-track-faces-priority-list' is set, the one from FACES who -is first in that list will be used. If nothing matches or if -`erc-track-faces-priority-list' is not set, the default mode-line -faces will be used. - -If `erc-track-faces-normal-list' is non-nil, use it to produce a -blinking effect that indicates channel activity when the first -element in FACES and the highest-ranking face among the rest of -FACES are both members of `erc-track-faces-normal-list'. - -If one of the faces is a list, then it will be ranked according -to its highest-tanking face member. A list of faces including -that member will take priority over just the single member -element." + "Return the face to use in the mode line." + (declare (obsolete erc-track-select-mode-line-face "28.1")) + (erc-track-select-mode-line-face (car faces) (cdr faces))) + +(defun erc-track-select-mode-line-face (cur-face new-faces) + "Return the face to use in the mode line. + +CUR-FACE is the face currently used in the mode line (for the +current buffer). NEW-FACES is the list of new faces that have +just been seen (in the current buffer). + +Initially, the selected face is the one with highest priority in +`erc-track-faces-priority-list' (i.e., the one closest to the +front of the list) among CUR-FACE and NEW-FACES. If nothing +matches (including if `erc-track-faces-priority-list' is not +set), the default mode-line faces will be used (NIL is returned). + +If the selected face is still CUR-FACE (highest priority), and +the highest priority face in NEW-FACES alone is different (which +necessarily means it has lower priority than CUR-FACE), and both +are in `erc-track-faces-normal-list', then the latter is selected +instead. This has the effect of allowing the current mode line +face, if a member of `erc-track-faces-normal-list', to be +replaced with another with lower priority face from NEW-FACES, if +that face with highest priority in NEW-FACES is also a member of +`erc-track-faces-normal-list'." (let ((choice (catch 'face - (dolist (candidate erc-track-faces-priority-list) - (when (member candidate faces) - (throw 'face candidate))))) - (no-first (and erc-track-faces-normal-list - (catch 'face - (dolist (candidate erc-track-faces-priority-list) - (when (member candidate (cdr faces)) - (throw 'face candidate))))))) - (cond ((null choice) - nil) - ((and (member choice erc-track-faces-normal-list) - (member no-first erc-track-faces-normal-list)) - no-first) - (t - choice)))) + (dolist (candidate erc-track-faces-priority-list) + (when (or (equal candidate cur-face) + (member candidate new-faces)) + (throw 'face candidate)))))) + (when choice + (if (and (equal choice cur-face) + (member choice erc-track-faces-normal-list)) + (let ((only-in-new + (catch 'face + (dolist (candidate erc-track-faces-priority-list) + (when (member candidate new-faces) + (throw 'face candidate)))))) + (if (member only-in-new erc-track-faces-normal-list) + only-in-new + choice)) + choice)))) (defun erc-track-modified-channels () - "Hook function for `erc-insert-post-hook' to check if the current -buffer should be added to the mode line as a hidden, modified -channel. Assumes it will only be called when current-buffer -is in `erc-mode'." + "Hook function for `erc-insert-post-hook'. +Check if the current buffer should be added to the mode line as a +hidden, modified channel. Assumes it will only be called when +the current buffer is in `erc-mode'." (let ((this-channel (or (erc-default-target) (buffer-name (current-buffer))))) (if (and (not (erc-buffer-visible (current-buffer))) @@ -790,17 +812,17 @@ is in `erc-mode'." ;; Add buffer, faces and counts (setq erc-modified-channels-alist (cons (cons (current-buffer) - (cons 1 (erc-track-find-face faces))) + (cons + 1 (erc-track-select-mode-line-face + nil faces))) erc-modified-channels-alist)) ;; Else modify the face for the buffer, if necessary. (when faces (let* ((cell (assq (current-buffer) erc-modified-channels-alist)) (old-face (cddr cell)) - (new-face (erc-track-find-face - (if old-face - (cons old-face faces) - faces)))) + (new-face (erc-track-select-mode-line-face + old-face faces))) (setcdr cell (cons (1+ (cadr cell)) new-face))))) ;; And display it (erc-modified-channels-display))) @@ -832,8 +854,7 @@ is in `erc-mode'." ;;; Buffer switching (defvar erc-track-last-non-erc-buffer nil - "Stores the name of the last buffer you were in before activating -`erc-track-switch-buffer'.") + "Name of the last buffer before activating `erc-track-switch-buffer'.") (defun erc-track-sort-by-activest () "Sort erc-modified-channels-alist by activity. @@ -843,9 +864,8 @@ That means the number of unseen messages in a channel." (lambda (a b) (> (nth 1 a) (nth 1 b)))))) (defun erc-track-face-priority (face) - "Return a number indicating the priority of FACE in -`erc-track-faces-priority-list'. Lower number means higher -priority. + "Return priority (a number) of FACE in `erc-track-faces-priority-list'. +Lower number means higher priority. If face is not in `erc-track-faces-priority-list', it will have a higher number than any other face in that list." diff --git a/lisp/erc/erc-truncate.el b/lisp/erc/erc-truncate.el index ff33fbc5570..2c4002f0ee0 100644 --- a/lisp/erc/erc-truncate.el +++ b/lisp/erc/erc-truncate.el @@ -25,8 +25,8 @@ ;;; Commentary: ;; This implements buffer truncation (and optional log file writing -;; support for the Emacs IRC client. Use `erc-truncate-mode' to switch -;; on. Use `erc-enable-logging' to enable logging of the stuff which +;; support for the Emacs IRC client. Use `erc-truncate-mode' to switch +;; on. Use `erc-enable-logging' to enable logging of the stuff which ;; is getting truncated. ;;; Code: @@ -34,7 +34,7 @@ (require 'erc) (defgroup erc-truncate nil - "Truncate buffers when they reach a certain size" + "Truncate buffers when they reach a certain size." :group 'erc) (defcustom erc-max-buffer-size 30000 diff --git a/lisp/erc/erc-xdcc.el b/lisp/erc/erc-xdcc.el index e1b9f0de3a7..c17eb59da31 100644 --- a/lisp/erc/erc-xdcc.el +++ b/lisp/erc/erc-xdcc.el @@ -68,7 +68,7 @@ being evaluated and should return strings." ;;;###autoload (defun erc-xdcc-add-file (file) - "Add a file to `erc-xdcc-files'." + "Add FILE to `erc-xdcc-files'." (interactive "fFilename to add to XDCC: ") (if (file-exists-p file) (add-to-list 'erc-xdcc-files file))) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 026c6f84164..30285687536 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3,6 +3,7 @@ ;; Copyright (C) 1997-2021 Free Software Foundation, Inc. ;; Author: Alexander L. Belikoff (alexander@belikoff.net) +;; Maintainer: Amin Bandali <bandali@gnu.org> ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu), ;; Mario Lang (mlang@delysid.org), ;; Alex Schroeder (alex@gnu.org) @@ -11,10 +12,10 @@ ;; David Edmondson (dme@dme.org) ;; Michael Olson (mwolson@gnu.org) ;; Kelvin White (kwhite@gnu.org) -;; Maintainer: Amin Bandali <bandali@gnu.org> +;; Version: 5.4.1 +;; Package-Requires: ((emacs "27.1")) ;; Keywords: IRC, chat, client, Internet - -;; Version: 5.3 +;; URL: https://www.gnu.org/software/emacs/erc.html ;; This file is part of GNU Emacs. @@ -57,7 +58,7 @@ ;;; Code: -(load "erc-loaddefs" nil t) +(load "erc-loaddefs" 'noerror 'nomessage) (require 'cl-lib) (require 'format-spec) @@ -68,10 +69,23 @@ (require 'iso8601) (eval-when-compile (require 'subr-x)) +(defconst erc-version "5.4.1" + "This version of ERC.") + (defvar erc-official-location "https://www.gnu.org/software/emacs/erc.html (mailing list: emacs-erc@gnu.org)" "Location of the ERC client on the Internet.") +;; Map each :package-version to the associated Emacs version. +;; (This eliminates the need for explicit :version keywords on the +;; custom definitions.) +(add-to-list + 'customize-package-emacs-version-alist + '(ERC ("5.2" . "22.1") + ("5.3" . "23.1") + ("5.4" . "28.1") + ("5.4.1" . "29.1"))) + (defgroup erc nil "Emacs Internet Relay Chat client." :link '(url-link "https://www.gnu.org/software/emacs/erc.html") @@ -80,32 +94,32 @@ :group 'applications) (defgroup erc-buffers nil - "Creating new ERC buffers" + "Creating new ERC buffers." :group 'erc) (defgroup erc-display nil - "Settings for how various things are displayed" + "Settings for how various things are displayed." :group 'erc) (defgroup erc-mode-line-and-header nil - "Displaying information in the mode-line and header" + "Displaying information in the mode-line and header." :group 'erc-display) (defgroup erc-ignore nil - "Ignoring certain messages" + "Ignoring certain messages." :group 'erc) (defgroup erc-lurker nil - "Hide specified message types sent by lurkers" + "Hide specified message types sent by lurkers." :version "24.3" :group 'erc-ignore) (defgroup erc-query nil - "Using separate buffers for private discussions" + "Using separate buffers for private discussions." :group 'erc) (defgroup erc-quit-and-part nil - "Quitting and parting channels" + "Quitting and parting channels." :group 'erc) (defgroup erc-paranoia nil @@ -113,7 +127,7 @@ :group 'erc) (defgroup erc-scripts nil - "Running scripts at startup and with /LOAD" + "Running scripts at startup and with /LOAD." :group 'erc) (require 'erc-backend) @@ -157,9 +171,7 @@ parameters and authentication." :type 'string) (defcustom erc-try-new-nick-p t - "If the nickname you chose isn't available, and this option is non-nil, -ERC should automatically attempt to connect with another nickname. - + "Non-nil means attempt to connect with another nickname if nickname unavailable. You can manually set another nickname with the /NICK command." :group 'erc :type 'boolean) @@ -189,10 +201,12 @@ parameters and authentication." It is not strictly necessary to provide this, since ERC will prompt you for it.") -(defcustom erc-user-mode nil +(defcustom erc-user-mode "+i" + ;; +i "Invisible". Hides user from global /who and /names. "Initial user modes to be set after a connection is established." :group 'erc - :type '(choice (const nil) string function)) + :type '(choice (const nil) string function) + :version "28.1") (defcustom erc-prompt-for-password t @@ -280,9 +294,9 @@ indicate it has handled the input." :type 'hook) (defcustom erc-join-hook nil - "Hook run when we join a channel. Hook functions are called -without arguments, with the current buffer set to the buffer of -the new channel. + "Hook run when we join a channel. +Hook functions are called without arguments, with the current +buffer set to the buffer of the new channel. See also `erc-server-JOIN-functions', `erc-part-hook'." :group 'erc-hooks @@ -328,15 +342,15 @@ Functions are passed a buffer as the first argument." (defvar-local erc-channel-users nil - "A hash table of members in the current channel, which -associates nicknames with cons cells of the form: + "Hash table of members in the current channel. +It associates nicknames with cons cells of the form: \(USER . MEMBER-DATA) where USER is a pointer to an erc-server-user struct, and MEMBER-DATA is a pointer to an erc-channel-user struct.") (defvar-local erc-server-users nil - "A hash table of users on the current server, which associates -nicknames with erc-server-user struct instances.") + "Hash table of users on the current server. +It associates nicknames with `erc-server-user' struct instances.") (defun erc-downcase (string) "Convert STRING to IRC standard conforming downcase." @@ -380,13 +394,11 @@ If no server buffer exists, return nil." (last-message-time nil)) (define-inline erc-get-channel-user (nick) - "Find the (USER . CHANNEL-DATA) element corresponding to NICK -in the current buffer's `erc-channel-users' hash table." + "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 the USER corresponding to NICK in the current server's -`erc-server-users' hash table." + "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))))) @@ -533,10 +545,10 @@ Removes all users in the current channel. This is called by (erc-channel-user-voice (cdr cdata)))))))) (defun erc-get-channel-user-list () - "Return a list of users in the current channel. Each element -of the list is of the form (USER . CHANNEL-DATA), where USER is -an erc-server-user struct, and CHANNEL-DATA is either nil or an -erc-channel-user struct. + "Return a list of users in the current channel. +Each element of the list is of the form (USER . CHANNEL-DATA), +where USER is an erc-server-user struct, and CHANNEL-DATA is +either nil or an erc-channel-user struct. See also: `erc-sort-channel-users-by-activity'." (let (users) @@ -816,7 +828,7 @@ set if some hacker is trying to flood you away." (defcustom erc-system-name nil "Use this as the name of your system. -If nil, ERC will call `system-name' to get this information." +If nil, ERC will call function `system-name' to get this information." :group 'erc :type '(choice (const :tag "Default system name" nil) string)) @@ -860,8 +872,8 @@ See `erc-server-flood-margin' for other flood-related parameters.") ;; Script parameters (defcustom erc-startup-file-list - (list (concat user-emacs-directory ".ercrc.el") - (concat user-emacs-directory ".ercrc") + (list (locate-user-emacs-file ".ercrc.el") + (locate-user-emacs-file ".ercrc") "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc") "List of files to try for a startup script. The first existent and readable one will get executed. @@ -1280,7 +1292,7 @@ Example: #\\='erc-replace-insert)) ((remove-hook \\='erc-insert-modify-hook #\\='erc-replace-insert)))" - (declare (doc-string 3)) + (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)))) @@ -1383,8 +1395,7 @@ If BUFFER is nil, the current buffer is used." (null (erc-default-target))))) (defun erc-open-server-buffer-p (&optional buffer) - "Return non-nil if argument BUFFER is an ERC server buffer that -has an open IRC process. + "Return non-nil if BUFFER is an ERC server buffer with an open IRC process. If BUFFER is nil, the current buffer is used." (and (erc-server-buffer-p buffer) @@ -1487,8 +1498,8 @@ Defaults to the server buffer." "IRC port to use if it cannot be detected otherwise.") (defconst erc-default-port-tls 6697 - "IRC port to use for encrypted connections if it cannot be - detected otherwise.") + "IRC port to use for encrypted connections if it cannot be \ +detected otherwise.") (defcustom erc-join-buffer 'buffer "Determines how to display a newly created IRC buffer. @@ -1732,20 +1743,11 @@ 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))) - ;; Make the evaluation have the correct order - (let ((pre (make-symbol "pre")) - (pro (make-symbol "pro"))) - `(let* ((,pro ,process) - (,pre ,pred) - (res (mapcar (lambda (buffer) - (with-current-buffer buffer - ,@forms)) - (erc-buffer-list ,pre - ,pro)))) - ;; Silence the byte-compiler by binding the result of mapcar to - ;; a variable. - (ignore res) - res))) + (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) @@ -2271,7 +2273,7 @@ first element is the certificate key file name, and the second element is the certificate file name itself, or t, which means that `auth-source' will be queried for the key and the certificate. Authenticating using a TLS client certificate is -also refered to as \"CertFP\" (Certificate Fingerprint) +also referred to as \"CertFP\" (Certificate Fingerprint) authentication by various IRC networks. Example usage: @@ -2312,6 +2314,22 @@ message instead, to make debugging easier." ;;; Debugging the protocol +(defvar erc-debug-irc-protocol-time-format "%FT%T.%6N%z " + "Timestamp format string for protocol logger.") + +(defconst erc-debug-irc-protocol-version "1" + "Protocol log format version number. +This exists to help tooling track changes to the format. + +In version 1, everything before and including the first double CRLF is +front matter, which must also be CRLF terminated. Lines beginning with +three asterisks must be ignored as comments. Other lines should be +interpreted as email-style headers. Folding is not supported. A second +double CRLF, if present, signals the end of a log. Session resumption +is not supported. Logger lines must adhere to the following format: +TIMESTAMP PEER-NAME FLOW-INDICATOR IRC-MESSAGE CRLF. Outgoing messages +are indicated with a >> and incoming with a <<.") + (defvar erc-debug-irc-protocol nil "If non-nil, log all IRC protocol traffic to the buffer \"*erc-protocol*\". @@ -2333,32 +2351,32 @@ This only has any effect if `erc-debug-irc-protocol' is non-nil. The buffer is created if it doesn't exist. -If OUTBOUND is non-nil, STRING is being sent to the IRC server -and appears in face `erc-input-face' in the buffer." +If OUTBOUND is non-nil, STRING is being sent to the IRC server and +appears in face `erc-input-face' in the buffer. Lines must already +contain CRLF endings. Peer is identified by the most precise label +available at run time, starting with the network name, followed by the +announced host name, and falling back to the dialed <server>:<port>." (when erc-debug-irc-protocol - (let ((network-name (or (ignore-errors (erc-network-name)) - "???"))) + (let ((esid (or (and (fboundp 'erc-network) + (erc-network) + (erc-network-name)) + erc-server-announced-name + (format "%s:%s" erc-session-server erc-session-port))) + (ts (when erc-debug-irc-protocol-time-format + (format-time-string erc-debug-irc-protocol-time-format)))) (with-current-buffer (get-buffer-create "*erc-protocol*") (save-excursion (goto-char (point-max)) (let ((inhibit-read-only t)) - (insert (if (not outbound) - ;; Cope with the fact that string might - ;; contain multiple lines of text. - (let ((lines (delete "" (split-string string - "\n\\|\r\n"))) - (result "")) - (dolist (line lines) - (setq result (concat result network-name - " << " line "\n"))) - result) - (propertize - (concat network-name " >> " string - (if (/= ?\n - (aref string - (1- (length string)))) - "\n")) - 'font-lock-face 'erc-input-face))))) + (insert (if outbound + (concat ts esid " >> " string) + ;; Cope with multi-line messages + (let ((lines (split-string string "[\r\n]+" t)) + result) + (dolist (line lines) + (setq result (concat result ts esid + " << " line "\r\n"))) + result))))) (let ((orig-win (selected-window)) (debug-buffer-window (get-buffer-window (current-buffer) t))) (when debug-buffer-window @@ -2377,9 +2395,17 @@ If ARG is non-nil, show the *erc-protocol* buffer." (with-current-buffer buf (view-mode-enter) (when (null (current-local-map)) - (let ((inhibit-read-only t)) - (insert (erc-make-notice "This buffer displays all IRC protocol traffic exchanged with each server.\n")) - (insert (erc-make-notice "Kill this buffer to terminate protocol logging.\n\n"))) + (let ((inhibit-read-only t) + (msg (list + (concat "Version: " erc-debug-irc-protocol-version) + (concat "ERC-Version: " erc-version) + (concat "Emacs-Version: " emacs-version) + (erc-make-notice + (concat "This buffer displays all IRC protocol " + "traffic exchanged with servers.")) + (erc-make-notice "Kill it to disable logging.") + (erc-make-notice "Press `t' to toggle.")))) + (insert (string-join msg "\r\n"))) (use-local-map (make-sparse-keymap)) (local-set-key (kbd "t") 'erc-toggle-debug-irc-protocol)) (add-hook 'kill-buffer-hook @@ -2387,10 +2413,12 @@ If ARG is non-nil, show the *erc-protocol* buffer." nil 'local) (goto-char (point-max)) (let ((inhibit-read-only t)) - (insert (erc-make-notice - (format "IRC protocol logging %s at %s -- Press `t' to toggle logging.\n" + (insert (if erc-debug-irc-protocol "\r\n" "") + (erc-make-notice + (format "IRC protocol logging %s at %s" (if erc-debug-irc-protocol "disabled" "enabled") - (current-time-string)))))) + (current-time-string))) + (if erc-debug-irc-protocol "\r\n" "\r\n\r\n")))) (setq erc-debug-irc-protocol (not erc-debug-irc-protocol)) (if (and arg (not (get-buffer-window "*erc-protocol*" t))) @@ -2583,9 +2611,8 @@ See also `erc-lurker-trim-nicks'." Returns NICK unmodified unless `erc-lurker-trim-nicks' is non-nil." (if erc-lurker-trim-nicks - (replace-regexp-in-string - (regexp-opt-charset (string-to-list erc-lurker-ignore-chars)) - "" nick) + (string-trim-right + nick (rx-to-string `(+ (in ,@(string-to-list erc-lurker-ignore-chars))))) nick)) (defcustom erc-lurker-hide-list nil @@ -2709,9 +2736,8 @@ displayed hostnames." :type 'alist) (defun erc-canonicalize-server-name (server) - "Return the canonical network name for SERVER if any, -otherwise `erc-server-announced-name'. SERVER is matched against -`erc-common-server-suffixes'." + "Return canonical network name for SERVER or `erc-server-announced-name'. +SERVER is matched against `erc-common-server-suffixes'." (when server (or (cdar (cl-remove-if-not (lambda (net) (string-match (car net) server)) @@ -2791,20 +2817,17 @@ present." (let ((prop-val (erc-get-parsed-vector position))) (and prop-val (member (erc-response.command prop-val) list)))) -(defvar-local erc-send-input-line-function 'erc-send-input-line) +(defvar-local erc-send-input-line-function 'erc-send-input-line + "Function for sending lines lacking a leading user command. +When a line typed into a buffer contains an explicit command, like /msg, +a corresponding handler (here, erc-cmd-MSG) is called. But lines typed +into a channel or query buffer already have an implicit target and +command (PRIVMSG). This function is called on such occasions and also +for special purposes (see erc-dcc.el).") (defun erc-send-input-line (target line &optional force) - "Send LINE to TARGET. - -See also `erc-server-send'." - (setq line (format "PRIVMSG %s :%s" - target - ;; If the line is empty, we still want to - ;; send it - i.e. an empty pasted line. - (if (string= line "\n") - " \n" - line))) - (erc-server-send line force target)) + "Send LINE to TARGET." + (erc-message "PRIVMSG" (concat target " " line) force)) (defun erc-get-arglist (fun) "Return the argument list of a function without the parens." @@ -2942,7 +2965,7 @@ Commands for which no erc-cmd-xxx exists, are tunneled through this function. LINE is sent to the server verbatim, and therefore has to contain the command itself as well." (erc-log (format "cmd: DEFAULT: %s" line)) - (erc-server-send (substring line 1)) + (erc-server-send (string-trim-right (substring line 1) "[\r\n]")) t) (defvar erc--read-time-period-history nil) @@ -3288,19 +3311,39 @@ a script after exceeding the flood threshold." t) (t nil))) -(defun erc-cmd-WHOIS (user &optional server) - "Display whois information for USER. +(defun erc-cmd-WHOIS (first &optional second) + "Display whois information for the given user. + +With one argument, FIRST is the nickname of the user to request +whois information for. -If SERVER is non-nil, use that, rather than the current server." - ;; FIXME: is the above docstring correct? -- Lawrence 2004-01-08 - (let ((send (if server - (format "WHOIS %s %s" user server) - (format "WHOIS %s" user)))) +With two arguments, FIRST is the server, and SECOND is the user +nickname. + +Specifying the server is useful for getting the time the user has +been idle for, when the user is connected to a different server +on the same IRC network. (Only the server a user is connected to +knows how long the user has been idle for.)" + (let ((send (if second + (format "WHOIS %s %s" first second) + (format "WHOIS %s" first)))) (erc-log (format "cmd: %s" send)) (erc-server-send send) t)) (defalias 'erc-cmd-WI #'erc-cmd-WHOIS) +(defun erc-cmd-WII (nick) + "Display whois information for NICK, including idle time. + +This is a convenience function which calls `erc-cmd-WHOIS' with +the given NICK for both arguments. Using NICK in place of the +server argument -- effectively delegating to the IRC network the +looking up of the server to which NICK is connected -- is not +standardized, but is widely supported across IRC networks. + +See `erc-cmd-WHOIS' for more details." + (erc-cmd-WHOIS nick nick)) + (defun erc-cmd-WHOAMI () "Display whois information about yourself." (erc-cmd-WHOIS (erc-current-nick)) @@ -3545,8 +3588,7 @@ just as you provided it. Use this command with care!" (put 'erc-cmd-QUOTE 'do-not-parse-args t) (defcustom erc-query-display 'window - "Indicates how to display query buffers when using the /QUERY -command to talk to someone. + "How to display query buffers when using the /QUERY command to talk to someone. The default behavior is to display the message in a new window and bring it to the front. See the documentation for @@ -3582,7 +3624,7 @@ If USER is omitted, close the current query buffer if one exists (defun erc-quit/part-reason-default () "Default quit/part message." - (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version)) + (erc-version nil 'bold-erc)) (defun erc-quit-reason-normal (&optional s) @@ -3597,7 +3639,9 @@ If S is non-nil, it will be used as the quit reason." If S is non-nil, it will be used as the quit reason." (or s (if (fboundp 'yow) - (replace-regexp-in-string "\n" "" (yow)) + (if (>= emacs-major-version 28) + (string-replace "\n" "" (yow)) + (replace-regexp-in-string "\n" "" (yow))) (erc-quit/part-reason-default)))) (make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4") @@ -3624,7 +3668,9 @@ If S is non-nil, it will be used as the part reason." If S is non-nil, it will be used as the quit reason." (or s (if (fboundp 'yow) - (replace-regexp-in-string "\n" "" (yow)) + (if (>= emacs-major-version 28) + (string-replace "\n" "" (yow)) + (replace-regexp-in-string "\n" "" (yow))) (erc-quit/part-reason-default)))) (make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4") @@ -3706,13 +3752,17 @@ the message given by REASON." (setq buffer (current-buffer))) (with-current-buffer buffer (setq erc-server-quitting nil) - (setq erc-server-reconnecting t) + (with-suppressed-warnings ((obsolete erc-server-reconnecting)) + (setq erc-server-reconnecting t)) + (setq erc--server-reconnecting t) (setq erc-server-reconnect-count 0) (setq process (get-buffer-process (erc-server-buffer))) (if process (delete-process process) (erc-server-reconnect)) - (setq erc-server-reconnecting nil))) + (with-suppressed-warnings ((obsolete erc-server-reconnecting)) + (setq erc-server-reconnecting nil)) + (setq erc--server-reconnecting nil))) t) (put 'erc-cmd-RECONNECT 'process-not-needed t) @@ -3722,7 +3772,7 @@ the message given by REASON." (condition-case nil (erc :server server :nick (erc-current-nick)) (error - (erc-error "Cannot find host %s." server))) + (erc-error "Cannot find host: `%s'" server))) t) (put 'erc-cmd-SERVER 'process-not-needed t) @@ -3731,7 +3781,8 @@ the message given by REASON." (defun erc-cmd-SV () "Say the current ERC and Emacs version into channel." - (erc-send-message (format "I'm using ERC with GNU Emacs %s (%s%s)%s." + (erc-send-message (format "I'm using ERC %s with GNU Emacs %s (%s%s)%s." + erc-version emacs-version system-configuration (concat @@ -3783,6 +3834,24 @@ the message given by REASON." (mapconcat #'identity people " "))) t)) +(defun erc-cmd-OPME () + "Ask ChanServ to op the current nick in the current channel. + +This command assumes a ChanServ (channel service) available on +the IRC network which accepts an \"op\" command that takes the +channel name and the user's nick, and that the current nick is +allowed to become an operator in the current channel (typically +means that the user has a +o flag in the channel's access list)." + (erc-message "PRIVMSG" + (format "ChanServ op %s %s" + (erc-default-target) + (erc-current-nick)) + nil)) + +(defun erc-cmd-DEOPME () + "Deop the current nick in the current channel." + (erc-cmd-DEOP (erc-current-nick))) + (defun erc-cmd-TIME (&optional line) "Request the current time and date from the current server." (cond @@ -4280,8 +4349,8 @@ disconnected, you should set this option to t." :type 'boolean) (defcustom erc-format-query-as-channel-p t - "If non-nil, format text from others in a query buffer like in a channel, -otherwise format like a private message." + "If non-nil, format text from others in a query buffer like in a channel. +Otherwise format like a private message." :group 'erc-query :type 'boolean) @@ -4471,7 +4540,7 @@ also `erc-format-nick-function'." (propertize prefix 'font-lock-face 'erc-default-face)))) (defun erc-echo-notice-in-default-buffer (s parsed buffer _sender) - "Echos a private notice in the default buffer, namely the + "Echo a private notice in the default buffer, namely the target buffer specified by BUFFER, or there is no target buffer, the server buffer. This function is designed to be added to either `erc-echo-notice-hook' or `erc-echo-notice-always-hook', @@ -4480,30 +4549,32 @@ and always returns t." t) (defun erc-echo-notice-in-target-buffer (s parsed buffer _sender) - "Echos a private notice in BUFFER, if BUFFER is non-nil. This -function is designed to be added to either `erc-echo-notice-hook' -or `erc-echo-notice-always-hook', and returns non-nil if BUFFER -is non-nil." + "Echo a private notice in BUFFER, if BUFFER is non-nil. +This function is designed to be added to either +`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and +returns non-nil if BUFFER is non-nil." (if buffer (progn (erc-display-message parsed nil buffer s) t) nil)) (defun erc-echo-notice-in-minibuffer (s _parsed _buffer _sender) - "Echos a private notice in the minibuffer. This function is -designed to be added to either `erc-echo-notice-hook' or -`erc-echo-notice-always-hook', and always returns t." + "Echo a private notice in the minibuffer. +This function is designed to be added to either +`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and +always returns t." (message "%s" (concat "NOTICE: " s)) t) (defun erc-echo-notice-in-server-buffer (s parsed _buffer _sender) - "Echos a private notice in the server buffer. This function is -designed to be added to either `erc-echo-notice-hook' or -`erc-echo-notice-always-hook', and always returns t." + "Echo a private notice in the server buffer. +This function is designed to be added to either +`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and +always returns t." (erc-display-message parsed nil nil s) t) (defun erc-echo-notice-in-active-non-server-buffer (s parsed _buffer _sender) - "Echos a private notice in the active buffer if the active + "Echo a private notice in the active buffer if the active buffer is not the server buffer. This function is designed to be added to either `erc-echo-notice-hook' or `erc-echo-notice-always-hook', and returns non-nil if the active @@ -4513,15 +4584,16 @@ buffer is not the server buffer." nil)) (defun erc-echo-notice-in-active-buffer (s parsed _buffer _sender) - "Echos a private notice in the active buffer. This function is -designed to be added to either `erc-echo-notice-hook' or -`erc-echo-notice-always-hook', and always returns t." + "Echo a private notice in the active buffer. +This function is designed to be added to either +`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and +always returns t." (erc-display-message parsed nil 'active s) t) (defun erc-echo-notice-in-user-buffers (s parsed _buffer sender) - "Echos a private notice in all of the buffers for which SENDER -is a member. This function is designed to be added to either + "Echo a private notice in all of the buffers for which SENDER is a member. +This function is designed to be added to either `erc-echo-notice-hook' or `erc-echo-notice-always-hook', and returns non-nil if there is at least one buffer for which the sender is a member. @@ -4534,12 +4606,11 @@ See also: `erc-echo-notice-in-first-user-buffer', nil))) (defun erc-echo-notice-in-user-and-target-buffers (s parsed buffer sender) - "Echos a private notice in BUFFER and in all of the buffers for -which SENDER is a member. This function is designed to be added -to either `erc-echo-notice-hook' or -`erc-echo-notice-always-hook', and returns non-nil if there is -at least one buffer for which the sender is a member or the -default target. + "Echo a private notice in BUFFER and in all buffers for which SENDER is a member. +This function is designed to be added to either +`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and +returns non-nil if there is at least one buffer for which the +sender is a member or the default target. See also: `erc-echo-notice-in-user-buffers', `erc-buffer-list-with-nick'." @@ -4550,8 +4621,8 @@ See also: `erc-echo-notice-in-user-buffers', nil))) (defun erc-echo-notice-in-first-user-buffer (s parsed _buffer sender) - "Echos a private notice in one of the buffers for which SENDER -is a member. This function is designed to be added to either + "Echo a private notice in one of the buffers for which SENDER is a member. +This function is designed to be added to either `erc-echo-notice-hook' or `erc-echo-notice-always-hook', and returns non-nil if there is at least one buffer for which the sender is a member. @@ -4790,8 +4861,8 @@ See also `erc-display-message'." (unless erc-disable-ctcp-replies (erc-send-ctcp-notice nick (format - "VERSION \C-bERC\C-b - an IRC client for Emacs %s (\C-b%s\C-b)" - emacs-version + "VERSION %s (\C-b%s\C-b)" + (erc-version nil 'bold-erc) erc-official-location))) nil) @@ -5011,10 +5082,11 @@ See also: `erc-update-user'." (defun erc-update-user (user &optional new-nick host login full-name info) - "Update user info for USER. USER must be an erc-server-user -struct. Any of NEW-NICK, HOST, LOGIN, FULL-NAME, INFO which are -non-nil and not equal to the existing values for USER are used to -replace the stored values in USER. + "Update user info for USER. +USER must be an erc-server-user struct. Any of NEW-NICK, HOST, +LOGIN, FULL-NAME, INFO which are non-nil and not equal to the +existing values for USER are used to replace the stored values in +USER. If, and only if, a change is made, `erc-channel-members-changed-hook' is run for each channel for @@ -5159,8 +5231,7 @@ See also: `erc-update-user' and `erc-update-channel-member'." (defun erc-update-channel-member (channel nick new-nick &optional add voice halfop op admin owner host login full-name info update-message-time) - "Update user and channel information for the user with -nickname NICK in channel CHANNEL. + "Update user and channel for user with nickname NICK in channel CHANNEL. See also: `erc-update-current-channel-member'." (erc-with-buffer @@ -5551,9 +5622,9 @@ submitted line to be intentional." string insertp sendp) (defun erc-send-input (input) - "Treat INPUT as typed in by the user. It is assumed that the input -and the prompt is already deleted. -This returns non-nil only if we actually send anything." + "Treat INPUT as typed in by the user. +It is assumed that the input and the prompt is already deleted. +Return non-nil only if we actually send anything." ;; Handle different kinds of inputs (cond ;; Ignore empty input @@ -5587,7 +5658,9 @@ This returns non-nil only if we actually send anything." (when (and (erc-input-sendp state) erc-send-this) (let ((string (erc-input-string state))) - (if (or (string-match "\n" string) + (if (or (if (>= emacs-major-version 28) + (string-search "\n" string) + (string-match "\n" string)) (not (string-match erc-command-regexp string))) (mapc (lambda (line) @@ -5626,8 +5699,7 @@ This returns non-nil only if we actually send anything." ;; (run-hooks 'erc-send-post-hook)))))) (defun erc-display-msg (line) - "Display LINE as a message of the user to the current target at the -current position." + "Display LINE as a message of the user to the current target at point." (when erc-insert-this (let ((insert-position (point))) (insert (erc-format-my-nick)) @@ -6359,8 +6431,8 @@ See `erc-mode-line-format' for which characters are can be used." :type 'boolean) (defcustom erc-header-line-uses-help-echo-p t - "Show the contents of the header line in the echo area or as a tooltip -when you move point into the header line." + "Show header line in echo area or as a tooltip +when point moves to the header line." :group 'erc-mode-line-and-header :type 'boolean) @@ -6449,8 +6521,7 @@ shortened server name instead." (t (buffer-name (current-buffer)))))) (defun erc-format-away-status () - "Return a formatted `erc-mode-line-away-status-format' -if `erc-away' is non-nil." + "Return a formatted `erc-mode-line-away-status-format' if `erc-away' is non-nil." (let ((a (erc-away-time))) (if a (format-time-string erc-mode-line-away-status-format a) @@ -6528,13 +6599,21 @@ if `erc-away' is non-nil." (fill-region (point-min) (point-max)) (buffer-string)))) (setq header-line-format - (replace-regexp-in-string - "%" - "%%" - (if face - (propertize header 'help-echo help-echo - 'face face) - (propertize header 'help-echo help-echo)))))) + (if (>= emacs-major-version 28) + (string-replace + "%" + "%%" + (if face + (propertize header 'help-echo help-echo + 'face face) + (propertize header 'help-echo help-echo))) + (replace-regexp-in-string + "%" + "%%" + (if face + (propertize header 'help-echo help-echo + 'face face) + (propertize header 'help-echo help-echo))))))) (t (setq header-line-format (if face (propertize header 'face face) @@ -6553,6 +6632,15 @@ If BUFFER is nil, update the mode line in all ERC buffers." ;; Miscellaneous +(defun erc-bug (subject) + "Send a bug report to the Emacs bug tracker and ERC mailing list." + (interactive "sBug Subject: ") + (report-emacs-bug + (format "ERC %s: %s" erc-version subject)) + (save-excursion + (goto-char (point-min)) + (insert "X-Debbugs-CC: emacs-erc@gnu.org\n"))) + (defun erc-port-to-string (p) "Convert port P to a string. P may be an integer or a service name." @@ -6569,12 +6657,18 @@ P may be an integer or a service name." s n)))) -(defun erc-version (&optional here) +(defun erc-version (&optional here bold-erc) "Show the version number of ERC in the minibuffer. -If optional argument HERE is non-nil, insert version number at point." +If optional argument HERE is non-nil, insert version number at point. +If optional argument BOLD-ERC is non-nil, display \"ERC\" as bold." (interactive "P") (let ((version-string - (format "ERC (IRC client for Emacs %s)" emacs-version))) + (format "%s %s (IRC client for GNU Emacs %s)" + (if bold-erc + "\C-bERC\C-b" + "ERC") + erc-version + emacs-version))) (if here (insert version-string) (if (called-interactively-p 'interactive) @@ -6804,7 +6898,9 @@ functions." nick user host channel (if (not (string= reason "")) (format ": %s" - (replace-regexp-in-string "%" "%%" reason)) + (if (>= emacs-major-version 28) + (string-replace "%" "%%" reason) + (replace-regexp-in-string "%" "%%" reason))) ""))))) |