Allow ERC modules to extend erc-nick-popup-alist

* etc/ERC-NEWS: Mention changes to `erc-button-alist' and superficial
changes to `erc-nick-popup-alist'.
* lisp/erc/erc-button.el (erc-nick-popup-alist): Change type to prefer
associating strings with functions instead of arbitrary sexps.
(erc-button-cmd-KICK, erc-button-cmd-MSG): New functions to serve as
interrogative wrappers for `erc-cmd-KICK' and `erc-cmd-MSG' in
`erc-nick-popup-alist'.  The first also fixes a bug in which all but
the first token of a given "reason" would be omitted from the
":trailing" portion of an outgoing "KICK" message.
(erc-button--nick-popup-alist): New variable to help built-in modules
expose special actions to `erc-nick-popup' without touching
`erc-nick-popup-alist'.
(erc-nick-popup): Present members from both `erc--nick-popup-alist'
and `erc-nick-popup-alist' to the invoking user.  Accommodate
functions as well as arbitrary sexps.  (bug#63569)
This commit is contained in:
F. Jason Park 2022-12-18 19:01:40 -08:00
parent 67f7ac2bbe
commit e560f9af8e
2 changed files with 59 additions and 23 deletions

View file

@ -116,13 +116,19 @@ asking users who've customized this option to switch to
that some other solution, like automatic migration, is justified,
please make that known on the bug list.
** The 'nicknames' entry in 'erc-button-alist' is officially exceptional.
** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly.
It's no secret that the 'buttons' module treats potential nicknames
specially. To simplify ERC's move to next-gen "rich UI" extensions,
this special treatment is being canonized. From now on, all values
other than the symbol 'erc-button-buttonize-nicks' appearing in the
"FORM" field (third element) of this entry are considered deprecated
and will incur a warning.
specially. This is perhaps most evident in its treatment of the
'nicknames' entry in 'erc-button-alist'. Indeed, to simplify ERC's
move to next-gen "rich UI" extensions, this special treatment is being
canonized. From here on out, this entry will no longer appear in the
option's default value but will instead be applied implicitly so long
as the option 'erc-button-buttonize-nicks' is non-nil, which it is by
default. Relatedly, the option 'erc-nick-popup-alist' now favors
functions, which ERC calls non-interactively, over arbitrary
s-expressions, which ERC will continue to honor. Although the default
lineup remains functionally equivalent, its members have all been
updated accordingly.
** Option 'erc-query-on-unjoined-chan-privmsg' restored and renamed.
This option was accidentally removed from the default client in ERC

View file

@ -685,20 +685,20 @@ greater than `point-min' with a text property of `erc-callback'.")
;;; Nickname buttons:
(defcustom erc-nick-popup-alist
'(("DeOp" . (erc-cmd-DEOP nick))
("Kick" . (erc-cmd-KICK (concat nick " "
(read-from-minibuffer
(concat "Kick " nick ", reason: ")))))
("Msg" . (erc-cmd-MSG (concat nick " "
(read-from-minibuffer
(concat "Message to " nick ": ")))))
("Op" . (erc-cmd-OP nick))
("Query" . (erc-cmd-QUERY nick))
("Whois" . (erc-cmd-WHOIS nick))
("Lastlog" . (erc-cmd-LASTLOG nick)))
'(("DeOp" . erc-cmd-DEOP)
("Kick" . erc-button-cmd-KICK)
("Msg" . erc-button-cmd-MSG)
("Op" . erc-cmd-OP)
("Query" . erc-cmd-QUERY)
("Whois" . erc-cmd-WHOIS)
("Lastlog" . erc-cmd-LASTLOG))
"An alist of possible actions to take on a nickname.
An entry looks like (\"Action\" . SEXP) where SEXP is evaluated with
the variable `nick' bound to the nick in question.
For all entries (ACTION . FUNC), ERC offers ACTION as a possible
completion item and calls the selected entry's FUNC with the
buttonized nickname at point as the only argument. For
historical reasons, FUNC can also be an arbitrary sexp, in which
case, ERC binds the nick in question to the variable `nick' and
evaluates the expression.
Examples:
(\"DebianDB\" .
@ -706,18 +706,48 @@ Examples:
(format
\"ldapsearch -x -P 2 -h db.debian.org -b dc=debian,dc=org ircnick=%s\"
nick)))"
:package-version '(ERC . "5.6") ; FIXME sync on release
:type '(repeat (cons (string :tag "Op")
sexp)))
(choice function sexp))))
(defun erc-button-cmd-KICK (nick)
"Prompt for a reason, then kick NICK via `erc-cmd-KICK'.
In server buffers, also prompt for a channel."
(erc-cmd-KICK
(or (and erc--target (erc-default-target))
(let ((targets (mapcar (lambda (b)
(cons (erc--target-string
(buffer-local-value 'erc--target b))
b))
(erc-channel-list erc-server-process))))
(completing-read (format "Channel (%s): " (caar targets))
targets (pcase-lambda (`(,_ . ,buf))
(with-current-buffer buf
(erc-get-channel-user nick)))
t nil t (caar targets))))
nick
(read-from-minibuffer "Reason: ")))
(defun erc-button-cmd-MSG (nick)
"Prompt for a message to NICK, and send it via `erc-cmd-MSG'."
(let ((msg (read-from-minibuffer (concat "Message to " nick ": "))))
(erc-cmd-MSG (concat nick " " msg))))
(defvar-local erc-button--nick-popup-alist nil
"Internally controlled items for `erc-nick-popup-alist'.")
(defun erc-nick-popup (nick)
(let* ((completion-ignore-case t)
(alist (append erc-nick-popup-alist erc-button--nick-popup-alist))
(action (completing-read (format-message
"What action to take on `%s'? " nick)
erc-nick-popup-alist))
(code (cdr (assoc action erc-nick-popup-alist))))
alist))
(code (cdr (assoc action alist))))
(when code
(erc-set-active-buffer (current-buffer))
(eval code `((nick . ,nick))))))
(if (functionp code)
(funcall code nick)
(eval code `((nick . ,nick)))))))
;;; Callback functions
(defun erc-button-describe-symbol (symbol-name)