Emacs 中有用于命令的 `flet` 吗?
Is there a `flet` for commands in Emacs?
我想动态地将一个命令重定向到另一个命令
某些函数使用周围的建议,像这样:
(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)
然而,这给出了一个错误(wrong-type-argument commandp f1)
,
表明当 flet
重新定义 f1
函数时,它没有
处理交互式表单并将其视为命令,因此它不能
被 call-interactively
.
调用
是否有 flet
的变体以这种方式适用于命令?
(这里是我真正想要做的重新定义:)
(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))
(编辑:cl-letf
宏可以在现代 emacs 中本地执行此操作。下面的答案可能对旧版本仍然有用。)
嗯,如果以前没有,现在有:
(require 'cl)
(require 'cl-lib)
(defmacro command-let (bindings &rest body)
"Like `flet', but works for interactive commands.
In addition to the standard `(FUNC ARGLIST BODY...)' syntax from
`flet', this also supports `(FUNC NEW-FUNC)' as a shorthand for
remapping command FUNC to another command NEW-FUNC, like this:
(defun FUNC (&rest ignored)
(interactive)
(call-interactively NEW-FUNC))
\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
(declare (indent 1))
(cl-loop for binding in bindings
collect (list (car binding) nil) into empty-bindings
collect (if (symbolp (cadr binding))
;; Remap one command to another
`(defun ,(car binding) (&rest args)
(interactive)
(call-interactively ',(cadr binding)))
;; Define command on the fly
(cons 'defun binding))
into defun-forms
finally return
`(flet (,@empty-bindings)
,@defun-forms
,@body)))
在行动:
(defadvice myfunc (around f1-to-f2 activate)
(command-let ((f1 f2))
ad-do-it))
(myfunc)
该代码现在根据需要使用 call-interactively
调用 f2
命令。
您在 flet 中遇到了一个愚蠢的错误:flet 的宏扩展将具有:(lambda (&rest args) (progn (interactive) (call-interactively 'f2)))
。注意那里添加的虚假 progn
,"hides" interactive
.
要获得更多控制(同时避免 cl.el),您可以:
(defadvice myfunc (around f1-to-f2 activate)
(cl-letf (((symbol-function 'f1)
(lambda (&rest args)
(interactive) (call-interactively 'f2))))
ad-do-it))
我想动态地将一个命令重定向到另一个命令 某些函数使用周围的建议,像这样:
(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)
然而,这给出了一个错误(wrong-type-argument commandp f1)
,
表明当 flet
重新定义 f1
函数时,它没有
处理交互式表单并将其视为命令,因此它不能
被 call-interactively
.
是否有 flet
的变体以这种方式适用于命令?
(这里是我真正想要做的重新定义:)
(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))
(编辑:cl-letf
宏可以在现代 emacs 中本地执行此操作。下面的答案可能对旧版本仍然有用。)
嗯,如果以前没有,现在有:
(require 'cl)
(require 'cl-lib)
(defmacro command-let (bindings &rest body)
"Like `flet', but works for interactive commands.
In addition to the standard `(FUNC ARGLIST BODY...)' syntax from
`flet', this also supports `(FUNC NEW-FUNC)' as a shorthand for
remapping command FUNC to another command NEW-FUNC, like this:
(defun FUNC (&rest ignored)
(interactive)
(call-interactively NEW-FUNC))
\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
(declare (indent 1))
(cl-loop for binding in bindings
collect (list (car binding) nil) into empty-bindings
collect (if (symbolp (cadr binding))
;; Remap one command to another
`(defun ,(car binding) (&rest args)
(interactive)
(call-interactively ',(cadr binding)))
;; Define command on the fly
(cons 'defun binding))
into defun-forms
finally return
`(flet (,@empty-bindings)
,@defun-forms
,@body)))
在行动:
(defadvice myfunc (around f1-to-f2 activate)
(command-let ((f1 f2))
ad-do-it))
(myfunc)
该代码现在根据需要使用 call-interactively
调用 f2
命令。
您在 flet 中遇到了一个愚蠢的错误:flet 的宏扩展将具有:(lambda (&rest args) (progn (interactive) (call-interactively 'f2)))
。注意那里添加的虚假 progn
,"hides" interactive
.
要获得更多控制(同时避免 cl.el),您可以:
(defadvice myfunc (around f1-to-f2 activate)
(cl-letf (((symbol-function 'f1)
(lambda (&rest args)
(interactive) (call-interactively 'f2))))
ad-do-it))