First, here is the full source code of my package.
Requirement
Currently I'm working on a package that provides a feature which upon the user invoking several times in a row certain command in a short amount of time, an alternative command is invoke instead. The assumption is made on the basis that the user has forgotten that the alternative command exist and that it is better/more efficient to achieve what he wants to achieve than the command he is using now.
Example use case
many invocations of next-line
or previous-line
through its bindings (either , C-n or , C-p), instead of letting the user keep invoking those two commands many more times, my package comes in and calls avy-goto-line
(because that's how the user previously configured it to work).
The problem
I want to force the user to comply with whatever input a command request, right now if the user fall asleep on any binding for next-line
, the alternative command goto-line
never executes, or at least that's how it looks. If the alternative command were avy-goto-line
it will throw an wrong-type-argument
rendering my feature useless for next invocations if I don't ignore-errors
.
I tried something like this:
(let* ((exit nil))
(while (not exit)
(setf exit (ignore-errors (avy-goto-line)))))
And it works, it does what I want to achieve. But for functions like goto-line
or even avy-goto-word-0
Emacs gets freeze and the mini-buffer never popups asking something to the user.
the code
Here is the relevant parts of my code:
(setf schrute-shortcuts-commands '((goto-char (left-char right-char))
(goto-line (next-line previous-line))))
(defun schrute--run-command ()
"Helper that will run an alternative-command."
(let* ((alternative-command)
(command-list))
(dolist (elem schrute-shortcuts-commands)
(setf alternative-command (car elem))
(setf command-list (cadr elem))
(when (or (member this-command command-list)
(eq this-command command-list))
(funcall-interactively alternative-command)))))
(defun schrute-check-last-command ()
"Check what command was used last time.
It also check the time between the last two invocations of the
same command and use the alternative command instead."
(when (eq this-command last-command)
(if (member this-command schrute--interesting-commands)
(let* ((time-passed (float-time (time-subtract (current-time) schrute--time-last-command))))
(if (<= time-passed 1.0)
(setf schrute--times-last-command (1+ schrute--times-last-command)))
(setf schrute--time-last-command (current-time)))))
(when (> schrute--times-last-command 2)
(setf schrute--times-last-command 0)
;; Call the alternative command for `this-command'
(ignore-errors (schrute--run-command))))
schrute-shortcuts-commands
.