diff options
author | F. Jason Park <jp@neverwas.me> | 2023-04-10 17:58:05 -0700 |
---|---|---|
committer | F. Jason Park <jp@neverwas.me> | 2023-05-05 17:18:01 -0700 |
commit | 2e18ba6302f3e4aa5485eeaca39c747beb55ca8f (patch) | |
tree | e8d2172243a5e3f03d70f11e428a893fbbaf5687 /lisp/erc/erc-button.el | |
parent | 2641dfd4b4334942282358b50d74f75424ebf4fa (diff) | |
download | emacs-2e18ba6302f3e4aa5485eeaca39c747beb55ca8f.tar.gz emacs-2e18ba6302f3e4aa5485eeaca39c747beb55ca8f.tar.bz2 emacs-2e18ba6302f3e4aa5485eeaca39c747beb55ca8f.zip |
Simplify erc-button movement commands
* etc/ERC-NEWS: Mention TAB being bound to new command `erc-tab' and
`erc-previous-button' now stopping at the start of buttons.
* lisp/erc/erc-button.el (erc-button-mode, erc-button-enable,
erc-button-disable): Add and remove `erc-button-next' to
`erc--tab-functions' hook, which is tantamount to binding the command
in the read-only area of an ERC buffer.
(erc-button-next-function): Deprecate and remove from client code path
because this module doesn't concern itself with prompt input and thus
no longer needs to conform to the `completion-at-point-functions'
interface.
(erc-button--prev-next-predicate-functions): New variable, a hook to
determine whether to continue searching for a button. Other modules
should utilize this as needed.
(erc-button--end-of-button-p): Add function to serve as default value
for `erc-button--continue-predicate'.
(erc--button-next): Add generalized button-movement function.
(erc-button-next, erc-button-previous): Make `erc-button-previous'
behave more predictably by having it land at the beginning of buttons.
And remove roundabout appeal to HOF in `erc-button-next'.
(erc-button-previous-of-nick): New command to jump to previous
appearance of nick at point.
* lisp/erc/erc-fill.el (erc-fill-wrap, erc-fill-wrap-enable,
erc-fill-wrap-disable): Add and remove merge-related hookee from
`erc-button--prev-next-predicate-functions'.
(erc-fill--wrap-merged-button-p): New function to detect redundant
speakers.
* lisp/erc/erc.el (erc-complete-functions): Quote TAB in doc string.
(erc-mode-map): Bind `erc-tab' to TAB.
(erc--tab-functions, erc-tab): Add new command and hook to serve as
unified dispatch for TAB-related operations. It calls `c-a-p' in the
input area and defers to module code in the read-only message area.
* test/lisp/erc/erc-button-tests.el: New file.
* test/lisp/erc/erc-fill-tests.el (erc-fill-tests--wrap-populate): Run
finalizer for transient keymap timer.
* test/lisp/erc/erc-tests.el
(erc-button--display-error-notice-with-keys): Move to new dedicated
test file for erc-button and fix expected behavior of
`erc-button-previous'. (Bug#62834)
Diffstat (limited to 'lisp/erc/erc-button.el')
-rw-r--r-- | lisp/erc/erc-button.el | 93 |
1 files changed, 70 insertions, 23 deletions
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 33e69f3b0b8..e2447deecde 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -55,11 +55,11 @@ ((erc-button--check-nicknames-entry) (add-hook 'erc-insert-modify-hook #'erc-button-add-buttons 'append) (add-hook 'erc-send-modify-hook #'erc-button-add-buttons 'append) - (add-hook 'erc-complete-functions #'erc-button-next-function) + (add-hook 'erc--tab-functions #'erc-button-next) (erc--modify-local-map t "<backtab>" #'erc-button-previous)) ((remove-hook 'erc-insert-modify-hook #'erc-button-add-buttons) (remove-hook 'erc-send-modify-hook #'erc-button-add-buttons) - (remove-hook 'erc-complete-functions #'erc-button-next-function) + (remove-hook 'erc--tab-functions #'erc-button-next) (erc--modify-local-map nil "<backtab>" #'erc-button-previous))) ;;; Variables @@ -529,6 +529,7 @@ call it with the value of the `erc-data' text property." (defun erc-button-next-function () "Pseudo completion function that actually jumps to the next button. For use on `completion-at-point-functions'." + (declare (obsolete erc-nickserv-identify "30.1")) ;; FIXME: This is an abuse of completion-at-point-functions. (when (< (point) (erc-beg-of-input-line)) (let ((start (point))) @@ -546,27 +547,73 @@ For use on `completion-at-point-functions'." (error "No next button")) t))))) -(defun erc-button-next () - "Go to the next button in this buffer." - (interactive) - (let ((f (erc-button-next-function))) - (if f (funcall f)))) - -(defun erc-button-previous () - "Go to the previous button in this buffer." - (interactive) - (let ((here (point))) - (when (< here (erc-beg-of-input-line)) - (while (and (get-text-property here 'erc-callback) - (not (= here (point-min)))) - (setq here (1- here))) - (while (and (not (get-text-property here 'erc-callback)) - (not (= here (point-min)))) - (setq here (1- here))) - (if (> here (point-min)) - (goto-char here) - (error "No previous button")) - t))) +(defvar erc-button--prev-next-predicate-functions + '(erc-button--end-of-button-p) + "Abnormal hook whose members can return non-nil to continue searching. +Otherwise, if all members return nil, point will stay at the +current button. Called with a single arg, a buffer position +greater than `point-min' with a text property of `erc-callback'.") + +(defun erc-button--end-of-button-p (point) + (get-text-property (1- point) 'erc-callback)) + +(defun erc--button-next (arg) + (let* ((nextp (prog1 (>= arg 1) (setq arg (max 1 (abs arg))))) + (search-fn (if nextp + #'next-single-char-property-change + #'previous-single-char-property-change)) + (start (point)) + (p start)) + (while (progn + ;; Break out of current search context. + (when-let ((low (max (point-min) (1- (pos-bol)))) + (high (min (point-max) (1+ (pos-eol)))) + (prop (get-text-property p 'erc-callback)) + (q (if nextp + (text-property-not-all p high + 'erc-callback prop) + (funcall search-fn p 'erc-callback nil low))) + ((< low q high))) + (setq p q)) + ;; Assume that buttons occur frequently enough that + ;; omitting LIMIT is acceptable. + (while + (and (setq p (funcall search-fn p 'erc-callback)) + (if nextp (< p erc-insert-marker) (/= p (point-min))) + (run-hook-with-args-until-success + 'erc-button--prev-next-predicate-functions p))) + (and arg + (< (point-min) p erc-insert-marker) + (goto-char p) + (not (zerop (cl-decf arg)))))) + (when (= (point) start) + (user-error (if nextp "No next button" "No previous button"))) + t)) + +(defun erc-button-next (&optional arg) + "Go to the ARGth next button." + (declare (advertised-calling-convention (arg) "30.1")) + (interactive "p") + (setq arg (pcase arg ((pred listp) (prefix-numeric-value arg)) (_ arg))) + (erc--button-next arg)) + +(defun erc-button-previous (&optional arg) + "Go to ARGth previous button." + (declare (advertised-calling-convention (arg) "30.1")) + (interactive "p") + (setq arg (pcase arg ((pred listp) (prefix-numeric-value arg)) (_ arg))) + (erc--button-next (- arg))) + +(defun erc-button-previous-of-nick (arg) + "Go to ARGth previous button for nick at point." + (interactive "p") + (if-let* ((prop (get-text-property (point) 'erc-data)) + (erc-button--prev-next-predicate-functions + (cons (lambda (p) + (not (equal (get-text-property p 'erc-data) prop))) + erc-button--prev-next-predicate-functions))) + (erc--button-next (- arg)) + (user-error "No nick at point"))) (defun erc-browse-emacswiki (thing) "Browse to THING in the emacs-wiki." |