mirror of
https://github.com/nix-community/nixvim.git
synced 2025-12-07 17:41:04 +01:00
plugins/lsp: use the new lsp module under the hood
- Re-implement setup wrapping and capabilities to preserve existing behaviour - Alias `package` options to new lsp module - Alias `packageFallback` options to new lsp module - Alias `preConfig` and `postConfig` to `lsp.luaConfig`
This commit is contained in:
parent
cb3653a1a8
commit
94331cc50d
4 changed files with 148 additions and 135 deletions
|
|
@ -10,6 +10,7 @@ let
|
||||||
inherit (lib.nixvim) toLuaObject;
|
inherit (lib.nixvim) toLuaObject;
|
||||||
|
|
||||||
cfg = config.lsp;
|
cfg = config.lsp;
|
||||||
|
oldCfg = config.plugins.lsp;
|
||||||
|
|
||||||
# Import `server.nix` and apply args
|
# Import `server.nix` and apply args
|
||||||
# For convenience, we set a default here for args.pkgs
|
# For convenience, we set a default here for args.pkgs
|
||||||
|
|
@ -156,13 +157,37 @@ in
|
||||||
let
|
let
|
||||||
luaName = toLuaObject server.name;
|
luaName = toLuaObject server.name;
|
||||||
luaSettings = toLuaObject server.settings;
|
luaSettings = toLuaObject server.settings;
|
||||||
|
wrap = server.__settingsWrapper or lib.id;
|
||||||
in
|
in
|
||||||
[
|
[
|
||||||
(lib.mkIf (server.settings != { }) "vim.lsp.config(${luaName}, ${luaSettings})")
|
(lib.mkIf (server.settings != { }) "vim.lsp.config(${luaName}, ${wrap luaSettings})")
|
||||||
(lib.mkIf (server.activate or false) "vim.lsp.enable(${luaName})")
|
(lib.mkIf (server.activate or false) "vim.lsp.enable(${luaName})")
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
lib.mkMerge (builtins.concatMap mkServerConfig enabledServers);
|
lib.mkMerge (
|
||||||
|
# Implement the legacy settings wrapping and capabilities mutation when `plugins.lsp` is enabled
|
||||||
|
lib.optional oldCfg.enable ''
|
||||||
|
local __lspCapabilities = function()
|
||||||
|
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||||
|
|
||||||
|
${oldCfg.capabilities}
|
||||||
|
|
||||||
|
return capabilities
|
||||||
|
end
|
||||||
|
|
||||||
|
local __setup = ${lib.foldr lib.id "{ capabilities = __lspCapabilities() }" oldCfg.setupWrappers}
|
||||||
|
|
||||||
|
local __wrapSettings = function(settings)
|
||||||
|
if settings == nil then
|
||||||
|
settings = __setup
|
||||||
|
else
|
||||||
|
settings = vim.tbl_extend("keep", settings, __setup)
|
||||||
|
end
|
||||||
|
return settings
|
||||||
|
end
|
||||||
|
''
|
||||||
|
++ builtins.concatMap mkServerConfig enabledServers
|
||||||
|
);
|
||||||
|
|
||||||
# Propagate per-server warnings
|
# Propagate per-server warnings
|
||||||
warnings = lib.mkIf (serverWarnings != [ ]) serverWarnings;
|
warnings = lib.mkIf (serverWarnings != [ ]) serverWarnings;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
{ lib, config, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
options,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
in
|
in
|
||||||
|
|
@ -11,7 +16,10 @@ lib.nixvim.plugins.mkNeovimPlugin {
|
||||||
|
|
||||||
maintainers = [ lib.maintainers.HeitorAugustoLN ];
|
maintainers = [ lib.maintainers.HeitorAugustoLN ];
|
||||||
|
|
||||||
imports = [ ./language-servers ];
|
imports = [
|
||||||
|
./language-servers
|
||||||
|
(lib.mkRemovedOptionModule [ "plugins" "lsp" "enabledServers" ] "Internal option has been removed.")
|
||||||
|
];
|
||||||
|
|
||||||
extraOptions = {
|
extraOptions = {
|
||||||
keymaps = {
|
keymaps = {
|
||||||
|
|
@ -77,28 +85,6 @@ lib.nixvim.plugins.mkNeovimPlugin {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enabledServers = mkOption {
|
|
||||||
type =
|
|
||||||
with types;
|
|
||||||
listOf (submodule {
|
|
||||||
options = {
|
|
||||||
name = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "The server's name";
|
|
||||||
};
|
|
||||||
|
|
||||||
extraOptions = mkOption {
|
|
||||||
type = attrsOf anything;
|
|
||||||
description = "Extra options for the server";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
description = "A list of enabled LSP servers. Don't use this directly.";
|
|
||||||
default = [ ];
|
|
||||||
internal = true;
|
|
||||||
visible = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
inlayHints = mkOption {
|
inlayHints = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
@ -136,13 +122,33 @@ lib.nixvim.plugins.mkNeovimPlugin {
|
||||||
preConfig = mkOption {
|
preConfig = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
description = "Code to be run before loading the LSP. Useful for requiring plugins";
|
description = "Code to be run before loading the LSP. Useful for requiring plugins";
|
||||||
default = "";
|
# When `plugins.lsp` is enabled, definitions are aliased to `lsp.luaConfig.pre`; so read that final value here.
|
||||||
|
# This is slightly complicated because `lsp.luaConfig.pre` is nullable, unlike this option.
|
||||||
|
# The other half of this two-way alias is below in `extraConfig`.
|
||||||
|
apply =
|
||||||
|
value:
|
||||||
|
if config.plugins.lsp.enable then
|
||||||
|
if config.lsp.luaConfig.pre == null then "" else config.lsp.luaConfig.pre
|
||||||
|
else if options.plugins.lsp.preConfig.isDefined then
|
||||||
|
value
|
||||||
|
else
|
||||||
|
"";
|
||||||
};
|
};
|
||||||
|
|
||||||
postConfig = mkOption {
|
postConfig = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
description = "Code to be run after loading the LSP. This is an internal option";
|
description = "Code to be run after loading the LSP. This is an internal option";
|
||||||
default = "";
|
# When `plugins.lsp` is enabled, definitions are aliased to `lsp.luaConfig.post`; so read that final value here.
|
||||||
|
# This is slightly complicated because `lsp.luaConfig.post` is nullable, unlike this option.
|
||||||
|
# The other half of this two-way alias is below in `extraConfig`.
|
||||||
|
apply =
|
||||||
|
value:
|
||||||
|
if config.plugins.lsp.enable then
|
||||||
|
if config.lsp.luaConfig.post == null then "" else config.lsp.luaConfig.post
|
||||||
|
else if options.plugins.lsp.postConfig.isDefined then
|
||||||
|
value
|
||||||
|
else
|
||||||
|
"";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -195,46 +201,8 @@ lib.nixvim.plugins.mkNeovimPlugin {
|
||||||
lsp = {
|
lsp = {
|
||||||
onAttach = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.onAttach;
|
onAttach = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.onAttach;
|
||||||
inlayHints.enable = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.inlayHints;
|
inlayHints.enable = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.inlayHints;
|
||||||
|
luaConfig.pre = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.preConfig;
|
||||||
|
luaConfig.post = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.postConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
plugins.lsp.luaConfig.content =
|
|
||||||
let
|
|
||||||
runWrappers =
|
|
||||||
wrappers: s:
|
|
||||||
if wrappers == [ ] then s else (builtins.head wrappers) (runWrappers (builtins.tail wrappers) s);
|
|
||||||
in
|
|
||||||
''
|
|
||||||
-- nvim-lspconfig {{{
|
|
||||||
do
|
|
||||||
${cfg.preConfig}
|
|
||||||
|
|
||||||
local __lspServers = ${lib.nixvim.toLuaObject cfg.enabledServers}
|
|
||||||
|
|
||||||
local __lspCapabilities = function()
|
|
||||||
capabilities = vim.lsp.protocol.make_client_capabilities()
|
|
||||||
|
|
||||||
${cfg.capabilities}
|
|
||||||
|
|
||||||
return capabilities
|
|
||||||
end
|
|
||||||
|
|
||||||
local __setup = ${runWrappers cfg.setupWrappers "{ capabilities = __lspCapabilities() }"}
|
|
||||||
|
|
||||||
for i, server in ipairs(__lspServers) do
|
|
||||||
local options = ${runWrappers cfg.setupWrappers "server.extraOptions"}
|
|
||||||
|
|
||||||
if options == nil then
|
|
||||||
options = __setup
|
|
||||||
else
|
|
||||||
options = vim.tbl_extend("keep", options, __setup)
|
|
||||||
end
|
|
||||||
|
|
||||||
require("lspconfig")[server.name].setup(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
${cfg.postConfig}
|
|
||||||
end
|
|
||||||
-- }}}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
}@args:
|
}@args:
|
||||||
# returns a module
|
# returns a module
|
||||||
{
|
{
|
||||||
pkgs,
|
|
||||||
config,
|
config,
|
||||||
options,
|
options,
|
||||||
lib,
|
lib,
|
||||||
|
|
@ -51,9 +50,41 @@ in
|
||||||
plugins.lsp.servers.${name} = {
|
plugins.lsp.servers.${name} = {
|
||||||
enable = lib.mkEnableOption description;
|
enable = lib.mkEnableOption description;
|
||||||
|
|
||||||
|
# alias to lsp.servers.${name}.package
|
||||||
package =
|
package =
|
||||||
lib.nixvim.mkMaybeUnpackagedOption "plugins.lsp.servers.${name}.package" pkgs name
|
let
|
||||||
package;
|
getSubOptions = opt: opt.type.getSubOptions opt.loc;
|
||||||
|
serverOpts = getSubOptions options.lsp.servers;
|
||||||
|
opt = lib.pipe serverOpts [
|
||||||
|
(lib.getAttr serverName)
|
||||||
|
getSubOptions
|
||||||
|
(lib.getAttr "package")
|
||||||
|
];
|
||||||
|
pkg = config.lsp.servers.${serverName}.package;
|
||||||
|
self = options.plugins.lsp.servers.${name}.package;
|
||||||
|
in
|
||||||
|
if serverOpts ? ${serverName} then
|
||||||
|
lib.mkOption (
|
||||||
|
{
|
||||||
|
inherit (opt) type default description;
|
||||||
|
apply =
|
||||||
|
v:
|
||||||
|
if enabled then
|
||||||
|
pkg
|
||||||
|
else if self.isDefined then
|
||||||
|
v
|
||||||
|
else
|
||||||
|
opt.default or v;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (opt ? example) { inherit (opt) example; }
|
||||||
|
// lib.optionalAttrs (opt ? defaultText) { inherit (opt) defaultText; }
|
||||||
|
)
|
||||||
|
else
|
||||||
|
# If there's no explicit option, that means there isn't a known package, so the server uses freeformType
|
||||||
|
lib.nixvim.mkUnpackagedOption options.plugins.lsp.servers.${name}.package name
|
||||||
|
// {
|
||||||
|
apply = v: if enabled then config.lsp.servers.${serverName}.packageFallback else v;
|
||||||
|
};
|
||||||
|
|
||||||
packageFallback = mkOption {
|
packageFallback = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
|
@ -63,6 +94,7 @@ in
|
||||||
|
|
||||||
This can be useful if you want local versions of the language server (e.g. from a devshell) to override the nixvim version.
|
This can be useful if you want local versions of the language server (e.g. from a devshell) to override the nixvim version.
|
||||||
'';
|
'';
|
||||||
|
apply = v: if enabled then config.lsp.servers.${serverName}.packageFallback else v;
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd = mkOption {
|
cmd = mkOption {
|
||||||
|
|
@ -159,16 +191,40 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf enabled {
|
config = lib.mkIf enabled {
|
||||||
extraPackages = lib.optional (!cfg.packageFallback) cfg.package;
|
# The server submodule is using `shorthandOnlyDefinesConfig`,
|
||||||
extraPackagesAfter = lib.optional cfg.packageFallback cfg.package;
|
# so define a "longhand" function module.
|
||||||
|
lsp.servers.${serverName} = _: {
|
||||||
|
# Top-secret internal option that only exists when the server is enabled via the old API.
|
||||||
|
# The new API checks if this attr exists and uses it to wrap the server's settings string.
|
||||||
|
options.__settingsWrapper = lib.mkOption {
|
||||||
|
type = lib.types.functionTo lib.types.str;
|
||||||
|
description = ''
|
||||||
|
This internal option exists to preserve the old `plugins.lsp` behaviour.
|
||||||
|
|
||||||
plugins.lsp.enabledServers = [
|
> [!IMPORTANT]
|
||||||
{
|
> This option should not be used by end-users!
|
||||||
name = serverName;
|
> It will be removed when `plugins.lsp` is dropped.
|
||||||
extraOptions = {
|
'';
|
||||||
inherit (cfg) cmd filetypes autostart;
|
readOnly = true;
|
||||||
root_markers = cfg.rootMarkers;
|
internal = true;
|
||||||
on_attach = lib.nixvim.ifNonNull' cfg.onAttach (
|
visible = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Propagate definitions to the new lsp module
|
||||||
|
config = {
|
||||||
|
enable = true;
|
||||||
|
package = lib.mkIf (opts.package.highestPrio < 1500) (
|
||||||
|
lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.package
|
||||||
|
);
|
||||||
|
packageFallback = lib.modules.mkAliasAndWrapDefsWithPriority lib.id opts.packageFallback;
|
||||||
|
__settingsWrapper =
|
||||||
|
settings: "__wrapSettings(${lib.foldr lib.id settings config.plugins.lsp.setupWrappers})";
|
||||||
|
settings = {
|
||||||
|
autostart = lib.mkIf (cfg.autostart != null) cfg.autostart;
|
||||||
|
cmd = lib.mkIf (cfg.cmd != null) cfg.cmd;
|
||||||
|
filetypes = lib.mkIf (cfg.filetypes != null) cfg.filetypes;
|
||||||
|
root_markers = lib.mkIf (cfg.rootMarkers != null) cfg.rootMarkers;
|
||||||
|
on_attach = lib.mkIf (cfg.onAttach != null) (
|
||||||
lib.nixvim.mkRaw ''
|
lib.nixvim.mkRaw ''
|
||||||
function(client, bufnr)
|
function(client, bufnr)
|
||||||
${lib.optionalString (!cfg.onAttach.override) config.plugins.lsp.onAttach}
|
${lib.optionalString (!cfg.onAttach.override) config.plugins.lsp.onAttach}
|
||||||
|
|
@ -184,8 +240,8 @@ in
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// cfg.extraOptions;
|
// cfg.extraOptions;
|
||||||
}
|
};
|
||||||
];
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports =
|
imports =
|
||||||
|
|
|
||||||
|
|
@ -173,25 +173,13 @@
|
||||||
"example"
|
"example"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
enabledServers = lib.mkAfter [
|
|
||||||
{
|
|
||||||
name = "second";
|
|
||||||
extraOptions.settings = lib.mkIf false {
|
|
||||||
should.be = "missing";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "third";
|
|
||||||
extraOptions.settings = lib.mkIf true {
|
|
||||||
should.be = "present";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
assertions =
|
assertions =
|
||||||
let
|
let
|
||||||
|
enabledServers = builtins.filter (server: server.enable) (builtins.attrValues config.lsp.servers);
|
||||||
|
|
||||||
toLua = lib.nixvim.lua.toLua' {
|
toLua = lib.nixvim.lua.toLua' {
|
||||||
removeNullAttrValues = true;
|
removeNullAttrValues = true;
|
||||||
removeEmptyAttrValues = true;
|
removeEmptyAttrValues = true;
|
||||||
|
|
@ -200,39 +188,35 @@
|
||||||
multiline = true;
|
multiline = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
print = lib.generators.toPretty {
|
serverCount = builtins.length enabledServers;
|
||||||
multiline = true;
|
expectedCount = 2;
|
||||||
};
|
|
||||||
|
|
||||||
serverCount = builtins.length config.plugins.lsp.enabledServers;
|
baseServer = builtins.elemAt enabledServers 0;
|
||||||
expectedCount = 3;
|
|
||||||
|
|
||||||
nilServer = builtins.head config.plugins.lsp.enabledServers;
|
nilServer = builtins.elemAt enabledServers 1;
|
||||||
nilSettings = toLua nilServer.extraOptions.settings;
|
nilSettings = toLua nilServer.settings.settings;
|
||||||
expectedNilSettings = toLua {
|
expectedNilSettings = toLua {
|
||||||
nil.formatting.command = [
|
nil.formatting.command = [
|
||||||
"real"
|
"real"
|
||||||
"example"
|
"example"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
secondServer = builtins.elemAt config.plugins.lsp.enabledServers 1;
|
|
||||||
expectedSecondServer = {
|
|
||||||
name = "second";
|
|
||||||
extraOptions = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
thirdServer = builtins.elemAt config.plugins.lsp.enabledServers 2;
|
|
||||||
expectedThirdServer = {
|
|
||||||
name = "third";
|
|
||||||
extraOptions.settings.should.be = "present";
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
assertion = serverCount == expectedCount;
|
assertion = serverCount == expectedCount;
|
||||||
message = "Expected ${toString expectedCount} enabled LSP server!";
|
message = "Expected ${toString expectedCount} enabled LSP server!";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
assertion = baseServer.name == "*";
|
||||||
|
message = ''
|
||||||
|
baseServer's `name` does not match expected value.
|
||||||
|
|
||||||
|
Expected: "*"
|
||||||
|
|
||||||
|
Actual: ${baseServer.name}
|
||||||
|
'';
|
||||||
|
}
|
||||||
{
|
{
|
||||||
assertion = nilSettings == expectedNilSettings;
|
assertion = nilSettings == expectedNilSettings;
|
||||||
message = ''
|
message = ''
|
||||||
|
|
@ -243,26 +227,6 @@
|
||||||
Actual: ${nilSettings}
|
Actual: ${nilSettings}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
{
|
|
||||||
assertion = secondServer == expectedSecondServer;
|
|
||||||
message = ''
|
|
||||||
`secondServer` does not match expected value.
|
|
||||||
|
|
||||||
Expected: ${print expectedSecondServer}
|
|
||||||
|
|
||||||
Actual: ${print secondServer}
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = secondServer == expectedSecondServer;
|
|
||||||
message = ''
|
|
||||||
`thirdServer` does not match expected value.
|
|
||||||
|
|
||||||
Expected: ${print expectedThirdServer}
|
|
||||||
|
|
||||||
Actual: ${print thirdServer}
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue