-*- mode: org; mode: visual-line; -*-
- Overview
- Setup
- Emacs Setup
- Testing Clojure
- ClojureScript, Figwheel and Chestnut
- The Main Application
- Issues
- To Do
This is a test WebGL project using Karsten Schmidt’s thi.ng tools for ClojureScript, written in a literate programming style using Emacs, Org mode and Babel.
This project was created with
lein new chestnut thi-ng-geom-starter -- --reagent
Chestnut seems to do its own initial git commit, so if a repository of the same name is created on GitHub, it just takes a quick
git remote add origin [email protected]:<username>/thi-ng-geom-starter.git
followed by a git push -u origin master
to get everything synchronised.
A couple of notes on the initial project build:
- We’re using Chestnut rather than plain Figwheel because it seems to bring up a proper ClojureScript REPL that we can connect into from Emacs (in fact, we can switch between them by saying
(browser-repl)
from Clojure and:cljs/quit
from ClojureScript) - We’ve gone Reagent rather than Om for simplicity
- We’ve only provided a flat namespace (
thi-ng-geom-starter
) rather than a qualified namespace (eu.cassiel/[...]
) because of a bug in Chestnut which messes up the directory structure for qualified names
To get a fully functioning REPL for CIDER, I’ve added the following plugin dependencies:
[cider/cider-nrepl "0.9.1"]
[refactor-nrepl "1.1.0"]
We’re using Sam Aaron’s Emacs Live, which comes with support for Clojure (via CIDER). Org-mode babel supports Clojure, but this needs to be loaded via
(require 'ob-clojure)
Assuming you trust all the code in this repository, you can turn off confirmation when executing blocks:
(setq org-confirm-babel-evaluate nil)
Since we’ll be switching to/from sub-edit modes a lot, I sacrifice F12 to this:
(define-key org-mode-map (kbd "<f12>") 'org-edit-special)
(define-key org-src-mode-map (kbd "<f12>") 'org-edit-src-exit)
Also, a quick key for exporting via tangle:
(define-key org-mode-map (kbd "<M-f12>") 'org-babel-tangle)
TODO: those should be in the hooks for org-mode
and org-src-mode
.
Nice-to-have: Org mode table of contents. Needs this hook:
(if (require 'toc-org nil t)
(add-hook 'org-mode-hook 'toc-org-enable)
(warn "toc-org not found"))
Start a Clojure session in the usual way, via M-x cider-jack-in
.
Here’s a quick test. In this block, type C-c C-c
to execute the code, or type C-c \acute{}
to open a custom editor session for the block, with the usual Clojure editing tools.
(range 10)
Since a single Clojure session underlies Babel, all blocks share the same environment:
(def A (range 10))
A
To start the Figwheel server:
(run)
To switch from Clojure to ClojureScript:
(browser-repl)
Note: this requires a browser to be running and connected to http://localhost:3449
.
And back:
:cljs/quit
To see which environment we’re currently in:
#?(:clj (str "Clojure @ " (java.util.Date.))
:cljs (str "ClojureScript @ " (js/Date.)))
See the main application. This is the entry point for the Leiningen build. We (currently) have no server-side Clojure source code at all - everything is ClojureScript.
- There’s a problem with the behaviour of
org-mode-fontify
(which decorates code blocks): temporary buffers are associated with files, causing bogus “save file” prompts. Following the link on StackExchange, this seems to be a workround:
(defun kill-org-src-buffers (&rest args)
"Kill temporary buffers created by
org-src-font-lock-fontify-block so they don't interfere with
magit-mode."
(dolist (b (buffer-list))
(let ((bufname (buffer-name b)))
(if (string-prefix-p " org-src-fontification:" bufname)
(kill-buffer b)))))
(advice-add 'org-src-font-lock-fontify-block
:after #'kill-org-src-buffers)
- Namespace handling is awkward. When working with pure Clojure or ClojureScript files, CIDER searches upwards for
ns
declarations to establish the correct namespace; in Org mode this doesn’t work. Every org file will probably start off with a code block containing anns
declaration to do various:require
and:refer
calls, so as long as you evaluate this block first all should be fine. We explicitly bindcider-buffer-ns
in the (Emacs) variables for each file, useful if you visit a file for the first time after a session is already established. A more serious problem is that inedit-special
(C-c \acute{}
) sessions new buffers are established, and it’s not clear how to set the default namespace for them. We need some Emacs lisp-fu to make that work. (We can’t just add anns
statement to each block, since on export the multiple statements will be rejected in ClojureScript.) So, for now, it’s not possible to REPL-evaluate in sub-edit.(And here’s a gotcha: if you’re refactoring, and do a “save as” to copy code to a new namespace, it’s not enough to edit the value of
cider-buffer-ns
in the prelude; the value must be rebound as well. Easiest way: kill the new buffer and reload.) - Evaluated source files won’t carry line numbers that relate closely to code blocks, potentially making debugging a little tricky. (That’s already true of REPL evaluation via
C-M-x
.) I actually keep a second independent editor open on a second screen which auto-refreshes the exported code files, so that I can quickly eyeball what Clojure(Script) is seeing. (I’ve found Brackets to work well.) - I’m a little in the dark on Clojure reloading - I generally use
cider-load-file
(C-c C-l
in Clojure mode) and/or follow Stuart Sierra’s workflow. Perhaps that needs to be tied into tangle exporting somehow. (lein-autoreload might help.) - Sorry about the
acute{}
business: there doesn’t seem to be any way to format inline code containing isolated quotes.
- We could do with a “tangle all Org files” command.