# "Embedded" LSP Server

## New Elixir LSP Server design

The old/current elixir-ls project starts a language server per project, running the language server in the
project's directory so that things like asdf-vm pick up the project's version of OTP and Elixir, which is
what we want. This has two major drawbacks:

* Elixir-LS gets compiled with the lowest supported OTP/Elixir versions, but that can introduce incompatibilities
  between the two versions that are now in play (compile time and run time). This happened, for example, with the
  big logging overhauls in Erlang.

* The server that gets started now contains the language server applications, including their dependencies, which
  may include common dependencies like a JSON parser. This can cause conflicts between elixir-ls dependencies and
  project dependencies.

The new design tries to solve this by running a BEAM instance per project and one "controller" that runs the show. The
controller contains all of Elixir-LS, and the per-project BEAM instances contain just a very small application with
a random (and therefore hopefully unique) name and no dependencies. Inter-BEAM communications works through Erlang

The new startup sequence is:

* The wrapper script compiles, using the project OTP/Elixir, this application caches it;
* The wrapper script starts the just-compiled application;
* The application enables clustering and tries to find the Elixir-LS process under a well-known global name;
* If it is not found, Elixir-LS is started using its distribution in the background and the finding is retried;
* The embedded server registers with Elixir-LS and starts piping stdin/stdout to it;
* Elixir-LS handles the LSP protocol, as usual, but calls back to the embedded server for anything it needs
  to figure out.

It is a little bit roundabout and makes implementing Elixir-LS somewhat harder because of all the remote calls, but
it solves all the versioning problems.

This application contains the per-beam code and therefore cannot contain any dependencies; also, it is compiled
at run-time to make sure that there are no incompatibilities.

Note that there is a potential for conflict with another application called `eels`. This can be alleviated simply
by renaming this application to something obscure, like `eels_24692c715a9dc2f8c3a88632dbb18704` but that's probably
best postponed to when it actually is needed. To reduce the change of this happening, `eels` is published as
a Hex package.