Where parallels cross

Interesting bits of life

How (simple is) to install a Clojure tree-sitter grammar and use it from Emacs

I am a fan of tree-sitter because it is opening a world of possibilities for my little Emacs extension for moldable development.

During last EmacsConf Tuấn-Anh Nguyễn showed us how to make tree-sitter and Emacs work together with his package emacs-tree-sitter.

Since I am a fan of Clojure and I am going to work with it soon, I thought it was the right time to try integrating a grammar for Clojure in my workflow. Thanks to sogaiu for his nice little grammar, I could get to something to share!

There is not much to share actually because everybody documented things nicely! I will just summarize what I understood so far.

The emacs-tree-sitter package comes with some grammars by default to avoid users the installation of all the most common grammars. Anyway, tree-sitter grammars are NPM packages at the end of the day. So anytime you run npm install in a grammar, it becomes available also to emacs=tree-sitter.

So I first just followed sogaiu's instructions, which boil down to:

git clone https://github.com/sogaiu/tree-sitter-clojure
cd tree-sitter-clojure

# create `node_modules` and populate with dependencies
npm install

# create `src` and populate with tree-sitter .c goodness
npx tree-sitter generate

# create `build` and populate with 
npx node-gyp configure

# create `build/Release` and build `tree_sitter_clojure_binding.node`
npx node-gyp rebuild

# finally generate the dynamic library for emacs-tree-sitter
# Note: you need tree-sitter-cli for this
tree-sitter generate

Please be careful that the requirement for this is a recent version of NodeJS. (I found how to upgrade in Ubuntu here https://askubuntu.com/questions/426750/how-can-i-update-my-nodejs-to-the-latest-version#)

Anyway, once you run the commands above, you just need to run the following Elisp snippet in Emacs.

(add-to-list
 'tree-sitter-major-mode-language-alist
 '(clojure-mode . clojure))

With that you should be able to parse the following code.

(ns my-project.core
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

And obtain the following syntax tree with the interactive Emacs function tree-sitter-debug-mode.

source:
  list_lit:
    sym_lit:
    sym_lit:
    list_lit:
      kwd_lit:
  list_lit:
    sym_lit:
    sym_lit:
    str_lit:
    vec_lit:
      sym_lit:
      sym_lit:
    list_lit:
      sym_lit:
      str_lit:

It is basic but still quite useful for my mode nonetheless! I hope to have time to learn how to contribute to this grammar later. It already recognizes all the basic Clojure data structures like maps, sets and vectors, so it is very valuable to me.

Hope this is useful for your workflow as well!

Happy coding!

Comments