diff --git a/flake.lock b/flake.lock index 5b7dcf117..c2be67aca 100644 --- a/flake.lock +++ b/flake.lock @@ -35,11 +35,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714562304, - "narHash": "sha256-Mr3U37Rh6tH0FbaDFu0aZDwk9mPAe7ASaqDOGgLqqLU=", + "lastModified": 1730831018, + "narHash": "sha256-2S0HwIFRxYp+afuoFORcZA9TjryAf512GmE0MTfEOPU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bcd44e224fd68ce7d269b4f44d24c2220fd821e7", + "rev": "8c4dc69b9732f6bbe826b5fbb32184987520ff26", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 66a478326..719b49369 100644 --- a/flake.nix +++ b/flake.nix @@ -33,7 +33,7 @@ callPackage stdenv ; - nix = nixVersions.nix_2_19; + nix = nixVersions.nix_2_24; llvmPackages = llvmPackages_16; nixf = callPackage ./libnixf { }; nixt = callPackage ./libnixt { inherit nix; }; diff --git a/libnixt/include/nixt/InitEval.h b/libnixt/include/nixt/InitEval.h index 4e4651c88..3896f7868 100644 --- a/libnixt/include/nixt/InitEval.h +++ b/libnixt/include/nixt/InitEval.h @@ -1,6 +1,11 @@ #pragma once +#include +#include +#include #include +#include +#include #include #include @@ -9,6 +14,7 @@ namespace nixt { inline void initEval() { nix::initNix(); nix::initLibStore(); + nix::flake::initLib(nix::flakeSettings); nix::initPlugins(); nix::initGC(); } diff --git a/libnixt/lib/Flake.cpp b/libnixt/lib/Flake.cpp index 6b940f4d1..6121fa55e 100644 --- a/libnixt/lib/Flake.cpp +++ b/libnixt/lib/Flake.cpp @@ -147,12 +147,12 @@ void nixt::callDirtyFlake(EvalState &State, std::string_view Src, nix::Value &VRes) { nix::Value *VSrc = State.allocValue(); - VSrc->mkPath(State.rootPath(nix::CanonPath(Src, nix::CanonPath::fromCwd()))); + VSrc->mkPath(State.rootPath(nix::CanonPath(Src))); auto *VFlakeCompat = State.allocValue(); - nix::Expr *EFlakeCompat = State.parseExprFromString( - FlakeCompat, State.rootPath(nix::CanonPath::fromCwd())); + nix::Expr *EFlakeCompat = + State.parseExprFromString(FlakeCompat, State.rootPath(".")); State.eval(EFlakeCompat, *VFlakeCompat); State.callFunction(*VFlakeCompat, *VSrc, VRes, noPos); diff --git a/libnixt/lib/Value.cpp b/libnixt/lib/Value.cpp index aaedb205f..088905f34 100644 --- a/libnixt/lib/Value.cpp +++ b/libnixt/lib/Value.cpp @@ -14,7 +14,7 @@ std::optional nixt::getField(nix::EvalState &State, nix::Value &V, return std::nullopt; nix::Symbol SFiled = State.symbols.create(Field); - if (auto *It = V.attrs->find(SFiled); It != V.attrs->end()) + if (auto *It = V.attrs()->find(SFiled); It != V.attrs()->end()) return *It->value; return std::nullopt; @@ -86,11 +86,11 @@ nix::Value &nixt::selectAttr(nix::EvalState &State, nix::Value &V, State.forceValue(V, nix::noPos); if (V.type() != nix::ValueType::nAttrs) - throw nix::TypeError("value is not an attrset"); + throw nix::TypeError(State, "value is not an attrset"); - assert(V.attrs && "nix must allocate non-null attrs!"); - auto *Nested = V.attrs->find(Attr); - if (Nested == V.attrs->end()) + assert(V.attrs() && "nix must allocate non-null attrs!"); + auto *Nested = V.attrs()->find(Attr); + if (Nested == V.attrs()->end()) throw nix::AttrPathNotFound("attrname " + State.symbols[Attr] + " not found in attrset"); @@ -145,11 +145,12 @@ nix::Value getSubOptions(nix::EvalState &State, nix::Value &Type) { nix::Value &GetSubOptions = selectAttr(State, Type, State.symbols.create("getSubOptions")); - nix::Value EmptyList; - EmptyList.mkList(0); + auto list = State.buildList(0); + auto EmptyList = State.allocValue(); + EmptyList->mkList(list); // Invoke "GetSubOptions" nix::Value VResult; - State.callFunction(GetSubOptions, EmptyList, VResult, nix::noPos); + State.callFunction(GetSubOptions, *EmptyList, VResult, nix::noPos); return VResult; } diff --git a/libnixt/lib/meson.build b/libnixt/lib/meson.build index cf482694c..6d6c67a68 100644 --- a/libnixt/lib/meson.build +++ b/libnixt/lib/meson.build @@ -1,4 +1,4 @@ -libnixt_deps = [ nix_expr, nix_main, nix_cmd, boost ] +libnixt_deps = [ nix_expr, nix_flake, nix_main, nix_cmd, boost ] libnixd_inc = include_directories('../include') @@ -19,7 +19,7 @@ pkgconfig.generate(name: 'nixt', description: 'nix compatible layer', subdirs: [ 'nixt' ], libraries: libnixt, - requires: [ 'nix-expr', 'nix-main', 'nix-cmd' ] + requires: [ 'nix-expr', 'nix-main', 'nix-cmd', 'nix-flake' ] ) diff --git a/libnixt/meson.build b/libnixt/meson.build index 81b87f24a..3b1e7b835 100644 --- a/libnixt/meson.build +++ b/libnixt/meson.build @@ -14,6 +14,7 @@ pkgconfig = import('pkgconfig') nix_main = dependency('nix-main') nix_expr = dependency('nix-expr') nix_cmd = dependency('nix-cmd') +nix_flake = dependency('nix-flake') subdir('lib') subdir('test') diff --git a/libnixt/test/StateTest.h b/libnixt/test/StateTest.h index 9f702c161..f8303d5ed 100644 --- a/libnixt/test/StateTest.h +++ b/libnixt/test/StateTest.h @@ -1,5 +1,6 @@ #include +#include #include #include @@ -7,7 +8,11 @@ namespace nixt { struct StateTest : testing::Test { std::unique_ptr State; - StateTest() : State(new nix::EvalState{{}, nix::openStore("dummy://")}) {} + StateTest() + : State(new nix::EvalState{{}, + nix::openStore("dummy://"), + nix::fetchSettings, + nix::evalSettings}) {} }; } // namespace nixt diff --git a/libnixt/test/Value.cpp b/libnixt/test/Value.cpp index c7a1f4710..30a2b8536 100644 --- a/libnixt/test/Value.cpp +++ b/libnixt/test/Value.cpp @@ -7,7 +7,7 @@ using namespace nixt; namespace { struct ValueTest : StateTest { - nix::SourcePath cwd() { return State->rootPath(nix::CanonPath::fromCwd()); } + nix::SourcePath cwd() { return State->rootPath("."); } }; TEST_F(ValueTest, IsOption_neg) { @@ -58,7 +58,7 @@ TEST_F(ValueTest, selectAttrPath) { nix::Value &Kern = selectStringViews(*State, Nested, {"c", "d"}); ASSERT_EQ(Kern.type(), nix::ValueType::nInt); - ASSERT_EQ(Kern.integer, 1); + ASSERT_EQ(Kern.integer(), 1); } } // namespace diff --git a/meson.build b/meson.build index 5e7c1180c..881fe9a4e 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,7 @@ subdir('libnixf/test') nix_main = dependency('nix-main') nix_expr = dependency('nix-expr') nix_cmd = dependency('nix-cmd') +nix_flake = dependency('nix-flake') subdir('libnixt/lib') diff --git a/nixd/docs/configuration.md b/nixd/docs/configuration.md index d162b25af..f20f25e22 100644 --- a/nixd/docs/configuration.md +++ b/nixd/docs/configuration.md @@ -110,6 +110,33 @@ nvim_lsp.nixd.setup({ ``` +
+ Emacs + + Configuration via [lsp-mode](https://github.com/emacs-lsp/lsp-mode) plugin. As of Oct 24, 2024, lsp-mode master has support for nixd autocompletion and formatting options. + + ```elisp +(use-package nix-mode + :after lsp-mode + :ensure t + :hook + (nix-mode . lsp-deferred) ;; So that envrc mode will work + :custom + (lsp-disabled-clients '((nix-mode . nix-nil))) ;; Disable nil so that nixd will be used as lsp-server + :config + (setq lsp-nix-nixd-server-path "nixd" + lsp-nix-nixd-formatting-command [ "nixfmt" ] + lsp-nix-nixd-nixpkgs-expr "import { }" + lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/nb/nixos\").nixosConfigurations.mnd.options" + lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/nb/nixos\").homeConfigurations.\"nb@mnd\".options")) + +(add-hook! 'nix-mode-hook + ;; enable autocompletion with company + (setq company-idle-delay 0.1)) + + ``` +
+ ### Configuration overview > [!NOTE] diff --git a/nixd/docs/editor-setup.md b/nixd/docs/editor-setup.md index 98a194884..48061bda8 100644 --- a/nixd/docs/editor-setup.md +++ b/nixd/docs/editor-setup.md @@ -80,7 +80,7 @@ According to `:help coc-config.txt`, `coc-settings.json`: ### Neovim Neovim native LSP and [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig). -We are officially supported by nvim-lspconfig, see [upstream docs](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.txt#nixd) +We are officially supported by nvim-lspconfig, see [upstream docs](https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.txt#nixd) ### Emacs @@ -110,6 +110,21 @@ A simple Emacs Lisp configuration that adds nixd to LSP Mode in the mean time is :server-id 'nixd))) ``` +### Helix + +`nixd` will be supported by default in the next release after 24.07. + +#### languages.toml + +```toml +[[language]] +name = "nix" +language-servers = ["nixd","nil"] + +[language-server.nixd] +command = "nixd" +``` + ## Change the configuration. Read the [configuration](configuration.md) docs here. diff --git a/nixd/docs/editors/vscodium.nix b/nixd/docs/editors/vscodium.nix index b132c88f6..359ad53f1 100644 --- a/nixd/docs/editors/vscodium.nix +++ b/nixd/docs/editors/vscodium.nix @@ -1,4 +1,6 @@ -{ pkgs ? import { } }: +{ + pkgs ? import { }, +}: with pkgs; let codium = vscode-with-extensions.override { diff --git a/nixd/docs/examples/NixOS_Home-Manager/flake.nix b/nixd/docs/examples/NixOS_Home-Manager/flake.nix index dbd3eae98..7b59e8ea6 100644 --- a/nixd/docs/examples/NixOS_Home-Manager/flake.nix +++ b/nixd/docs/examples/NixOS_Home-Manager/flake.nix @@ -10,7 +10,8 @@ flake-parts.url = "github:hercules-ci/flake-parts"; }; - outputs = inputs@{ self, flake-parts, ... }: + outputs = + inputs@{ self, flake-parts, ... }: flake-parts.lib.mkFlake { inherit inputs; } { debug = true; @@ -23,12 +24,15 @@ hostname = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ - ({ pkgs, ... }: { - networking.hostName = "hostname"; - environment.systemPackages = with pkgs; [ - nixd - ]; - }) + ( + { pkgs, ... }: + { + networking.hostName = "hostname"; + environment.systemPackages = with pkgs; [ + nixd + ]; + } + ) ]; }; }; @@ -42,9 +46,12 @@ home.username = "user"; home.homeDirectory = "/home/user"; } - ({ pkgs, ... }: { - wayland.windowManager.hyprland.enable = true; - }) + ( + { pkgs, ... }: + { + wayland.windowManager.hyprland.enable = true; + } + ) ]; }; }; diff --git a/nixd/lib/Controller/Definition.cpp b/nixd/lib/Controller/Definition.cpp index 95bbebea4..8e2394812 100644 --- a/nixd/lib/Controller/Definition.cpp +++ b/nixd/lib/Controller/Definition.cpp @@ -134,7 +134,7 @@ class WorkerReportedException : std::exception { llvm::Error E; public: - WorkerReportedException(llvm::Error E) : E(std::move(E)){}; + WorkerReportedException(llvm::Error E) : E(std::move(E)) {}; llvm::Error takeError() { return std::move(E); } [[nodiscard]] const char *what() const noexcept override { diff --git a/nixd/lib/Eval/AttrSetProvider.cpp b/nixd/lib/Eval/AttrSetProvider.cpp index 963ffdf8b..dd01a23f7 100644 --- a/nixd/lib/Eval/AttrSetProvider.cpp +++ b/nixd/lib/Eval/AttrSetProvider.cpp @@ -4,6 +4,7 @@ #include "lspserver/Protocol.h" #include +#include #include #include #include @@ -22,7 +23,7 @@ void fillString(nix::EvalState &State, nix::Value &V, nix::Value &Select = nixt::selectStringViews(State, V, AttrPath); State.forceValue(Select, nix::noPos); if (Select.type() == nix::ValueType::nString) - Field = Select.string.c_str; + Field = Select.string_view(); } catch (std::exception &E) { Field = std::nullopt; } @@ -85,8 +86,8 @@ void fillUnsafeGetAttrPosLocation(nix::EvalState &State, nix::Value &V, Column.type() == nix::ValueType::nInt) { // Nix position starts from "1" however lsp starts from zero. - lspserver::Position Pos = {static_cast(Line.integer) - 1, - static_cast(Column.integer) - 1}; + lspserver::Position Pos = {static_cast(Line.integer()) - 1, + static_cast(Column.integer()) - 1}; Loc.range = {Pos, Pos}; } } @@ -131,16 +132,16 @@ void fillOptionDescription(nix::EvalState &State, nix::Value &V, fillOptionDeclarations(State, V, R); // FIXME: add definitions location. if (V.type() == nix::ValueType::nAttrs) [[likely]] { - assert(V.attrs); - if (auto *It = V.attrs->find(State.symbols.create("type")); - It != V.attrs->end()) [[likely]] { + assert(V.attrs()); + if (auto *It = V.attrs()->find(State.symbols.create("type")); + It != V.attrs()->end()) [[likely]] { OptionType Type; fillOptionType(State, *It->value, Type); R.Type = std::move(Type); } - if (auto *It = V.attrs->find(State.symbols.create("example")); - It != V.attrs->end()) { + if (auto *It = V.attrs()->find(State.symbols.create("example")); + It != V.attrs()->end()) { State.forceValue(*It->value, It->pos); // In nixpkgs some examples are nested in "literalExpression" @@ -148,7 +149,7 @@ void fillOptionDescription(nix::EvalState &State, nix::Value &V, R.Example = nixt::getFieldString(State, *It->value, "text"); } else { std::ostringstream OS; - It->value->print(State.symbols, OS); + It->value->print(State, OS); R.Example = OS.str(); } } @@ -160,7 +161,8 @@ void fillOptionDescription(nix::EvalState &State, nix::Value &V, AttrSetProvider::AttrSetProvider(std::unique_ptr In, std::unique_ptr Out) : LSPServer(std::move(In), std::move(Out)), - State(new nix::EvalState({}, nix::openStore())) { + State(new nix::EvalState({}, nix::openStore(), nix::fetchSettings, + nix::evalSettings)) { Registry.addMethod(rpcMethod::EvalExpr, this, &AttrSetProvider::onEvalExpr); Registry.addMethod(rpcMethod::AttrPathInfo, this, &AttrSetProvider::onAttrPathInfo); @@ -176,8 +178,7 @@ void AttrSetProvider::onEvalExpr( const std::string &Name, lspserver::Callback> Reply) { try { - nix::Expr *AST = state().parseExprFromString( - Name, state().rootPath(nix::CanonPath::fromCwd())); + nix::Expr *AST = state().parseExprFromString(Name, state().rootPath(".")); state().eval(AST, Nixpkgs); Reply(std::nullopt); return; @@ -234,9 +235,9 @@ void AttrSetProvider::onAttrPathComplete( // evaluating package details. // "Trie"s may not beneficial becausae it cannot speedup eval. for (const auto *AttrPtr : - Scope.attrs->lexicographicOrder(state().symbols)) { + Scope.attrs()->lexicographicOrder(state().symbols)) { const nix::Attr &Attr = *AttrPtr; - const std::string Name = state().symbols[Attr.name]; + const std::string_view Name = state().symbols[Attr.name]; if (Name.starts_with(Params.Prefix)) { ++Num; Names.emplace_back(Name); @@ -309,9 +310,9 @@ void AttrSetProvider::onOptionComplete( // evaluating package details. // "Trie"s may not beneficial becausae it cannot speedup eval. for (const auto *AttrPtr : - Scope.attrs->lexicographicOrder(state().symbols)) { + Scope.attrs()->lexicographicOrder(state().symbols)) { const nix::Attr &Attr = *AttrPtr; - std::string Name = state().symbols[Attr.name]; + std::string_view Name = state().symbols[Attr.name]; if (Name.starts_with(Params.Prefix)) { // Add a new "OptionField", see it's type. assert(Attr.value); diff --git a/nixd/lspserver/include/lspserver/Connection.h b/nixd/lspserver/include/lspserver/Connection.h index e71e0a6c9..61f0f31a5 100644 --- a/nixd/lspserver/include/lspserver/Connection.h +++ b/nixd/lspserver/include/lspserver/Connection.h @@ -49,7 +49,7 @@ class InboundPort { InboundPort(int In = STDIN_FILENO, JSONStreamStyle StreamStyle = JSONStreamStyle::Standard) - : Close(false), In(In), StreamStyle(StreamStyle){}; + : Close(false), In(In), StreamStyle(StreamStyle) {}; /// Read messages specified in LSP standard, and collect standard json string /// into \p JSONString. diff --git a/nixd/lspserver/include/lspserver/LSPServer.h b/nixd/lspserver/include/lspserver/LSPServer.h index cf4318f90..14a946aa6 100644 --- a/nixd/lspserver/include/lspserver/LSPServer.h +++ b/nixd/lspserver/include/lspserver/LSPServer.h @@ -85,7 +85,7 @@ class LSPServer : public MessageHandler { public: LSPServer(std::unique_ptr In, std::unique_ptr Out) - : In(std::move(In)), Out(std::move(Out)){}; + : In(std::move(In)), Out(std::move(Out)) {}; /// \brief Close the inbound port. void closeInbound() { In->close(); } diff --git a/nixd/tools/nixd-attrset-eval/test/lit.cfg.py b/nixd/tools/nixd-attrset-eval/test/lit.cfg.py index d6461ad3d..2eac06c11 100644 --- a/nixd/tools/nixd-attrset-eval/test/lit.cfg.py +++ b/nixd/tools/nixd-attrset-eval/test/lit.cfg.py @@ -3,14 +3,14 @@ config.name = "nixd-attrset-eval" -config.suffixes = ['.md'] +config.suffixes = [".md"] # testFormat: The test format to use to interpret tests. config.test_format = lit.formats.ShTest() test_root = os.path.dirname(__file__) -build_dir = os.getenv('MESON_BUILD_ROOT', default = '/dev/null') +build_dir = os.getenv("MESON_BUILD_ROOT", default="/dev/null") # test_source_root: The root path where tests are located. config.test_source_root = test_root diff --git a/nixd/tools/nixd/test/lit.cfg.py b/nixd/tools/nixd/test/lit.cfg.py index b8350bb8d..c99dc5a9a 100644 --- a/nixd/tools/nixd/test/lit.cfg.py +++ b/nixd/tools/nixd/test/lit.cfg.py @@ -3,17 +3,17 @@ config.name = "nixd" -config.suffixes = ['.md'] +config.suffixes = [".md"] # testFormat: The test format to use to interpret tests. config.test_format = lit.formats.ShTest() test_root = os.path.dirname(__file__) -build_dir = os.getenv('MESON_BUILD_ROOT', default = '/dev/null') +build_dir = os.getenv("MESON_BUILD_ROOT", default="/dev/null") -config.environment['NIXD_ATTRSET_EVAL'] = os.getenv('NIXD_ATTRSET_EVAL') -config.environment['NIX_PATH'] = os.getenv('NIX_PATH') +config.environment["NIXD_ATTRSET_EVAL"] = os.getenv("NIXD_ATTRSET_EVAL") +config.environment["NIX_PATH"] = os.getenv("NIX_PATH") # test_source_root: The root path where tests are located.