diff --git a/modules/lsp/servers/default.nix b/modules/lsp/servers/default.nix index 59d587c5..9f0ba63d 100644 --- a/modules/lsp/servers/default.nix +++ b/modules/lsp/servers/default.nix @@ -138,9 +138,16 @@ in (builtins.catAttrs "warnings") builtins.concatLists ]; + + packages = lib.pipe enabledServers [ + (builtins.filter (server: server ? package)) + (builtins.groupBy (server: if server.packageFallback then "suffix" else "prefix")) + (builtins.mapAttrs (_: builtins.catAttrs "package")) + ]; in { - extraPackages = builtins.catAttrs "package" enabledServers; + extraPackages = lib.mkIf (packages.prefix or [ ] != [ ]) packages.prefix; + extraPackagesAfter = lib.mkIf (packages.suffix or [ ] != [ ]) packages.suffix; lsp.luaConfig.content = let diff --git a/modules/lsp/servers/server.nix b/modules/lsp/servers/server.nix index b0d368af..a4800964 100644 --- a/modules/lsp/servers/server.nix +++ b/modules/lsp/servers/server.nix @@ -54,6 +54,16 @@ in ''; }; + packageFallback = lib.mkOption { + type = types.bool; + default = false; + description = '' + When enabled, the language server package will be added to the end of the `PATH` _(suffix)_ instead of the beginning _(prefix)_. + + This can be useful if you want local versions of the language server (e.g. from a devshell) to override the nixvim version. + ''; + }; + settings = lib.mkOption { type = with types; attrsOf anything; description = '' diff --git a/tests/test-sources/modules/lsp.nix b/tests/test-sources/modules/lsp.nix index a7ed8ded..299e1d16 100644 --- a/tests/test-sources/modules/lsp.nix +++ b/tests/test-sources/modules/lsp.nix @@ -28,4 +28,54 @@ }; }; }; + + package-fallback = + { lib, config, ... }: + { + test.buildNixvim = false; + + lsp = { + servers = { + nil_ls.enable = true; + rust_analyzer = { + enable = true; + packageFallback = true; + }; + hls = { + enable = true; + packageFallback = true; + }; + }; + }; + + assertions = + let + assertPrefix = name: pkg: [ + { + assertion = lib.all (x: x == pkg) config.extraPackages; + message = "Expected `${name}` to be in extraPackages"; + } + { + assertion = lib.any (x: x != pkg) config.extraPackagesAfter; + message = "Expected `${name}` not to be in extraPackagesAfter"; + } + ]; + assertSuffix = name: pkg: [ + { + assertion = lib.all (x: x != pkg) config.extraPackages; + message = "Expected `${name}` not to be in extraPackages"; + } + { + assertion = lib.any (x: x == pkg) config.extraPackagesAfter; + message = "Expected `${name}` to be in extraPackagesAfter"; + } + ]; + in + with config.lsp.servers; + ( + assertPrefix "nil" nil_ls.package + ++ assertSuffix "rust-analyzer" rust_analyzer.package + ++ assertSuffix "haskell-language-server" hls.package + ); + }; }