Skip to content

cassiel/thi-ng-geom-starter

Repository files navigation

-*- mode: org; mode: visual-line; -*-

Contents

Overview

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.

Setup

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 git@github.com:<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"]

Emacs Setup

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"))

Testing Clojure

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

ClojureScript, Figwheel and Chestnut

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.)))

The Main Application

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.

Issues

  • 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 an ns declaration to do various :require and :refer calls, so as long as you evaluate this block first all should be fine. We explicitly bind cider-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 in edit-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 an ns 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.

To Do

  • We could do with a “tangle all Org files” command.

Releases

No releases published

Packages

No packages published

Languages