>From e218aaef38f6dc0f9affa516aafa18b77c2a3a1e Mon Sep 17 00:00:00 2001 From: Frederick Giasson Date: Wed, 6 Apr 2016 12:19:11 -0400 Subject: [PATCH 4/4] Adding a new feature :async feature to org-babel-clojure. With this new feature, someone can evaluate Clojure code in Org-mode code blocks asynchronously. --- lisp/ob-clojure.el | 78 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/lisp/ob-clojure.el b/lisp/ob-clojure.el index 86f1cff..6059d7d 100644 --- a/lisp/ob-clojure.el +++ b/lisp/ob-clojure.el @@ -91,35 +91,79 @@ body))) (defun org-babel-execute:clojure (body params) - "Execute a block of Clojure code with Babel." + "Execute a block of Clojure code with Babel. The block can be executed + synchenously by default or asynchronously with the :async parameter" (let ((expanded (org-babel-expand-body:clojure body params)) + (sbuffer "*Clojure Sub Buffer*") + (async (if (assoc :async params) t nil)) + (response (cons 'dict nil)) + status result) (case org-babel-clojure-backend (cider (require 'cider) (let ((result-params (cdr (assoc :result-params params)))) - (setq result - (nrepl-dict-get - (let ((nrepl-sync-request-timeout org-babel-clojure-sync-nrepl-timeout)) - (nrepl-sync-request:eval - expanded (cider-current-connection) (cider-current-session))) - (if (or (member "output" result-params) - (member "pp" result-params)) - "out" - "value"))))) + ; Check if the user want to run code asynchronously + (when async + ; Create a new window with the async output buffer + (switch-to-buffer-other-window sbuffer) + + ; Run the Clojure code asynchronously in nREPL + (nrepl-request:eval + expanded + (lambda (resp) + (when (member "out" resp) + ; Print the output of the nREPL in the asyn output buffer + (princ (nrepl-dict-get resp "out") (get-buffer sbuffer))) + (nrepl--merge response resp) + ; Update the status of the nREPL output session + (setq status (nrepl-dict-get response "status"))) + (cider-current-connection) + (cider-current-session)) + + ; Wait until the nREPL code finished to be processed + (while (not (member "done" status)) + (nrepl-dict-put response "status" (remove "need-input" status)) + (accept-process-output nil 0.01) + (redisplay)) + + ; Delete the async buffer & window when the processing is finalized + (let ((wins (get-buffer-window-list sbuffer nil t))) + (dolist (win wins) + (delete-window win)) + (kill-buffer sbuffer)) + + ; Put the output or the value in the result section of the code block + (setq result (nrepl-dict-get response + (if (or (member "output" result-params) + (member "pp" result-params)) + "out" + "value")))) + ; Check if user want to run code synchronously + (when (not async) + (setq result + (nrepl-dict-get + (let ((nrepl-sync-request-timeout + org-babel-clojure-sync-nrepl-timeout)) + (nrepl-sync-request:eval + expanded (cider-current-connection) (cider-current-session))) + (if (or (member "output" result-params) + (member "pp" result-params)) + "out" + "value")))))) (slime (require 'slime) (with-temp-buffer - (insert expanded) - (setq result - (slime-eval - `(swank:eval-and-grab-output - ,(buffer-substring-no-properties (point-min) (point-max))) - (cdr (assoc :package params))))))) + (insert expanded) + (setq result + (slime-eval + `(swank:eval-and-grab-output + ,(buffer-substring-no-properties (point-min) (point-max))) + (cdr (assoc :package params))))))) (org-babel-result-cond (cdr (assoc :result-params params)) result (condition-case nil (org-babel-script-escape result) - (error result))))) + (error result))))) (provide 'ob-clojure) -- 1.9.5.msysgit.0