- About
hls-wrapper-nix
- Installation
- Editor configuration
- Default operation
- Configuring by file
- Testing a project
- Command-line reference
Our editors need to call HLS, but to get better control of dependencies, some of our projects may need to have HLS invoked within a Nix shell. HLS needs to run in an environment with all the project's dependencies.
Most editors with support for the Language Server Protocol (LSP) have a configuration to specify which executable to call to run HLS for a project. If you used the upstream-recommended haskell-language-server-wrapper
, then HLS would start, but not with the environment provided by a project's Nix shell.
To get HLS running in the correct environment, this project provides a hls-wrapper-nix
script that will call haskell-language-server-wrapper
from within a Nix shell if detected or requested (configurable per-project).
Even if your projects don't require a Nix shell yet, using hls-wrapper-nix
as a replacement for haskell-language-server-wrapper
is simple, and provides you flexibility in the future.
This document discusses installation and configuration of hls-wrapper-nix
. We assume you're familiar with everything discussed in the root-level README file.
Note that you shouldn't use the HLS Nix wrapper script if you're using Direnv and Lorelei to solve the same problem. Direnv and Lorelei has more configuration steps, but can help if the time to enter a Nix shell is too long and annoying.
Install hls-wrapper-nix
with the Nix expression provided by this project.
If you followed the root-level README's section on a user-based installation, you likely have already installed the script. If not, you can execute the following:
nix-env --install --file . --attr hls-wrapper-nix
installing 'hls-wrapper-nix'
A Language Server Protocol (LSP) -enabled editor will need to know what LSP service to load for a given project. For Haskell projects, the official HLS instructions recommend specifying haskell-language-server-wrapper
. You'll use hls-wrapper-nix
instead.
How this configuration is specified will vary based on the editor. See the documentation for the plugin your editor uses to provide LSP support.
By default, the HLS Nix wrapper will detect if a project has a shell.nix
or default.nix
file, and if so load haskell-language-server-wrapper
from within a Nix shell. Any arguments not parsed by hls-wrapper-nix
are passed through to haskell-language-server-wrapper
, including the --lsp
switch used by editors to start HLS as a background process.
The Nix shell is invoked with --pure
by default, which means that any environment variables in your normal user's environment are not available to the invocation of haskell-language-server-wrapper
, only the environment variables configured by your project's Nix expression.
The defaults of hls-wrapper-nix
may not be appropriate for every project you want to use with HLS. Consider these scenarios:
- Your project needs to use another Nix file than the detected
shell.nix
ordefault.nix
. - Your project needs to run an impure Nix shell (no
--pure
switch) so tools installed outside the Nix shell are also included in the environment HLS runs in.
Though hls-wrapper-nix
can be configured with CLI switches, doing so would require configuring our editors to call different projects differently. Some editors don't make this easy. Furthermore, we'd have to do this configuration for each editor we want to use with HLS.
Instead, we recommend you configure hls-wrapper-nix
with a centralized configuration file. By default this configuration file will be read from ~/.config/haskell-language-server/wrapper-nix.yaml
.
This file is in the YAML format, and maps a canonical filepath for your project to the project's configuration for hls-wrapper-nix
.
The canonical filepath mostly resolves symlinks. As a convenience, you can use nix-wrapper-nix --show-path "$SOME_PATH"
to see exactly how a filepath canonicalizes.
You can configure the following per-project in your YAML file:
mode
: either "detect", "shell", or "bypass"detect
: the default behavior to autodetect whether a project requires anix-shell
invocation.shell
: force invoking HLS from within a Nix shellbypass
: invoke HLS directly, bypassing a Nix shell invocation
shell_file
: the relative path to a Nix file to callnix-shell
with (implies amode
of "shell")pure
: a boolean indicating whether to invokenix-shell
with--pure
The following is an example of a valid configuration:
/home/youruser/src/some-project:
- shell_file: shell-alt.nix
- pure: false
/home/youruser/src/another-project:
- mode: bypass
You should be able to test your configuration of hls-wrapper-nix
by running it with no arguments at the root of a Haskell project. It should exit successfully with no reported errors.
We can use the provided example projects to illustrate this test. Here's a run of hls-wrapper-nix
on the Cabal example project:
hls-wrapper-nix --cwd examples/example-cabal
INFO: Entering pure Nix shell
Found "/home/tnks/src/shajra/haskell-hls-nix/examples/example-cabal/hie.yaml" for "/home/tnks/src/shajra/haskell-hls-nix/examples/example-cabal/a"
Run entered for haskell-language-server-wrapper(haskell-language-server-wrapper) Version 1.4.0.0 x86_64 ghc-8.10.7
…
Completed (5 files worked, 0 files failed)
2021-09-21 02:11:20.16832857 [ThreadId 383] INFO hls: finish: GenerateCore (took 0.00s)
And here we see that the script works for the Stack example project as well:
hls-wrapper-nix --cwd examples/example-stack
INFO: Entering pure Nix shell
No 'hie.yaml' found. Try to discover the project type!
Run entered for haskell-language-server-wrapper(haskell-language-server-wrapper) Version 1.4.0.0 x86_64 ghc-8.10.7
…
Completed (3 files worked, 0 files failed)
2021-09-21 02:13:13.261875187 [ThreadId 643] INFO hls: finish: GenerateCore (took 0.00s)
We recommend configuring hls-wrapper-nix
with a file, but there are CLI switches for configuration that override the configuration file. You may find these useful for testing.
For reference, here's the output of running hls-wrapper-nix --help
:
USAGE: hls-wrapper-nix [OPTION]... [HLS_OPTIONS]...
hls-wrapper-nix --show-path PATH
hls-wrapper-nix --help
DESCRIPTION:
Run the Haskell Language Server wrapper, possibly in a Nix Shell.
OPTIONS:
--help print this help message
--show-path PATH print path to use in configuration file
--config PATH configuration file to read instead of default
--shell-file PATH explicitly specified Nix file for shell
--auto-detect don't run in Nix shell if not clear how (default)
--shell-always always run in a Nix shell
--shell-never never run in a Nix shell
--pure run pure Nix shell (no external environment)
--impure allow external environment variables in Nix shell
--nix PATH filepath to 'nix' binary to put on PATH
Note, when using options concurrently (like '--auto-detect',
'--shell-always', or '--shell-never'), the last one has precedent.
HLS OPTIONS:
--version Show haskell-language-server-wrapper and GHC versions
--numeric-version Show numeric version of
haskell-language-server-wrapper
--probe-tools Show haskell-language-server-wrapper version and
other tools of interest
--list-plugins List all avaliable plugins
--print-cradle Print the project cradle type
--lsp Start talking to an LSP server
--cwd DIR Change to this directory
--shake-profiling DIR Dump profiling reports to this directory
--test Enable additional lsp messages used by the testsuite
--example Include the Example Plugin. For Plugin devs only
-d,--debug Generate debug output
-l,--logfile LOGFILE File to log to, defaults to stdout
-j NUM Number of threads (0: automatic) (default: 0)
--project-ghc-version Work out the project GHC version and print it
Available commands:
typecheck Used as a test bed to check your IDE will work
hiedb Query .hie files
lsp Start talking to an LSP client
vscode-extension-schema Print generic config schema for plugins (used in the
package.json of haskell vscode extension)
generate-default-config Print config supported by the server with default
values