diff options
| author | F. Jason Park | 2022-12-18 19:01:40 -0800 |
|---|---|---|
| committer | F. Jason Park | 2023-04-08 14:23:51 -0700 |
| commit | 8184a815aff52cbf1f1b8680d80af2fbf2dce248 (patch) | |
| tree | f168a082dd2c4f9bfd8f33fa0700ad175a671093 | |
| parent | 1f1cd467c6afc8100a338e9b44bae8cebfa093f6 (diff) | |
| download | emacs-8184a815aff52cbf1f1b8680d80af2fbf2dce248.tar.gz emacs-8184a815aff52cbf1f1b8680d80af2fbf2dce248.zip | |
Add erc-button helper for substituting command keys
* lisp/erc/erc-button.el (erc-button-mode, erc-button-enable): Warn if
`erc-button-alist' contains deprecated FORM field in `nicknames'
entry.
(erc-button-alist): Discourage arbitrary sexp form for third item of
entries and offer more useful bounds-modifying function in its place.
Mention that anything other than `erc-button-buttonize-nicks' is
deprecated as the FORM field in a `nicknames' entry. Bump
package-version even though this doesn't introduce a visible change in
the default value.
(erc-button--maybe-warn-arbitrary-sexp): Add helper for validating
third `erc-button-alist' field.
(erc-button--check-nicknames-entry): Add helper to check for
deprecated items in `erc-button-alist'.
(erc-button--preserve-bounds): Add function to serve as default value
for `erc-button--modify-nick-function).
(erc-button--modify-nick-function): Add new variable to hold a
function that filters nickname bounds when buttonizing.
(erc-button--phantom-users, erc-button--add-phantom-speaker,
erc-button--phantom-users-mode): Add new internal minor mode for
treating unseen speakers of PRIVMSGs as known members of the server
for things like coloring nicks during buffer playback.
(erc-button--get-user-from-speaker-naive): Add temporary utility
function to scrape nick from speaker in narrowed buffer. This will be
replaced by an account-aware version in next major ERC release.
(erc-button-add-nickname-buttons): Accommodate function variant for
"form" field of `erc-button-alist' entries. Minor optimizations.
This function will likely become the primary juncture for applying
text properties that support nickname-related user-intelligence
features.
(erc-button-add-buttons-1): Show warning when arbitrary sexp for third
"form" field encountered. Accommodate binary function instead.
(erc-button--substitute-command-keys-in-region): Add helper function
for applying key substitutions in ERC warning messages.
(erc-button--display-error-notice-with-keys): Add new helper function
for displaying ad hoc warnings that possibly require key substitution.
(erc-button--display-error-notice-with-keys-and-warn): Add variant of
`erc-button--display-error-notice-with-keys' that also emits warnings.
* lisp/erc/erc-networks.el (erc-networks--ensure-announced,
erc-networks--on-MOTD-end): Use new key-substitutions helper from
erc-button.
* test/lisp/erc/erc-tests.el
(erc-button--display-error-notice-with-keys): New test.
* test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld: Add
unknown speaker in channel for phantom store to handle. Currently
requires manual intervention to leverage. (Bug#60933.)
| -rw-r--r-- | lisp/erc/erc-button.el | 208 | ||||
| -rw-r--r-- | lisp/erc/erc-networks.el | 20 | ||||
| -rw-r--r-- | test/lisp/erc/erc-tests.el | 61 | ||||
| -rw-r--r-- | test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld | 1 |
4 files changed, 270 insertions, 20 deletions
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 48f6a5d1794..33e69f3b0b8 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el | |||
| @@ -52,7 +52,8 @@ | |||
| 52 | ;;;###autoload(autoload 'erc-button-mode "erc-button" nil t) | 52 | ;;;###autoload(autoload 'erc-button-mode "erc-button" nil t) |
| 53 | (define-erc-module button nil | 53 | (define-erc-module button nil |
| 54 | "This mode buttonizes all messages according to `erc-button-alist'." | 54 | "This mode buttonizes all messages according to `erc-button-alist'." |
| 55 | ((add-hook 'erc-insert-modify-hook #'erc-button-add-buttons 'append) | 55 | ((erc-button--check-nicknames-entry) |
| 56 | (add-hook 'erc-insert-modify-hook #'erc-button-add-buttons 'append) | ||
| 56 | (add-hook 'erc-send-modify-hook #'erc-button-add-buttons 'append) | 57 | (add-hook 'erc-send-modify-hook #'erc-button-add-buttons 'append) |
| 57 | (add-hook 'erc-complete-functions #'erc-button-next-function) | 58 | (add-hook 'erc-complete-functions #'erc-button-next-function) |
| 58 | (erc--modify-local-map t "<backtab>" #'erc-button-previous)) | 59 | (erc--modify-local-map t "<backtab>" #'erc-button-previous)) |
| @@ -165,8 +166,17 @@ REGEXP is the string matching text around the button or a symbol | |||
| 165 | BUTTON is the number of the regexp grouping actually matching the | 166 | BUTTON is the number of the regexp grouping actually matching the |
| 166 | button. This is ignored if REGEXP is `nicknames'. | 167 | button. This is ignored if REGEXP is `nicknames'. |
| 167 | 168 | ||
| 168 | FORM is a Lisp expression which must eval to true for the button to | 169 | FORM is a Lisp symbol for a special variable whose value must be |
| 169 | be added. | 170 | true for the button to be added. Alternatively, when REGEXP is |
| 171 | not `nicknames', FORM can be a function whose arguments are BEG | ||
| 172 | and END, the bounds of the button in the current buffer. It's | ||
| 173 | expected to return a cons of (possibly identical) bounds or | ||
| 174 | nil, to deny. For the extent of the call, all face options | ||
| 175 | defined for the button module are re-bound, shadowing | ||
| 176 | themselves, so the function is free to change their values. | ||
| 177 | When regexp is the special symbol `nicknames', FORM must be the | ||
| 178 | symbol `erc-button-buttonize-nicks'. Specifying anything else | ||
| 179 | is deprecated. | ||
| 170 | 180 | ||
| 171 | CALLBACK is the function to call when the user push this button. | 181 | CALLBACK is the function to call when the user push this button. |
| 172 | CALLBACK can also be a symbol. Its variable value will be used | 182 | CALLBACK can also be a symbol. Its variable value will be used |
| @@ -176,7 +186,7 @@ PAR is a number of a regexp grouping whose text will be passed to | |||
| 176 | CALLBACK. There can be several PAR arguments. If REGEXP is | 186 | CALLBACK. There can be several PAR arguments. If REGEXP is |
| 177 | `nicknames', these are ignored, and CALLBACK will be called with | 187 | `nicknames', these are ignored, and CALLBACK will be called with |
| 178 | the nickname matched as the argument." | 188 | the nickname matched as the argument." |
| 179 | :package-version '(ERC . "5.5") | 189 | :package-version '(ERC . "5.6") ; FIXME sync on release |
| 180 | :type '(repeat | 190 | :type '(repeat |
| 181 | (list :tag "Button" | 191 | (list :tag "Button" |
| 182 | (choice :tag "Matches" | 192 | (choice :tag "Matches" |
| @@ -277,22 +287,127 @@ specified by `erc-button-alist'." | |||
| 277 | (concat "\\<" (regexp-quote (car elem)) "\\>") | 287 | (concat "\\<" (regexp-quote (car elem)) "\\>") |
| 278 | entry))))))))))) | 288 | entry))))))))))) |
| 279 | 289 | ||
| 290 | (defun erc-button--maybe-warn-arbitrary-sexp (form) | ||
| 291 | (if (and (symbolp form) (special-variable-p form)) | ||
| 292 | (symbol-value form) | ||
| 293 | (unless (get 'erc-button--maybe-warn-arbitrary-sexp 'warned-arbitrary-sexp) | ||
| 294 | (put 'erc-button--maybe-warn-arbitrary-sexp 'warned-arbitrary-sexp t) | ||
| 295 | (lwarn 'erc :warning | ||
| 296 | (concat "Arbitrary sexps for the third FORM" | ||
| 297 | " slot of `erc-button-alist' entries" | ||
| 298 | " have been deprecated."))) | ||
| 299 | (eval form t))) | ||
| 300 | |||
| 301 | (defun erc-button--check-nicknames-entry () | ||
| 302 | ;; This helper exists because the module is defined after its options. | ||
| 303 | (when-let (((eq major-mode 'erc-mode)) | ||
| 304 | (entry (alist-get 'nicknames erc-button-alist))) | ||
| 305 | (unless (eq 'erc-button-buttonize-nicks (nth 1 entry)) | ||
| 306 | (erc-button--display-error-notice-with-keys-and-warn | ||
| 307 | "Values other than `erc-button-buttonize-nicks' in the third slot of " | ||
| 308 | "the `nicknames' entry of `erc-button-alist' are deprecated.")))) | ||
| 309 | |||
| 310 | (defun erc-button--preserve-bounds (bounds _ server-user _) | ||
| 311 | "Return BOUNDS.\n\n(fn BOUNDS NICKNAME SERVER-USER CHANNEL-USER)" | ||
| 312 | (and server-user bounds)) | ||
| 313 | |||
| 314 | ;; This variable is intended to serve as a "core" to be wrapped by | ||
| 315 | ;; (built-in) modules during setup. It's unclear whether | ||
| 316 | ;; `add-function's practice of removing existing advice before | ||
| 317 | ;; re-adding it is desirable when integrating modules since we're | ||
| 318 | ;; mostly concerned with ensuring one "piece" precedes or follows | ||
| 319 | ;; another (specific piece), which may not yet (or ever) be present. | ||
| 320 | |||
| 321 | (defvar erc-button--modify-nick-function #'erc-button--preserve-bounds | ||
| 322 | "Function to possibly modify aspects of nick being buttonized. | ||
| 323 | Called with four args: BOUNDS NICKNAME SERVER-USER CHANNEL-USER. | ||
| 324 | BOUNDS is a cons of (BEG . END) marking the position of the nick | ||
| 325 | in the current message, which occupies the whole of the narrowed | ||
| 326 | buffer. BEG is normally also point. NICKNAME is a case-mapped | ||
| 327 | string without text properties. SERVER-USER and CHANNEL-USER are | ||
| 328 | the nick's `erc-server-users' entry and its associated (though | ||
| 329 | possibly nil) `erc-channel-user' object. The function should | ||
| 330 | return BOUNDS or a suitable replacement to indicate that | ||
| 331 | buttonizing ought to proceed, and nil if it should be inhibited.") | ||
| 332 | |||
| 333 | (defvar-local erc-button--phantom-users nil) | ||
| 334 | |||
| 335 | (defun erc-button--add-phantom-speaker (args) | ||
| 336 | "Maybe substitute fake `server-user' for speaker at point." | ||
| 337 | (pcase args | ||
| 338 | (`(,bounds ,downcased-nick nil ,channel-user) | ||
| 339 | (list bounds downcased-nick | ||
| 340 | ;; Like `with-memoization' but don't cache when value is nil. | ||
| 341 | (or (gethash downcased-nick erc-button--phantom-users) | ||
| 342 | (and-let* ((user (erc-button--get-user-from-speaker-naive | ||
| 343 | (car bounds)))) | ||
| 344 | (puthash downcased-nick user erc-button--phantom-users))) | ||
| 345 | channel-user)) | ||
| 346 | (_ args))) | ||
| 347 | |||
| 348 | (define-minor-mode erc-button--phantom-users-mode | ||
| 349 | "Minor mode to recognize unknown speakers. | ||
| 350 | Expect to be used by module setup code for creating placeholder | ||
| 351 | users on the fly during history playback. Treat an unknown | ||
| 352 | PRIVMSG speaker, like <bob>, as if they were present in a 353 and | ||
| 353 | are thus a member of the channel. However, don't bother creating | ||
| 354 | an actual `erc-channel-user' object because their status prefix | ||
| 355 | is unknown. Instead, just spoof an `erc-server-user' by applying | ||
| 356 | early (outer), args-filtering advice wrapping | ||
| 357 | `erc-button--modify-nick-function'." | ||
| 358 | :interactive nil | ||
| 359 | (if erc-button--phantom-users-mode | ||
| 360 | (progn | ||
| 361 | (add-function :filter-args (local 'erc-button--modify-nick-function) | ||
| 362 | #'erc-button--add-phantom-speaker '((depth . -90))) | ||
| 363 | (setq erc-button--phantom-users (make-hash-table :test #'equal))) | ||
| 364 | (remove-function (local 'erc-button--modify-nick-function) | ||
| 365 | #'erc-button--add-phantom-speaker) | ||
| 366 | (kill-local-variable 'erc-nicks--phantom-users))) | ||
| 367 | |||
| 368 | ;; FIXME replace this after making ERC account-aware. | ||
| 369 | (defun erc-button--get-user-from-speaker-naive (point) | ||
| 370 | "Return `erc-server-user' object for nick at POINT." | ||
| 371 | (when-let* | ||
| 372 | (((eql ?< (char-before point))) | ||
| 373 | ((eq (get-text-property point 'font-lock-face) 'erc-nick-default-face)) | ||
| 374 | (parsed (erc-get-parsed-vector point))) | ||
| 375 | (pcase-let* ((`(,nick ,login ,host) | ||
| 376 | (erc-parse-user (erc-response.sender parsed)))) | ||
| 377 | (make-erc-server-user | ||
| 378 | :nickname nick | ||
| 379 | :host (and (not (string-empty-p host)) host) | ||
| 380 | :login (and (not (string-empty-p login)) login))))) | ||
| 381 | |||
| 280 | (defun erc-button-add-nickname-buttons (entry) | 382 | (defun erc-button-add-nickname-buttons (entry) |
| 281 | "Search through the buffer for nicknames, and add buttons." | 383 | "Search through the buffer for nicknames, and add buttons." |
| 282 | (let ((form (nth 2 entry)) | 384 | (let ((form (nth 2 entry)) |
| 283 | (fun (nth 3 entry)) | 385 | (fun (nth 3 entry)) |
| 284 | bounds word) | 386 | bounds word) |
| 285 | (when (or (eq t form) | 387 | (when (eq form 'erc-button-buttonize-nicks) |
| 286 | (eval form t)) | 388 | (setq form (and (symbol-value form) erc-button--modify-nick-function))) |
| 389 | (when (or (functionp form) | ||
| 390 | (eq t form) | ||
| 391 | (and form (erc-button--maybe-warn-arbitrary-sexp form))) | ||
| 287 | (goto-char (point-min)) | 392 | (goto-char (point-min)) |
| 288 | (while (erc-forward-word) | 393 | (while (erc-forward-word) |
| 289 | (when (setq bounds (erc-bounds-of-word-at-point)) | 394 | (when (setq bounds (erc-bounds-of-word-at-point)) |
| 290 | (setq word (buffer-substring-no-properties | 395 | (setq word (buffer-substring-no-properties |
| 291 | (car bounds) (cdr bounds))) | 396 | (car bounds) (cdr bounds))) |
| 292 | (when (or (and (erc-server-buffer-p) (erc-get-server-user word)) | 397 | (let* ((erc-button-face erc-button-face) |
| 293 | (and erc-channel-users (erc-get-channel-user word))) | 398 | (erc-button-mouse-face erc-button-mouse-face) |
| 294 | (erc-button-add-button (car bounds) (cdr bounds) | 399 | (erc-button-nickname-face erc-button-nickname-face) |
| 295 | fun t (list word)))))))) | 400 | (down (erc-downcase word)) |
| 401 | (cuser (and erc-channel-users | ||
| 402 | (gethash down erc-channel-users))) | ||
| 403 | (user (or (and cuser (car cuser)) | ||
| 404 | (and erc-server-users | ||
| 405 | (gethash down erc-server-users))))) | ||
| 406 | (when (or (not (functionp form)) | ||
| 407 | (setq bounds | ||
| 408 | (funcall form bounds down user (cdr cuser)))) | ||
| 409 | (erc-button-add-button (car bounds) (cdr bounds) | ||
| 410 | fun t (list word))))))))) | ||
| 296 | 411 | ||
| 297 | (defun erc-button-add-buttons-1 (regexp entry) | 412 | (defun erc-button-add-buttons-1 (regexp entry) |
| 298 | "Search through the buffer for matches to ENTRY and add buttons." | 413 | "Search through the buffer for matches to ENTRY and add buttons." |
| @@ -304,7 +419,14 @@ specified by `erc-button-alist'." | |||
| 304 | (fun (nth 3 entry)) | 419 | (fun (nth 3 entry)) |
| 305 | (data (mapcar #'match-string-no-properties (nthcdr 4 entry)))) | 420 | (data (mapcar #'match-string-no-properties (nthcdr 4 entry)))) |
| 306 | (when (or (eq t form) | 421 | (when (or (eq t form) |
| 307 | (eval form t)) | 422 | (and (functionp form) |
| 423 | (let* ((erc-button-face erc-button-face) | ||
| 424 | (erc-button-mouse-face erc-button-mouse-face) | ||
| 425 | (erc-button-nickname-face erc-button-nickname-face) | ||
| 426 | (rv (funcall form start end))) | ||
| 427 | (when rv | ||
| 428 | (setq end (cdr rv) start (car rv))))) | ||
| 429 | (erc-button--maybe-warn-arbitrary-sexp form)) | ||
| 308 | (erc-button-add-button start end fun nil data regexp))))) | 430 | (erc-button-add-button start end fun nil data regexp))))) |
| 309 | 431 | ||
| 310 | (defun erc-button-remove-old-buttons () | 432 | (defun erc-button-remove-old-buttons () |
| @@ -513,6 +635,70 @@ and `apropos' for other symbols." | |||
| 513 | (message "@%s is %d:%02d local time" | 635 | (message "@%s is %d:%02d local time" |
| 514 | beats hours minutes))) | 636 | beats hours minutes))) |
| 515 | 637 | ||
| 638 | (defun erc-button--substitute-command-keys-in-region (beg end) | ||
| 639 | "Replace command in region with keys and return new bounds" | ||
| 640 | (let* ((o (buffer-substring beg end)) | ||
| 641 | (s (substitute-command-keys o))) | ||
| 642 | (unless (equal o s) | ||
| 643 | (setq erc-button-face nil)) | ||
| 644 | (delete-region beg end) | ||
| 645 | (insert s)) | ||
| 646 | (cons beg (point))) | ||
| 647 | |||
| 648 | ;;;###autoload | ||
| 649 | (defun erc-button--display-error-notice-with-keys (&optional parsed buffer | ||
| 650 | &rest strings) | ||
| 651 | "Add help keys to STRINGS for configuration-related admonishments. | ||
| 652 | Return inserted result. Expect PARSED to be an `erc-response' | ||
| 653 | object, a string, or nil. Expect BUFFER to be a buffer, a string, | ||
| 654 | or nil. As a special case, allow PARSED to be a buffer as long | ||
| 655 | as BUFFER is a string or nil. If STRINGS contains any trailing | ||
| 656 | non-strings, concatenate leading string members before applying | ||
| 657 | `format'. Otherwise, just concatenate everything." | ||
| 658 | (when (stringp buffer) | ||
| 659 | (push buffer strings) | ||
| 660 | (setq buffer nil)) | ||
| 661 | (when (stringp parsed) | ||
| 662 | (push parsed strings) | ||
| 663 | (setq parsed nil)) | ||
| 664 | (when (bufferp parsed) | ||
| 665 | (cl-assert (null buffer)) | ||
| 666 | (setq buffer parsed | ||
| 667 | parsed nil)) | ||
| 668 | (let* ((op (if (seq-every-p #'stringp (cdr strings)) | ||
| 669 | #'concat | ||
| 670 | (let ((head (pop strings))) | ||
| 671 | (while (stringp (car strings)) | ||
| 672 | (setq head (concat head (pop strings)))) | ||
| 673 | (push head strings)) | ||
| 674 | #'format)) | ||
| 675 | (string (apply op strings)) | ||
| 676 | (erc-insert-post-hook | ||
| 677 | (cons (lambda () | ||
| 678 | (setq string (buffer-substring (point-min) | ||
| 679 | (1- (point-max))))) | ||
| 680 | erc-insert-post-hook)) | ||
| 681 | (erc-button-alist | ||
| 682 | `((,(rx "\\[" (group (+ (not "]"))) "]") 0 | ||
| 683 | erc-button--substitute-command-keys-in-region | ||
| 684 | erc-button-describe-symbol 1) | ||
| 685 | ,@erc-button-alist))) | ||
| 686 | (erc-display-message parsed '(notice error) (or buffer 'active) string) | ||
| 687 | string)) | ||
| 688 | |||
| 689 | ;;;###autoload | ||
| 690 | (defun erc-button--display-error-notice-with-keys-and-warn (&rest args) | ||
| 691 | "Like `erc-button--display-error-notice-with-keys' but also warn." | ||
| 692 | (let ((string (apply #'erc-button--display-error-notice-with-keys args))) | ||
| 693 | (with-temp-buffer | ||
| 694 | (insert string) | ||
| 695 | (goto-char (point-min)) | ||
| 696 | (with-syntax-table lisp-mode-syntax-table | ||
| 697 | (skip-syntax-forward "^-")) | ||
| 698 | (forward-char) | ||
| 699 | (display-warning | ||
| 700 | 'erc (buffer-substring-no-properties (point) (point-max)))))) | ||
| 701 | |||
| 516 | (provide 'erc-button) | 702 | (provide 'erc-button) |
| 517 | 703 | ||
| 518 | ;;; erc-button.el ends here | 704 | ;;; erc-button.el ends here |
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 4337d633cfa..dd481032e7e 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el | |||
| @@ -67,6 +67,9 @@ | |||
| 67 | (declare-function erc-server-process-alive "erc-backend" (&optional buffer)) | 67 | (declare-function erc-server-process-alive "erc-backend" (&optional buffer)) |
| 68 | (declare-function erc-set-active-buffer "erc" (buffer)) | 68 | (declare-function erc-set-active-buffer "erc" (buffer)) |
| 69 | 69 | ||
| 70 | (declare-function erc-button--display-error-notice-with-keys | ||
| 71 | (parsed &rest strings)) | ||
| 72 | |||
| 70 | ;; Variables | 73 | ;; Variables |
| 71 | 74 | ||
| 72 | (defgroup erc-networks nil | 75 | (defgroup erc-networks nil |
| @@ -1310,12 +1313,11 @@ shutting down the connection." | |||
| 1310 | Copy source (prefix) from MOTD-ish message as a last resort." | 1313 | Copy source (prefix) from MOTD-ish message as a last resort." |
| 1311 | ;; The 004 handler never ran; see 2004-03-10 Diane Murray in change log | 1314 | ;; The 004 handler never ran; see 2004-03-10 Diane Murray in change log |
| 1312 | (unless erc-server-announced-name | 1315 | (unless erc-server-announced-name |
| 1313 | (setq erc-server-announced-name (erc-response.sender parsed)) | 1316 | (require 'erc-button) |
| 1314 | (erc-display-error-notice | 1317 | (erc-button--display-error-notice-with-keys |
| 1315 | parsed (concat "Failed to determine server name. Using \"" | 1318 | parsed "Failed to determine server name. Using \"" |
| 1316 | erc-server-announced-name "\" instead." | 1319 | (setq erc-server-announced-name (erc-response.sender parsed)) "\" instead" |
| 1317 | " If this was unexpected, consider reporting it via " | 1320 | ". If this was unexpected, consider reporting it via \\[erc-bug]" ".")) |
| 1318 | (substitute-command-keys "\\[erc-bug]") "."))) | ||
| 1319 | nil) | 1321 | nil) |
| 1320 | 1322 | ||
| 1321 | (defun erc-unset-network-name (_nick _ip _reason) | 1323 | (defun erc-unset-network-name (_nick _ip _reason) |
| @@ -1493,9 +1495,9 @@ to be a false alarm. If `erc-reuse-buffers' is nil, let | |||
| 1493 | (memq (erc--target-symbol erc--target) | 1495 | (memq (erc--target-symbol erc--target) |
| 1494 | erc-networks--bouncer-targets))) | 1496 | erc-networks--bouncer-targets))) |
| 1495 | proc) | 1497 | proc) |
| 1496 | (let ((m (concat "Unexpected state detected. Please report via " | 1498 | (require 'erc-button) |
| 1497 | (substitute-command-keys "\\[erc-bug]") "."))) | 1499 | (erc-button--display-error-notice-with-keys |
| 1498 | (erc-display-error-notice parsed m)))) | 1500 | parsed "Unexpected state detected. Please report via \\[erc-bug]."))) |
| 1499 | 1501 | ||
| 1500 | ;; For now, retain compatibility with erc-server-NNN-functions. | 1502 | ;; For now, retain compatibility with erc-server-NNN-functions. |
| 1501 | (or (erc-networks--ensure-announced proc parsed) | 1503 | (or (erc-networks--ensure-announced proc parsed) |
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 6e66de53edd..b155f85ab8a 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el | |||
| @@ -1790,4 +1790,65 @@ connection." | |||
| 1790 | (put 'erc-mname-enable 'definition-name 'mname) | 1790 | (put 'erc-mname-enable 'definition-name 'mname) |
| 1791 | (put 'erc-mname-disable 'definition-name 'mname)))))) | 1791 | (put 'erc-mname-disable 'definition-name 'mname)))))) |
| 1792 | 1792 | ||
| 1793 | |||
| 1794 | ;; XXX move erc-button tests to new file if more added. | ||
| 1795 | (require 'erc-button) | ||
| 1796 | |||
| 1797 | ;; See also `erc-scenarios-networks-announced-missing' in | ||
| 1798 | ;; erc-scenarios-misc.el for a more realistic example. | ||
| 1799 | (ert-deftest erc-button--display-error-notice-with-keys () | ||
| 1800 | (with-current-buffer (get-buffer-create "*fake*") | ||
| 1801 | (let ((mode erc-button-mode) | ||
| 1802 | (inhibit-message noninteractive) | ||
| 1803 | erc-modules | ||
| 1804 | erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook) | ||
| 1805 | (erc-mode) | ||
| 1806 | (erc-tests--set-fake-server-process "sleep" "1") | ||
| 1807 | (erc--initialize-markers (point) nil) | ||
| 1808 | (erc-button-mode +1) | ||
| 1809 | (should (equal (erc-button--display-error-notice-with-keys | ||
| 1810 | "If \\[erc-bol] fails, " | ||
| 1811 | "see \\[erc-bug] or `erc-mode-map'.") | ||
| 1812 | "*** If C-a fails, see M-x erc-bug or `erc-mode-map'.")) | ||
| 1813 | (goto-char (point-min)) | ||
| 1814 | |||
| 1815 | (ert-info ("Keymap substitution succeeds") | ||
| 1816 | (erc-button-next) | ||
| 1817 | (should (looking-at "C-a")) | ||
| 1818 | (should (eq (get-text-property (point) 'mouse-face) 'highlight)) | ||
| 1819 | (erc-button-press-button) | ||
| 1820 | (with-current-buffer "*Help*" | ||
| 1821 | (goto-char (point-min)) | ||
| 1822 | (should (search-forward "erc-bol" nil t))) | ||
| 1823 | (erc-button-next) | ||
| 1824 | (erc-button-previous) ; end of interval correct | ||
| 1825 | (should (looking-at "a fails"))) | ||
| 1826 | |||
| 1827 | (ert-info ("Extended command mapping succeeds") | ||
| 1828 | (erc-button-next) | ||
| 1829 | (should (looking-at "M-x erc-bug")) | ||
| 1830 | (erc-button-press-button) | ||
| 1831 | (should (eq (get-text-property (point) 'mouse-face) 'highlight)) | ||
| 1832 | (with-current-buffer "*Help*" | ||
| 1833 | (goto-char (point-min)) | ||
| 1834 | (should (search-forward "erc-bug" nil t)))) | ||
| 1835 | |||
| 1836 | (ert-info ("Symbol-description face preserved") ; mutated by d-e-n-w-k | ||
| 1837 | (erc-button-next) | ||
| 1838 | (should (equal (get-text-property (point) 'font-lock-face) | ||
| 1839 | '(erc-button erc-error-face))) | ||
| 1840 | (should (eq (get-text-property (point) 'mouse-face) 'highlight)) | ||
| 1841 | (should (eq erc-button-face 'erc-button))) ; extent evaporates | ||
| 1842 | |||
| 1843 | (ert-info ("Format when trailing args include non-strings") | ||
| 1844 | (should (equal (erc-button--display-error-notice-with-keys | ||
| 1845 | "abc" " %d def" " 45%s" 123 '\6) | ||
| 1846 | "*** abc 123 def 456"))) | ||
| 1847 | |||
| 1848 | (when noninteractive | ||
| 1849 | (unless mode | ||
| 1850 | (erc-button-mode -1)) | ||
| 1851 | (kill-buffer "*Help*") | ||
| 1852 | (kill-buffer))))) | ||
| 1853 | |||
| 1793 | ;;; erc-tests.el ends here | 1854 | ;;; erc-tests.el ends here |
diff --git a/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld index 58df79e19fa..f34ae02f4e4 100644 --- a/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld +++ b/test/lisp/erc/resources/base/assoc/bouncer-history/foonet.eld | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the lovers, full of joy and mirth.") | 27 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:02] alice: Here come the lovers, full of joy and mirth.") |
| 28 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to the fool's bolt, sir, and such dulcet diseases.") | 28 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:07] bob: According to the fool's bolt, sir, and such dulcet diseases.") |
| 29 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang himself. I pray you, do my greeting.") | 29 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:10] alice: And hang himself. I pray you, do my greeting.") |
| 30 | (0 ":someone!~u@abcdefg.irc PRIVMSG #chan :[07:04:10] hi everyone.") | ||
| 30 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat smiling at his cruel prey.") | 31 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:18] bob: And you sat smiling at his cruel prey.") |
| 31 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after look me in the face.") | 32 | (0 ":bob!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:21] alice: Or never after look me in the face.") |
| 32 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may be, than all is well. Come, sit down, every mother's son, and rehearse your parts. Pyramus, you begin: when you have spoken your speech, enter into that brake; and so every one according to his cue.") | 33 | (0 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :[07:04:25] bob: If that may be, than all is well. Come, sit down, every mother's son, and rehearse your parts. Pyramus, you begin: when you have spoken your speech, enter into that brake; and so every one according to his cue.") |