-*- 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 -- --reagentChestnut 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.gitfollowed 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/quitfrom 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))ATo 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/quitTo 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
nsdeclarations to establish the correct namespace; in Org mode this doesn’t work. Every org file will probably start off with a code block containing annsdeclaration to do various:requireand:refercalls, so as long as you evaluate this block first all should be fine. We explicitly bindcider-buffer-nsin 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 annsstatement 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-nsin 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-lin 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.