fixing an emacs + typescript-ts-mode problem

Recently, I’ve been having a problem with Typescript files in Emacs — any time I open one and it tries to activate eglot (the new-ish built-in LSP mode), I would get this massive multi-line error that started with query pattern is malformed. Read on to see how I fixed it.

Step one, of course, was to search for the error message, which led me to an r/emacs post about the same problem, in which the offered and reported-to-work solution was “downgrade the treesitter grammar” …but nowhere in the thread does anybody explain how one might go about doing that, and searching for “how to downgrade treesitter grammar” was not a helpful exercise.

Now, I knew from the thread what version of the grammar I needed to grab — v0.20.3 — and since I use a helper package called treesit-auto to help manage tree-sitter grammars, I figured the answer was probably somewhere in there. After poking around a little bit, I found treesit-auto-recipe-list, which is a list of grammars, their github repos, what modes they associate with, and how to compile them. I even found the entries for typescript-ts-mode and tsx-ts-mode in that list.

Each of the recipes is the list is the output from a function called make-treesit-auto-recipe, and all of them look roughly like this:

(make-treesit-auto-recipe
  :lang 'typescript
  :ts-mode 'typescript-ts-mode
  :remap 'typescript-mode
  :requires 'tsx
  :url "https://github.com/tree-sitter/tree-sitter-typescript"
  :revision "master"
  :source-dir "typescript/src"
  :ext "\\.ts\\'")

Clearly the fix here is to get that :revision "master" bit to instead say :revision "v0.20.3" — but how? Ideally I’d replace the entry in the existing list, but that felt like it would turn into a rat-hole of searching for ELsip list-munging functions. A quick skim of the documentation and code in treesit-auto strongly suggested that the list would be checked in order and the first entry that matched the ts-mode node would be the one that got used — so my fix ended up looking like this:

;; this fixes a problem where v0.20.4 of this grammar blows up with emacs
(defvar genehack/tsx-treesit-auto-recipe
  (make-treesit-auto-recipe
   :lang 'tsx
   :ts-mode 'tsx-ts-mode
   :remap '(typescript-tsx-mode)
   :requires 'typescript
   :url "https://github.com/tree-sitter/tree-sitter-typescript"
   :revision "v0.20.3"
   :source-dir "tsx/src"
   :ext "\\.tsx\\'")
  "Recipe for libtree-sitter-tsx.dylib")
(add-to-list 'treesit-auto-recipe-list genehack/tsx-treesit-auto-recipe)

(defvar genehack/typescript-treesit-auto-recipe
  (make-treesit-auto-recipe
   :lang 'typescript
   :ts-mode 'typescript-ts-mode
   :remap 'typescript-mode
   :requires 'tsx
   :url "https://github.com/tree-sitter/tree-sitter-typescript"
   :revision "v0.20.3"
   :source-dir "typescript/src"
   :ext "\\.ts\\'")
  "Recipe for libtree-sitter-typescript.dylib")
(add-to-list 'treesit-auto-recipe-list genehack/typescript-treesit-auto-recipe)

Once I added that to my config, deleted the existing grammar libraries (they were at tree-sitter/libtree-sitter-tsx.dylib and tree-sitter/libtree-sitter-typescript.dylib in my Emacs configuration directory), and restarted Emacs, when I visited a TS file, I got prompted to install the Typescript tree-sitter grammar, which I did, and then everything went back to working. A fine use of an hour on Sunday morning…

And now that I’ve written this all up, I will return to the r/emacs post where i found the answer, and link to this post, so that hopefully the next person that runs across this issue and finds that post doesn’t have to spend an hour figuring out how to downgrade the typescript tree-sitter grammar…

Onwards.