At this time (2023-06-14), nixd is under rapid development and it is highly recommended to install nixd from source.
Package nixd
can be found in nixpkgs, there are different ways to install nixd, pick your favourite:
NixOS Configuration
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [
nixd
];
}
nix-env(legacy commands)
On NixOS:$ nix-env -iA nixos.nixd
On Non NixOS:
$ nix-env -iA nixpkgs.nixd
nix profile
$ nix profile install github:nixos/nixpkgs#nixd
And our flake.nix provides a package named nixd
, and an overlay to nixpkgs that add the nixd
package.
Note that please do NOT override nixpkgs revision for nixd inputs. The source code have tested on specific version on NixOS/nix, which may not work at your version.
This is a guide for build the project from git source.
nix-build --expr 'with import <nixpkgs> { }; callPackage ./. { }'
nix build -L .#
We support LSP standard workspace/configuration
for server configurations.
Configuration overview:
Note: we support a configuration file named .nixd.json
at your workspace directory.
This is a feature requested by nvim users.
Typically, you can write a nix file, and evaluate the result into .nixd.json
, because json does not support comments:
# .nixd.nix
{
eval = {
# Example target for writing a package.
target = {
args = [ "--expr" "with import <nixpkgs> { }; callPackage ./somePackage.nix { }" ];
installable = "";
};
# Force thunks
depth = 10;
};
formatting.command = "nixpkgs-fmt";
options = {
enable = true;
target = {
args = [ ];
# Example installable for flake-parts, nixos, and home-manager
# flake-parts
installable = "/flakeref#debug.options";
# nixOS configuration
installable = "/flakeref#nixosConfigurations.<adrastea>.options";
# home-manager configuration
installable = "/flakeref#homeConfigurations.<name>.options";
};
};
}
nix eval --json --file .nixd.nix > .nixd.json
Unlike any other nix lsp implementation, you may need to explicitly specify a installable
in your workspace.
The language server will consider the installable
is your desired "object file", and it is the cross-file analysis pivot.
For example, here is a nix pacakge:
{ stdenv
, lib
}:
stdenv.mkDerivation {
pname = "...";
version = "...";
}
From a language perspective, the lambda expression only accepts one argument and returns an AttrSet, without any special properties of a "package". So how do we know what argument it will accept?
For nixd, you can write a project-specific installable that will be evaluated. e.g.
nix eval --expr "with import <nixpkgs> { }; callPackage ./some-package.nix { }"
We accept the same argument as nix eval
, and perform evaluation for language analysis.
{
"eval": {
"target": {
// Same as:
// nix eval --expr "..."
"args": [
"--expr",
"with import <nixpkgs> { }; callPackage ./some-package.nix { } "
],
// AttrPath
"installable": ""
}
}
}
This is much similar to compile_commands.json
in C/C++ world.
Here is the demo video that I used the above installable in my workspace:
Nix evaluator will be lazily peform evaluation on your specified task1.
As for language service, we have an custom extension to nix evaluator that allows you to force thunks being evaluated in a desired depth.
{
"eval": {
"depth": 5
}
}
Nixd evals your project concurrently. You can specify how many workers will be used for language tasks, e.g. parsing & evaluation.
{
"eval": {
"workers": 5
}
}
The default value is std::thread::hardware_concurrency()
.
To configure which command will be used for formatting, you can change the "formatting" section.
{
"formatting": {
// The external command to be invoked for formatting
"command": ""
}
}
This is our support for nixpkgs option system.
Generally options are merged under a special attribute path. For example, NixOS options could be found at:
<flakeref>#nixosConfigurations.<name>.options
And, home-manager options also could be found at:
<flakeref>#homeConfigurations.<name>.options
In our option system, you need to specify which option set you'd like to use.
{
"options": {
// Disable it if you are not writting modules.
"enable": true,
"target": {
"args": [],
// Example of NixOS options.
"installable": "<flakeref>#nixosConfigurations.<name>.options"
}
}
}
The eval subsystems requires flakes evaluating in-place to get language callbacks. The options subsystem does not need to eval flakes in-place.
However, nix flakes are now hardcoded being evaluated in your store, e.g. /nix/store
.
That is, we cannot hack caches by injecting our own data structre.
So basically language callbacks (i.e. dynamic bindings & values) are not available.
Actually we are waiting for Source tree abstraction (by edolstra), to handle this issue.
If you would like to use nixd
in your personal flake, you can use flake-compat
to turn your project in a "non-flake" installable.
Note that flake-compat
by edolstra will fetch a git project in nix store, that will break everything just as the same case as normal flakes (i.e. not being evaluated in-pllace).
Here we have a fork of flake-compat
, won't fetch git repositories at github:inclyc/flake-compat
.
So tldr, to use nixd
in your flake project, you have to:
- Turn your project into a legacy one, by using
flake-compat
- Use
inclyc/flake-compat
which will not fetch git repository in nix store
We have a working example here