From mboxrd@z Thu Jan 1 00:00:00 1970 From: stardiviner Subject: [PATCH] ob-clojure and ob-clojure-literate support :ns header argument [V1] Date: Tue, 27 Mar 2018 11:02:03 +0800 Message-ID: <80a3c661-f0f1-ccd6-94ef-13b59f4da637@gmail.com> References: <4d7d38a2-4a7b-c22a-3d5c-fc05a99aabb8@gmail.com> <7ab04864-666d-b84b-b9ea-6a26868f5cdd@gmail.com> <2e8bf589-83e4-4b95-0df5-874c92c18d28@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------0196EB47A0A4B4A320EA0679" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:60554) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1f0esH-0006Mh-AH for emacs-orgmode@gnu.org; Mon, 26 Mar 2018 23:02:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1f0esE-0003VO-3N for emacs-orgmode@gnu.org; Mon, 26 Mar 2018 23:02:13 -0400 Received: from mail-pl0-x22e.google.com ([2607:f8b0:400e:c01::22e]:35790) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1f0esD-0003Uh-Is for emacs-orgmode@gnu.org; Mon, 26 Mar 2018 23:02:10 -0400 Received: by mail-pl0-x22e.google.com with SMTP id p9-v6so13246382pls.2 for ; Mon, 26 Mar 2018 20:02:09 -0700 (PDT) In-Reply-To: <2e8bf589-83e4-4b95-0df5-874c92c18d28@gmail.com> Content-Language: en-US List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: org-mode Cc: Nicolas Goaziou This is a multi-part message in MIME format. --------------0196EB47A0A4B4A320EA0679 Content-Type: multipart/alternative; boundary="------------6D249B791C3BDFE2B71CFCF5" --------------6D249B791C3BDFE2B71CFCF5 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit This should be this finalize version patch. The whole discussion is here: https://github.com/clojure-emacs/clojure-mode/pull/465 After test many case (all passed): ```org #+begin_src clojure :results pp ;; (def greeting "hi there!") *ns* #+end_src #+RESULTS[<2018-03-26 14:43:51> 2d1907bb790168e9429b9b07b4409d08ac8ca274]: : #namespace[user] Test internal ns in body. # TODO: this has a weird behavior, the result changes, sometimes is #'kk.test/he, second time will be #'user/he - [X] confirmed org-babel-expand-body:clojure is fine - [X] check org-babel-execute:clojure #+begin_src clojure :results pp (ns kk.test) (def he "hi") #+end_src #+RESULTS[<2018-03-26 12:52:06> fb9ad1efe68a43d880e53205f1326c000d1522d3]: : #'kk.test/he Deeper testing: #+begin_src emacs-lisp :results pp (nrepl-sync-request:eval  "(clojure.pprint/pprint (do (ns user)\n (ns kk.test)\n (def he 2)))"  (cider-current-connection)  "user"  ) #+end_src #+RESULTS[<2018-03-26 19:26:24> 36ac1cb6a3df8b20edb0bf11c1247399bc041390]: : (dict "status" :       ("done" "state") :       "id" "362" "out" "#'user/he\n" "session" "5ba759a7-a80a-4b02-a934-a0d7686ee211" "ns" "kk.test" "value" "nil" "changed-namespaces" :       (dict) :       "repl-type" "clj") #+begin_src clojure :results value :ns kk2 (def he "hi") *ns* #+end_src #+RESULTS[<2018-03-26 13:43:22> 0bfbd971f26d1f097d19dc0e3230decc31cc9e6e]: : nil#'kk2/he#namespace[kk2] What about another src block without ~:ns~ specified after previous specified src block? #+begin_src clojure :results value (def he "hi") *ns* #+end_src #+RESULTS[<2018-03-26 12:53:27> 6c547cacff4e65305cc9f855117ca43ffd9d2eab]: : nil#'user/he#namespace[user] More complex example: #+begin_src clojure :results output :var he="hi" :ns kk ;; (def he "hi") (prn he) (prn *ns*) #+end_src #+RESULTS: : "hi" : #namespace[kk] ``` On 03/26/2018 12:38 PM, stardiviner wrote: > Previous `ob-clojure.el` patch implement method is not good enough. > Here is a better implementation. > Sorry for this over posting. > > > On 03/26/2018 09:59 AM, stardiviner wrote: >> >> - support :ns header (as discussed at here >> https://github.com/clojure-emacs/clojure-mode/pull/465#discussion_r158009538) >> >> - supoort inject CIDER outside of project >> >> - support :varinitialization when :session initialization prepare. >> >> >> On 03/22/2018 01:49 AM, stardiviner wrote: >>> >>> Two patches >>> >>> One is to support ob-clojure.el future coming header argument :ns. >>> >>> The second is to support jack-in CIDER outside of Clojure project by >>> default. Not no need to ob-clojure project to be created anymore. >>> >> > --------------6D249B791C3BDFE2B71CFCF5 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: 8bit

