Doom-emacs + scala + metals

5 minute read Published: 2019-10-05

I've seen a few people on twitter recommend emacs for haskell, but then go on to say they don't know how to use emacs at all. I got into emacs (specifically spacemacs) when working through Programming Languages Part A on Coursera a few years back as it had a standard-ml mode. I've moved on from spacemacs to something called doom-emacs which is lovely and easy to setup and still has evil (vim) mode.

I have no idea how to use most of emacs-mode.

This is a (WIP) guide for using doom-emacs w/ scala and metals.

EMACS

You will need to install emacs (>= 25.1) for this. I use emacs26. Figure out how to do this on whatever distribution you have. I've tested it on ubuntu/mac and had no problems other than having to compile it on mac.

DOOM-EMACS

Grab a copy of doom-emacs from here. We are going to skip the master branch and go straight to the develop branch.

git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
mkdir ~/.doom.d
cd ~/.emacs.d
git checkout develop
bin/doom install

This will get you a minimal setup going. Edit ~/doom.d/init.el and uncomment the following besides the defaults: lsp, term, neotree. For languages do what you like (may I suggest haskell, purescript, elm?). When you uncomment scala replace it with (scala +lsp) Save the file. Go back to your ~/.emacs.d dir and run bin/doom refresh.

METALS

You need to install the metals-emacs client(?). Go here and scroll down for how to build metals-emacs. Change /usr/local/bin/metals-emacs to point at something in your path (in my case it was ~/.local/bin.

You also need to set a JAVA_HOME properly

CUSTOMIZING DOOM-EMACS

This is much easier than it used to be. Put all your stuff in `~/.doom.d/config.el~ now. Some super fancy stuff can be found here. But I don't recommend loading it. Peruse for how to customize your own stuff. There is some docs around this on the doom-emacs github page.

I like line numbers, a certain font, and some settings for code completion so mine looks like

(setq doom-font (font-spec :family "Hasklig" :size 15))
(load-theme 'doom-palenight t)

(when (version<= "26.0.50" emacs-version )
  (global-display-line-numbers-mode))

;; company-mode auto-completion, to turn off use :company-complete
(require 'company)
(setq company-idle-delay 0.2
      company-minimum-prefix-length 3)

USING DOOM-EMACS WITH METALS

Nothing gets bound to help you run language server commands. Most the language server isn't implemented and I'm still figuring out what works and what doesn't. The docs on the official site are terrible here.

In your ~/.doom/config.el do something like the following:

;; scala metals binds 

(map! :map scala-mode-map
      "C-c C-t" #'lsp-ui-doc-show               ;; shows type under cursor as a hover 
      "C-c T" #'lsp-describe-thing-at-point     ;; shows type under cursor in temp buffer below
      "C-c H" #'lsp-ui-doc-mode                 ;; toggle auto-showing type under cursor as a hover  
      "C-c F" #'lsp-format-buffer               ;; run scalafmt on the entire buffer
      "C-c f" #'lsp-format-region               ;; run scalafmt on the selected region
)

I'm still trying to figure out go to type under cursor via some lsp commands. You can access the lsp commands via M-x and then typing lsp- but none of the type ones seem to implemented? For now you can use:

The keys you bound are bound to the major mode. When in a scala file if you Ctrl-c (hence C-c) those will be bound for you. E.g. Ctrl-c Ctrl-t is C-c C-t. If you see docs that say M-x that means Alt-x.

You will probably be opening a ton of buffers. So look into buffer management in spc-b to close the ones you aren't using after jumping around. Jump to definition mostly works, including into library sources, but sometimes craps out on some library functions that I know it can see since it's giving me the type info. I suspect I'm missing a certain lsp- command but I can't figure out which one! If you know, let me know on twitter.

Navigate to a scala project. If it's a git project the first time you run emacs in that dir it will get added to the projectile projects so you can just run emacs globally and use spc-p-p to switch to the project. If it's not a git repo, you can manually add it to the list of projectile projects (look undo spc-p for how to do this. If everything is setup correctly you should get a prompt to import the project using metals. You can check the status of the import by using spc-b-B and looking for the metals buffer which may give you a helpful log if things are not working. You can also M-x and run a few metlas commands (use M-x and then type metals to see what they are).