1

我想编写一个函数来调用 emacs 中的函数列表(特别是,kill-buffer-query-functions),但是如果它们中的任何一个需要用户交互,我想让它们简单地返回nil,这样整个事情就会以非交互方式运行。我正在考虑使用defadvice来修改通常会提示用户 throw使用值为nil. 然后我将用catch表格包装所有内容。唯一的麻烦是,我没有一份详尽的列表,列出所有可能提示用户输入某些内容的 emacs elisp 函数。

有没有人有这样的清单,或者有没有更简单的方法来解决这个问题?例如,函数yes-or-no-py-or-n-p肯定会在这个列表中,就像read-string和一样completing-read

基本上,我想在这段代码中填写省略号:

(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。”

4

2 回答 2

0

我认为您可以只使用“commandp”来判断特定功能是否是交互式的。

所以只要运行(remove-if 'commandp kill-buffer-query-functions)

于 2010-08-04T04:34:58.870 回答
0

我只是偶然发现了一个可能的答案:

M-x describe-function minibuffer-with-setup-hook

(minibuffer-with-setup-hook FUN &rest BODY)

在执行 BODY 时将 FUN 添加到 `minibuffer-setup-hook'。BODY 最多应该使用一次 minibuffer。minibuffer 的递归使用不会受到影响。

因此,使用它,如果我想评估但如果尝试使用 minibuffer则BODY中止并返回,也许我可以使用它:nilBODY

(catch 'tried-to-use-minibuffer
  (minibuffer-with-setup-hook 
      (lambda (&rest args) (throw 'tried-to-use-minibuffer nil))
    BODY))

我稍后会对此进行测试。


稍后,我已经对此进行了测试。它工作得很好。这是我的最终代码:

(defmacro without-minibuffer (&rest body)
  "Like `progn', but stop and return nil if any of BODY forms tries to use the minibuffer.

Also disable dialogs while evaluating BODY forms, since dialogs
are just an alternative to the minibuffer."
  `(catch 'tried-to-use-minibuffer
     (minibuffer-with-setup-hook
         (lambda (&rest args) (throw 'tried-to-use-minibuffer nil))
       (let ((use-dialog-box))          ; No cheating by using dialogs instead of minibuffer
         ,@body))))

;; This should be indented like progn
(put 'without-minibuffer 'lisp-indent-function (get 'progn 'lisp-indent-function))
于 2010-08-05T03:59:07.797 回答