Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Name of executable (why -wrapper?) #101

Open
Profpatsch opened this issue Jan 10, 2021 · 2 comments
Open

Name of executable (why -wrapper?) #101

Profpatsch opened this issue Jan 10, 2021 · 2 comments

Comments

@Profpatsch
Copy link

lsp-haskell/lsp-haskell.el

Lines 162 to 166 in 5d3f481

(defcustom lsp-haskell-server-path
"haskell-language-server-wrapper"
"The language server executable. Can be something on the $PATH (e.g. 'ghcide') or a path to an executable itself."
:group 'lsp-haskell
:type 'string)

I am trying to set up the haskell-language-server, and I’m wondering why the default executable name in this module is called haskell-language-server-wrapper instead of just haskell-language-server. As far as I can see the latter is how hls expects users to call the binary.

@alanz
Copy link
Contributor

alanz commented Jan 10, 2021

If you install hls the expected way, via downloading the executables using ghcup, you actually end up with a set of binaries, one per GHC version, and one called haskell-language-server-wrapper.

The wrapper exe works out which GHC version is used for the file/project being opened, and then execs the appropriate GHC-specific haskell-language-server version.

@Anton-Latukha
Copy link
Contributor

Anton-Latukha commented Jan 31, 2021

Indeed.

In other words. wrapper in HLS does what is needed to abstract the environment complexities from the server HLS implementation.
For example, a while ago I wanted to add Nix environment support to the wrapper, but was rebuffed. And maybe rightfully so. Maybe Nix needs indeed be outside for the HLS, or be a Cradle implementation. Nix community itself can not standardize the approach and even an entry point, it is custom who-likes-what implementations all the way. But that is another topic.

wrapper is there to abstract env that particular project developer uses. Wrapper reads Cradle information, differentiates between Cabal & Stack project setups and package resolution, and resolves the GHC version - all that resolves to what developer has chosen to use currently in the project, which allows to load the according fully compatible (hopefully) with that env HLS - that uses the same resolving process (Cabal, Hackage, Stack, Stackage, (Nix, Nixpkgs if run inside Nix env)) and loads the HLS that compiled in and supports the same version of the GHC that project is developed in.

Without the wrapper we would ask Alan and others HLS devs to "just support" binaries of HLS compiled to arbitrary GHC be ready for and support internalls of other arbitrary GHCs all at once. The wrapper allows them to abstract from project environments and dependencies resolution and concentrates on supporting recent GHC branches, and ship single HLS-API-GHC pairings:

Oversimplification:

wrapper :: GhcVer -> IO Hls
wrapper ghcVer = (\v -> interfaceWith v $ runFor v $ compileTo v $ implementHlsFor v) ghcVer

If you want - they essentially recreate the static environment for themself (as Nix project envs do), and consistent single entry point for us.

The downside - is that we need to load and store several HLS backends, just like in Nix downside.:

haskell-language-server-wrapper -> haskell-language-server-wrapper-0.8.0

haskell-language-server-wrapper-0.8.0
haskell-language-server-8.6.4 -> haskell-language-server-8.6.4~0.8.0
haskell-language-server-8.6.4~0.8.0
haskell-language-server-8.6.5 -> haskell-language-server-8.6.5~0.8.0
haskell-language-server-8.6.5~0.8.0
haskell-language-server-8.8.2 -> haskell-language-server-8.8.2~0.8.0
haskell-language-server-8.8.2~0.8.0
haskell-language-server-8.8.3 -> haskell-language-server-8.8.3~0.8.0
haskell-language-server-8.8.3~0.8.0
haskell-language-server-8.8.4 -> haskell-language-server-8.8.4~0.8.0
haskell-language-server-8.8.4~0.8.0
haskell-language-server-8.10.1 -> haskell-language-server-8.10.1~0.8.0
haskell-language-server-8.10.1~0.8.0
haskell-language-server-8.10.2 -> haskell-language-server-8.10.2~0.8.0
haskell-language-server-8.10.2~0.8.0
haskell-language-server-8.10.3 -> haskell-language-server-8.10.3~0.8.0
haskell-language-server-8.10.3~0.8.0

haskell-language-server-wrapper-0.9.0
haskell-language-server-8.6.4~0.9.0
haskell-language-server-8.6.5~0.9.0
haskell-language-server-8.8.2~0.9.0
haskell-language-server-8.8.3~0.9.0
haskell-language-server-8.8.4~0.9.0
haskell-language-server-8.10.1~0.9.0
haskell-language-server-8.10.2~0.9.0
haskell-language-server-8.10.3~0.9.0

If haskell-language-server-wrapper looks like executable in Nix user profile env entry, and the chain looks like closure resolution for compiled binaries - because it is, it does the same thing for the particular purpose of shipping HLS portable for "all" Haskell ecosystems.

The upside - they have the same frontend executable entry point and the perfect HLS-for-GHC pairings so HLS works for everybody. And they have lightweight wrapper that supports everybody, without the need for anyone to force into learn/maintain Nix, have coupling/maintenance of revs and coupling on Nixpkgs version resolutions and so on. Their simple solution so far works for everybody.

Otherwise, they would've needed support the Cartesian product of Haskell envs possible.

And with the Haskell env ecosystem fragmentation and nuances... they need a wrapper simplification to abstract from it.

The existence and reliance on the wrapping of HLS is a Haskell env ecosystem fragmentation question and HLS upstream implementation simplification, it is not Emacs lsp-haskell package question in any shape or form. And I am happy that it works nicely for HLS devs and for Haskell devs.

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

No branches or pull requests

3 participants