Navigating Elixir Standard Library in Emacs

Short answer : Compile Elixir yourself

Long answer :

Many times I find myself exploring Elixir source code in a separate frame. Either to learn how something is implemented or to know how something is used. What is a better reference to learn a language than the language source itself?

I'm using elixir-ls language server with Eglot as LSP front-end. elixir-ls internally use elixir-sense to get relevant information from source. A quick look at elixir-sense revealed that every module has source metadata attached to it. This metadata points to the source file from which beam file is generated. Since its done by Erlang, both Erlang and Elixir modules have this information as metadata. You can check this in iex.

iex(3)> Enum.module_info(:compile)
[
  version: '7.2.6',
  options: [],
  source: '/private/tmp/elixir-20181026-69137-ms45yr/elixir-1.7.4/lib/elixir/lib/enum.ex'
]

Since brew by default installs pre-built binaries. The source path is invalid in my machine. So to have correct source, we just have to compile it locally.

It's fairly easy to compile with asdf

Install asdf

Follow the instructs at asdf

Install correct erlang/OTP plugin

Note that each version of elixir supports a specific version of erlang/OTP version, make sure you install the correct version. I wanted to use elixir 1.7.4, I installed Erlang/OTP 21.2. Check asdf-erlang.

Install elixir with ref tag

asdf-elixir installs pre-built binaries if you just use version tags. you need to use ref:<commit_sha> for compiling from source. see releases to find the commit id for a particular release. Check asdf-elixir.

In my case, it will be

asdf plugin-add elixir
asdf plugin-add erlang

asdf install erlang 21.2
asdf global erlang 21.2

asdf install elixir ref:eb5679b
asdf global elixir ref:eb5679b

Now source should point to correct local path for both Elixir and Erlang modules

iex(2)> Enum.module_info(:compile)[:source]
'/Users/akash/.asdf/installs/elixir/ref-eb5679b/lib/elixir/lib/enum.ex'

iex(3)> :ets.module_info(:compile)[:source]
'/Users/akash/.asdf/plugins/erlang/kerl-home/builds/asdf_21.2/otp_src_21.2/lib/stdlib/src/ets.erl'

With this source code navigation works as expected in the Emacs

Bonus Tip

Mostly likely that you don't want to modify any of the elixir/Erlang source files. You can use M-x projectile-toggle-project-read-only to always open these files with read-only mode.