Skip to content

Conversation

@smaximov
Copy link
Contributor

@smaximov smaximov commented Aug 28, 2023

Greetings!

elixir_sense uses mod.module_info(:compile)[:source] in order to retrieve the source file for a module. While it works for regular Elixir files and dependencies, it fails for the Elixir sources (i.e., for the applications like :elixir, :ex_unit, :eex that ship with Elixir) if Elixir was built in a sandboxed environment. That happens, for example, on NixOS as it returns a path to a build location that no longer exists:

iex(1)> String.module_info(:compile)[:source]
'/build/source/lib/elixir/lib/string.ex'

("/build/source" refers to a location that contained Elixir source while it was being built inside a sandbox.)

Despite that, on NixOS it's easy to install the Elixir source as a package and provide the path to it as an environment variable.

Click me to get NixOS-specific info!

flake.nix:

{
  inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; };

  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems =
        [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
      perSystem = { config, self', inputs', pkgs, system, ... }: {
        devShells.default = with pkgs;
          mkShell {
            name = "elixir_ls";

            # Define packages that will be available for our project
            buildInputs = [ elixir erlang elixir_ls ];

            ERL_AFLAGS = "-kernel shell_history enabled";

            # Define envvar $ELIXIR_SRC that points to Elixir sources, it looks like this:
            # /nix/store/cq9kb2qq08y95j2ym4by6f3jk0ix9sni-source
            ELIXIR_SRC = "${elixir.src}";
          };
      };
    };
}

This PR makes ElixirSense.Location to look up Elixir sources under the configured location as a fallback. This will allow for code navigation to Elixir sources to work on environments like NixOS.

Sadly, I have no idea how to write tests for this, so any suggestion is appreciated. Meanwhile I tested it manually on my machine in an IEX session:

iex(1)> ElixirSense.Location.find_mod_fun_source(String, :length, 1)
nil
iex(2)> ElixirSense.Location.find_type_source(DateTime, :t, 0)
nil
iex(3)> elixir_src = System.get_env("ELIXIR_SRC")
"/nix/store/cq9kb2qq08y95j2ym4by6f3jk0ix9sni-source"
iex(4)> Application.put_env(:elixir_sense, :elixir_src, elixir_src)
:ok
iex(5)> ElixirSense.Location.find_mod_fun_source(String, :length, 1)
%ElixirSense.Location{
  type: :function,
  file: "/nix/store/cq9kb2qq08y95j2ym4by6f3jk0ix9sni-source/lib/elixir/lib/string.ex",
  line: 2017,
  column: 3
}
iex(6)> ElixirSense.Location.find_type_source(DateTime, :t, 0)
%ElixirSense.Location{
  type: :typespec,
  file: "/nix/store/cq9kb2qq08y95j2ym4by6f3jk0ix9sni-source/lib/elixir/lib/calendar/datetime.ex",
  line: 125,
  column: 3
}

If this PR is merged, I will open another one in https://github.com/elixir-lsp/elixir-ls that will read $ELIXIR_SRC at the server startup and configure :elixir_sense accordingly.

@smaximov smaximov force-pushed the specify-elixir-src branch from a6d97b7 to 0c69496 Compare August 28, 2023 21:39
@smaximov
Copy link
Contributor Author

I added two basic tests, but they will work only in environments that don't have Elixir sources. Please let me know what you think.

@smaximov smaximov force-pushed the specify-elixir-src branch from 0c69496 to 567ccf8 Compare August 28, 2023 21:41
@smaximov smaximov force-pushed the specify-elixir-src branch from 567ccf8 to 372ab29 Compare August 28, 2023 21:54
@lukaszsamson
Copy link
Collaborator

Nice, that was something on my todo list.

I added two basic tests, but they will work only in environments that don't have Elixir sources. Please let me know what you think.

Fake elixir source file is a right way here

Would you mind creating a similar PR adding OTP source location?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants