2016-12-06 57 views
2

如何在異步調用期間使用cl-letf或類似函數覆蓋符號的函數值?我想在呼叫start-processstart-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

謝謝,但這似乎與我的嘗試有相同的結果 - 對異步版本沒有影響。我認爲它不會工作,因爲在異步調用完成之前放鬆身體保護不會起作用 – jenesaisquoi

+0

@jenesaisquoi謝謝,我現在明白了。我改變了我的答案。不完美,但它的工作原理。 – coredump

+0

真棒謝謝!所以我猜這個詞彙環境在普通的設置過程 - 定點調用中被拋出了某個地方?我希望我能更好地理解。我曾嘗試黑客哨兵,但無法讓它工作。幸運的是,我的定位功能使用set-process-sentinel,所以這是完美的 – jenesaisquoi