Last time I checked a Cirru related topic on Reddit I tried to gather some histories related to Calcit Editor. I realised that the earlier version of Calcit Editor, would be more appealing to people who want to try and explore. That project was Stack Editor:
The project has not been updated for 3 years. shadow-cljs was just release 0.x at that time. So I did some updates to the project based on my current toolchains.
Difference from Calcit Editor
I highlighted the main differences between Stack Editor and Calcit Editor:
- Stack Editor uses
stack.cirru
as the snapshot file, which is mostly vectors in Cirru EDN and human-readable.
- Stack Editor connects server via HTTP, which is a bit clumsy for data syncing.
- Stack Editor loads all the code in browser, so available for more analysis.
- Stack Editor has not been actively maintained in years, fewer features…
The snapshot file was ir.edn
and after refactoring in these days, the file became stack.cirru
. It’s an indented version of EDN. I believe it’s more compact and diff-friendlier than EDN. You might feel it unfamiliar to read though. Try my Cirru EDN → X converter if you would like…
{} (:package |app)
:root $ {} (:ns |main) (:def |main!)
:files $ {}
|updater.router $ {}
:ns $ [] |ns |app.updater.router
[] |:require ([] |[] |app.util.stack |:refer $ [] |[] |get-path) ([] |[] |clojure.string |:as |string)
:defs $ {}
|toggle-palette $ [] |defn |toggle-palette ([] |store |op-data |op-id)
[] |update-in |store ([] |[] |:router |:show-palette?) (, |not)
|route $ [] |defn |route ([] |store |op-data)
[] |let ([] $ [] |router |op-data) ([] |assoc |store |:router |router)
|open-file-tree $ [] |defn |open-file-tree ([] |store |op-data |op-id)
[] |let
[] $ [] |code-path ([] |get-path |store)
[] |-> |store
[] |assoc-in ([] |[] |:router |:name) (, |:file-tree)
[] |assoc-in ([] |[] |:graph |:ns-path)
[] |vec $ [] |string/split ([] |:ns |code-path) (, ||.)
:procs $ []
|comp.brief-file $ {}
:ns $ [] |ns |app.comp.brief-file
[] |:require ([] |[] |hsl.core |:refer $ [] |[] |hsl) ([] |[] |respo.core |:refer $ [] |[] |defcomp |div |list-> |<> |span |input) ([] |[] |clojure.string |:as |string) ([] |[] |respo-ui.core |:as |ui) ([] |[] |respo.comp.space |:refer $ [] |[] |=<) ([] |[] |app.style.widget |:as |widget) ([] |[] |app.util.keycode |:as |keycode)
:defs $ {}
a whole file: stack-editor/stack.cirru at master · Cirru/stack-editor · GitHub
Stack Editor has the very basic features of Calcit Editor: creating files, editing functions, goto definitions(for internal ones), search and jump… I used it for development for at least some months.
The reason I moved to Calcit Editor is I got WebSockets for syncing every change from users, it’s more reliable and more extensive. But there are indeed several nice features I can’t clone to Calcit Editor.
Dependency graph
In Stack Editor, the whole snapshot file is sent to browser via HTTP. That means I have chance to analyze all entries just in browser. The picture shows how each function is depending on other functions, starting from app.main/main!
function:
Goto references
In Stack Editor, if you press “Command u”, it will find functions that are using current function. It can be quite useful sometimes.
I can hardly add this feature in Calcit Editor since it only loads small parts of code in browser. I might have chance to do that on the server-side, but turned out to be a bit expensive. Besides, another person might be editing the code in realtime and bringing more edge cases to handle.
Storage file editing
As shown above, stack.cirru
is quite a simple format, good for git merge, good for manual editing. Run op=compile stack-editor
code regenerated again. If you prefer EDN, just fork project and use EDN. Previously I added a package called cirru/favored-edn
for writing EDN in a way similar to JSON, it was also available.
Meanwhile calcit.cirru
from Calcit Editor just looks like a mess. I want to say calcit.cirru
is mostly maintained by the CLI, watching file, syncing to browsers… in a lot more details. Those things can be hardly finished if I just use simple HTTP connections.
Implementations
The UI part of the editor is rendered with Respo, my own virtual DOM library. And its editor component is splitted in respo-cirru-editor , code generation using sepal.clj like in Calcit Editor, so not much code was left inside stack-editor repo.
If you want, just reuse the storage format, code generation library, and create your own version of Stack Editor. Analyzing basic informations from a tree is way easier compared to analysing Clojure code.
Yes, the limitation is mainly from the data structure of stack.cirru
. We have libraries from jars located in ~/.m2/repository
. Those pieces are not analyzed in this way. I always imagined one day(fool’s days is approaching…) we store code in snapshots(like in Smalltalk?) rather than in text files. Then we don’t have to build that many parsers but instead build UIs with HTML/CSS. Then we have interperter reading snapshot file and run directly. It appears we won’t get there at least in ten years…
And yes we need another way for Macros too, sepal.clj
does not generate macros since it’s using FIPP… so for now if you want macros, add another folder to classpaths for adding macros…