2016-12-06 10 views
2

Как использовать cl-letf или аналогично переопределять значение функции символа во время асинхронного вызова? Я хочу остановить отображение буфера после вызовов на start-process или start-process-shell-command, а вместо этого вместо этого вернет строку.Значение функции переопределения с асинхронным вызовом

Вот упрощенный пример, где привязка display-buffer работает для синхронной версии, но не для асинхронной версии. Кроме того, я установил лексическое привязку к true.

(defun tst-fun-sync (url) 
    (call-process "wget" nil "*wget*" nil url "-O" "-") 
    (with-current-buffer "*wget*" 
    (display-buffer (current-buffer)))) 

(defun tst-fun-async (url) 
    (set-process-sentinel 
    (start-process "wget" "*wget*" "wget" url "-O" "-") 
    #'(lambda (p _m) 
     (when (zerop (process-exit-status p)) 
     (with-current-buffer (process-buffer p) 
      (display-buffer (current-buffer))))))) 

(defun tst-fun-no-display (fun &rest args) 
    (cl-letf (((symbol-function 'display-buffer) 
      #'(lambda (&rest _ignored) 
       (message "%s" (buffer-string))))) 
    (apply fun args))) 

;; The first has desired result, but not the second 
;; (tst-fun-no-display 'tst-fun-sync "http://www.stackoverflow.com") 
;; (tst-fun-no-display 'tst-fun-async "http://www.stackoverflow.com") 
+1

Как насчет использования 'shell-command-to-string'? Например, '(replace-regexp-in-string" \ n "" "(shell-command-to-string" date "))' Нет необходимости отображать буфер для работы с ним, т. Е. Нет нужно использовать «display-buffer» в вашем примере, который я вижу. – lawlist

+0

Вы также можете быть заинтересованы в фильтрах процессов, которые могут захватывать весь вывод процесса в виде строк. https://www.gnu.org/software/emacs/manual/html_node/elisp/Filter-Functions.html – lawlist

ответ

2

Давайте определим макрос, который временно set-process-sentinel связывания все так, что функция сторожевой может быть украшена с функцией обертки.

(defmacro with-sentinel-wrapper (wrapper-fn &rest body) 
    (let ((sps (gensym)) 
     (proc (gensym)) 
     (fn (gensym))) 
    `(let ((,sps (symbol-function 'set-process-sentinel))) 
     (cl-letf (((symbol-function 'set-process-sentinel) 
        (lambda (,proc ,fn) 
        (funcall ,sps ,proc (funcall ,wrapper-fn ,fn))))) 
       ,@body)))) 

Обертка может изменить динамический контекст, в котором сторожевого называется, путем создания каких-либо полезных динамических привязок. Здесь я повторно ваш cl-letf, чтобы изменить то, что дисплей делает:

(with-sentinel-wrapper (lambda (fn) 
         (lexical-let ((fun fn)) 
          (lambda (p m) 
          (cl-letf (((symbol-function 'display-buffer) 
             #'(lambda (&rest _ignored) 
              (message "%s" (buffer-string))))) 
           (funcall fun p m))))) 
    (tst-fun-async "http://www.stackoverflow.com")) 

Теперь, если вы не уверены в том, что асинхронный процесс фактически вызывает set-process-sentinel, вы, возможно, придется взломать другие функции.

+0

спасибо, но это похоже на тот же результат, что и моя попытка - не влияя на версию async. Я думаю, что это не сработает, так как разматывать формы тела до того, как асинхронный вызов заканчивается – jenesaisquoi

+0

@jenesaisquoi Спасибо, я понимаю. Я изменил свой ответ. Не идеально, но он работает. – coredump

+0

Огромное спасибо! Итак, я полагаю, что лексическая среда отбрасывается где-то в обычном вызове set-process-sentinel? Хотел бы я лучше понять это. Я попытался изначально взломать дозорного, но не мог заставить это работать. К счастью, функции Im targeting используют set-process-sentinel, поэтому ths отлично – jenesaisquoi

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

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