Skip to content

modules/lsp/server: declare package defaults #3243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions modules/lsp/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,63 @@
lib,
config,
options,
pkgs,
...
}:
let
inherit (lib) types;
inherit (lib.nixvim) toLuaObject;

cfg = config.lsp;

# Import `server.nix` and apply args
# For convenience, we set a default here for args.pkgs
mkServerModule = args: lib.modules.importApply ./server.nix ({ inherit pkgs; } // args);

# Create a submodule type from `server.nix`
# Used as the type for both the freeform `lsp.servers.<name>`
# and the explicitly declared `lsp.servers.*` options
mkServerType = args: types.submodule (mkServerModule args);

# Create a server option
# Used below for the `lsp.servers.*` options
mkServerOption =
name: args:
let
homepage = lib.pipe options.lsp.servers [
# Get suboptions of `lsp.servers`
(opt: opt.type.getSubOptions opt.loc)
# Get suboptions of `lsp.servers.<name>`
(opts: opts.${name}.type.getSubOptions opts.${name}.loc)
# Get package option's homepage
(opts: opts.package.default.meta.homepage or null)
];

# If there's a known homepage for this language server,
# we'll link to it in the option description
nameLink = if homepage == null then name else "[${name}](${homepage})";
in
lib.mkOption {
type = mkServerType args;
description = ''
The ${nameLink} language server.
'';
default = { };
};

# Combine `packages` and `customCmd` sets from `lsp-packages.nix`
# We use this set to generate the package-option defaults
serverPackages =
let
inherit (import ../../plugins/lsp/lsp-packages.nix)
packages
customCmd
;
in
builtins.mapAttrs (name: v: {
inherit name;
package = v.package or v;
}) (packages // customCmd);
in
{
options.lsp = {
Expand All @@ -25,7 +75,11 @@ in
};

servers = lib.mkOption {
type = types.attrsOf (types.submodule ./server.nix);
type = types.submodule {
freeformType = types.attrsOf (mkServerType { });
options = builtins.mapAttrs mkServerOption serverPackages;
};

description = ''
LSP servers to enable and/or configure.

Expand All @@ -35,7 +89,7 @@ in
This can be installed using [`${options.plugins.lspconfig.enable}`][`plugins.lspconfig`].

[nvim-lspconfig]: ${options.plugins.lspconfig.package.default.meta.homepage}
[`plugins.lspconfig`]: ../plugins/lspconfig/index.md
[`plugins.lspconfig`]: ../../plugins/lspconfig/index.md
'';
default = { };
example = {
Expand Down
67 changes: 41 additions & 26 deletions modules/lsp/server.nix
Original file line number Diff line number Diff line change
@@ -1,59 +1,74 @@
# Usage: lib.importApply ./server.nix { /*args*/ }
{
name ? null,
package ? null,
# Avoid naming conflict with the `config` module arg
# TODO: consider renaming the `config` option to something like `settings`?
configOption ? null,
pkgs ? { },
}@args:
{ lib, name, ... }:
let
inherit (lib) types;
displayName = args.name or "the language server";
packageName = package.name or (lib.strings.removePrefix "the " displayName);
in
{
options = {
enable = lib.mkEnableOption "the language server";
enable = lib.mkEnableOption displayName;

name = lib.mkOption {
type = types.maybeRaw types.str;
description = ''
The name of the language server, supplied to functions like `vim.lsp.enable()`.
The name to use for ${displayName}.
Supplied to functions like `vim.lsp.enable()`.
'';
default = name;
defaultText = lib.literalMD "the attribute name";
# Use the supplied attr name, or fallback to the name module-arg
default = args.name or name;
defaultText = args.name or (lib.literalMD "the attribute name");
};

activate = lib.mkOption {
type = types.bool;
description = ''
Whether to call `vim.lsp.enable()` for this server.
Whether to call `vim.lsp.enable()` for ${displayName}.
'';
default = true;
example = false;
};

package = lib.mkOption {
type = with types; nullOr package;
default = null;
description = ''
Package to use for this language server.
package = lib.mkPackageOption pkgs packageName {
nullable = true;
default = package.default or package;
example = package.example or null;
extraDescription = ''
${package.extraDescription or ""}

Alternatively, the language server should be available on your `$PATH`.
Alternatively, ${displayName} should be installed on your `$PATH`.
'';
};

config = lib.mkOption {
type = with types; attrsOf anything;
description = ''
Configurations for each language server.
Configurations for ${displayName}. ${configOption.extraDescription or ""}
'';
default = { };
example = {
cmd = [
"clangd"
"--background-index"
];
root_markers = [
"compile_commands.json"
"compile_flags.txt"
];
filetypes = [
"c"
"cpp"
];
};
example =
configOption.example or {
cmd = [
"clangd"
"--background-index"
];
root_markers = [
"compile_commands.json"
"compile_flags.txt"
];
filetypes = [
"c"
"cpp"
];
};
};
};
}
2 changes: 1 addition & 1 deletion plugins/by-name/lspconfig/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ lib.nixvim.plugins.mkNeovimPlugin {
> setup that relate to neovim's builtin LSP and are now being moved to the
> new [`lsp`] module.

[`lsp`]: ../../lsp/servers.md
[`lsp`]: ../../lsp/servers/index.md
[`plugins.lsp`]: ../lsp/index.md
[nvim-lspconfig]: ${opts.package.default.meta.homepage}
'';
Expand Down