nvf/modules/plugins/languages/rust.nix
NotAShelf c56ec752ba
Some checks are pending
Set up binary cache / cachix (default) (push) Waiting to run
Set up binary cache / cachix (maximal) (push) Waiting to run
Set up binary cache / cachix (nix) (push) Waiting to run
Treewide Checks / Validate flake (push) Waiting to run
Treewide Checks / Check formatting (push) Waiting to run
Treewide Checks / Check source tree for typos (push) Waiting to run
Treewide Checks / Validate documentation builds (push) Waiting to run
Treewide Checks / Validate documentation builds-1 (push) Waiting to run
Treewide Checks / Validate documentation builds-2 (push) Waiting to run
Treewide Checks / Validate documentation builds-3 (push) Waiting to run
Treewide Checks / Validate hyperlinks in documentation sources (push) Waiting to run
Treewide Checks / Validate Editorconfig conformance (push) Waiting to run
Build and deploy documentation / Check latest commit (push) Waiting to run
Build and deploy documentation / publish (push) Blocked by required conditions
langauges: add defaultText to all values dependent on toggles
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Idf55a40882e53006048fdd876c869f906a6a6964
2026-03-12 09:56:14 +03:00

282 lines
9.1 KiB
Nix

{
config,
pkgs,
lib,
...
}: let
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.options) mkOption mkEnableOption literalMD literalExpression;
inherit (lib.strings) optionalString;
inherit (lib.lists) isList;
inherit (lib.attrsets) attrNames;
inherit (lib.types) bool package str listOf either enum int;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) mkGrammarOption mkPluginSetupOption deprecatedSingleOrListOf;
inherit (lib.nvim.dag) entryAfter entryAnywhere;
cfg = config.vim.languages.rust;
defaultFormat = ["rustfmt"];
formats = {
rustfmt = {
command = getExe pkgs.rustfmt;
};
};
in {
options.vim.languages.rust = {
enable = mkEnableOption "Rust language support";
treesitter = {
enable =
mkEnableOption "Rust treesitter"
// {
default = config.vim.languages.enableTreesitter;
defaultText = literalExpression "config.vim.languages.enableTreesitter";
};
package = mkGrammarOption pkgs "rust";
};
lsp = {
enable =
mkEnableOption "Rust LSP support (rust-analyzer with extra tools)"
// {
default = config.vim.lsp.enable;
defaultText = literalExpression "config.vim.lsp.enable";
};
package = mkOption {
description = "rust-analyzer package, or the command to run as a list of strings";
example = ''[lib.getExe pkgs.jdt-language-server "-data" "~/.cache/jdtls/workspace"]'';
type = either package (listOf str);
default = pkgs.rust-analyzer;
};
opts = mkOption {
description = "Options to pass to rust analyzer";
type = str;
default = "";
example = ''
['rust-analyzer'] = {
cargo = {allFeature = true},
checkOnSave = true,
procMacro = {
enable = true,
},
},
'';
};
};
format = {
enable =
mkEnableOption "Rust formatting"
// {
default = !cfg.lsp.enable && config.vim.languages.enableFormat;
defaultText = literalMD ''
Disabled if Rust LSP is enabled, otherwise follows {option}`vim.languages.enableFormat`
'';
};
type = mkOption {
description = "Rust formatter to use";
type = deprecatedSingleOrListOf "vim.language.rust.format.type" (enum (attrNames formats));
default = defaultFormat;
};
};
dap = {
enable = mkOption {
description = "Rust Debug Adapter support";
type = bool;
default = config.vim.languages.enableDAP;
defaultText = literalExpression "config.vim.languages.enableDAP";
};
package = mkOption {
description = "lldb package";
type = package;
default = pkgs.lldb;
};
adapter = mkOption {
type = enum ["lldb-dap" "codelldb"];
default = "codelldb";
description = ''
Select which LLDB-based debug adapter to use:
- "codelldb": use the CodeLLDB adapter from the vadimcn.vscode-lldb extension.
- "lldb-dap": use the LLDB DAP implementation shipped with LLVM (lldb-dap).
The default "codelldb" backend generally provides a better debugging experience for Rust.
'';
};
};
extensions = {
crates-nvim = {
enable = mkEnableOption "crates.io dependency management [crates-nvim]";
setupOpts = mkPluginSetupOption "crates-nvim" {
lsp = {
enabled =
mkEnableOption "crates.nvim's in-process language server"
// {
default = cfg.extensions.crates-nvim.enable;
defaultText = literalExpression "config.vim.languages.rust.extensions.crates-nvim.enable";
};
actions =
mkEnableOption "actions for crates-nvim's in-process language server"
// {
default = cfg.extensions.crates-nvim.enable;
defaultText = literalExpression "config.vim.languages.rust.extensions.crates-nvim.enable";
};
completion =
mkEnableOption "completion for crates-nvim's in-process language server"
// {
default = cfg.extensions.crates-nvim.enable;
defaultText = literalExpression "config.vim.languages.rust.extensions.crates-nvim.enable";
};
hover =
mkEnableOption "hover actions for crates-nvim's in-process language server"
// {
default = cfg.extensions.crates-nvim.enable;
defaultText = literalExpression "config.vim.languages.rust.extensions.crates-nvim.enable";
};
};
completion = {
crates = {
enabled =
mkEnableOption "completion for crates-nvim's in-process language server"
// {
default = cfg.extensions.crates-nvim.enable;
defaultText = literalExpression "config.vim.languages.rust.extensions.crates-nvim.enable";
};
max_results = mkOption {
description = "The maximum number of search results to display";
type = int;
default = 8;
};
min_chars = mkOption {
description = "The minimum number of characters to type before completions begin appearing";
type = int;
default = 3;
};
};
};
};
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
})
(mkIf cfg.format.enable {
vim.formatter.conform-nvim = {
enable = true;
setupOpts = {
formatters_by_ft.rust = cfg.format.type;
formatters =
mapListToAttrs (name: {
inherit name;
value = formats.${name};
})
cfg.format.type;
};
};
})
(mkIf (cfg.lsp.enable || cfg.dap.enable) {
vim = {
startPlugins = ["rustaceanvim"];
pluginRC.rustaceanvim = entryAfter ["lsp-setup"] ''
vim.g.rustaceanvim = {
${optionalString cfg.lsp.enable ''
-- LSP
tools = {
hover_actions = {
replace_builtin_hover = false
},
},
server = {
cmd = ${
if isList cfg.lsp.package
then toLuaObject cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/rust-analyzer"}''
},
default_settings = {
${cfg.lsp.opts}
},
on_attach = function(client, bufnr)
default_on_attach(client, bufnr)
local opts = { noremap=true, silent=true, buffer = bufnr }
vim.keymap.set("n", "<localleader>rr", ":RustLsp runnables<CR>", opts)
vim.keymap.set("n", "<localleader>rp", ":RustLsp parentModule<CR>", opts)
vim.keymap.set("n", "<localleader>rm", ":RustLsp expandMacro<CR>", opts)
vim.keymap.set("n", "<localleader>rc", ":RustLsp openCargo", opts)
vim.keymap.set("n", "<localleader>rg", ":RustLsp crateGraph x11", opts)
${optionalString cfg.dap.enable ''
vim.keymap.set("n", "<localleader>rd", ":RustLsp debuggables<cr>", opts)
vim.keymap.set(
"n", "${config.vim.debugger.nvim-dap.mappings.continue}",
function()
local dap = require("dap")
if dap.status() == "" then
vim.cmd "RustLsp debuggables"
else
dap.continue()
end
end,
opts
)
''}
end
},
''}
${optionalString cfg.dap.enable ''
dap = {
adapter = ${
if cfg.dap.adapter == "lldb-dap"
then ''
{
type = "executable",
command = "${cfg.dap.package}/bin/lldb-dap",
name = "rustacean_lldb",
}''
else let
codelldb = pkgs.vscode-extensions.vadimcn.vscode-lldb.adapter;
codelldbPath = "${codelldb}/bin/codelldb";
liblldbPath = "${codelldb}/share/lldb/lib/liblldb.so";
in ''require("rustaceanvim.config").get_codelldb_adapter("${codelldbPath}", "${liblldbPath}")''
},
},
''}
}
'';
};
})
(mkIf cfg.extensions.crates-nvim.enable {
vim = mkMerge [
{
lazy.plugins.crates-nvim = {
package = "crates-nvim";
setupModule = "crates";
setupOpts = cfg.extensions.crates-nvim.setupOpts;
event = [
{
event = "BufRead";
pattern = "Cargo.toml";
}
];
};
}
];
})
]);
}