This should be this finalize version patch.

The whole discussion is here: https://github.com/clojure-emacs/clojure-mode/pull/465

After test many case (all passed):

```org

#+begin_src clojure :results pp
;; (def greeting "hi there!")
*ns*
#+end_src

#+RESULTS[<2018-03-26 14:43:51> 2d1907bb790168e9429b9b07b4409d08ac8ca274]:
: #namespace[user]

Test internal ns in body.
# TODO: this has a weird behavior, the result changes, sometimes is #'kk.test/he, second time will be #'user/he
- [X] confirmed org-babel-expand-body:clojure is fine
- [X] check org-babel-execute:clojure

#+begin_src clojure :results pp
(ns kk.test)
(def he "hi")
#+end_src

#+RESULTS[<2018-03-26 12:52:06> fb9ad1efe68a43d880e53205f1326c000d1522d3]:
: #'kk.test/he

Deeper testing:

#+begin_src emacs-lisp :results pp
(nrepl-sync-request:eval
 "(clojure.pprint/pprint (do (ns user)\n (ns kk.test)\n (def he 2)))"
 (cider-current-connection)
 "user"
 )
#+end_src

#+RESULTS[<2018-03-26 19:26:24> 36ac1cb6a3df8b20edb0bf11c1247399bc041390]:
: (dict "status"
:       ("done" "state")
:       "id" "362" "out" "#'user/he\n" "session" "5ba759a7-a80a-4b02-a934-a0d7686ee211" "ns" "kk.test" "value" "nil" "changed-namespaces"
:       (dict)
:       "repl-type" "clj")

#+begin_src clojure :results value :ns kk2
(def he "hi")
*ns*
#+end_src

#+RESULTS[<2018-03-26 13:43:22> 0bfbd971f26d1f097d19dc0e3230decc31cc9e6e]:
: nil#'kk2/he#namespace[kk2]

What about another src block without ~:ns~ specified after previous specified src block?

#+begin_src clojure :results value
(def he "hi")
*ns*
#+end_src

#+RESULTS[<2018-03-26 12:53:27> 6c547cacff4e65305cc9f855117ca43ffd9d2eab]:
: nil#'user/he#namespace[user]

More complex example:

#+begin_src clojure :results output :var he="hi" :ns kk
;; (def he "hi")
(prn he)
(prn *ns*)
#+end_src

#+RESULTS:
: "hi"
: #namespace[kk]

```


On 03/26/2018 12:38 PM, stardiviner wrote:
Previous `ob-clojure.el` patch implement method is not good enough. Here is a better implementation.
Sorry for this over posting.


On 03/26/2018 09:59 AM, stardiviner wrote:

