https://github.com/bbatsov/ob-clojure-literate
Setup scaffold for Clojure Literate Programming in Org-mode.
https://github.com/bbatsov/ob-clojure-literate
Last synced: 9 months ago
JSON representation
Setup scaffold for Clojure Literate Programming in Org-mode.
- Host: GitHub
- URL: https://github.com/bbatsov/ob-clojure-literate
- Owner: bbatsov
- License: gpl-3.0
- Created: 2018-01-04T10:15:03.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2018-01-04T10:15:28.000Z (about 8 years ago)
- Last Synced: 2025-02-10T08:45:41.582Z (11 months ago)
- Language: Emacs Lisp
- Size: 29.3 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.org
- License: LICENSE
Awesome Lists containing this project
README
#+TITLE: ob-clojure-literate
* Screenshots
** use default session
#+begin_src org
,#+begin_src clojure :session "*cider-repl ob-clojure*" :results output
(prn *ns*)
,#+end_src
,#+RESULTS:
: #namespace[user]
#+end_src
** support generate plot
** support header argument :dir
* Installation
** use-package
#+begin_src emacs-lisp
(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)
)
#+end_src
* Motivation
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.
* Todos
** TODO Support generate inline plot image under current working directory
:LOGBOOK:
- State "TODO" from [2017-12-22 Fri 09:52]
:END:
** TODO Support babel header argument :dir
:LOGBOOK:
- State "TODO" from [2017-12-22 Fri 09:52]
:END:
* Usage
** This package workflow
*** auto start an CIDER REPL for ob-clojure
1. First, create a plain Clojure project with Leiningen to used for ob-clojure.
#+begin_src shell :dir "~/.emacs.d/Org-mode/"
lein new ob-clojure
#+end_src
2. Then auto start CIDER REPL session in this plain Clojure project.
1. Set ob-clojure default header arguments to a static session name:
#+begin_src emacs-lisp
(add-to-list 'org-babel-default-header-args:clojure
'(:session . "*cider-repl ob-clojure*"))
#+end_src
2. open a file in project to prepare for CIDER jack-in.
#+begin_src emacs-lisp
(progn
(find-file (expand-file-name "~/.emacs.d/Org-mode/ob-clojure/src/ob_clojure/core.clj"))
(cider-jack-in))
#+end_src
3. 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:
#+begin_src org
,* 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
#+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 function
~cider-current-ns~) docstring description.
#+begin_example
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.
#+end_example
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~" in ~cider-repl ob-clojure~ session.
- Maybe I should use elisp code to manually set this ~ns~ to ~user~.
4. So the final solution source code is:
#+begin_src emacs-lisp
;; 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)
#+end_src
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.
#+begin_src emacs-lisp
(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)))
#+end_src