#+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]].