- support :ns header (as discussed at here https://github.com/clojure-emacs/clojure-mode/pull/465#discussion_r158009538)

- supoort inject CIDER outside of project

- support :var initialization when :session initialization prepare.


On 03/22/2018 01:49 AM, stardiviner wrote:

Two patches

One is to support ob-clojure.el future coming header argument :ns.

The second is to support jack-in CIDER outside of Clojure project by default. Not no need to ob-clojure project to be created anymore.




--------------6D249B791C3BDFE2B71CFCF5-- --------------0196EB47A0A4B4A320EA0679 Content-Type: text/x-patch; name="0001-ob-clojure-literate.el-CIDER-jack-in-outside-of-proj.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-ob-clojure-literate.el-CIDER-jack-in-outside-of-proj.pa"; filename*1="tch" >From bc575705704ebff7f7630cd35ff936844c89f66a Mon Sep 17 00:00:00 2001 From: stardiviner Date: Thu, 22 Mar 2018 01:21:22 +0800 Subject: [PATCH 1/4] * ob-clojure-literate.el: CIDER jack-in outside of project by default. --- contrib/lisp/ob-clojure-literate.el | 50 ++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/contrib/lisp/ob-clojure-literate.el b/contrib/lisp/ob-clojure-literate.el index a7ab1894d..8d419b0b4 100644 --- a/contrib/lisp/ob-clojure-literate.el +++ b/contrib/lisp/ob-clojure-literate.el @@ -35,8 +35,10 @@ Don't auto jack in by default for not rude." :type 'boolean :group 'ob-clojure-literate) -(defcustom ob-clojure-literate-project-location (concat user-emacs-directory "Org-mode/") - "The location for `ob-clojure-literate' scaffold project." +(defcustom ob-clojure-literate-project-location nil + "The location for `ob-clojure-literate' scaffold project. +If it is nil, then `cider-jack-in' will jack-in outside of Clojure project. +If it is a directory, `ob-clojure-literate' will try to create Clojure project automatically." :type 'string :group 'ob-clojure-literate) @@ -45,7 +47,7 @@ Don't auto jack in by default for not rude." (defvar ob-clojure-literate-session-ns nil) (defvar ob-clojure-literate-cider-connections nil) -(defcustom ob-clojure-literate-default-session "*cider-repl ob-clojure*" +(defcustom ob-clojure-literate-default-session "*cider-repl localhost*" "The default session name for `ob-clojure-literate'." :type 'string :group 'ob-clojure-literate) @@ -104,23 +106,31 @@ Don't auto jack in by default for not rude." (defun ob-clojure-literate-auto-jackin () "Auto setup ob-clojure-literate scaffold and jack-in Clojure project." (interactive) - (unless (file-directory-p (expand-file-name ob-clojure-literate-project-location)) - (make-directory ob-clojure-literate-project-location t) - (let ((default-directory ob-clojure-literate-project-location)) - (shell-command "lein new ob-clojure"))) - (unless (or - (and (cider-connected-p) - (if (not (null ob-clojure-literate-session)) - (seq-contains cider-connections (get-buffer ob-clojure-literate-session)))) - cider-connections - (not (null ob-clojure-literate-session))) - ;; return back to original file. - (if (not (and (= (length (ob-clojure-literate-get-session-list)) 1) - (-contains-p (ob-clojure-literate-get-session-list) ob-clojure-literate-default-session))) - (save-window-excursion - (find-file (expand-file-name (concat ob-clojure-literate-project-location "ob-clojure/src/ob_clojure/core.clj"))) - (with-current-buffer "core.clj" - (cider-jack-in)))))) + (cond + ;; jack-in outside of Clojure project. + ((null ob-clojure-literate-project-location) + (if (member (get-buffer "*cider-repl localhost*") cider-connections) + (message "CIDER default session already launched.") + (cider-jack-in nil))) + ((not (null ob-clojure-literate-project-location)) + (unless (file-directory-p (expand-file-name ob-clojure-literate-project-location)) + (make-directory ob-clojure-literate-project-location t) + (let ((default-directory ob-clojure-literate-project-location)) + (shell-command "lein new ob-clojure"))) + (unless (or + (and (cider-connected-p) + (if (not (null ob-clojure-literate-session)) + (seq-contains cider-connections (get-buffer ob-clojure-literate-session)))) + cider-connections + (not (null ob-clojure-literate-session))) + ;; return back to original file. + (if (not (and (= (length (ob-clojure-literate-get-session-list)) 1) + (-contains-p (ob-clojure-literate-get-session-list) ob-clojure-literate-default-session))) + (save-window-excursion + (find-file (expand-file-name (concat ob-clojure-literate-project-location "ob-clojure/src/ob_clojure/core.clj"))) + (with-current-buffer "core.clj" + (cider-jack-in)))))) + )) (defun ob-clojure-literate-set-local-cider-connections (toggle?) "Set buffer local `cider-connections' for `ob-clojure-literate-mode' `TOGGLE?'." -- 2.16.3 --------------0196EB47A0A4B4A320EA0679 Content-Type: text/x-patch; name="0002-ob-clojure-literate.el-support-use-ns-header-argumen.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0002-ob-clojure-literate.el-support-use-ns-header-argumen.pa"; filename*1="tch" >From 25e75ded1466b413a0d098041ad40f52e1707432 Mon Sep 17 00:00:00 2001 From: stardiviner Date: Thu, 22 Mar 2018 01:43:18 +0800 Subject: [PATCH 2/4] * ob-clojure-literate.el: support use :ns header argument. - rename ob-clojure-literate-cider-do-not-find-ns to ob-clojure-literate-set-ns --- contrib/lisp/ob-clojure-literate.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/contrib/lisp/ob-clojure-literate.el b/contrib/lisp/ob-clojure-literate.el index 8d419b0b4..71ea909ba 100644 --- a/contrib/lisp/ob-clojure-literate.el +++ b/contrib/lisp/ob-clojure-literate.el @@ -151,14 +151,15 @@ If it is a directory, `ob-clojure-literate' will try to create Clojure project a ;; (setq-local cider-connections '()) )) -(defun ob-clojure-literate-cider-do-not-find-ns (body params) +(defun ob-clojure-literate-set-ns (body params) "Fix the issue that `cider-current-ns' try to invoke `clojure-find-ns' to extract ns from buffer." ;; TODO: Is it possible to find ns in `body'? (when (ob-clojure-literate-any-connection-p) (setq ob-clojure-literate-original-ns (cider-current-ns)) (with-current-buffer ob-clojure-literate-session (setq ob-clojure-literate-session-ns cider-buffer-ns)) - (setq-local cider-buffer-ns ob-clojure-literate-session-ns)) + (setq-local cider-buffer-ns (or (cdr (assq :ns params)) + ob-clojure-literate-session-ns))) (message (format "ob-clojure-literate: current CIDER ns is [%s]." cider-buffer-ns))) (defun ob-clojure-literate-set-local-session (toggle?) @@ -302,7 +303,7 @@ reset `RESULT' to `nil'." (equal major-mode 'org-mode)) ; `ob-clojure-literate-mode' only works in `org-mode'. (ob-clojure-literate-set-local-cider-connections ob-clojure-literate-mode) (ob-clojure-literate-set-local-session ob-clojure-literate-mode) - (advice-add 'org-babel-execute:clojure :before #'ob-clojure-literate-cider-do-not-find-ns) + (advice-add 'org-babel-execute:clojure :before #'ob-clojure-literate-set-ns) (advice-add 'org-babel-expand-body:clojure :filter-args #'ob-clojure-literate-inject-code) (advice-add 'org-babel-execute:clojure :filter-return #'ob-clojure-literate-support-graphics-result) (message "ob-clojure-literate minor mode enabled."))) @@ -310,7 +311,7 @@ reset `RESULT' to `nil'." ;;;###autoload (defun ob-clojure-literate-disable () "Disable Org-mode buffer locally for `ob-clojure-literate'." - (advice-remove 'org-babel-execute:clojure #'ob-clojure-literate-cider-do-not-find-ns) + (advice-remove 'org-babel-execute:clojure #'ob-clojure-literate-set-ns) (advice-remove 'org-babel-expand-body:clojure #'ob-clojure-literate-inject-code) (advice-remove 'org-babel-execute:clojure #'ob-clojure-literate-support-graphics-result) (setq-local cider-buffer-ns ob-clojure-literate-original-ns) -- 2.16.3 --------------0196EB47A0A4B4A320EA0679 Content-Type: text/x-patch; name="0003-ob-clojure-literate.el-support-vars-initialization-w.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0003-ob-clojure-literate.el-support-vars-initialization-w.pa"; filename*1="tch" >From fc8a9082712704f70eabe60c6c612600f16e58d1 Mon Sep 17 00:00:00 2001 From: stardiviner Date: Mon, 26 Mar 2018 09:47:54 +0800 Subject: [PATCH 3/4] * ob-clojure-literate.el: support vars initialization when prepare session. - org-babel-clojure-var-to-clojure --- contrib/lisp/ob-clojure-literate.el | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contrib/lisp/ob-clojure-literate.el b/contrib/lisp/ob-clojure-literate.el index 71ea909ba..2d1d30db8 100644 --- a/contrib/lisp/ob-clojure-literate.el +++ b/contrib/lisp/ob-clojure-literate.el @@ -221,7 +221,14 @@ If it is a directory, `ob-clojure-literate' will try to create Clojure project a (defun org-babel-clojure-var-to-clojure (var) "Convert src block's `VAR' to Clojure variable." - ;; TODO: reference `org-babel-python-var-to-python' + (if (listp var) + (replace-regexp-in-string "(" "'(" var) + (cond + ((stringp var) + ;; wrap org-babel passed in header argument value with quote in Clojure. + (format "\"%s\"" var)) + (t + (format "%s" var)))) ) (defun org-babel-variable-assignments:clojure (params) @@ -230,8 +237,7 @@ If it is a directory, `ob-clojure-literate' will try to create Clojure project a (lambda (pair) (format "(def %s %s)" (car pair) - ;; (org-babel-clojure-var-to-clojure (cdr pair)) - (cdr pair))) + (org-babel-clojure-var-to-clojure (cdr pair)))) (org-babel--get-vars params))) ;;; Support header arguments :results graphics :file "image.png" by inject Clojure code. -- 2.16.3 --------------0196EB47A0A4B4A320EA0679 Content-Type: text/x-patch; name="0004-ob-clojure.el-org-babel-execute-clojure-support-ns-h.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0004-ob-clojure.el-org-babel-execute-clojure-support-ns-h.pa"; filename*1="tch" >From 71c57149ca0975f13f66bc22ad540fd442cb4798 Mon Sep 17 00:00:00 2001 From: Bastien Date: Mon, 26 Mar 2018 11:35:21 +0800 Subject: [PATCH 4/4] * ob-clojure.el (org-babel-execute:clojure) support :ns header argument. Remove optional parameter (cider-current-ns) to better handling namespace. --- lisp/ob-clojure.el | 54 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/lisp/ob-clojure.el b/lisp/ob-clojure.el index 890f60ada..35b4c3fe5 100644 --- a/lisp/ob-clojure.el +++ b/lisp/ob-clojure.el @@ -41,6 +41,7 @@ ;;; Code: (require 'cl-lib) (require 'ob) +(require 'subr-x) (declare-function cider-current-connection "ext:cider-client" (&optional type)) (declare-function cider-current-ns "ext:cider-client" ()) @@ -55,6 +56,7 @@ (declare-function slime-eval "ext:slime" (sexp &optional package)) (defvar nrepl-sync-request-timeout) +(defvar cider-buffer-ns) (defvar org-babel-tangle-lang-exts) (add-to-list 'org-babel-tangle-lang-exts '("clojure" . "clj")) @@ -80,19 +82,43 @@ If the value is nil, timeout is disabled." (const :tag "cider" cider) (const :tag "SLIME" slime))) +(defcustom org-babel-clojure-default-ns "user" + "Default Clojure namespace for src block when all find ns ways failed." + :type 'string + :group 'org-babel) + +(defun org-babel-clojure-cider-current-ns () + "Like `cider-current-ns' except `cider-find-ns'." + (or cider-buffer-ns + (when-let* ((repl-buf (cider-current-connection))) + (buffer-local-value 'cider-buffer-ns repl-buf)) + org-babel-clojure-default-ns)) + (defun org-babel-expand-body:clojure (body params) "Expand BODY according to PARAMS, return the expanded body." (let* ((vars (org-babel--get-vars params)) + (ns (cdr (assq :ns params))) + (ns-fallback (org-babel-clojure-cider-current-ns)) (result-params (cdr (assq :result-params params))) (print-level nil) (print-length nil) + (bind-vars (lambda (body) + (if (null vars) (org-trim body) + (concat + "(let [" + (mapconcat + (lambda (var) + (format "%S (quote %S)" (car var) (cdr var))) + vars "\n ") + "]\n" body ")")))) + (specify-namespace (lambda (body) + (concat + "(ns " (if (null ns) ns-fallback ns) ")\n" body))) (body (org-trim - (if (null vars) (org-trim body) - (concat "(let [" - (mapconcat - (lambda (var) - (format "%S (quote %S)" (car var) (cdr var))) - vars "\n ") - "]\n" body ")"))))) + (thread-last body + ;; variables binding + (funcall bind-vars) + ;; src block specified namespace :ns + (funcall specify-namespace))))) (if (or (member "code" result-params) (member "pp" result-params)) (format "(clojure.pprint/pprint (do %s))" body) @@ -102,9 +128,11 @@ If the value is nil, timeout is disabled." "Execute a block of Clojure code with Babel. The underlying process performed by the code block can be output using the :show-process parameter." - (let ((expanded (org-babel-expand-body:clojure body params)) - (response (list 'dict)) - result) + (let* ((expanded (org-babel-expand-body:clojure body params)) + (ns (cdr (assq :ns params))) + (ns-fallback (org-babel-clojure-cider-current-ns)) + (response (list 'dict)) + result) (cl-case org-babel-clojure-backend (cider (require 'cider) @@ -117,8 +145,7 @@ using the :show-process parameter." (let ((nrepl-sync-request-timeout org-babel-clojure-sync-nrepl-timeout)) (nrepl-sync-request:eval expanded - (cider-current-connection) - (cider-current-ns)))) + (cider-current-connection)))) (setq result (concat (nrepl-dict-get response @@ -152,8 +179,7 @@ using the :show-process parameter." (nrepl--merge response resp) ;; Update the status of the nREPL output session. (setq status (nrepl-dict-get response "status"))) - (cider-current-connection) - (cider-current-ns)) + (cider-current-connection)) ;; Wait until the nREPL code finished to be processed. (while (not (member "done" status)) -- 2.16.3 --------------0196EB47A0A4B4A320EA0679--