github soundcloud
scala
Nov 9, 2019
2 minutes read

This post describes the prerequisites to get my Emacs config to work with Scala, sbt, Metals and lsp-mode on macOS.

On Mac we need Java 8 for Metals (see SO):

brew tap adoptopenjdk/openjdk

brew cask install adoptopenjdk8

brew cask info adoptopenjdk/openjdk/adoptopenjdk8

Install coursier:

brew install coursier/formulas/coursier

Coming from Python, coursier seems pretty nice and well thought out. coursier bootstrap seems to be similar to pipx, pipsi or shiv - creating a small jar file that fetches dependencies on first run.

coursier is a dependency resolver / fetcher à la Maven / Ivy, entirely rewritten from scratch in Scala. It aims at being fast and easy to embed in other contexts. Its core embraces functional programming principles.

It handles many features of the Maven model, and is able to fetch metadata and artifacts from both Maven and Ivy repositories. It handles parallel downloads out-of-the-box without resorting to global locks.

We can also tell sbt to use coursier for fetching dependencies.

Anyway, let’s install scalafmt using coursier bootstrap:

coursier bootstrap org.scalameta:scalafmt-cli_2.12:2.2.2 \
  -r sonatype:snapshots \
  -o /usr/local/bin/scalafmt --standalone --main org.scalafmt.cli.Cli

You might consider changing -o - -o ~/bin/scalafmt would be a safe bet.

I use reformatter.el to easily run scalafmt on every save:

(use-package reformatter
  :config (reformatter-define scalafmt :program "scalafmt" :args '("--stdin")))

This creates the functions scalafmt-buffer and scalafmt-on-save-mode among others. So I set it up with a hook:

(use-package scala-mode
  :mode "\\.s\\(cala\\|bt\\)$"
  :gfhook '(scalafmt-on-save-mode))

See my Emacs config for more details.

Now run a even stranger coursier command to install metals-emacs (the Language Server Protocol server):

coursier bootstrap \
  --java-opt -Xss4m \
  --java-opt -Xms100m \
  --java-opt -Dmetals.client=emacs \
  org.scalameta:metals_2.12:0.7.6 \
  -r bintray:scalacenter/releases \
  -r sonatype:snapshots \
  -o /usr/local/bin/metals-emacs

You might want to consider changing -o - maybe -o ~/bin/metals-emacs.

Now, lsp-mode knows how to look for metals-emacs as long as its in your PATH.

Before trying Emacs, I tested with VS Code and noticed it complained about not being able to find Java 8. So I figured it will probably also fail with lsp-mode. I found the lsp-metals-java-home variable and set it as such:

(setq lsp-metals-java-home "/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home")

I don’t know how to know about that folder, I just came across it while searching the web. Later I have learnt that you can run /usr/libexec/java_home -V to see all your Java homes. This tool is included in macOS.

Setting JAVA_HOME on Mac OS

Confusion settles.


Back to posts