vscode-elixir-ls icon indicating copy to clipboard operation
vscode-elixir-ls copied to clipboard

Navigation leads user to the elixir stdlib but user can't navigate the stdlib

Open giuscri opened this issue 3 years ago • 3 comments

Environment

  • Elixir & Erlang versions (elixir --version): 1.13.4
  • Elixir Language Server version: v0.11.0
  • Operating system: macOS 12.4
  • Editor or IDE name (e.g. Emacs/VSCode): VSCode
  • Editor Plugin/LSP Client name and version: ElixirLS v0.11.0

Current behavior

  • Open file containing IO.puts("")
  • ctrl-click on puts, navigate to the io.ex file from the stdlib
...
  def puts(device \\ :stdio, item) when is_device(device) do
    :io.put_chars(map_dev(device), [to_chardata(item), ?\n])
  end
...
  • Try to ctrl-click on :io.put_chars or map_dev but it does nothing

Expected behavior

  • Open file containing IO.puts("")
  • ctrl-click on puts, navigate to the io.ex file from the stdlib
...
  def puts(device \\ :stdio, item) when is_device(device) do
    :io.put_chars(map_dev(device), [to_chardata(item), ?\n])
  end
...
  • ctrl-click on :io.put_chars should lead to the erlang implementation; ctrl-click on map_dev should lead you to the implementation on io.ex

giuscri avatar Aug 24 '22 19:08 giuscri

I can confirm that the issue is that vscode is not sending requests to the server at all

lukaszsamson avatar Oct 06 '22 15:10 lukaszsamson

Unfortunately this issue can't be fixed without breaking multiroot workspace support. When we create a language client for a workspace folder (e.g. /home/src/my_project) we pass a document selector {language: "elixir", scheme: "file", pattern: "/home/src/my_project/**/*"}. This way we can direct requests to language server instance running in that directory.

Obviously the path to standard lib won't match that glob pattern. We have to set this pattern as otherwise VSCode will send multiplicated request to each language server in each workspace folder.

Note that the issue is not present when no workspace folders are open. In that case we create a default language client with {language: "elixir", scheme: "file"} document selector that gets all the requests.

We cannot create the default server when there are workspace folders as VSCode passes rootUri of the first workspace folder anyway. This leads to 2 servers running in the same directory. If we won't start dedicated server in first workspace folder, then the default one will be getting requests from all other clients.

We cannot use negative glob patterns to filter requests - there's no such API in VSCode. Middleware API does not support easy filtering and would require overriding every request type.

Possible workarounds:

  1. Adding stdlib as workspace folder - this way it will get it's own language server instance
  2. Starting dedicated language client for stdlib - the extension would need to know the path to stdlib to create a glob pattern
  3. Starting default client with initializationOptions so that language server can know it's a default instance that should not run mix etc. and filter requests for things related to workspace folder - complicated and not likely
  4. Some solution combining 2 and 3 - possible but still complicated
  5. Refactoring language server and extension to start only one instance - not likely

lukaszsamson avatar May 10 '23 21:05 lukaszsamson

Actually when working on 46284e3d6983973d04130fbbbe996cd077a6f8f6 I've made a fix for one of the scenarios - single folder workspace. So now:

  • working when no workspace and no workspace folder is open
  • working when no workspace and a single folder is open (AKA single folder workspace)
  • not working when workspace is open (aka multi-root workspace)

Another news is in vscode-languageclient v8.2 a new support for request middleware is going to be introduced https://github.com/microsoft/vscode-languageserver-node/issues/1229

lukaszsamson avatar May 11 '23 21:05 lukaszsamson