Emacs Setup for Elixir and Vue

I had been an avid user of Spacemacs for a long time. However, it could sometimes be time-consuming to get the setup just right in Emacs land. I would like to share some of my configurations here for a satisfactory editing experience for Elixir and Vue.

Language Server Protocol

Language Server Protocol (LSP) was created by Microsoft to define a common standard for providing editor-agnostic code intelligence support. It has become widely popular since its creation.

Emacs support for lsp comes with the lsp-mode package. Both of the following setups depend on it. Therefore, one needs to install it first, either directly or via the Spacemacs lsp layer.

      # In `dotspacemacs/layers`:
      lsp

Vue.js

The landscape surrounding Vue support on Emacs has been quite confusing.

There had been an old vue-mode package, which is likely to be the first result on Google. However, the package lacks many features compared to Vetur (a popular VSCode extension) such as autocompletion, and is not being actively developed anymore.

There is also a legacy lsp-vue package, which is supposed to leverage vue-language-server from Vetur. However, this package is not compatible with the the newest version of Emacs’ lsp-mode.

Actually, the new lsp-mode already ships with a lsp-vetur.el, which provides support for Vue via vue-language-server. There is even a non-official Vue layer for Spacemacs that integrates with ESLint and Prettier to provide a complete editing experience similar to Vetur in VSCode. I have been using this layer for a while and it works great. The author has mentioned submitting a MR to Spacemacs to incorporate it into the list of official layers, but hasn’t done so yet. That partly explains why it might take one some digging to find it.

To install the layer:

# Folder for private layers
cd ~/.emacs.d/private
git clone git@github.com:thanhvg/vue.git

# Install the necessary tools manually
# vue-language-server is the language server developed by vetur
npm install -g eslint prettier vue-language-server

To configure the layer in your .spacemacs file:

      # In `dotspacemacs/layers`
      (vue :variables
           vue-backend 'lsp)

       # Depends on whether you already configured this variable in the `javascript` layer
       (node :variable node-add-modules-path)

If you want to format the Vue file with prettier automatically upon saving, add the following:

  # In dotspacemacs/user-config
  (add-hook 'vue-mode-hook
            (lambda ()
              (add-hook 'before-save-hook #'prettier-js nil t)))

You can then enjoy Vetur-like editing capabilities in Emacs. You can find default shortcuts in the layer README.

Elixir

alchemist.el had been the go-to code intelligence tool for Elixir a couple of years ago. However, its development has stalled, and elixir-ls, which provides more complete code intelligence out of the box, is currently the recommended IDE server for Elixir.

While vscode-elixir-ls downloads and builds elixir-ls automatically, we can also manually clone and build the project, so that it can be used by Emacs (and other editors), similar to what we did with vue-language-server.

git clone git@github.com:elixir-lsp/elixir-ls.git
cd elixir-ls
mix compile
# For example, when the target Elixir version is 1.9.0
mix elixir_ls.release -o release-1.9.0

Since we have several projects with different Elixir versions, I also made sure to compile several versions of elixir-ls using asdf, each corresponding to one of the target projects. One just needs to change the .tool-versions file in elixir-ls folder before compiling and releasing again.

The newest lsp-modeprovides support for elixir-ls already. A recent PR to Spacemacs’ Elixir layer introduced support for lsp backend.

      # In `dotspacemacs/layers`:
      (elixir :variables
              elixir-backend 'lsp
              elixir-ls-path "path-to-elixir-ls/release-1.9.0"

To switch between the different versions of elixir-ls compiled for different Elixir versions, we can make elixir-ls-path a directory local variable, by having a .dir-locals.el file in the project root folder:

((elixir-mode
  (elixir-ls-path . "path-to-elixir-ls/release-1.8.1")))

To add auto formatting on save:

  # In `dotspacemacs/user-config`:
  (add-hook 'elixir-mode-hook
            (lambda ()
              (add-hook 'before-save-hook #'lsp-format-buffer nil t)))

You could also refer to the comprehensive FAQ on ElixirForum, should you have any questions regarding the setup.

Tweaks and Customizations

On MacOS, you might get an error about exceeding the maximum limit of file descriptors, since lsp-mode tries to watch the folder for changes. Some workarounds are described in this post. If none of them works, you can also disable the file watching altogether:

      (lsp :variables
           lsp-enable-file-watchers nil
           )

By default, lsp-mode displays a floating window that displays documentation following your cursor movement, which I found a bit intrusive. You can turn it off by setting lsp-ui-doc-enable to nil

      (lsp :variables
           lsp-ui-doc-enable nil)

Then one can display the documentation with , h h.


I don’t like the default behavior, where the documentation buffer pops up at the bottom of the editor. After some digging, it turns out that the *Help* buffer is controlled by popwin. By adding the following configuration, I was able to view the documentation buffer to the right of the screen:

  (setcdr (assoc "*Help*" popwin:special-display-config)
          '(:dedicated t :position right :stick t :noselect t :width 0.3))