2010-08-04 5 views
1

Я хочу написать функцию, которая вызовет список функций в emacs (в частности, kill-buffer-query-functions), но если кто-то из них требует взаимодействия с пользователем, я хочу, чтобы они просто вернули nil, так что все это будет работать без -interactively. Я думаю использовать defadvice для изменения каждой функции, которая обычно запрашивает у пользователя вместо throw исключение со значением nil. Затем я буду обернуть все форму catch. Единственная проблема заключается в том, что у меня нет исчерпывающего списка всех функций emacs elisp, которые могли бы спросить пользователя о чем-то.Как поймать все вызовы функций elisp, требующие взаимодействия с пользователем?

У кого-нибудь есть такой список, или есть более простой способ сделать это? В качестве примеров функции yes-or-no-p и y-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 

В принципе, я обернуть все в водосборный блоке, то я определить функцию органа, который будет просто принимать какие-либо аргументы и бросить соответствующий исключение. Я установил список переопределений для передачи flet, который временно переопределит эти функции для использования вышеупомянутого тела исключения. Наконец, я оцениваю form с этими временными переопределениями функций.

Теперь, вероятно, в этом коде есть некоторые ошибки цитирования, но я думаю, что это сработает, если у меня будет только соответствующий список функций для переопределения.

Обратите внимание, что я хочу, чтобы вся форма возвращалась, если требуется какое-либо взаимодействие с пользователем, а не только конкретный вызов функции в форме, требующей взаимодействия с пользователем. Чтобы узнать, зачем мне это нужно, подумайте, что в этой форме могут возникнуть вопросы:

  • Вы хотите удалить этот очень важный файл? да или нет
  • Вы хотите сохранить этот очень важный файл? да или нет

Очевидно, что если бы я только изменил yes-or-no-p не всегда возвращать nil (что означает «нет»), что до сих пор не гарантировано, чтобы сохранить свой важный файл от удаления. Поэтому, поскольку я не знаю, какие вопросы могут быть заданы, я хочу, чтобы вся форма просто прерывалась и возвращала определенное значение, если она хочет спросить что-либо о пользователе.

По сути, я хочу сказать «Оцените этот код, но если вам нужно что-то спросить, просто забудьте об этом и верните nil».

ответ

0

Я просто наткнулся на возможный ответ на это:

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

(Минибуфер-с-установки крюка FUN & остальное ТЕЛА)

Добавить FUN в `minibuffer-setup-hook ' во время выполнения BODY. 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

Это, кажется, отлично работает. Может ли кто-нибудь подумать о разумном способе запроса пользователя, который не включает ни минибуфер, ни диалоговое окно? –

0

Я думаю, вы можете просто использовать «commandp», чтобы определить, является ли конкретная функция интерактивной.

Так просто запустить (remove-if 'commandp kill-buffer-query-functions)

+0

Несколько проблем с этим. Сначала не все функции, обозначенные как '(интерактивные)', фактически требуют ввода пользователя. Во-вторых, я не просто хочу поймать интерактивные функции в 'kill-buffer-query-functions', я хочу поймать любой вызов функции, требующей ввода пользователем в любом месте стека вызовов, при оценке каждого из« kill-buffer » -query-functions'. Я уточню свой ответ, чтобы прояснить это. –

 Смежные вопросы

  • Нет связанных вопросов^_^