;;; erc.el --- An Emacs Internet Relay Chat client -*- lexical-binding:t -*- ;; Copyright (C) 1997-2023 Free Software Foundation, Inc. ;; Author: Alexander L. Belikoff ;; Maintainer: Amin Bandali , F. Jason Park ;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu), ;; Mario Lang (mlang@delysid.org), ;; Alex Schroeder (alex@gnu.org) ;; Andreas Fuchs (afs@void.at) ;; Gergely Nagy (algernon@midgard.debian.net) ;; David Edmondson (dme@dme.org) ;; Michael Olson (mwolson@gnu.org) ;; Kelvin White (kwhite@gnu.org) ;; Version: 5.6-git ;; Package-Requires: ((emacs "27.1") (compat "29.1.4.3")) ;; Keywords: IRC, chat, client, Internet ;; URL: https://www.gnu.org/software/emacs/erc.html ;; This is a GNU ELPA :core package. Avoid functionality that is not ;; compatible with the version of Emacs recorded above. ;; 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 . ;;; Commentary: ;; ERC is a powerful, modular, and extensible IRC client for Emacs. ;; For more information, visit the ERC page at ;; . ;; Configuration: ;; Use M-x customize-group RET erc RET to get an overview ;; of all the variables you can tweak. ;; Usage: ;; To connect to an IRC server, do ;; ;; M-x erc RET ;; ;; or ;; ;; M-x erc-tls RET ;; ;; to connect over TLS (encrypted). Once you are connected to a ;; server, you can use C-h m or have a look at the ERC menu. ;;; Code: (eval-and-compile (load "erc-loaddefs" 'noerror 'nomessage)) (require 'erc-networks) (require 'erc-backend) (require 'cl-lib) (require 'format-spec) (require 'auth-source) (eval-when-compile (require 'subr-x)) (defconst erc-version "5.6-git" "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") ("5.5" . "29.1") ("5.6" . "30.1"))) (defgroup erc nil "Emacs Internet Relay Chat client." :link '(url-link "https://www.gnu.org/software/emacs/erc.html") :link '(custom-manual "(erc) Top") :prefix "erc-" :group 'applications) (defgroup erc-buffers nil "Creating new ERC buffers." :group 'erc) (defgroup erc-display nil "Settings controlling how various things are displayed. See the customization group `erc-buffers' for display options concerning buffers." :group 'erc) (defgroup erc-mode-line-and-header nil "Displaying information in the mode-line and header." :group 'erc-display) (defgroup erc-ignore nil "Ignoring certain messages." :group 'erc) (defgroup erc-lurker nil "Hide specified message types sent by lurkers." :version "24.3" :group 'erc-ignore) (defgroup erc-query nil "Using separate buffers for private discussions." :group 'erc) (defgroup erc-quit-and-part nil "Quitting and parting channels." :group 'erc) (defgroup erc-paranoia nil "Know what is sent and received; control the display of sensitive data." :group 'erc) (defgroup erc-scripts nil "Running scripts at startup and with /LOAD." :group 'erc) (defvar erc-message-parsed) ; only known to this file (defvar erc--msg-props nil "Hash table containing metadata properties for current message. Provided by the insertion functions `erc-display-message' and `erc-display-msg' while running their modification hooks. Initialized when null for each visitation round from function parameters and environmental factors, as well as the alist `erc--msg-prop-overrides'. Keys are symbols. Values are opaque objects, unless otherwise specified. Items present after running `erc-insert-post-hook' or `erc-send-post-hook' become text properties added to the first character of an inserted message. A given message therefore spans the interval extending from one set of such properties to the newline before the next (or `erc-insert-marker'). As of ERC 5.6, this forms the basis for visiting and editing inserted messages. Modules should align their markers accordingly. The following properties have meaning as of ERC 5.6: - `erc-msg': a symbol, guaranteed present; values include: `msg', signifying a `PRIVMSG' or an incoming `NOTICE'; `unknown', a fallback for `erc-display-message'; a catalog key, such as `s401' or `finished'; an `erc-display-message' TYPE parameter, like `notice' - `erc-cmd': a message's associated IRC command, as read by `erc--get-eq-comparable-cmd'; currently either a symbol, like `PRIVMSG', or a number, like 5, which represents the numeric \"005\"; absent on \"local\" messages, such as simple warnings and help text, and on outgoing messages unless echoed back by the server (assuming future support) - `erc-ctcp': a CTCP command, like `ACTION' - `erc-ts': a timestamp, possibly provided by the server; as of 5.6, a ticks/hertz pair on Emacs 29 and above, and a \"list\" type otherwise; managed by the `stamp' module - `erc-ephemeral': a symbol prefixed by or matching a module name; indicates to other modules and members of modification hooks that the current message should not affect stateful operations, such as recording a channel's most recent speaker This is an internal API, and the selection of related helper utilities is fluid and provisional. As of ERC 5.6, see the functions `erc--check-msg-prop' and `erc--get-inserted-msg-prop'.") (defvar erc--msg-prop-overrides nil "Alist of \"message properties\" for populating `erc--msg-props'. These override any defaults normally shown to modification hooks by `erc-display-msg' and `erc-display-message'. Modules should accommodate existing overrides when applicable. Items toward the front shadow any that follow. Ignored when `erc--msg-props' is already non-nil.") ;; Forward declarations (defvar tabbar--local-hlf) (defvar motif-version-string) (defvar gtk-version-string) (declare-function decoded-time-period "time-date" (time)) (declare-function iso8601-parse-duration "iso8601" (string)) (declare-function word-at-point "thingatpt" (&optional no-properties)) (autoload 'word-at-point "thingatpt") ; for hl-nicks (declare-function gnutls-negotiate "gnutls" (&rest rest)) (declare-function socks-open-network-stream "socks" (name buffer host service)) (declare-function url-host "url-parse" (cl-x)) (declare-function url-password "url-parse" (cl-x)) (declare-function url-portspec "url-parse" (cl-x)) (declare-function url-type "url-parse" (cl-x)) (declare-function url-user "url-parse" (cl-x)) ;; tunable connection and authentication parameters (defcustom erc-server nil "IRC server to use if one is not provided. See function `erc-compute-server' for more details on connection parameters and authentication." :group 'erc :type '(choice (const :tag "None" nil) (string :tag "Server"))) (defcustom erc-port nil "IRC port to use if not specified. This can be either a string or a number." :group 'erc :type '(choice (const :tag "None" nil) (integer :tag "Port number") (string :tag "Port string"))) (defcustom erc-nick nil "Nickname to use if one is not provided. This can be either a string, or a list of strings. In the latter case, if the first nick in the list is already in use, other nicks are tried in the list order. See function `erc-compute-nick' for more details on connection parameters and authentication." :group 'erc :type '(choice (const :tag "None" nil) (string :tag "Nickname") (repeat (string :tag "Nickname")))) (defcustom erc-nick-uniquifier "`" "The string to append to the nick if it is already in use." :group 'erc :type 'string) (defcustom erc-try-new-nick-p t "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) (defcustom erc-user-full-name nil "User full name. This can be either a string or a function to call. See function `erc-compute-full-name' for more details on connection parameters and authentication." :group 'erc :type '(choice (const :tag "No name" nil) (string :tag "Name") (function :tag "Get from function")) :set (lambda (sym val) (set sym (if (functionp val) (funcall val) val)))) (defcustom erc-rename-buffers t "Non-nil means rename buffers with network name, if available." :version "24.5" :group 'erc :type 'boolean) ;; For the sake of compatibility, an ID will be created on the user's ;; behalf when `erc-rename-buffers' is nil and one wasn't provided. ;; The name will simply be that of the buffer, usually SERVER:PORT. ;; This violates the policy of treating provided IDs as gospel, but ;; it'll have to do for now. (make-obsolete-variable 'erc-rename-buffers "old behavior when t now permanent" "29.1") (defvar erc-password nil "Password to use when authenticating to an IRC server interactively. This variable only exists for legacy reasons. It's not customizable and is limited to a single server password. Users looking for similar functionality should consider auth-source instead. See Info node `(auth) Top' and Info node `(erc) auth-source'.") (make-obsolete-variable 'erc-password "use auth-source instead" "29.1") (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) :version "28.1") (defcustom erc-prompt-for-password t "Ask for a server password when invoking `erc-tls' interactively." :group 'erc :type 'boolean) (defcustom erc-warn-about-blank-lines t "Warn the user if they attempt to send a blank line. When non-nil, ERC signals a `user-error' upon encountering prompt input containing empty or whitespace-only lines. When nil, ERC still inhibits sending but does so silently. With the companion option `erc-send-whitespace-lines' enabled, ERC sends pending input and prints a message in the echo area indicating the amount of padding and/or stripping applied, if any. Setting this option to nil suppresses such reporting." :group 'erc :type 'boolean) (defcustom erc-send-whitespace-lines nil "If set to non-nil, send lines consisting of only whitespace." :group 'erc :type 'boolean) (defcustom erc-inhibit-multiline-input nil "When non-nil, conditionally disallow input consisting of multiple lines. Issue an error when the number of input lines submitted for sending meets or exceeds this value. The value t is synonymous with a value of 2 and means disallow more than 1 line of input." :package-version '(ERC . "5.5") :group 'erc :type '(choice integer boolean)) (defcustom erc-ask-about-multiline-input nil "Whether to ask to ignore `erc-inhibit-multiline-input' when tripped." :package-version '(ERC . "5.5") :group 'erc :type 'boolean) (defcustom erc-prompt-hidden ">" "Text to show in lieu of the prompt when hidden." :package-version '(ERC . "5.5") :group 'erc-display :type 'string) (defcustom erc-hide-prompt t "If non-nil, hide input prompt upon disconnecting. To unhide, type something in the input area. Once revealed, a prompt remains unhidden until the next disconnection. Channel prompts are unhidden upon rejoining. For behavior concerning query prompts, see `erc-unhide-query-prompt'. Longtime ERC users should note that this option was repurposed in ERC 5.5 because it had lain dormant for years after being sidelined in 5.3 when its only use in the interactive client was removed. Before then, its role was controlling whether `erc-command-indicator' would appear alongside echoed slash-command lines." :package-version '(ERC . "5.5") :group 'erc-display :type '(choice (const :tag "Always hide prompt" t) (set (const server) (const query) (const channel)))) (defcustom erc-unhide-query-prompt nil "When non-nil, always reveal query prompts upon reconnecting. Otherwise, prompts in a connection's query buffers remain hidden until the user types in the input area or a new message arrives from the target." :package-version '(ERC . "5.5") :group 'erc-display ;; Extensions may one day offer a way to discover whether a target ;; is online. When that happens, this can be expanded accordingly. :type 'boolean) ;; tunable GUI stuff (defcustom erc-show-my-nick t "If non-nil, display one's own nickname when sending a message. If non-nil, \"\" will be shown. If nil, only \"> \" will be shown." :group 'erc-display :type 'boolean) (define-widget 'erc-message-type 'set "A set of standard IRC Message types." :args '((const "JOIN") (const "KICK") (const "NICK") (const "PART") (const "QUIT") (const "MODE") (repeat :inline t :tag "Others" (string :tag "IRC Message Type")))) (defcustom erc-hide-list nil "A global list of IRC message types to hide. A typical value would be \(\"JOIN\" \"PART\" \"QUIT\")." :group 'erc-ignore :type 'erc-message-type) (defcustom erc-network-hide-list nil "A list of IRC networks to hide message types from. A typical value would be \((\"Libera.Chat\" \"MODE\") \(\"OFTC\" \"JOIN\" \"QUIT\"))." :version "25.1" :group 'erc-ignore :type '(alist :key-type string :value-type erc-message-type :options ("Libera.Chat"))) (defcustom erc-channel-hide-list nil "A list of IRC channels to hide message types from. A typical value would be \((\"#emacs\" \"QUIT\" \"JOIN\") \(\"#erc\" \"NICK\")." :version "25.1" :group 'erc-ignore :type '(alist :key-type string :value-type erc-message-type :options ("#emacs"))) (defcustom erc-disconnected-hook nil "Run this hook with arguments (NICK IP REASON) when disconnected. This happens before automatic reconnection. Note, that `erc-server-QUIT-functions' might not be run when we disconnect, simply because we do not necessarily receive the QUIT event." :group 'erc-hooks :type 'hook) (defcustom erc-complete-functions nil "These functions get called when the user hits \\`TAB' in ERC. Each function in turn is called until one returns non-nil to indicate it has handled the input." :group 'erc-hooks :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. See also `erc-server-JOIN-functions', `erc-part-hook'." :group 'erc-hooks :type 'hook) (defcustom erc-quit-hook nil "Hook run when processing a quit command directed at our nick. The hook receives one argument, the current PROCESS. See also `erc-server-QUIT-functions' and `erc-disconnected-hook'." :group 'erc-hooks :type 'hook) (defcustom erc-part-hook nil "Hook run when processing a PART message directed at our nick. The hook receives one argument, the current BUFFER. See also `erc-server-QUIT-functions', `erc-quit-hook' and `erc-disconnected-hook'." :group 'erc-hooks :type 'hook) (defcustom erc-kick-hook nil "Hook run when processing a KICK message directed at our nick. The hook receives one argument, the current BUFFER. See also `erc-server-PART-functions' and `erc-part-hook'." :group 'erc-hooks :type 'hook) (defcustom erc-nick-changed-functions nil "List of functions run when your nick was successfully changed. Each function should accept two arguments, NEW-NICK and OLD-NICK." :group 'erc-hooks :type 'hook) (defcustom erc-connect-pre-hook '(erc-initialize-log-marker) "Hook called just before `erc' calls `erc-connect'. Functions are passed a buffer as the first argument." :group 'erc-hooks :type 'hook) (defvar-local erc-channel-users nil "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 "Hash table of users on the current server. It associates nicknames with `erc-server-user' struct instances.") (defconst erc--casemapping-rfc1459-strict (let ((tbl (copy-sequence ascii-case-table)) (cup (copy-sequence (char-table-extra-slot ascii-case-table 0)))) (set-char-table-extra-slot tbl 0 cup) (set-char-table-extra-slot tbl 1 nil) (set-char-table-extra-slot tbl 2 nil) (pcase-dolist (`(,uc . ,lc) '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|))) (aset tbl uc lc) (aset tbl lc lc) (aset cup uc uc)) tbl)) (defconst erc--casemapping-rfc1459 (let ((tbl (copy-sequence erc--casemapping-rfc1459-strict)) (cup (copy-sequence (char-table-extra-slot erc--casemapping-rfc1459-strict 0)))) (set-char-table-extra-slot tbl 0 cup) (aset tbl ?~ ?^) (aset tbl ?^ ?^) (aset cup ?~ ?~) tbl)) (defun erc-add-server-user (nick user) "This function is for internal use only. Adds USER with nickname NICK to the `erc-server-users' hash table." (erc-with-server-buffer (puthash (erc-downcase nick) user erc-server-users))) (defun erc-remove-server-user (nick) "This function is for internal use only. Removes the user with nickname NICK from the `erc-server-users' hash table. This user is not removed from the `erc-channel-users' lists of other buffers. See also: `erc-remove-user'." (erc-with-server-buffer (remhash (erc-downcase nick) erc-server-users))) (defun erc-change-user-nickname (user new-nick) "This function is for internal use only. Changes the nickname of USER to NEW-NICK in the `erc-server-users' hash table. The `erc-channel-users' lists of other buffers are also changed." (let ((nick (erc-server-user-nickname user))) (setf (erc-server-user-nickname user) new-nick) (erc-with-server-buffer (remhash (erc-downcase nick) erc-server-users) (puthash (erc-downcase new-nick) user erc-server-users)) (dolist (buf (erc-server-user-buffers user)) (if (buffer-live-p buf) (with-current-buffer buf (let ((cdata (erc-get-channel-user nick))) (remhash (erc-downcase nick) erc-channel-users) (puthash (erc-downcase new-nick) cdata erc-channel-users))))))) (defun erc-remove-channel-user (nick) "This function is for internal use only. Removes the user with nickname NICK from the `erc-channel-users' list for this channel. If this user is not in the `erc-channel-users' list of any other buffers, the user is also removed from the server's `erc-server-users' list. See also: `erc-remove-server-user' and `erc-remove-user'." (let ((channel-data (erc-get-channel-user nick))) (when channel-data (let ((user (car channel-data))) (setf (erc-server-user-buffers user) (delq (current-buffer) (erc-server-user-buffers user))) (remhash (erc-downcase nick) erc-channel-users) (if (null (erc-server-user-buffers user)) (erc-remove-server-user nick)))))) (defun erc-remove-user (nick) "This function is for internal use only. Removes the user with nickname NICK from the `erc-server-users' list as well as from all `erc-channel-users' lists. See also: `erc-remove-server-user' and `erc-remove-channel-user'." (let ((user (erc-get-server-user nick))) (when user (let ((buffers (erc-server-user-buffers user))) (dolist (buf buffers) (if (buffer-live-p buf) (with-current-buffer buf (remhash (erc-downcase nick) erc-channel-users) (run-hooks 'erc-channel-members-changed-hook))))) (erc-remove-server-user nick)))) (defun erc-remove-channel-users () "This function is for internal use only. Removes all users in the current channel. This is called by `erc-server-PART' and `erc-server-QUIT'." (when (erc--target-channel-p erc--target) (setf (erc--target-channel-joined-p erc--target) nil)) (when (and erc-server-connected (erc-server-process-alive) (hash-table-p erc-channel-users)) (maphash (lambda (nick _cdata) (erc-remove-channel-user nick)) erc-channel-users) (clrhash erc-channel-users))) (defun erc-channel-user-owner-p (nick) "Return non-nil if NICK is an owner of the current channel." (and nick (hash-table-p erc-channel-users) (let ((cdata (erc-get-channel-user nick))) (and cdata (cdr cdata) (erc-channel-user-owner (cdr cdata)))))) (defun erc-channel-user-admin-p (nick) "Return non-nil if NICK is an admin in the current channel." (and nick (hash-table-p erc-channel-users) (let ((cdata (erc-get-channel-user nick))) (and cdata (cdr cdata) (erc-channel-user-admin (cdr cdata)))))) (defun erc-channel-user-op-p (nick) "Return non-nil if NICK is an operator in the current channel." (and nick (hash-table-p erc-channel-users) (let ((cdata (erc-get-channel-user nick))) (and cdata (cdr cdata) (erc-channel-user-op (cdr cdata)))))) (defun erc-channel-user-halfop-p (nick) "Return non-nil if NICK is a half-operator in the current channel." (and nick (hash-table-p erc-channel-users) (let ((cdata (erc-get-channel-user nick))) (and cdata (cdr cdata) (erc-channel-user-halfop (cdr cdata)))))) (defun erc-channel-user-voice-p (nick) "Return non-nil if NICK has voice in the current channel." (and nick (hash-table-p erc-channel-users) (let ((cdata (erc-get-channel-user nick))) (and cdata (cdr cdata) (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. See also: `erc-sort-channel-users-by-activity'." (let (users) (if (hash-table-p erc-channel-users) (maphash (lambda (_nick cdata) (setq users (cons cdata users))) erc-channel-users)) users)) (defun erc-get-server-nickname-list () "Return a list of known nicknames on the current server." (erc-with-server-buffer (let (nicks) (when (hash-table-p erc-server-users) (maphash (lambda (_n user) (setq nicks (cons (erc-server-user-nickname user) nicks))) erc-server-users) nicks)))) (defun erc-get-channel-nickname-list () "Return a list of known nicknames on the current channel." (let (nicks) (when (hash-table-p erc-channel-users) (maphash (lambda (_n cdata) (setq nicks (cons (erc-server-user-nickname (car cdata)) nicks))) erc-channel-users) nicks))) (defun erc-get-server-nickname-alist () "Return an alist of known nicknames on the current server." (erc-with-server-buffer (let (nicks) (when (hash-table-p erc-server-users) (maphash (lambda (_n user) (setq nicks (cons (cons (erc-server-user-nickname user) nil) nicks))) erc-server-users) nicks)))) (defun erc-get-channel-nickname-alist () "Return an alist of known nicknames on the current channel." (let (nicks) (when (hash-table-p erc-channel-users) (maphash (lambda (_n cdata) (setq nicks (cons (cons (erc-server-user-nickname (car cdata)) nil) nicks))) erc-channel-users) nicks))) (defun erc-sort-channel-users-by-activity (list) "Sort LIST such that users which have spoken most recently are listed first. LIST must be of the form (USER . CHANNEL-DATA). See also: `erc-get-channel-user-list'." (sort list (lambda (x y) (when (and (cdr x) (cdr y)) (let ((tx (erc-channel-user-last-message-time (cdr x))) (ty (erc-channel-user-last-message-time (cdr y)))) (and tx (or (not ty) (time-less-p ty tx)))))))) (defun erc-sort-channel-users-alphabetically (list) "Sort LIST so that users' nicknames are in alphabetical order. LIST must be of the form (USER . CHANNEL-DATA). See also: `erc-get-channel-user-list'." (sort list (lambda (x y) (when (and (cdr x) (cdr y)) (let ((nickx (downcase (erc-server-user-nickname (car x)))) (nicky (downcase (erc-server-user-nickname (car y))))) (and nickx (or (not nicky) (string-lessp nickx nicky)))))))) (defvar-local erc-channel-topic nil "A topic string for the channel. Should only be used in channel-buffers.") (defvar-local erc-channel-modes nil "List of letters, as strings, representing channel modes. For example, (\"i\" \"m\" \"s\"). Modes that take accompanying parameters are not included.") (defvar-local erc-insert-marker nil "The place where insertion of new text in erc buffers should happen.") (defvar-local erc-input-marker nil "The marker where input should be inserted.") (defun erc-string-no-properties (string) "Return a copy of STRING will all text-properties removed." (let ((newstring (copy-sequence string))) (set-text-properties 0 (length newstring) nil newstring) newstring)) (defcustom erc-prompt "ERC>" "Prompt used by ERC. Trailing whitespace is not required." :group 'erc-display :type '(choice string (function-item :tag "Interpret format specifiers" erc-prompt-format) function)) (defvar erc--prompt-format-face-example #("%p%m%a\u00b7%b>" 0 2 (font-lock-face erc-my-nick-prefix-face) 2 4 (font-lock-face font-lock-keyword-face) 4 6 (font-lock-face erc-error-face) 6 7 (font-lock-face shadow) 7 9 (font-lock-face font-lock-constant-face) 9 10 (font-lock-face shadow)) "An example value for option `erc-prompt-format' with faces.") (defcustom erc-prompt-format erc--prompt-format-face-example "Format string when `erc-prompt' is `erc-prompt-format'. ERC recognizes these substitution specifiers: %a - away indicator %b - buffer name %t - channel or query target, server domain, or dialed address %S - target@network or buffer name %s - target@server or server %N - current network, like Libera.Chat %p - channel membership prefix, like @ or + %n - current nickname %c - channel modes with args for select modes %C - channel modes with all args %u - user modes %m - channel modes sans args in channels, user modes elsewhere %M - like %m but show nothing in query buffers To pick your own colors, do something like: (setopt erc-prompt-format (concat (propertize \"%b\" \\='font-lock-face \\='erc-input-face) (propertize \"%a\" \\='font-lock-face \\='erc-error-face))) Please remember that ERC ignores this option completely unless the \"parent\" option `erc-prompt' is set to `erc-prompt-format'." :package-version '(ERC . "5.6") :group 'erc-display :type `(choice (const :tag "{Prefix}{Mode}{Away}{MIDDLE DOT}{Buffer}>" ,erc--prompt-format-face-example) string)) (defun erc-prompt-format () "Make predefined `format-spec' substitutions. See option `erc-prompt-format' and option `erc-prompt'." (format-spec erc-prompt-format (erc-compat--defer-format-spec-in-buffer (?C erc--channel-modes 3 ",") (?M erc--format-modes 'no-query-p) (?N erc-format-network) (?S erc-format-target-and/or-network) (?a erc--format-away-indicator) (?b buffer-name) (?c erc-format-channel-modes) (?m erc--format-modes) (?n erc-current-nick) (?p erc--format-channel-status-prefix) (?s erc-format-target-and/or-server) (?t erc-format-target) (?u erc--format-user-modes)) 'ignore-missing)) ; formerly `only-present' (defun erc-prompt () "Return the input prompt as a string. See also the variable `erc-prompt'." (let ((prompt (if (functionp erc-prompt) (funcall erc-prompt) erc-prompt))) (if (> (length prompt) 0) (concat prompt " ") prompt))) (defcustom erc-notice-prefix "*** " "Prefix for all notices." :group 'erc-display :type 'string) (defcustom erc-notice-highlight-type 'all "Determines how to highlight notices. See `erc-notice-prefix'. The following values are allowed: `prefix' - highlight notice prefix only `all' - highlight the entire notice Any other value disables notice's highlighting altogether." :group 'erc-display :type '(choice (const :tag "highlight notice prefix only" prefix) (const :tag "highlight the entire notice" all) (const :tag "don't highlight notices at all" nil))) (defcustom erc-echo-notice-hook nil "List of functions to call to echo a private notice. Each function is called with four arguments, the string to display, the parsed server message, the target buffer (or nil), and the sender. The functions are called in order, until a function evaluates to non-nil. These hooks are called after those specified in `erc-echo-notice-always-hook'. See also: `erc-echo-notice-always-hook', `erc-echo-notice-in-default-buffer', `erc-echo-notice-in-target-buffer', `erc-echo-notice-in-minibuffer', `erc-echo-notice-in-server-buffer', `erc-echo-notice-in-active-non-server-buffer', `erc-echo-notice-in-active-buffer', `erc-echo-notice-in-user-buffers', `erc-echo-notice-in-user-and-target-buffers', `erc-echo-notice-in-first-user-buffer'." :group 'erc-hooks :type 'hook :options '(erc-echo-notice-in-default-buffer erc-echo-notice-in-target-buffer erc-echo-notice-in-minibuffer erc-echo-notice-in-server-buffer erc-echo-notice-in-active-non-server-buffer erc-echo-notice-in-active-buffer erc-echo-notice-in-user-buffers erc-echo-notice-in-user-and-target-buffers erc-echo-notice-in-first-user-buffer)) (defcustom erc-echo-notice-always-hook '(erc-echo-notice-in-default-buffer) "List of functions to call to echo a private notice. Each function is called with four arguments, the string to display, the parsed server message, the target buffer (or nil), and the sender. The functions are called in order, and all functions are called. These hooks are called before those specified in `erc-echo-notice-hook'. See also: `erc-echo-notice-hook', `erc-echo-notice-in-default-buffer', `erc-echo-notice-in-target-buffer', `erc-echo-notice-in-minibuffer', `erc-echo-notice-in-server-buffer', `erc-echo-notice-in-active-non-server-buffer', `erc-echo-notice-in-active-buffer', `erc-echo-notice-in-user-buffers', `erc-echo-notice-in-user-and-target-buffers', `erc-echo-notice-in-first-user-buffer'." :group 'erc-hooks :type 'hook :options '(erc-echo-notice-in-default-buffer erc-echo-notice-in-target-buffer erc-echo-notice-in-minibuffer erc-echo-notice-in-server-buffer erc-echo-notice-in-active-non-server-buffer erc-echo-notice-in-active-buffer erc-echo-notice-in-user-buffers erc-echo-notice-in-user-and-target-buffers erc-echo-notice-in-first-user-buffer)) ;; other tunable parameters (defcustom erc-whowas-on-nosuchnick nil "If non-nil, do a whowas on a nick if no such nick." :group 'erc :type 'boolean) (defcustom erc-verbose-server-ping nil "If non-nil, show every time you get a PING or PONG from the server." :group 'erc-paranoia :type 'boolean) (defcustom erc-public-away-p nil "Let others know you are back when you are no longer marked away. This happens in this form: * is back (gone for