Skip to content
nickmain edited this page Sep 14, 2010 · 15 revisions

Clojure Runtime

There is a single Clojure runtime in the JVM on which Freemind is running. This means that any namespaces created by code evaluated in any mind-map will be shared by all the open mind-maps.

Likewise, there is a common classloader used by the plug-in across all mind-maps. Any URLs added to the classpath will be used by the Clojure runtime in all mind-maps.

Clojure Source

Clojure source can be laid out in a sub-tree of the mind-map in whatever way is deemed suitable, according to the following rules:

  • The source is read in a depth-first fashion, thus:

    is read as
(foo bar) (willy wonka) makes [very fine] )chocolate 
  • Any opening delimiter that does not have a matching closing delimiter in the same node will cause the closing delimiter to be automatically added after reading all the child nodes. This can be seen in the example above – the “(willy wonka) makes” node starts with an opening parenthesis but does not end with one, so one is added after reading the child.

Another example:

reads as

(foo [ a b c ]) 
  • Any opening delimiter at the end of a node will also add the corresponding closing delimiter after the children. The closing delimiter is added before the closing delimiter corresponding to the start delimiter (if any).
    Example:

    reads as
(foo (bar [ a b c ])) 

The delimiters that are recognized are:

Open Close
#{ }
#^{ }
#( )
’( )
`( )
( )
{ }
[ ]
  • Clojure comments (starting with a semi-colon) have a newline added to the end, so that any children or following nodes are not commented out.

For example, the top sub-tree is equivalent to the node below it:

(It’s ugly but the Clojure reader doesn’t care).

Non-Clojure Comments

Any node that starts with a double slash (//) is skipped when reading Clojure source. This allows entire sub-trees to be commented out.

Node Links

Freemind allows local links between nodes. Select two nodes and right-click > Insert > Add Local Hyperlink, or option-L (for OS X) – a link to the second node is added to the first.

When reading Clojure source from a sub-tree, a node with a local link will read the target node and sub-tree in place of the node itself. The text in the link-start node is ignored and can be used to comment on the role of the included link-target. Any children of the link node are skipped.

For example:

where the link node (green arrow) links to the “; Copyright ..” node. The highlighted node’s sub-tree reads as

; Copyright (c) 2010, Nick Main.
; All rights reserved.
; This code is covered under an open-source license
(ns test) (println "hello world") (defn funk [a] (* a 2)) "done loading" 

File Links

Clojure also allows a node to link to a file – right-click > Insert > Hyperlink (File Chooser) …

A node with a file link will include the text of the file when read. This allows external Clojure source files to be included in the read. The text of the node and any children are ignored.

Note that the mind-map needs to have been saved with a filename in order for file links to work.

Evaluation

Parent Evaluation

Typing a single question-mark in a node will cause the expression in the parent node to be evaluated:

The result will replace the question-mark.

If the grand-parent node starts with "(ns " then it will be included, too. This allow the expression to be evaluated within a particular namespace. For example:

The text in the node(s) are simply concatenated, without any of the delimiter or other rules detailed above. Links are not followed.

The evaluation is performed via the Clojure load-string function so the text can contain multiple statements, not just a single expression.

Sub-tree Evaluation

In order to evaluate a sub-tree with all the Clojure source reading rules described above, type two question-marks in a node immediately beneath the root node of the sub-tree.

For example:

results in

The “test” namespace will have been created and the function “funk” defined within it. The last expression in the script was the string “done loading” and that was returned as the result.

To see which namespaces have been defined type “(all-ns)” in a node and then a question mark in a child node. For example, the screenshot shows the (all-ns) result before and after the evaluation of the (ns test) tree. The “test” namespace has been added.

Result Unpacking

If the result of evaluation is a sequence then the result will simply be the string representation. To “unpack” the result into individual child nodes use “?>” instead of a question-mark:

results in

“?>” has a limit of 30 elements – any beyond that are dropped. To unpack larger sequences use “?>>” (limit 100) or “?>>>” (limit 1000).

To unpack the results of evaluating a sub-tree use “??>” instead of “??” in a node beneath. For larger size limits “??>>” (100) and “??>>>” (1000) can be used.

Source Preview

As a debugging tool, typing three question-marks (“???”) in a node will be replaced by the result of reading the source in the sub-tree above, without any evaluation.

Special Hooks

Freemind allows “hooks”, which are essentially custom listeners attached to specific nodes. The ClojureMind plug-in implements some special hooks and provides means to attach them to nodes.

Classpath

The classpath hook allows URLs (folders or Jars) to be added to the classpath used by the Clojure runtime. This classpath is used when looking for Java classes and for Clojure source files.

To install the hook, type “/classpath”:

An icon is added to the node to indicate its special status:

The classpath hook is now attached to the node. The hook is persisted with the mind-map and does not need to be added again.

To define a URL to be added to the classpath, add a child node with a file link:

Select a Jar file (you will probably need to select the “All Files” file format/type in order to enable selecting non-mind-maps):

The resulting link is shown as a red arrow on the node:

The Jar is now added to the classpath (it will also be added the next time the mind-map is opened). To verify this, let’s instantiate a class from the jar we just added:

Multiple Jars and folders can be added:

On file-load they are processed in order, top to bottom.

To create a link to a folder use the “Hyperlink (Text Field) …” menu option and enter the relative path to the folder manually.

The classpath hook will add to the classpath when one of the child nodes changes. Any URL already added to the classpath is ignored, so there will be no duplicates.

The classpath is also processed when the mind-map is first opened, before any other Clojure scripts in the map are loaded.

Initialization Scripts

The initialization hook will execute Clojure scripts when the mind-map is opened (after the classpath is set).

To install the hook, type “/init” in a node:

As with the classpath the hook is now attached to the node.

To add a script, add a child node. The script in the sub-tree rooted in the child node will be executed when the mind-map is opened. The children will be evaluated in order, top to bottom (in case there are any namespace dependencies between them).

The best way to use this hook is to link the child nodes to namespace definitions elsewhere in the map. For example, a link has been added to the (ns test) node:

Thus the (ns test) sub-tree will be evaluated and the “test” namespace will be set up, ready for use, when the map is opened.

File Save

The file-save hook will save the source of sub-trees to external files whenever the mind-map is saved. Note, however, that Freemind auto-saves every minute (by default), so the saving will happen more frequently than dictated by the user.

To install the hook, type “/save” in a node:

The child nodes should contain the name of the file, relative to the folder containing the mind-map. The node should have an internal link to the sub-tree to be saved. For example:

This will save the (ns test) definition to a file named “test.clj” in the same folder.

Note that the source is not formatted. It can be read by Clojure but is not in a form that a human would write. Formatting of the exported code is a feature that will be added soon.

User Hooks

TODO