I want to dynamically redirect one command to another one within a certain function using around advice, something like this:
(defun f1 (arg)
(interactive (list (read-from-minibuffer "F1: ")))
(message "f1: %S" arg)
arg)
(defun f2 (arg)
(interactive (list (read-from-minibuffer "F2: ")))
(message "f2: %S" arg)
arg)
;; Function that invokes the f1 command
(defun myfunc ()
(call-interactively 'f1))
;; I want myfunc to invoke f2 instead whenever it would invoke f1
(defadvice myfunc (around f1-to-f2 activate)
(flet ((f1 (&rest args) (interactive) (call-interactively 'f2)))
ad-do-it))
(myfunc)
However, this gives an error (wrong-type-argument commandp f1)
,
indicating that when flet
redefined the f1
function, it didn't
process the interactive form and treat it like a command, so it can't
be invoked by call-interactively
.
Is there a variant of flet
that will work for commands in this way?
(Here are the actual redefinitions I want to do:)
(defadvice org-metaleft (around osx-command activate)
(flet ((backward-word (&rest args)
(interactive)
(call-interactively #'move-beginning-of-line)))
ad-do-it))
(defadvice org-metaright (around osx-command activate)
(flet ((forward-word (&rest args)
(interactive)
(call-interactively #'move-end-of-line)))
ad-do-it))
You're bumping into a silly bug in flet: the macroexpansion of flet will have: (lambda (&rest args) (progn (interactive) (call-interactively 'f2)))
. Notice the spurious progn
added in there, which "hides" the interactive
.
To get more control (and avoid cl.el at the same time), you can do:
(defadvice myfunc (around f1-to-f2 activate)
(cl-letf (((symbol-function 'f1)
(lambda (&rest args)
(interactive) (call-interactively 'f2))))
ad-do-it))