#+begin_src clojure :session "*cider-repl ob-clojure*" :results output
(prn *ns*)
#+end_src
#+RESULTS:
: #namespace[user]
(use-package ob-clojure-literate
:ensure t
:after org
:init
(setq ob-clojure-literate-auto-jackin-p t)
(add-hook 'org-mode-hook #'ob-clojure-literate-mode)
)
I like Emacs Org-mode “Literate Programming” very much. It’s a kind of paradigm.
I can apply this idea on many places. Now Clojure is my favourite programming
language. I hope to combine them together. But ob-clojure
does not suitable for
Literate Programming very much like other language babel (like Python) supports.
This README is totally written in Org-mode Literate Programming.
So I decide to solve this problem in my way.
- State “TODO” from [2017-12-22 Fri 09:52]
- State “TODO” from [2017-12-22 Fri 09:52]
- First, create a plain Clojure project with Leiningen to used for ob-clojure.
lein new ob-clojure
- Then auto start CIDER REPL session in this plain Clojure project.
- Set ob-clojure default header arguments to a static session name:
(add-to-list 'org-babel-default-header-args:clojure '(:session . "*cider-repl ob-clojure*"))
- open a file in project to prepare for CIDER jack-in.
(progn (find-file (expand-file-name "~/.emacs.d/Org-mode/ob-clojure/src/ob_clojure/core.clj")) (cider-jack-in))
- Set ob-clojure default header arguments to a static session name:
- To fix
org-babel-execute:clojure
has a line(cider-current-ns)
which will invoke(cider-find-ns)
. The(cider-find-ns)
will try to extract Clojure namespace from current buffer.This will cause a problem, like in following org-mode file content:
* test results output #+BEGIN_SRC clojure :result output (println "hi") (println (str *ns*)) #+END_SRC When I execute first src block [C-c C-c], it will find namespace and return wrong namespace ~kk~ in second src block. This is not a expected behavior. * different namespace #+BEGIN_SRC clojure :result output (in-ns 'kk) (println (str *ns*)) #+END_SRC
In order to fix this problem, I asked a lot of places, and try many methods.
Finally I found the variable
cider-buffer-ns
(which in functioncider-current-ns
) docstring description.Current Clojure namespace of some buffer. Useful for special buffers (e.g. REPL, doc buffers) that have to keep track of a namespace. This should never be set in Clojure buffers, as there the namespace should be extracted from the buffer's ns form.
Then I come up an idea:
- should I include org-mode as special for CIDER
cider-buffer-ns
?- It is
nil
in Clojure buffer. - It is ”
user
” incider-repl ob-clojure
session. - Maybe I should use elisp code to manually set this
ns
touser
.
- It is
- should I include org-mode as special for CIDER
- So the final solution source code is:
;; auto start CIDER REPL session in a complete Leiningen project environment for Org-mode Babel by jack-in. (add-to-list 'org-babel-default-header-args:clojure '(:session . "*cider-repl ob-clojure*")) (progn (find-file (expand-file-name "~/.emacs.d/Org-mode/ob-clojure/src/ob_clojure/core.clj")) (cider-jack-in)) (defun ob-clojure-cider-do-not-find-ns () "Fix the issue that `cider-current-ns' try to invoke `clojure-find-ns' to extract ns from buffer." (setq-local cider-buffer-ns "user")) (add-hook 'org-mode-hook #'ob-clojure-cider-do-not-find-ns)
But the function
ob-clojure-cider-don-not-find-ns
can be smarter:How to execute elisp code in a specific buffer without actually switching to it? I can writing a function get a buffer local variable in a specific (regex matched) buffer.
(defun ob-clojure-cider-do-not-find-ns () "Fix the issue that `cider-current-ns' try to invoke `clojure-find-ns' to extract ns from buffer." (with-current-buffer "*cider-repl ob-clojure*" (defvar ob-clojure-cider-repl-ns cider-buffer-ns) (setq-local cider-buffer-ns ob-clojure-cider-repl-ns)))