#+TITLE: Elixir layer

#+TAGS: general|layer|multi-paradigm|programming

[[file:img/elixir.png]]

* Table of Contents                     :TOC_5_gh:noexport:
- [[#description][Description]]
  - [[#features][Features:]]
- [[#install][Install]]
  - [[#layer][Layer]]
  - [[#choosing-a-backend][Choosing a backend]]
    - [[#feature-comparison-in-backends][Feature comparison in backends]]
- [[#configuration][Configuration]]
  - [[#flycheck][Flycheck]]
    - [[#credo][Credo]]
    - [[#dogma][Dogma]]
  - [[#language-server-protocol][Language server protocol]]
  - [[#debugger][Debugger]]
- [[#key-bindings][Key bindings]]
  - [[#alchemist][Alchemist]]
    - [[#refcard][Refcard]]
    - [[#help][Help]]
    - [[#mix][Mix]]
    - [[#project][Project]]
    - [[#evaluation-in-place][Evaluation in place]]
    - [[#repl-interactions][REPL interactions]]
    - [[#tests][Tests]]
    - [[#compile][Compile]]
    - [[#execute][Execute]]
    - [[#code-definition-jump][Code Definition Jump]]
    - [[#hex-packages][Hex (packages)]]
    - [[#macro-expand][Macro expand]]
    - [[#formatting][Formatting]]
    - [[#debugging][Debugging]]
  - [[#lsp][LSP]]
    - [[#debugging-1][Debugging]]

* Description
This layer adds support for [[http://elixir-lang.org/][Elixir]].

[[https://github.com/tonini/alchemist.el][Alchemist]] brings the Elixir tooling to Emacs and comes with a bunch of features.
[[https://github.com/emacs-lsp/lsp-mode][Lsp-mode]] brings IDE like features following Language Server Protocol, through [[https://github.com/JakeBecker/elixir-ls][elixir-ls]]

As Alchemist is no longer maintained, elixir-ls is a preferred solution, even though it has less features at the moment.

** Features:
- Powerful IEx integration
- Mix integration
- Compile & Execution of Elixir code
- Inline code evaluation
- Documentation lookup
- Definition lookup
- Smart code completion
- Elixir project management
- Integration with [[http://company-mode.github.io/][company-mode]]
- Flycheck support for [[https://github.com/rrrene/credo][credo]]
- Flycheck support for test results
- Interactive debugger using [[https://github.com/emacs-lsp/dap-mode][dap-mode]]

* Install
** Layer
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =elixir= to the existing =dotspacemacs-configuration-layers= list in this
file.

** Choosing a backend
To choose a default backend set the layer variable =elixir-backend=:

#+BEGIN_SRC elisp
  (elixir :variables elixir-backend 'alchemist)
#+END_SRC

Alternatively the =lsp= backend will be automatically chosen if the layer =lsp=
is used and you did not specify any value for =elixir-backend=.

Backend can be chosen on a per project basis using directory local variables
(files named =.dir-locals.el= at the root of a project), an example to use the
=lsp= backend:

#+BEGIN_SRC elisp
  ;;; Directory Local Variables
  ;;; For more information see (info "(emacs) Directory Variables")

  ((elixir-mode (elixir-backend . lsp)))
#+END_SRC

*Note:* you can easily add a directory local variable with ~SPC f v d~.

The available options are:

| symbol     | description       |
|------------+-------------------|
| 'alchemist | Default           |
| 'lsp       | elixir-ls package |

*** Feature comparison in backends

| features                           | Alchemist | Lsp |
|------------------------------------+-----------+-----|
| Powerful IEx integration           | yes       | no  |
| Mix integration                    | yes       | no  |
| Compile & Execution of Elixir code | yes       | no  |
| Inline code evaluation             | yes       | no  |
| Documentation lookup               | yes       | yes |
| Definition lookup                  | yes       | yes |
| Smart code completion              | yes       | yes |
| Elixir project management          | yes       | no  |
| Integration with =company-mode=    | yes       | yes |
| Flycheck support                   | yes       | yes |

* Configuration
** Flycheck
*Note:* since flycheck checkers are slow, the checks are enabled only at save
time.

*** Credo
You need to install [[https://github.com/rrrene/credo][credo]] into your project. For this, add the following snippet
to dependencies of your project (in file =mix.exs=):

#+BEGIN_SRC elixir
  {:credo, "~> 0.5", only: [:dev, :test]}
#+END_SRC

Then run in your shell:

#+BEGIN_SRC shell
  $ mix deps.get
#+END_SRC

For more info about mix [[http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html][see]].

You can tell flycheck-credo to call credo with the '--strict' argument.

#+BEGIN_SRC elisp
  (setq flycheck-elixir-credo-strict t)
#+END_SRC

*** Dogma
In order to lint your code, you also need to install [[https://github.com/lpil/dogma][dogma]] into your project.
For this, add the following snippet to the dependencies in your =mix.exs= file:

#+BEGIN_SRC elixir
  {:dogma, "~> 0.1", only: [:dev]}
#+END_SRC

Then run in your shell:

#+BEGIN_SRC shell
  $ mix deps.get
#+END_SRC

** Language server protocol
The =lsp= backend uses [[https://github.com/JakeBecker/elixir-ls][elixir-ls]] as its language server implementation
Clone the project to your system and follow the building instructions [[https://github.com/JakeBecker/elixir-ls#building-and-running][here]]
Or the lsp-elixir [[https://github.com/elixir-lsp/elixir-ls][fork]], which is actively maintained as well

set the =elixir-ls-path= to the release folder of =elixir-ls= in .spacemacs =dotspacemacs/user-config=

#+BEGIN_SRC elisp
  (setq elixir-ls-path "*path to folder*/elixir-ls/release")
#+END_SRC

or in the layer definition

#+BEGIN_SRC elisp
  (elixir :variables elixir-backend 'lsp elixir-ls-path "*path to folder*/elixir-ls/release")
#+END_SRC

by default =elixir-ls-path= is equal to ="~/elixir-ls/release"=

** Debugger
For =lsp= backend only

=lsp= backend supports debugging of your elixir project through [[https://github.com/emacs-lsp/dap-mode][dap]]
simply follow [[https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Btools/dap#layer-installation][dap layer]] installation and configuration instructions
as well as make sure to read this elixir-ls [[https://github.com/elixir-lsp/elixir-ls#debugger-support][debugger support note]]

* Key bindings
** Alchemist
*** Refcard
You find and overview of all the key bindings on the [[https://github.com/tonini/alchemist.el/blob/master/doc/alchemist-refcard.pdf][Alchemist-Refcard]].

*** Help

| Key binding | Description                         |
|-------------+-------------------------------------|
| ~SPC m h :~ | Run custom search for help          |
| ~SPC m h h~ | Show help of the current expression |
| ~SPC m h H~ | Toggle through search history       |
| ~SPC m h r~ | Show help for current region        |

*** Mix

| Key binding | Description                                                |
|-------------+------------------------------------------------------------|
| ~SPC m m :~ | Prompt for a =mix= command                                 |
| ~SPC m m c~ | Compile the whole application                              |
| ~SPC m m h~ | Show help for a specific =mix= command                     |
| ~SPC m m x~ | Run the given expression in the Elixir application context |

*** Project

| Key binding | Description                                                |
|-------------+------------------------------------------------------------|
| ~SPC m g t~ | Toggle between a file and its tests in the current window. |
| ~SPC m g T~ | Toggle between a file and its tests in other window.       |

*** Evaluation in place

| Key binding | Description                             |
|-------------+-----------------------------------------|
| ~SPC m e b~ | Evaluate buffer                         |
| ~SPC m e B~ | Evaluate buffer and insert result       |
| ~SPC m e l~ | Evaluate current line                   |
| ~SPC m e L~ | Evaluate current line and insert result |
| ~SPC m e r~ | Evaluate region                         |
| ~SPC m e R~ | Evaluate region and insert result       |

*** REPL interactions

| Key binding | Description                                                     |
|-------------+-----------------------------------------------------------------|
| ~SPC m s c~ | Compiles the current buffer in the IEx process.                 |
| ~SPC m s i~ | Start an =iex= inferior process                                 |
| ~SPC m s I~ | Start an IEx process with mix (=iex -S mix=)                    |
| ~SPC m s l~ | Send current line to REPL buffer                                |
| ~SPC m s L~ | Send current line to REPL buffer and focus it in =insert state= |
| ~SPC m s m~ | Reloads the module in the current buffer in your IEx process    |
| ~SPC m s r~ | Send region to REPL buffer                                      |
| ~SPC m s R~ | Send region to REPL buffer and focus it in =insert state=       |

*** Tests

| Key binding | Description                                                                           |
|-------------+---------------------------------------------------------------------------------------|
| ~SPC m g t~ | Open the test file for current buffer                                                 |
| ~SPC m t a~ | Run all the tests                                                                     |
| ~SPC m t b~ | Run all the tests from current buffer                                                 |
| ~SPC m t B~ | Run all the tests from current file; if test file not found, after confirm, create it |
| ~SPC m t f~ | Choose test file to run                                                               |
| ~SPC m t t~ | Run test under point                                                                  |
| ~SPC m t r~ | Rerun the last test                                                                   |
| ~SPC m t n~ | Jump to next test                                                                     |
| ~SPC m t N~ | Jump to previous test                                                                 |
| ~SPC m t s~ | Run stale tests (~mix test --stale~)                                                  |
| ~SPC m t R~ | Toggle test report window                                                             |
| ~SPC m t F~ | Open project test directory and list all test files.                                  |

*** Compile

| Key binding | Description                                        |
|-------------+----------------------------------------------------|
| ~SPC m c :~ | Run a custom compile command with =elixirc=        |
| ~SPC m c b~ | Compile the current buffer with elixirc. =elixirc= |
| ~SPC m c f~ | Compile the given filename with =elixirc=          |

*** Execute

| Key binding | Description                                |
|-------------+--------------------------------------------|
| ~SPC m x :~ | Run a custom execute command with =elixir= |
| ~SPC m x b~ | Run the current buffer through =elixir=    |
| ~SPC m x f~ | Run =elixir= with the given filename       |

*** Code Definition Jump

| Key binding | Description                                        |
|-------------+----------------------------------------------------|
| ~SPC m g g~ | Jump to the elixir expression definition at point. |
| ~SPC m .~   | Jump to the elixir expression definition at point. |
| ~SPC m g b~ | Pop back to where ~SPC m g g~ was last invoked.    |
| ~SPC m ,~   | Pop back to where ~SPC m g g~ was last invoked.    |
| ~SPC m g n~ | Jump to next symbol definition                     |
| ~SPC m g N~ | Jump to previous symbol definition                 |
| ~SPC m g j~ | Choose which symbol definition to jump to          |

*** Hex (packages)
Hex is the package manager for Elixir & Erlang ecosystem. See [[https://hex.pm]].

| Key binding | Description                                              |
|-------------+----------------------------------------------------------|
| ~SPC m X i~ | Display Hex package information for the package at point |
| ~SPC m X r~ | Display Hex package releases for the package at point    |
| ~SPC m X R~ | Display Hex package releases for a certain package       |
| ~SPC m X I~ | Display Hex package info for a certain package           |
| ~SPC m X s~ | Search for Hex packages                                  |

*** Macro expand

| Key binding | Description                                                                       |
|-------------+-----------------------------------------------------------------------------------|
| ~SPC m o l~ | Macro expand once the Elixir code on the current line                             |
| ~SPC m o L~ | Macro expand once the Elixir code on the current line and insert the result       |
| ~SPC m o k~ | Macro expand completely the Elixir code on the current line                       |
| ~SPC m o K~ | Macro expand completely the Elixir code on the current line and insert the result |
| ~SPC m o i~ | Macro expand once the Elixir code on marked region                                |
| ~SPC m o I~ | Macro expand once the Elixir code on marked region once and insert the result     |
| ~SPC m o r~ | Macro expand completely the Elixir code on marked region                          |
| ~SPC m o R~ | Macro expand completely the Elixir code on marked region and insert the result    |

*** Formatting

| Key binding | Description               |
|-------------+---------------------------|
| ~SPC m =~   | Format the current buffer |

*** Debugging

| Key binding | Description               |
|-------------+---------------------------|
| ~SPC m d b~ | Toggle IEx.pry breakpoint |

** LSP
You find and overview of all the key bindings on the [[https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Btools/lsp#key-bindings][lsp layer description]].

*** Debugging
Using the =dap= layer you'll get access to all the DAP key bindings, see the
complete list of key bindings on the [[https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Btools/dap#key-bindings][dap layer description]].
