2010-08-04 63 views
1

我想寫一個函數,它會調用emacs中的函數列表(具體來說,是kill-buffer-query-functions),但是如果它們中的任何一個需要用戶交互,我希望它們只是簡單地返回nil,以便整個事物將運行非-interactively。我正在考慮使用defadvice來修改每個通常會提示用戶輸入throw的函數,該函數的值爲nil。然後,我會用catch表單包裝所有內容。唯一的問題是,我沒有列出所有emacs elisp函數的詳盡列表,這些列表可能會提示用戶提供某些東西。如何捕獲所有需要用戶交互的elisp函數調用?

有沒有人有這樣的清單,或者是否有更簡單的方法來解決這個問題?作爲示例,功能yes-or-no-py-or-n-p肯定會在此列表中,read-stringcompleting-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或no

顯然,如果我只是修改yes-or-no-p總是返回nil(意爲「無」),仍然不能保證被刪除保存我的重要文件。因此,由於我不知道可能會問什麼問題,因此如果想要詢問用戶的任何內容,我想讓整個表單簡單地中止並返回一個特定的值。基本上,我想說的是「評估這段代碼,但是如果你必須要問我什麼才能這樣做,那就把它忘掉吧,然後返回nil」。

回答

0

我只是偶然發現了一個可能的答案是:

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

(小緩衝區與 - 設置掛機FUN &休息 BODY)

在執行BODY時將FUN添加到`minibuffer-setup-hook' 。 BODY最多隻能使用 微型緩衝器一次。遞歸 使用的小緩衝區將不會受到 的影響。

因此,利用這一點,如果我想評價BODY但中止並返回nil如果BODY嘗試使用迷你緩衝區,也許我可以用這個:

(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)) 
+0

這似乎很好。任何人都可以想到任何合理的提示用戶的方式,不涉及minibuffer或對話框? – 2010-08-05 15:52:31

0

我想你可以使用「commandp」來判斷一個特定的函數是否是交互式的。

所以只需運行(remove-if 'commandp kill-buffer-query-functions)

+0

有一些問題。首先,並非所有標記爲「(交互式)」的功能都需要用戶輸入。其次,我不只是想在'kill-buffer-query-functions'中捕捉交互函數,我想要在調用堆棧中的任何位置時,捕獲任何需要用戶輸入的函數調用,同時評估每個kill-buffer -query-functions'。我會更新我的答案來澄清這一點。 – 2010-08-04 17:40:09

相關問題