Emacs and R with Tree-sitter and LSP

Roger Schürch

last updated: Thu Aug 21, 2025

I have been using Emacs to write my R code since my PhD. Back in the day, there were simply no other programs that could compete with Emacs. Now, of course, there is RStudio, and VS Code, and Neovim, and many other editors that people love. I got used to doing things in Emacs, and because Org Mode is such an absolute killer app, I will probably not change my ways anytime soon. I find Org Mode still superior to Rmarkdown and Quarto, and the general editing experience in Emacs far better than in RStudio.

Anyhow, I have my first batch of grad students in my lab that I encouraged to use Org Mode to write their student proposals rather using Word. Now that we are entering the analysis phase, I thought it was prudent for them to try write their R scripts and analyze their data from Emacs as well. However … they are on Windows. I was not quite prepared for the headache that ensued to get eglot (the Emacs native language server protocol implementation) and Tree-sitter to work.

Here I show how we got the machines set up in the end. Maybe it will be useful to some.n

I am assuming that we will start from a Windows machine that has been set up with R and Emacs. R can be installed from CRAN (https://cran.r-project.org/). Pre-compiled Windows binaries for GNU Emacs are available from https://www.gnu.org/software/emacs/download.html#nonfree. Select a mirror of your choice from there and download the installer. Then follow the instructions.

Emacs Speaks Statistics

To enable Emacs to speak to R, we need to use the Emacs Speaks Statistics (ESS) Package. Setting this up is pretty easy and reading the manual should suffice, mostly. The one thing that is important to note is that when telling ESS where to look for the R process, you should choose the Rterm.exe binary. Set the inferior-ess-r-program to point to the binary like so:

(setq inferior-ess-r-program "C:/path/to/your/R/installation/bin/Rterm.exe")

Note that you either have to escape the backslashes from the path (i.e., you have to have two backslashes in a row C:\\path\\tofile), or use forward slashes (as in the example above).

MSYS2

Current versions of Emacs come with Tree-sitter support. However, to install the language grammars that then allow Emacs to parse the files, you will need a working compiler on your system. Specifically, you need to have a C-compiler (the cc command specifically) that Emacs can use to compile the sources from the grammars. We ultimately got this accomplished using the MSYS2.

Follow the instructions on https://www.msys2.org/, including the installation of the GCC compiler from UCRT64 environment:

pacman -S mingw-w64-ucrt-x86_64-gcc

Add the path to the compilers to the environment variables: Go to the Start menu, search for "environment variables", then edit the path to include the path to the compiler binaries. If you are unsure where to find the cc.exe file, you can use the which cc command in the UCRT64 environment where you installed GCC. Make sure you properly reference the path by changing forward slashes to backslashes.

Tree-sitter

While Tree-sitter support is available in Emacs, the user needs to install the language grammars. This can be accomplished with something like this:

(setq treesit-language-source-alist
   '((bash "https://github.com/tree-sitter/tree-sitter-bash")
     (cmake "https://github.com/uyha/tree-sitter-cmake")
     (css "https://github.com/tree-sitter/tree-sitter-css")
     (elisp "https://github.com/Wilfred/tree-sitter-elisp")
     (go "https://github.com/tree-sitter/tree-sitter-go")
     (html "https://github.com/tree-sitter/tree-sitter-html")
     (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
     (json "https://github.com/tree-sitter/tree-sitter-json")
     (make "https://github.com/alemuller/tree-sitter-make")
     (markdown "https://github.com/ikatyang/tree-sitter-markdown")
     (python "https://github.com/tree-sitter/tree-sitter-python")
     (r "https://github.com/r-lib/tree-sitter-r")
     (toml "https://github.com/tree-sitter/tree-sitter-toml")
     (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
     (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
     (yaml "https://github.com/ikatyang/tree-sitter-yaml")))

(mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))

This is taken from Mastering Emacs, I just added the the link to the tree-sitter-r repository. You don't need to execute this code every time you start Emacs, so it should not go into the init file. I have saved the code in a separate tree-sitter-grammar-install.el file that I can open and run when I need to.

If the install of MSYS2 worked without a hitch, then Tree-sitter grammars should be installed into a sub-directory of the .emacs.d directory.

Language Server Protocol

Like Tree-sitter, the support for the language server protocol is baked into emacs with the eglot package. The main sticking point here was that we first added the path to Rterm.exe to the eglot-server-programs association list, but this should be Rscript.exe. In the end, the following code in the students init file worked:

;; eglot
(use-package eglot
  :ensure t
  :init
  (add-hook 'R-mode-hook 'eglot-ensure)
  :config
  (add-to-list
   'eglot-server-programs
   '((R-mode ess-r-mode) . ("C:\\Program Files\\R\\R-4.4.1\\bin\\x64\\Rscript.exe" "--slave" "-e" "languageserver::run()"))
   ))

Again, the backslashes have to be escaped, or forward slashes must be used.