如何捕获所有需要用户交互的 elisp 函数调用?
我想编写一个函数来调用 emacs 中的函数列表(具体来说,kill-buffer-query-functions
),但如果其中任何一个需要用户交互,我想让它们简单地返回相反,nil
,这样整个过程将以非交互方式运行。我正在考虑使用 defadvice 来修改通常会提示用户抛出
值为 nil
的异常的每个函数。然后我将用 catch
表单包装所有内容。唯一的麻烦是,我没有可能提示用户输入某些内容的所有 emacs elisp 函数的详尽列表。
有谁有这样的列表,或者有更简单的方法吗?例如,函数 yes-or-no-p
和 y-or-np
肯定会出现在这个列表中,read-string
也会出现在这个列表中> 和完成读取
。
基本上,我想填写此代码中的省略号:
(defun eval-but-return-if-requires-user (form &optional interactive-return)
"Evaluate FORM, but immediately stop and return INTERACTIVE-RETURN if any part of FORM would require user interaction."
;; Set up the safety net
(catch 'ui-required
(let ((ui-requiring-functions '( ... )) ; What goes in this list?
(ui-required-callback
;; A function that takes any number of args and throws an exception
'(lambda (&rest args)
(throw 'ui-required interactive-return)))
(flet-redefinitions
;; Use the above callback to create a list of redefinitions for `flet'
(mapcar (lambda (func)
(cons func (cdr ui-required-callback)))
ui-requiring-functions)))
`(flet
,flet-redefinitions ; Perform the function redefinitions,
,form)))) ; Then evaluate FORM
基本上,我将所有内容包装在 catch 块中,然后定义一个函数体,该函数体将简单地接受任何参数并抛出适当的异常。我设置了一个要传递给 flet
的重定义列表,它将临时重新定义这些函数以使用前面提到的异常抛出主体。最后,我使用这些临时函数重新定义来评估 form
。
现在,该代码中可能存在一些引用错误,但我认为如果我有要重新定义的函数的适当列表,它就会起作用。
请注意,如果需要任何用户交互,我希望返回整个表单,而不仅仅是表单中需要用户交互的特定函数调用。要了解为什么我需要这个,请考虑该表单可能想要询问以下任一问题:
- 您想删除这个非常重要的文件吗?是或否
- 您想保留这个非常重要的文件吗?是或否
显然,如果我只是修改了 yes-or-no-p 来始终返回 nil (这意味着“否”),仍然不能保证保存我的重要文件免遭删除。因此,由于我不知道可能会问什么问题,所以如果它想询问用户任何问题,我想让整个表单简单地中止并返回特定值。
本质上,我想说“评估这段代码,但如果你必须问我任何问题才能这样做,那就忘记它并返回 nil 。”
I want to write a function that will call a list of functions in emacs (specifically, kill-buffer-query-functions
), but if any of them require user interaction, I want to have them simply return nil
instead, so that the whole thing will run non-interactively. I am thinking of using defadvice
to modify every function that would normally prompts the user to instead throw
an exception with a value of nil
. Then I will wrap everything with a catch
form. The only trouble is, I don't have an exhaustive list of all emacs elisp functions that might prompt the user for something.
Does anyone have such a list, or is there an easier way to go about this? As examples, the functions yes-or-no-p
and y-or-n-p
would certainly be on this list, as would read-string
and completing-read
.
Basically, I want to fill in the ellipsis in this code:
(defun eval-but-return-if-requires-user (form &optional interactive-return)
"Evaluate FORM, but immediately stop and return INTERACTIVE-RETURN if any part of FORM would require user interaction."
;; Set up the safety net
(catch 'ui-required
(let ((ui-requiring-functions '( ... )) ; What goes in this list?
(ui-required-callback
;; A function that takes any number of args and throws an exception
'(lambda (&rest args)
(throw 'ui-required interactive-return)))
(flet-redefinitions
;; Use the above callback to create a list of redefinitions for `flet'
(mapcar (lambda (func)
(cons func (cdr ui-required-callback)))
ui-requiring-functions)))
`(flet
,flet-redefinitions ; Perform the function redefinitions,
,form)))) ; Then evaluate FORM
Basically, I wrap everything in a catch block, then I define a function body that will simply take any arguments and throw an appropriate exception. I set up a list of redefinitions to be passed to flet
, which will temporarily redefine those functions to use the aforementioned exception-throwing body. Finally, I evaluate form
with those temporary function redefinitions in place.
Now, there's probably some quoting errors in that code, but I think that it would work if I just had the appropriate list of which functions to redefine.
Note that I want the entire form to return if any user interaction is required, not just the particular function call within the form that required user interaction. To see why I need this, consider that the form could possibly want to ask either of the following questions:
- Do you want to delete this very important file? yes or no
- Do you want to keep this very important file? yes or no
Obviously, if I just modified yes-or-no-p
to always return nil
(which means "no"), that still isn't guaranteed to save my important file from deletion. So, since I don't know what questions might be asked, I want to cause the entire form to simply abort and return a specific value if it wants to ask anything of the user.
Essentially, I want to say "Evaluate this code, but if you have to ask me anything in order to do so, just forget about it and return nil
."
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为你可以使用“commandp”来判断特定功能是否是交互式的。
所以只需运行
(remove-if 'commandp Kill-buffer-query-functions)
I think you can just use "commandp" to tell whether a particular function is interactive.
So just run
(remove-if 'commandp kill-buffer-query-functions)
我刚刚偶然发现了一个可能的答案:
Mx describe-function minibuffer-with-setup-hook
因此,使用它,如果我想评估
BODY
但如果BODY
尝试使用迷你缓冲区,则中止并返回nil
,也许我可以使用这个:稍后我会测试一下。
后来的事了,我已经测试过了。效果很好。这是我的最终代码:
I just stumbled upon a possible answer to this:
M-x describe-function minibuffer-with-setup-hook
So, using that, if I wanted to evaluate
BODY
but abort and returnnil
ifBODY
tries to use the minibuffer, maybe I could use this:I will test this out later.
It's later, and I've tested this out. It works great. Here's my final code for this: