This commit is contained in:
raf 2025-09-05 13:44:09 +08:00 committed by GitHub
commit 6ea577b382
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 3219 additions and 1529 deletions

2
.github/typos.toml vendored
View file

@ -5,6 +5,8 @@ default.extend-ignore-words-re = [
"befores",
"annote",
"viw",
"edn",
"esy",
"BA", # somehow "BANanaD3V" is valid, but BA is not...
]

View file

@ -31,6 +31,7 @@ isMaximal: {
lspSignature.enable = !isMaximal; # conflicts with blink in maximal
otter-nvim.enable = isMaximal;
nvim-docs-view.enable = isMaximal;
harper-ls.enable = isMaximal;
};
debugger = {
@ -56,6 +57,7 @@ isMaximal: {
clang.enable = isMaximal;
css.enable = isMaximal;
html.enable = isMaximal;
json.enable = isMaximal;
sql.enable = isMaximal;
java.enable = isMaximal;
kotlin.enable = isMaximal;
@ -84,8 +86,11 @@ isMaximal: {
ocaml.enable = false;
elixir.enable = false;
haskell.enable = false;
hcl.enable = false;
ruby.enable = false;
fsharp.enable = false;
just.enable = false;
qml.enable = false;
tailwind.enable = false;
svelte.enable = false;
@ -188,6 +193,7 @@ isMaximal: {
vim-wakatime.enable = false;
diffview-nvim.enable = true;
yanky-nvim.enable = false;
qmk-nvim.enable = false; # requires hardware specific options
icon-picker.enable = isMaximal;
surround.enable = isMaximal;
leetcode-nvim.enable = isMaximal;

View file

@ -1,10 +1,10 @@
# Language Support {#ch-languages}
Language specific support means there is a combination of language specific
plugins, `treesitter` support, `nvim-lspconfig` language servers, and `null-ls`
integration. This gets you capabilities ranging from autocompletion to
formatting to diagnostics. The following languages have sections under the
`vim.languages` attribute.
plugins, `treesitter` support, `nvim-lspconfig` language servers, `conform-nvim`
formatters, and `nvim-lint` linter integration. This gets you capabilities
ranging from autocompletion to formatting to diagnostics. The following
languages have sections under the `vim.languages` attribute.
- Rust: [vim.languages.rust.enable](#opt-vim.languages.rust.enable)
- Nix: [vim.languages.nix.enable](#opt-vim.languages.nix.enable)
@ -20,6 +20,35 @@ formatting to diagnostics. The following languages have sections under the
- Lua: [vim.languages.lua.enable](#opt-vim.languages.lua.enable)
- PHP: [vim.languages.php.enable](#opt-vim.languages.php.enable)
- F#: [vim.languages.fsharp.enable](#opt-vim.languages.fsharp.enable)
- Assembly: [vim.languages.assembly.enable](#opt-vim.languages.assembly.enable)
- Astro: [vim.languages.astro.enable](#opt-vim.languages.astro.enable)
- Bash: [vim.languages.bash.enable](#opt-vim.languages.bash.enable)
- Clang: [vim.languages.clang.enable](#opt-vim.languages.clang.enable)
- Clojure: [vim.languages.clojure.enable](#opt-vim.languages.clojure.enable)
- C#: [vim.languages.csharp.enable](#opt-vim.languages.csharp.enable)
- CSS: [vim.languages.css.enable](#opt-vim.languages.css.enable)
- CUE: [vim.languages.cue.enable](#opt-vim.languages.cue.enable)
- Elixir: [vim.languages.elixir.enable](#opt-vim.languages.elixir.enable)
- Gleam: [vim.languages.gleam.enable](#opt-vim.languages.gleam.enable)
- HCL: [vim.languages.hcl.enable](#opt-vim.languages.hcl.enable)
- Helm: [vim.languages.helm.enable](#opt-vim.languages.helm.enable)
- Julia: [vim.languages.julia.enable](#opt-vim.languages.julia.enable)
- Kotlin: [vim.languages.kotlin.enable](#opt-vim.languages.kotlin.enable)
- Nim: [vim.languages.nim.enable](#opt-vim.languages.nim.enable)
- Nu: [vim.languages.nu.enable](#opt-vim.languages.nu.enable)
- OCaml: [vim.languages.ocaml.enable](#opt-vim.languages.ocaml.enable)
- Odin: [vim.languages.odin.enable](#opt-vim.languages.odin.enable)
- R: [vim.languages.r.enable](#opt-vim.languages.r.enable)
- Ruby: [vim.languages.ruby.enable](#opt-vim.languages.ruby.enable)
- Scala: [vim.languages.scala.enable](#opt-vim.languages.scala.enable)
- Svelte: [vim.languages.svelte.enable](#opt-vim.languages.svelte.enable)
- Tailwind: [vim.languages.tailwind.enable](#opt-vim.languages.tailwind.enable)
- Terraform:
[vim.languages.terraform.enable](#opt-vim.languages.terraform.enable)
- Typst: [vim.languages.typst.enable](#opt-vim.languages.typst.enable)
- Vala: [vim.languages.vala.enable](#opt-vim.languages.vala.enable)
- WGSL: [vim.languages.wgsl.enable](#opt-vim.languages.wgsl.enable)
- YAML: [vim.languages.yaml.enable](#opt-vim.languages.yaml.enable)
Adding support for more languages, and improving support for existing ones are
great places where you can contribute with a PR.

View file

@ -111,6 +111,11 @@
- Add [hunk.nvim], Neovim plugin & tool for splitting diffs in Neovim. Available
as `vim.git.hunk-nvim`
[sjcobb2022](https://github.com/sjcobb2022):
- Migrate all current lsp configurations to `vim.lsp.server` and remove internal
dependency on `nvim-lspconfig`
[amadaluzia](https://github.com/amadaluzia):
[haskell-tools.nvim]: https://github.com/MrcJkb/haskell-tools.nvim
@ -319,6 +324,7 @@
- Add global function `nvf_lint` under
`vim.diagnostics.nvim-lint.lint_function`.
- Deprecate `vim.scrollOffset` in favor of `vim.options.scrolloff`.
- Fix `svelte-language-server` not reloading .js/.ts files on change.
[Sc3l3t0n](https://github.com/Sc3l3t0n):
@ -389,9 +395,12 @@
[poz](https://poz.pet):
[everforest]: https://github.com/sainnhe/everforest
[oil]: https://github.com/stevearc/oil.nvim
[oil-git-status]: https://github.com/refractalize/oil-git-status.nvim
- Fix gitsigns null-ls issue.
- Add [everforest] theme support.
- Add [oil-git-status] support to [oil] module.
[Haskex](https://github.com/haskex):
@ -480,19 +489,62 @@
- fix broken `neorg` grammars
- remove obsolete warning in the `otter` module
[Cool-Game-Dev](https://github.com/Cool-Game-Dev):
[nvim-biscuits]: https://github.com/code-biscuits/nvim-biscuits
- Add [nvim-biscuits] to show block context. Available at
`vim.utility.nvim-biscuits`.
[JManch](https://github.com/JManch):
- Fix default [blink.cmp] sources "path" and "buffer" not working when
`autocomplete.nvim-cmp.enable` was disabled and
`autocomplete.nvim-cmp.sources` had not been modified.
[Poseidon](https://github.com/poseidon-rises):
[nvim-biscuits]: https://github.com/code-biscuits/nvim-biscuits
[just-lsp]: https://github.com/terror/just-lsp
[roslyn-ls]: https://github.com/dotnet/vscode-csharp
[jsonls]: https://github.com/microsoft/vscode/tree/1.101.2/extensions/json-language-features/server
[jsonfmt]: https://github.com/caarlos0/jsonfmt
[superhtml]: https://github.com/kristoff-it/superhtml
[htmlHINT]: https://github.com/htmlhint/HTMLHint
[qmk-nvim]: https://github.com/codethread/qmk.nvim
[qmlls]: https://doc.qt.io/qt-6/qtqml-tooling-qmlls.html
[qmlformat]: https://doc.qt.io/qt-6/qtqml-tooling-qmlformat.html
- Add [nvim-biscuits] support under `vim.utility.nvim-biscuits`.
- Add just support under `vim.languages.just` using [just-lsp].
- Add [roslyn-ls] to the `vim.languages.csharp` module.
- Add JSON support under `vim.languages.json` using [jsonls] and [jsonfmt].
- Add advanced HTML support under `vim.languages.html` using [superhtml] and
[htmlHINT].
- Add QMK support under `vim.utility.qmk-nvim` via [qmk-nvim].
- Add QML support under `vim.languages.qml` using [qmlls] and [qmlformat].
[Morsicus](https://github.com/Morsicus):
- Add [EEx Treesitter Grammar](https://github.com/connorlay/tree-sitter-eex) for
Elixir
- Add
[HEEx Treesitter Grammar](https://github.com/phoenixframework/tree-sitter-heex)
for Elixir
[diced](https://github.com/diced):
- Fixed `typescript` treesitter grammar not being included by default.
[valterschutz](https://github.com/valterschutz):
[ruff]: (https://github.com/astral-sh/ruff)
- Add [ruff-fix] as a formatter option in `vim.languages.python.format.type`.
[gmvar](https://github.com/gmvar):
[harper-ls]: https://github.com/Automattic/harper
- Add [harper-ls] to the `vim.lsp` module.
[derethil](https://github.com/derethil):
- Fix `vim.lazy.plugins.<name>.enabled` Lua evaluation.
[Jules](https://github.com/jules-sommer):
[nvim-highlight-colors]: https://github.com/brenoprata10/nvim-highlight-colors

View file

@ -1,7 +1,7 @@
{lib}: let
inherit (builtins) isString getAttr;
inherit (lib.options) mkOption;
inherit (lib.types) listOf bool str submodule attrsOf anything either nullOr;
inherit (lib.types) listOf bool str submodule attrsOf anything either nullOr uniq;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) luaInline;
in {
@ -46,7 +46,7 @@ in {
capabilities = mkOption {
type = nullOr (either luaInline (attrsOf anything));
default = null;
description = "LSP capabilitiess to pass to lspconfig";
description = "LSP capabilities to pass to LSP server configuration";
};
on_attach = mkOption {
@ -58,11 +58,11 @@ in {
filetypes = mkOption {
type = nullOr (listOf str);
default = null;
description = "Filetypes to auto-attach LSP in";
description = "Filetypes to auto-attach LSP server in";
};
cmd = mkOption {
type = nullOr (listOf str);
type = nullOr (either luaInline (uniq (listOf str)));
default = null;
description = "Command used to start the LSP server";
};

View file

@ -1,7 +1,8 @@
{lib}: let
inherit (lib.options) mergeEqualOption;
inherit (lib.lists) singleton;
inherit (lib.strings) isString stringLength match;
inherit (lib.types) listOf mkOptionType;
inherit (lib.types) listOf mkOptionType coercedTo;
in {
mergelessListOf = elemType: let
super = listOf elemType;
@ -27,4 +28,6 @@ in {
description = "RGB color in hex format";
check = v: isString v && (match "#?[0-9a-fA-F]{6}" v) != null;
};
singleOrListOf = t: coercedTo t singleton (listOf t);
}

View file

@ -10,5 +10,5 @@ in {
inherit (typesDag) dagOf;
inherit (typesPlugin) pluginsOpt extraPluginType mkPluginSetupOption luaInline pluginType borderType;
inherit (typesLanguage) diagnostics mkGrammarOption;
inherit (customTypes) char hexColor mergelessListOf;
inherit (customTypes) char hexColor mergelessListOf singleOrListOf;
}

View file

@ -1,5 +1,6 @@
{lib, ...}: let
inherit (lib.modules) mkRemovedOptionModule mkRenamedOptionModule;
inherit (builtins) head warn;
inherit (lib.modules) mkRemovedOptionModule mkRenamedOptionModule doRename;
inherit (lib.lists) concatLists;
inherit (lib.nvim.config) batchRenameOptions;
@ -20,6 +21,27 @@
# 2025-02-07
scrollOffset = "scrolloff";
};
mkRemovedLspOpt = lang: (mkRemovedOptionModule ["vim" "languages" lang "lsp" "opts"] ''
`vim.languages.${lang}.lsp.opts` is now moved to `vim.lsp.servers.<server_name>.init_options`
'');
mkRemovedLspPackage = lang: (mkRemovedOptionModule ["vim" "languages" lang "lsp" "package"] ''
`vim.languages.${lang}.lsp.package` is now moved to `vim.lsp.servers.<server_name>.cmd`
'');
mkRenamedLspServer = lang:
doRename
{
from = ["vim" "languages" lang "lsp" "server"];
to = ["vim" "languages" lang "lsp" "servers"];
visible = false;
warn = true;
use = x:
warn
"Obsolete option `vim.languages.${lang}.lsp.server` used, use `vim.languages.${lang}.lsp.servers` instead."
(head x);
};
in {
imports = concatLists [
[
@ -120,6 +142,123 @@ in {
in 'vim.clipboard.registers'. Please see the documentation for the new module for more
details, or open an issue if you are confused.
'')
# 2025-07-12
(mkRenamedLspServer "assembly")
(mkRenamedLspServer "astro")
(mkRemovedLspPackage "astro")
(mkRenamedLspServer "bash")
(mkRemovedLspPackage "bash")
(mkRemovedLspOpt "clang")
(mkRemovedLspPackage "clang")
(mkRenamedLspServer "clang")
(mkRemovedLspPackage "clojure")
(mkRenamedLspServer "csharp")
(mkRemovedLspPackage "csharp")
(mkRenamedLspServer "css")
(mkRemovedLspPackage "css")
(mkRemovedLspPackage "cue")
(mkRenamedLspServer "dart")
(mkRemovedLspPackage "dart")
(mkRemovedLspOpt "dart")
(mkRenamedLspServer "elixir")
(mkRemovedLspPackage "elixir")
(mkRenamedLspServer "fsharp")
(mkRemovedLspPackage "fsharp")
(mkRenamedLspServer "gleam")
(mkRemovedLspPackage "gleam")
(mkRenamedLspServer "go")
(mkRemovedLspPackage "go")
(mkRemovedLspPackage "haskell")
(mkRemovedLspPackage "hcl")
(mkRenamedLspServer "helm")
(mkRemovedLspPackage "helm")
(mkRemovedLspPackage "java")
(mkRenamedLspServer "julia")
(mkRemovedLspPackage "julia")
(mkRemovedLspPackage "kotlin")
(mkRemovedLspPackage "lua")
(mkRenamedLspServer "markdown")
(mkRemovedLspPackage "markdown")
(mkRenamedLspServer "nim")
(mkRemovedLspPackage "nim")
(mkRenamedLspServer "nix")
(mkRemovedLspPackage "nix")
(mkRemovedOptionModule ["vim" "languages" "nix" "lsp" "options"] ''
`vim.languages.nix.lsp.options` has been moved to `vim.lsp.servers.<server_name>.init_options`.
'')
(mkRenamedLspServer "nu")
(mkRemovedLspPackage "nu")
(mkRenamedLspServer "ocaml")
(mkRemovedLspPackage "ocaml")
(mkRenamedLspServer "odin")
(mkRemovedLspPackage "odin")
(mkRenamedLspServer "php")
(mkRemovedLspPackage "php")
(mkRenamedLspServer "python")
(mkRemovedLspPackage "python")
(mkRenamedLspServer "r")
(mkRemovedLspPackage "r")
(mkRenamedLspServer "ruby")
(mkRemovedLspPackage "ruby")
(mkRenamedLspServer "sql")
(mkRemovedLspPackage "sql")
(mkRenamedLspServer "svelte")
(mkRemovedLspPackage "svelte")
(mkRenamedLspServer "tailwind")
(mkRemovedLspPackage "tailwind")
(mkRemovedLspPackage "terraform")
(mkRenamedLspServer "ts")
(mkRemovedLspPackage "ts")
(mkRenamedLspServer "typst")
(mkRemovedLspPackage "typst")
(mkRenamedLspServer "vala")
(mkRemovedLspPackage "vala")
(mkRenamedLspServer "wgsl")
(mkRemovedLspPackage "wgsl")
(mkRenamedLspServer "yaml")
(mkRemovedLspPackage "yaml")
(mkRenamedLspServer "zig")
(mkRemovedLspPackage "zig")
]
# Migrated via batchRenameOptions. Further batch renames must be below this line.

View file

@ -8,5 +8,6 @@
./highlight.nix
./lsp.nix
./spellcheck.nix
./util.nix
];
}

View file

@ -16,6 +16,7 @@
cfg = config.vim.lsp;
# TODO: lspConfigurations filter on enabledServers instead of cfg.servers?
lspConfigurations =
mapAttrsToList (
name: value: ''

View file

@ -0,0 +1,178 @@
{
config,
lib,
...
}: let
inherit (builtins) filter;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.dag) entryBefore;
cfg = config.vim.lsp;
in {
config = mkMerge [
(mkIf (cfg.servers != {}) {
vim.luaConfigRC.lsp-util =
entryBefore ["lsp-servers"]
/*
lua
*/
''
-- Port of nvim-lspconfig util
local util = { path = {} }
util.default_config = {
log_level = vim.lsp.protocol.MessageType.Warning,
message_level = vim.lsp.protocol.MessageType.Warning,
settings = vim.empty_dict(),
init_options = vim.empty_dict(),
handlers = {},
autostart = true,
capabilities = vim.lsp.protocol.make_client_capabilities(),
}
-- global on_setup hook
util.on_setup = nil
do
local validate = vim.validate
local api = vim.api
local lsp = vim.lsp
local nvim_eleven = vim.fn.has 'nvim-0.11' == 1
local iswin = vim.uv.os_uname().version:match 'Windows'
local function escape_wildcards(path)
return path:gsub('([%[%]%?%*])', '\\%1')
end
local function is_fs_root(path)
if iswin then
return path:match '^%a:$'
else
return path == '/'
end
end
local function traverse_parents(path, cb)
path = vim.uv.fs_realpath(path)
local dir = path
-- Just in case our algo is buggy, don't infinite loop.
for _ = 1, 100 do
dir = vim.fs.dirname(dir)
if not dir then
return
end
-- If we can't ascend further, then stop looking.
if cb(dir, path) then
return dir, path
end
if is_fs_root(dir) then
break
end
end
end
util.root_pattern = function(...)
local patterns = util.tbl_flatten { ... }
return function(startpath)
startpath = util.strip_archive_subpath(startpath)
for _, pattern in ipairs(patterns) do
local match = util.search_ancestors(startpath, function(path)
for _, p in ipairs(vim.fn.glob(table.concat({ escape_wildcards(path), pattern }, '/'), true, true)) do
if vim.uv.fs_stat(p) then
return path
end
end
end)
if match ~= nil then
return match
end
end
end
end
util.root_markers_with_field = function(root_files, new_names, field, fname)
local path = vim.fn.fnamemodify(fname, ':h')
local found = vim.fs.find(new_names, { path = path, upward = true })
for _, f in ipairs(found or {}) do
-- Match the given `field`.
for line in io.lines(f) do
if line:find(field) then
root_files[#root_files + 1] = vim.fs.basename(f)
break
end
end
end
return root_files
end
util.insert_package_json = function(root_files, field, fname)
return util.root_markers_with_field(root_files, { 'package.json', 'package.json5' }, field, fname)
end
util.strip_archive_subpath = function(path)
-- Matches regex from zip.vim / tar.vim
path = vim.fn.substitute(path, 'zipfile://\\(.\\{-}\\)::[^\\\\].*$', '\\1', ''')
path = vim.fn.substitute(path, 'tarfile:\\(.\\{-}\\)::.*$', '\\1', ''')
return path
end
util.get_typescript_server_path = function(root_dir)
local project_roots = vim.fs.find('node_modules', { path = root_dir, upward = true, limit = math.huge })
for _, project_root in ipairs(project_roots) do
local typescript_path = project_root .. '/typescript'
local stat = vim.loop.fs_stat(typescript_path)
if stat and stat.type == 'directory' then
return typescript_path .. '/lib'
end
end
return '''
end
util.search_ancestors = function(startpath, func)
if nvim_eleven then
validate('func', func, 'function')
end
if func(startpath) then
return startpath
end
local guard = 100
for path in vim.fs.parents(startpath) do
-- Prevent infinite recursion if our algorithm breaks
guard = guard - 1
if guard == 0 then
return
end
if func(path) then
return path
end
end
end
util.path.is_descendant = function(root, path)
if not path then
return false
end
local function cb(dir, _)
return dir == root
end
local dir, _ = traverse_parents(path, cb)
return dir == root
end
util.tbl_flatten = function(t)
--- @diagnostic disable-next-line:deprecated
return nvim_eleven and vim.iter(t):flatten(math.huge):totable() or vim.tbl_flatten(t)
end
end
'';
})
];
}

View file

@ -4,12 +4,24 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) package;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.meta) getExe;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.assembly;
defaultServers = ["asm-lsp"];
servers = {
asm-lsp = {
enable = true;
cmd = [(getExe pkgs.asm-lsp)];
filetypes = ["asm" "vmasm"];
root_markers = [".asm-lsp.toml" ".git"];
};
};
in {
options.vim.languages.assembly = {
enable = mkEnableOption "Assembly support";
@ -20,12 +32,11 @@ in {
};
lsp = {
enable = mkEnableOption "Assembly LSP support (asm-lsp)" // {default = config.vim.lsp.enable;};
package = mkOption {
type = package;
default = pkgs.asm-lsp;
description = "asm-lsp package";
enable = mkEnableOption "Assembly LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Assembly LSP server to use";
};
};
};
@ -36,14 +47,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.asm-lsp = ''
lspconfig.asm_lsp.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = {"${cfg.lsp.package}/bin/asm-lsp"},
}
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -7,29 +7,36 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.meta) getExe;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption diagnostics;
inherit (lib.types) enum package;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) mkGrammarOption diagnostics singleOrListOf;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.astro;
defaultServer = "astro";
defaultServers = ["astro"];
servers = {
astro = {
package = pkgs.astro-language-server;
lspConfig = ''
lspconfig.astro.setup {
capabilities = capabilities,
on_attach = attach_keymaps,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/astro-ls", "--stdio"}''
}
}
'';
enable = true;
cmd = [(getExe pkgs.astro-language-server) "--stdio"];
filetypes = ["astro"];
root_markers = ["package.json" "tsconfig.json" "jsconfig.json" ".git"];
init_options = {
typescript = {};
};
before_init =
mkLuaInline
/*
lua
*/
''
function(_, config)
if config.init_options and config.init_options.typescript and not config.init_options.typescript.tsdk then
config.init_options.typescript.tsdk = util.get_typescript_server_path(config.root_dir)
end
end
'';
};
};
@ -81,34 +88,26 @@ in {
lsp = {
enable = mkEnableOption "Astro LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Astro LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
example = ''[lib.getExe pkgs.astro-language-server "--minify" "--stdio"]'';
description = "Astro LSP server package, or the command to run as a list of strings";
};
};
format = {
enable = mkEnableOption "Astro formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Astro formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Astro formatter to use";
};
package = mkOption {
description = "Astro formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Astro formatter package";
};
};
@ -130,8 +129,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.astro-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -5,31 +5,28 @@
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkOption mkEnableOption literalExpression;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either package listOf str bool;
inherit (lib.nvim.types) diagnostics mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum package bool;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) diagnostics mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.bash;
defaultServer = "bash-ls";
defaultServers = ["bash-ls"];
servers = {
bash-ls = {
package = pkgs.bash-language-server;
lspConfig = ''
lspconfig.bashls.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/bash-language-server", "start"}''
enable = true;
cmd = [(getExe pkgs.bash-language-server) "start"];
filetypes = ["bash" "sh"];
root_markers = [".git"];
settings = {
basheIde = {
globPattern = mkLuaInline "vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)'";
};
}
'';
};
};
};
@ -56,38 +53,30 @@ in {
};
lsp = {
enable = mkEnableOption "Enable Bash LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
enable = mkEnableOption "Bash LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Bash LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "bash-language-server package, or the command to run as a list of strings";
example = literalExpression ''[lib.getExe pkgs.bash-language-server "start"]'';
type = either package (listOf str);
default = pkgs.bash-language-server;
};
};
format = {
enable = mkOption {
description = "Enable Bash formatting";
type = bool;
default = config.vim.languages.enableFormat;
description = "Enable Bash formatting";
};
type = mkOption {
description = "Bash formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Bash formatter to use";
};
package = mkOption {
description = "Bash formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Bash formatter package";
};
};
@ -108,8 +97,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.bash-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -5,47 +5,143 @@
...
}: let
inherit (builtins) attrNames;
inherit (lib.lists) isList;
inherit (lib.strings) optionalString;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) bool enum package either listOf str nullOr;
inherit (lib.types) bool enum package;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.dag) entryAfter;
packageToCmd = package: defaultCmd:
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{ "${cfg.lsp.package}/bin/${defaultCmd}" }'';
cfg = config.vim.languages.clang;
defaultServer = "clangd";
defaultServers = ["clangd"];
servers = {
ccls = {
package = pkgs.ccls;
lspConfig = ''
lspconfig.ccls.setup{
capabilities = capabilities;
on_attach=default_on_attach;
cmd = ${packageToCmd cfg.lsp.package "ccls"};
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"}
}
cmd = [(getExe pkgs.ccls)];
filetypes = ["c" "cpp" "objc" "objcpp" "cuda"];
offset_encoding = "utf-32";
root_markers = ["compile_commands.json" ".ccls" ".git"];
workspace_required = true;
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
local function switch_source_header(bufnr)
local method_name = "textDocument/switchSourceHeader"
local params = vim.lsp.util.make_text_document_params(bufnr)
client:request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result then
vim.notify('corresponding file cannot be determined')
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, bufnr)
end
vim.api.nvim_buf_create_user_command(
bufnr,
"LspCclsSwitchSourceHeader",
function(arg)
switch_source_header(client, 0)
end,
{desc = "Switch between source/header"}
)
end
'';
};
clangd = {
package = pkgs.clang-tools;
lspConfig = ''
local clangd_cap = capabilities
-- use same offsetEncoding as null-ls
clangd_cap.offsetEncoding = {"utf-16"}
lspconfig.clangd.setup{
capabilities = clangd_cap;
on_attach=default_on_attach;
cmd = ${packageToCmd cfg.lsp.package "clangd"};
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.opts}"}
}
cmd = ["${pkgs.clang-tools}/bin/clangd"];
filetypes = ["c" "cpp" "objc" "objcpp" "cuda" "proto"];
root_markers = [
".clangd"
".clang-tidy"
".clang-format"
"compile_commands.json"
"compile_flags.txt"
"configure.ac"
".git"
];
capabilities = {
textDocument = {
completion = {
editsNearCursor = true;
};
};
offsetEncoding = ["utf-8" "utf-16"];
};
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
local function switch_source_header(bufnr)
local method_name = "textDocument/switchSourceHeader"
local client = vim.lsp.get_clients({ bufnr = bufnr, name = "clangd", })[1]
if not client then
return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name))
end
local params = vim.lsp.util.make_text_document_params(bufnr)
client.request(method_name, params, function(err, result)
if err then
error(tostring(err))
end
if not result then
vim.notify('corresponding file cannot be determined')
return
end
vim.cmd.edit(vim.uri_to_fname(result))
end, bufnr)
end
local function symbol_info()
local bufnr = vim.api.nvim_get_current_buf()
local clangd_client = vim.lsp.get_clients({ bufnr = bufnr, name = "clangd" })[1]
if not clangd_client or not clangd_client.supports_method 'textDocument/symbolInfo' then
return vim.notify('Clangd client not found', vim.log.levels.ERROR)
end
local win = vim.api.nvim_get_current_win()
local params = vim.lsp.util.make_position_params(win, clangd_client.offset_encoding)
clangd_client:request('textDocument/symbolInfo', params, function(err, res)
if err or #res == 0 then
-- Clangd always returns an error, there is not reason to parse it
return
end
local container = string.format('container: %s', res[1].containerName) ---@type string
local name = string.format('name: %s', res[1].name) ---@type string
vim.lsp.util.open_floating_preview({ name, container }, "", {
height = 2,
width = math.max(string.len(name), string.len(container)),
focusable = false,
focus = false,
border = 'single',
title = 'Symbol Info',
})
end, bufnr)
end
vim.api.nvim_buf_create_user_command(
bufnr,
"ClangdSwitchSourceHeader",
function(arg)
switch_source_header(0)
end,
{desc = "Switch between source/header"}
)
vim.api.nvim_buf_create_user_command(
bufnr,
"ClangdShowSymbolInfo",
function(arg)
symbol_info()
end,
{desc = "Show symbol info"}
)
end
'';
};
};
@ -100,23 +196,10 @@ in {
lsp = {
enable = mkEnableOption "clang LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
description = "The clang LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "clang LSP server 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 = servers.${cfg.lsp.server}.package;
};
opts = mkOption {
description = "Options to pass to clang LSP server";
type = nullOr str;
default = null;
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
};
};
@ -150,9 +233,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.clang-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf cfg.dap.enable {

View file

@ -4,15 +4,27 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.lists) isList;
inherit (lib.types) either listOf package str;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.clojure;
defaultServers = ["clojure-lsp"];
servers = {
clojure-lsp = {
enable = true;
cmd = [(getExe pkgs.clojure-lsp)];
filetypes = ["clojure" "edn"];
root_markers = ["project.clj" "deps.edn" "build.boot" "shadow-cljs.edn" ".git" "bb.edn"];
};
};
in {
options.vim.languages.clojure = {
enable = mkEnableOption "Clojure language support";
@ -24,28 +36,22 @@ in {
lsp = {
enable = mkEnableOption "Clojure LSP support" // {default = config.vim.lsp.enable;};
package = mkOption {
type = either package (listOf str);
default = pkgs.clojure-lsp;
description = "Clojure LSP";
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Clojure LSP server to use";
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.clojure-lsp = ''
lspconfig.clojure_lsp.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${getExe cfg.lsp.package}"}''
};
}
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.treesitter.enable {

View file

@ -5,14 +5,16 @@
options,
...
}: let
inherit (builtins) attrNames;
inherit (builtins) attrNames concatMap;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) either listOf package str enum;
inherit (lib.types) enum;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.meta) getExe;
inherit (lib.generators) mkLuaInline;
inherit (lib.strings) optionalString;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.attrsets) mapListToAttrs;
lspKeyConfig = config.vim.lsp.mappings;
lspKeyOptions = options.vim.lsp.mappings;
@ -25,58 +27,148 @@
# Omnisharp doesn't have colors in popup docs for some reason, and I've also
# seen mentions of it being way slower, so until someone finds missing
# functionality, this will be the default.
defaultServer = "csharp_ls";
defaultServers = ["csharp_ls"];
servers = {
omnisharp = {
package = pkgs.omnisharp-roslyn;
internalFormatter = true;
lspConfig = ''
lspconfig.omnisharp.setup {
capabilities = capabilities,
on_attach = function(client, bufnr)
default_on_attach(client, bufnr)
cmd = mkLuaInline ''
{
${toLuaObject (getExe pkgs.omnisharp-roslyn)},
'-z', -- https://github.com/OmniSharp/omnisharp-vscode/pull/4300
'--hostPID',
tostring(vim.fn.getpid()),
'DotNet:enablePackageRestore=false',
'--encoding',
'utf-8',
'--languageserver',
}
'';
filetypes = ["cs" "vb"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local function find_root_pattern(fname, lua_pattern)
return vim.fs.root(0, function(name, path)
return name:match(lua_pattern)
end)
end
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
end
'';
init_options = {};
capabilities = {
workspace = {
workspaceFolders = false; # https://github.com/OmniSharp/omnisharp-roslyn/issues/909
};
};
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
local oe = require("omnisharp_extended")
${mkLspBinding "goToDefinition" "oe.lsp_definition"}
${mkLspBinding "goToType" "oe.lsp_type_definition"}
${mkLspBinding "listReferences" "oe.lsp_references"}
${mkLspBinding "listImplementations" "oe.lsp_implementation"}
end,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/OmniSharp'}"
}
}
end
'';
settings = {
FormattingOptions = {
# Enables support for reading code style, naming convention and analyzer
# settings from .editorconfig.
EnableEditorConfigSupport = true;
# Specifies whether 'using' directives should be grouped and sorted during
# document formatting.
OrganizeImports = null;
};
MsBuild = {
# If true, MSBuild project system will only load projects for files that
# were opened in the editor. This setting is useful for big C# codebases
# and allows for faster initialization of code navigation features only
# for projects that are relevant to code that is being edited. With this
# setting enabled OmniSharp may load fewer projects and may thus display
# incomplete reference lists for symbols.
LoadProjectsOnDemand = null;
};
RoslynExtensionsOptions = {
# Enables support for roslyn analyzers, code fixes and rulesets.
EnableAnalyzersSupport = null;
# Enables support for showing unimported types and unimported extension
# methods in completion lists. When committed, the appropriate using
# directive will be added at the top of the current file. This option can
# have a negative impact on initial completion responsiveness;
# particularly for the first few completion sessions after opening a
# solution.
EnableImportCompletion = null;
# Only run analyzers against open files when 'enableRoslynAnalyzers' is
# true
AnalyzeOpenDocumentsOnly = null;
# Enables the possibility to see the code in external nuget dependencies
EnableDecompilationSupport = null;
};
RenameOptions = {
RenameInComments = null;
RenameOverloads = null;
RenameInStrings = null;
};
Sdk = {
# Specifies whether to include preview versions of the .NET SDK when
# determining which version to use for project loading.
IncludePrereleases = true;
};
};
};
csharp_ls = {
package = pkgs.csharp-ls;
internalFormatter = true;
lspConfig = ''
local extended_handler = require("csharpls_extended").handler
cmd = [(lib.getExe pkgs.csharp-ls)];
filetypes = ["cs"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local function find_root_pattern(fname, lua_pattern)
return vim.fs.root(0, function(name, path)
return name:match(lua_pattern)
end)
end
lspconfig.csharp_ls.setup {
capabilities = capabilities,
on_attach = default_on_attach,
handlers = {
["textDocument/definition"] = extended_handler,
["textDocument/typeDefinition"] = extended_handler
},
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/csharp-ls'}"
}
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
end
'';
init_options = {
AutomaticWorkspaceInit = true;
};
};
roslyn_ls = {
cmd = mkLuaInline ''
{
${toLuaObject (getExe pkgs.roslyn-ls)},
'--logLevel=Warning',
'--extensionLogDirectory=' .. vim.fs.dirname(vim.lsp.get_log_path()),
'--stdio',
}
'';
filetypes = ["cs"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local function find_root_pattern(fname, lua_pattern)
return vim.fs.root(0, function(name, path)
return name:match(lua_pattern)
end)
end
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
end
'';
init_options = {};
};
};
extraServerPlugins = {
omnisharp = ["omnisharp-extended-lsp-nvim"];
csharp_ls = ["csharpls-extended-lsp-nvim"];
roslyn_ls = [];
};
cfg = config.vim.languages.csharp;
@ -92,16 +184,10 @@ in {
lsp = {
enable = mkEnableOption "C# LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
description = "C# LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "C# LSP server package, or the command to run as a list of strings";
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
};
};
};
@ -114,9 +200,13 @@ in {
})
(mkIf cfg.lsp.enable {
vim.startPlugins = extraServerPlugins.${cfg.lsp.server} or [];
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.csharp-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.startPlugins = concatMap (server: extraServerPlugins.${server}) cfg.lsp.servers;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,34 +8,25 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.css;
defaultServer = "vscode-langservers-extracted";
defaultServer = ["cssls"];
servers = {
vscode-langservers-extracted = {
package = pkgs.vscode-langservers-extracted;
lspConfig = ''
-- enable (broadcasting) snippet capability for completion
-- see <https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#cssls>
local css_capabilities = vim.lsp.protocol.make_client_capabilities()
css_capabilities.textDocument.completion.completionItem.snippetSupport = true
-- cssls setup
lspconfig.cssls.setup {
capabilities = css_capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/vscode-css-language-server", "--stdio"}''
}
}
'';
cssls = {
cmd = ["${pkgs.vscode-langservers-extracted}/bin/vscode-css-language-server" "--stdio"];
filetypes = ["css" "scss" "less"];
# needed to enable formatting
init_options = {provideFormatter = true;};
root_markers = [".git" "package.json"];
settings = {
css.validate = true;
scss.validate = true;
less.validate = true;
};
};
};
@ -82,17 +73,10 @@ in {
lsp = {
enable = mkEnableOption "CSS LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
description = "CSS LSP server to use";
type = enum (attrNames servers);
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServer;
};
package = mkOption {
description = "CSS LSP server 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 = servers.${cfg.lsp.server}.package;
description = "CSS LSP server to use";
};
};
@ -120,8 +104,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.css-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -4,11 +4,17 @@
lib,
...
}: let
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.options) mkEnableOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) package;
inherit (lib.nvim.types) mkGrammarOption;
lspOptions = {
cmd = [(getExe pkgs.cue) "lsp"];
filetypes = ["cue"];
root_markers = ["cue.mod" ".git"];
};
cfg = config.vim.languages.cue;
in {
options.vim.languages.cue = {
@ -22,12 +28,6 @@ in {
lsp = {
enable = mkEnableOption "CUE LSP support" // {default = config.vim.lsp.enable;};
package = mkOption {
type = package;
default = pkgs.cue;
description = "cue lsp implementation";
};
};
};
@ -38,14 +38,7 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.cue-lsp = ''
lspconfig.cue.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = {"${cfg.lsp.package}/bin/cue", "lsp"},
}
'';
vim.lsp.servers.cue = lspOptions;
})
]);
}

View file

@ -6,34 +6,38 @@
}: let
inherit (builtins) attrNames;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.trivial) boolToString;
inherit (lib.lists) isList;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) enum either listOf package nullOr str bool;
inherit (lib.types) enum package nullOr str bool;
inherit (lib.strings) optionalString;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.dag) entryAfter;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.dart;
ftcfg = cfg.flutter-tools;
defaultServer = "dart";
defaultServers = ["dart"];
servers = {
dart = {
package = pkgs.dart;
lspConfig = ''
lspconfig.dartls.setup{
capabilities = capabilities;
on_attach=default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/dart", "language-server", "--protocol=lsp"}''
enable = true;
cmd = [(getExe pkgs.dart) "language-server" "--protocol=lsp"];
filetypes = ["dart"];
root_markers = ["pubspec.yaml"];
init_options = {
onlyAnalyzeProjectsWithOpenFiles = true;
suggestFromUnimportedLibraries = true;
closingLabels = true;
outline = true;
flutterOutline = true;
};
settings = {
dart = {
completeFunctionCalls = true;
showTodos = true;
};
${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.dartOpts}"}
}
'';
};
};
};
in {
@ -46,23 +50,11 @@ in {
};
lsp = {
enable = mkEnableOption "Dart LSP support";
server = mkOption {
description = "The Dart LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
example = ''[lib.getExe pkgs.jdt-language-server "-data" "~/.cache/jdtls/workspace"]'';
description = "Dart LSP server package, or the command to run as a list of strings";
};
opts = mkOption {
type = nullOr str;
default = null;
description = "Options to pass to Dart LSP server";
enable = mkEnableOption "Dart LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Dart LSP server to use";
};
};
@ -131,19 +123,23 @@ in {
};
};
config.vim = mkIf cfg.enable (mkMerge [
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
treesitter.enable = true;
treesitter.grammars = [cfg.treesitter.package];
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
})
(mkIf cfg.lsp.enable {
lsp.lspconfig.enable = true;
lsp.lspconfig.sources.dart-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf ftcfg.enable {
startPlugins = [
vim.startPlugins = [
(
if ftcfg.enableNoResolvePatch
then "flutter-tools-patched"
@ -152,7 +148,7 @@ in {
"plenary-nvim"
];
pluginRC.flutter-tools = entryAfter ["lsp-setup"] ''
vim.pluginRC.flutter-tools = entryAfter ["lsp-servers"] ''
require('flutter-tools').setup {
${optionalString (ftcfg.flutterPackage != null) "flutter_path = \"${ftcfg.flutterPackage}/bin/flutter\","}
lsp = {

View file

@ -21,6 +21,7 @@ in {
./html.nix
./haskell.nix
./java.nix
./json.nix
./lua.nix
./markdown.nix
./nim.nix
@ -29,6 +30,7 @@ in {
./ocaml.nix
./php.nix
./python.nix
./qml.nix
./r.nix
./rust.nix
./scala.nix
@ -46,6 +48,7 @@ in {
./wgsl.nix
./yaml.nix
./ruby.nix
./just.nix
# This is now a hard deprecation.
(mkRenamedOptionModule ["vim" "languages" "enableLSP"] ["vim" "lsp" "enable"])

View file

@ -7,30 +7,36 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.types) enum package;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.elixir;
defaultServer = "elixirls";
defaultServers = ["elixirls"];
servers = {
elixirls = {
package = pkgs.elixir-ls;
lspConfig = ''
-- elixirls setup
lspconfig.elixirls.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/elixir-ls"}''
}
}
'';
enable = true;
cmd = [(getExe pkgs.elixir-ls)];
filetypes = ["elixir" "eelixir" "heex" "surface"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
local matches = vim.fs.find({ 'mix.exs' }, { upward = true, limit = 2, path = fname })
local child_or_root_path, maybe_umbrella_path = unpack(matches)
local root_dir = vim.fs.dirname(maybe_umbrella_path or child_or_root_path)
on_dir(root_dir)
end
'';
};
};
@ -50,22 +56,16 @@ in {
treesitter = {
enable = mkEnableOption "Elixir treesitter" // {default = config.vim.languages.enableTreesitter;};
package = mkGrammarOption pkgs "elixir";
heexPackage = mkGrammarOption pkgs "heex";
eexPackage = mkGrammarOption pkgs "eex";
};
lsp = {
enable = mkEnableOption "Elixir LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Elixir LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Elixir LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -73,15 +73,15 @@ in {
enable = mkEnableOption "Elixir formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Elixir formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Elixir formatter to use";
};
package = mkOption {
description = "Elixir formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Elixir formatter package";
};
};
@ -93,12 +93,20 @@ in {
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
vim.treesitter.grammars = [
cfg.treesitter.package
cfg.treesitter.heexPackage
cfg.treesitter.eexPackage
];
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.elixir-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -6,29 +6,48 @@
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) either listOf package str enum;
inherit (lib.types) package enum;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
defaultServer = "fsautocomplete";
defaultServer = ["fsautocomplete"];
servers = {
fsautocomplete = {
package = pkgs.fsautocomplete;
internalFormatter = false;
lspConfig = ''
lspconfig.fsautocomplete.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/fsautocomplete'}"
},
}
cmd = [(getExe pkgs.fsautocomplete) "--adaptive-lsp-server-enabled"];
filetypes = ["fsharp"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
on_dir(vim.fs.root(bufnr, function(name, path)
return name == ".git" or name:match("%.sln$") or name:match("%.fsproj$")
end))
end
'';
init_options = {
AutomaticWorkspaceInit = true;
};
settings = {
FSharp = {
keywordsAutocomplete = true;
ExternalAutocomplete = false;
Linter = true;
UnionCaseStubGeneration = true;
UnionCaseStubGenerationBody = ''failwith "Not Implemented"'';
RecordStubGeneration = true;
RecordStubGenerationBody = ''failwith "Not Implemented"'';
InterfaceStubGeneration = true;
InterfaceStubGenerationObjectIdentifier = "this";
InterfaceStubGenerationMethodBody = ''failwith "Not Implemented"'';
UnusedOpensAnalyzer = true;
UnusedDeclarationsAnalyzer = true;
UseSdkScripts = true;
SimplifyNameAnalyzer = true;
ResolveNamespaces = true;
EnableReferenceCodeLens = true;
};
};
};
};
@ -52,18 +71,11 @@ in {
lsp = {
enable = mkEnableOption "F# LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServer;
description = "F# LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
example = ''[lib.getExe pkgs.fsautocomplete "--state-directory" "~/.cache/fsautocomplete"]'';
description = "F# LSP server package, or the command to run as a list of strings";
};
};
format = {
enable = mkEnableOption "F# formatting" // {default = config.vim.languages.enableFormat;};
@ -90,8 +102,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.fsharp-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -7,28 +7,20 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.meta) getExe;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.gleam;
defaultServer = "gleam";
defaultServers = ["gleam"];
servers = {
gleam = {
package = pkgs.gleam;
lspConfig = ''
lspconfig.gleam.setup{
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/gleam", "lsp"}''
}
}
'';
enable = true;
cmd = [(getExe pkgs.gleam) "lsp"];
filetypes = ["gleam"];
root_markers = ["gleam.toml" ".git"];
};
};
in {
@ -42,18 +34,11 @@ in {
lsp = {
enable = mkEnableOption "Gleam LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Gleam LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
description = "Gleam LSP server package, or the command to run as a list of strings";
};
};
};
@ -64,8 +49,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.gleam-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,28 +8,53 @@
inherit (lib.options) mkEnableOption mkOption literalMD;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.lists) isList;
inherit (lib.types) bool enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.generators) mkLuaInline;
inherit (lib.types) bool enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.dag) entryAfter;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.go;
defaultServer = "gopls";
defaultServers = ["gopls"];
servers = {
gopls = {
package = pkgs.gopls;
lspConfig = ''
lspconfig.gopls.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/gopls", "serve"}''
},
}
cmd = [(getExe pkgs.gopls)];
filetypes = ["go" "gomod" "gowork" "gotmpl"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
local function get_root(fname)
if _G.nvf_gopls_mod_cache and fname:sub(1, #_G.nvf_gopls_mod_cache) == _G.nvf_gopls_mod_cache then
local clients = vim.lsp.get_clients { name = 'gopls' }
if #clients > 0 then
return clients[#clients].config.root_dir
end
end
return vim.fs.root(fname, 'go.work') or vim.fs.root(fname, 'go.mod') or vim.fs.root(fname, '.git')
end
-- see: https://github.com/neovim/nvim-lspconfig/issues/804
if _G.nvf_gopls_mod_cache then
on_dir(get_root(fname))
return
end
local cmd = { 'go', 'env', 'GOMODCACHE' }
local ok, err = pcall(vim.system, cmd, { text = true }, function(output)
if output.code == 0 then
if output.stdout then
_G.nvf_gopls_mod_cache = vim.trim(output.stdout)
end
on_dir(get_root(fname))
else
vim.schedule(function()
vim.notify(('[gopls] cmd failed with code %d: %s\n%s'):format(output.code, cmd, output.stderr))
end)
end
end)
if not ok then vim.notify(('[gopls] cmd failed: %s\n%s'):format(cmd, err)) end
end
'';
};
};
@ -69,17 +94,10 @@ in {
lsp = {
enable = mkEnableOption "Go LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Go LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Go LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -134,8 +152,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.go-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -4,17 +4,67 @@
pkgs,
...
}: let
inherit (builtins) isList;
inherit (lib.types) either package listOf str;
inherit (builtins) isList attrNames;
inherit (lib.types) either package enum listOf str;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.strings) optionalString;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.dag) entryAfter;
inherit (lib.nvim.dag) entryAfter entryBefore;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe';
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (pkgs) haskellPackages;
inherit (lib.nvim.lua) toLuaObject;
cfg = config.vim.languages.haskell;
defaultServers = ["hls"];
servers = {
hls = {
enable = false;
cmd = [(getExe' pkgs.haskellPackages.haskell-language-server "haskell-language-server-wrapper") "--lsp"];
filetypes = ["haskell" "lhaskell"];
on_attach =
mkLuaInline
/*
lua
*/
''
function(client, bufnr)
local ht = require("haskell-tools")
default_on_attach(client, bufnr, ht)
local opts = { noremap = true, silent = true, buffer = bufnr }
vim.keymap.set('n', '<localleader>cl', vim.lsp.codelens.run, opts)
vim.keymap.set('n', '<localleader>hs', ht.hoogle.hoogle_signature, opts)
vim.keymap.set('n', '<localleader>ea', ht.lsp.buf_eval_all, opts)
vim.keymap.set('n', '<localleader>rr', ht.repl.toggle, opts)
vim.keymap.set('n', '<localleader>rf', function()
ht.repl.toggle(vim.api.nvim_buf_get_name(0))
end, opts)
vim.keymap.set('n', '<localleader>rq', ht.repl.quit, opts)
end
'';
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern('hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml')(fname))
end
'';
settings = {
haskell = {
formattingProvider = "ormolu";
cabalFormattingProvider = "cabalfmt";
};
};
};
};
in {
options.vim.languages.haskell = {
enable = mkEnableOption "Haskell support";
@ -25,21 +75,20 @@ in {
};
lsp = {
enable = mkEnableOption "LSP support for Haskell" // {default = config.vim.lsp.enable;};
package = mkOption {
description = "Haskell LSP package or command to run the Haskell LSP";
example = ''[ (lib.getExe pkgs.haskellPackages.haskell-language-server) "--debug" ]'';
default = haskellPackages.haskell-language-server;
type = either package (listOf str);
enable = mkEnableOption "Haskell LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Haskell LSP server to use";
};
};
dap = {
enable = mkEnableOption "DAP support for Haskell" // {default = config.vim.languages.enableDAP;};
package = mkOption {
description = "Haskell DAP package or command to run the Haskell DAP";
default = haskellPackages.haskell-debug-adapter;
type = either package (listOf str);
description = "Haskell DAP package or command to run the Haskell DAP";
};
};
};
@ -57,7 +106,7 @@ in {
startPlugins = ["haskell-tools-nvim"];
luaConfigRC.haskell-tools-nvim =
entryAfter
["lsp-setup"]
["lsp-servers"]
''
vim.g.haskell_tools = {
${optionalString cfg.lsp.enable ''
@ -67,25 +116,7 @@ in {
enable = true,
},
},
hls = {
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/haskell-language-server-wrapper", "--lsp"}''
},
on_attach = function(client, bufnr, ht)
default_on_attach(client, bufnr, ht)
local opts = { noremap = true, silent = true, buffer = bufnr }
vim.keymap.set('n', '<localleader>cl', vim.lsp.codelens.run, opts)
vim.keymap.set('n', '<localleader>hs', ht.hoogle.hoogle_signature, opts)
vim.keymap.set('n', '<localleader>ea', ht.lsp.buf_eval_all, opts)
vim.keymap.set('n', '<localleader>rr', ht.repl.toggle, opts)
vim.keymap.set('n', '<localleader>rf', function()
ht.repl.toggle(vim.api.nvim_buf_get_name(0))
end, opts)
vim.keymap.set('n', '<localleader>rq', ht.repl.quit, opts)
end,
},
hls = ${toLuaObject servers.hls},
''}
${optionalString cfg.dap.enable ''
dap = {

View file

@ -8,22 +8,19 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) package bool enum;
inherit (lib.types) package bool enum listOf;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.hcl;
defaultServer = "terraform-ls";
defaultServers = ["terraform-ls"];
servers = {
terraform-ls = {
package = pkgs.terraform-ls;
lspConfig = ''
lspconfig.terraformls.setup {
capabilities = capabilities,
on_attach=default_on_attach,
cmd = {"${lib.getExe cfg.lsp.package}", "serve"},
}
'';
enable = true;
cmd = [(getExe pkgs.terraform-ls) "serve"];
filetypes = ["terraform" "terraform-vars"];
root_markers = [".terraform" ".git"];
};
};
@ -43,12 +40,11 @@ in {
};
lsp = {
enable = mkEnableOption "HCL LSP support (terraform-ls)" // {default = config.vim.lsp.enable;};
# TODO: (maybe, is it better?) it would be cooler to use vscode-extensions.hashicorp.hcl probably, shouldn't be too hard
package = mkOption {
type = package;
default = servers.${defaultServer}.package;
description = "HCL language server package (terraform-ls)";
enable = mkEnableOption "HCL LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "HCL LSP server to use";
};
};
@ -96,10 +92,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources = lib.optionalAttrs (! config.vim.languages.terraform.lsp.enable) {
terraform-ls = servers.${cfg.lsp.server}.lspConfig;
};
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -4,44 +4,37 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (builtins) attrNames head;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.helm;
yamlCfg = config.vim.languages.yaml;
helmCmd =
if isList cfg.lsp.package
then cfg.lsp.package
else ["${cfg.lsp.package}/bin/helm_ls" "serve"];
yamlCmd =
if isList yamlCfg.lsp.package
then builtins.elemAt yamlCfg.lsp.package 0
else "${yamlCfg.lsp.package}/bin/yaml-language-server";
defaultServer = "helm-ls";
defaultServers = ["helm-ls"];
servers = {
helm-ls = {
package = pkgs.helm-ls;
lspConfig = ''
lspconfig.helm_ls.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${expToLua helmCmd},
settings = {
['helm-ls'] = {
yamlls = {
path = "${yamlCmd}"
}
}
}
}
'';
enable = true;
cmd = [(getExe pkgs.helm-ls) "serve"];
filetypes = ["helm" "yaml.helm-values"];
root_markers = ["Chart.yaml"];
capabilities = {
didChangeWatchedFiles = {
dynamicRegistration = true;
};
};
settings = {
helm-ls = {
yamlls = {
# TODO: Determine if this is a good enough solution
path = (head yamlCfg.lsp.servers).cmd;
};
};
};
};
};
in {
@ -55,17 +48,10 @@ in {
lsp = {
enable = mkEnableOption "Helm LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Helm LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Helm LSP server package";
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
};
};
};
@ -77,8 +63,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.helm-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
{

View file

@ -4,14 +4,44 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.meta) getExe;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) bool;
inherit (lib.types) bool enum package;
inherit (lib.lists) optional;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.types) mkGrammarOption diagnostics singleOrListOf;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.html;
defaultServers = ["superhtml"];
servers = {
superhtml = {
cmd = [(getExe pkgs.superhtml) "lsp"];
filetypes = ["html" "shtml" "htm"];
root_markers = ["index.html" ".git"];
};
};
defaultFormat = "superhtml";
formats = {
superhtml = {
package = pkgs.writeShellApplication {
name = "superhtml_fmt";
runtimeInputs = [pkgs.superhtml];
text = "superhtml fmt -";
};
};
};
defaultDiagnosticsProvider = ["htmlhint"];
diagnosticsProviders = {
htmlhint = {
config.cmd = getExe pkgs.htmlhint;
};
};
in {
options.vim.languages.html = {
enable = mkEnableOption "HTML language support";
@ -19,9 +49,44 @@ in {
enable = mkEnableOption "HTML treesitter support" // {default = config.vim.languages.enableTreesitter;};
package = mkGrammarOption pkgs "html";
autotagHtml = mkOption {
description = "Enable autoclose/autorename of html tags (nvim-ts-autotag)";
type = bool;
default = true;
description = "Enable autoclose/autorename of html tags (nvim-ts-autotag)";
};
};
lsp = {
enable = mkEnableOption "HTML LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "HTML LSP server to use";
};
};
format = {
enable = mkEnableOption "HTML formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
type = enum (attrNames formats);
default = defaultFormat;
description = "HTML formatter to use";
};
package = mkOption {
type = package;
default = formats.${cfg.format.type}.package;
description = "HTML formatter package";
};
};
extraDiagnostics = {
enable = mkEnableOption "extra HTML diagnostics" // {default = config.vim.languages.enableExtraDiagnostics;};
types = diagnostics {
langDesc = "HTML";
inherit diagnosticsProviders;
inherit defaultDiagnosticsProvider;
};
};
};
@ -41,5 +106,35 @@ in {
'');
};
})
(mkIf cfg.lsp.enable {
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf (cfg.format.enable && !cfg.lsp.enable) {
vim.formatter.conform-nvim = {
enable = true;
setupOpts.formatters_by_ft.html = [cfg.format.type];
setupOpts.formatters.${cfg.format.type} = {
command = getExe cfg.format.package;
};
};
})
(mkIf cfg.extraDiagnostics.enable {
vim.diagnostics.nvim-lint = {
enable = true;
linters_by_ft.html = cfg.extraDiagnostics.types;
linters = mkMerge (map (name: {
${name} = diagnosticsProviders.${name}.config;
})
cfg.extraDiagnostics.types);
};
})
]);
}

View file

@ -7,12 +7,59 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.lists) isList;
inherit (lib.types) either listOf package str;
inherit (builtins) attrNames;
inherit (lib.types) listOf enum;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.dag) entryBefore;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.java;
defaultServers = ["jdtls"];
servers = {
jdtls = {
enable = true;
cmd =
mkLuaInline
/*
lua
*/
''
{
'${getExe pkgs.jdt-language-server}',
'-configuration',
get_jdtls_config_dir(),
'-data',
get_jdtls_workspace_dir(),
get_jdtls_jvm_args(),
}
'';
filetypes = ["java"];
root_markers = [
# Multi-module projects
".git"
"build.gradle"
"build.gradle.kts"
# Single-module projects
"build.xml" # Ant
"pom.xml" # Maven
"settings.gradle" # Gradle
"settings.gradle.kts" # Gradle
];
init_options = {
workspace = mkLuaInline "get_jdtls_workspace_dir()";
jvm_args = {};
os_config = mkLuaInline "nil";
};
handlers = {
"textDocument/codeAction" = mkLuaInline "jdtls_on_textdocument_codeaction";
"textDocument/rename" = mkLuaInline "jdtls_on_textdocument_rename";
"workspace/applyEdit" = mkLuaInline "jdtls_on_workspace_applyedit";
"language/status" = mkLuaInline "vim.schedule_wrap(jdtls_on_language_status)";
};
};
};
in {
options.vim.languages.java = {
enable = mkEnableOption "Java language support";
@ -23,30 +70,107 @@ in {
};
lsp = {
enable = mkEnableOption "Java LSP support (java-language-server)" // {default = config.vim.lsp.enable;};
package = mkOption {
description = "java language server 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.jdt-language-server;
enable = mkEnableOption "Java LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Java LSP server to use";
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.jdtls = ''
lspconfig.jdtls.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${getExe cfg.lsp.package}", "-data", vim.fn.stdpath("cache").."/jdtls/workspace"}''
},
}
'';
vim.luaConfigRC.jdtls-util =
entryBefore ["lsp-servers"]
/*
lua
*/
''
local jdtls_handlers = require 'vim.lsp.handlers'
local jdtls_env = {
HOME = vim.uv.os_homedir(),
XDG_CACHE_HOME = os.getenv 'XDG_CACHE_HOME',
JDTLS_JVM_ARGS = os.getenv 'JDTLS_JVM_ARGS',
}
local function get_cache_dir()
return jdtls_env.XDG_CACHE_HOME and jdtls_env.XDG_CACHE_HOME or jdtls_env.HOME .. '/.cache'
end
local function get_jdtls_cache_dir()
return get_cache_dir() .. '/jdtls'
end
local function get_jdtls_config_dir()
return get_jdtls_cache_dir() .. '/config'
end
local function get_jdtls_workspace_dir()
return get_jdtls_cache_dir() .. '/workspace'
end
local function get_jdtls_jvm_args()
local args = {}
for a in string.gmatch((jdtls_env.JDTLS_JVM_ARGS or '''), '%S+') do
local arg = string.format('--jvm-arg=%s', a)
table.insert(args, arg)
end
return unpack(args)
end
-- TextDocument version is reported as 0, override with nil so that
-- the client doesn't think the document is newer and refuses to update
-- See: https://github.com/eclipse/eclipse.jdt.ls/issues/1695
local function jdtls_fix_zero_version(workspace_edit)
if workspace_edit and workspace_edit.documentChanges then
for _, change in pairs(workspace_edit.documentChanges) do
local text_document = change.textDocument
if text_document and text_document.version and text_document.version == 0 then
text_document.version = nil
end
end
end
return workspace_edit
end
local function jdtls_on_textdocument_codeaction(err, actions, ctx)
for _, action in ipairs(actions) do
-- TODO: (steelsojka) Handle more than one edit?
if action.command == 'java.apply.workspaceEdit' then -- 'action' is Command in java format
action.edit = jdtls_fix_zero_version(action.edit or action.arguments[1])
elseif type(action.command) == 'table' and action.command.command == 'java.apply.workspaceEdit' then -- 'action' is CodeAction in java format
action.edit = jdtls_fix_zero_version(action.edit or action.command.arguments[1])
end
end
jdtls_handlers[ctx.method](err, actions, ctx)
end
local function jdtls_on_textdocument_rename(err, workspace_edit, ctx)
jdtls_handlers[ctx.method](err, jdtls_fix_zero_version(workspace_edit), ctx)
end
local function jdtls_on_workspace_applyedit(err, workspace_edit, ctx)
jdtls_handlers[ctx.method](err, jdtls_fix_zero_version(workspace_edit), ctx)
end
-- Non-standard notification that can be used to display progress
local function jdtls_on_language_status(_, result)
local command = vim.api.nvim_command
command 'echohl ModeMsg'
command(string.format('echo "%s"', result.message))
command 'echohl None'
end
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.treesitter.enable {

View file

@ -0,0 +1,100 @@
{
config,
pkgs,
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.meta) getExe' getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.json;
defaultServers = ["jsonls"];
servers = {
jsonls = {
cmd = [(getExe' pkgs.vscode-langservers-extracted "vscode-json-languageserver") "--stdio"];
filetypes = ["json" "jsonc"];
init_options = {provideFormatter = true;};
root_markers = [".git"];
};
};
defaultFormat = "jsonfmt";
formats = {
jsonfmt = {
package = pkgs.writeShellApplication {
name = "jsonfmt";
runtimeInputs = [pkgs.jsonfmt];
text = "jsonfmt -w -";
};
};
};
in {
options.vim.languages.json = {
enable = mkEnableOption "JSON language support";
treesitter = {
enable = mkEnableOption "JSON treesitter" // {default = config.vim.languages.enableTreesitter;};
package = mkGrammarOption pkgs "json";
};
lsp = {
enable = mkEnableOption "JSON LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "JSON LSP server to use";
};
};
format = {
enable = mkEnableOption "JSON formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "JSON formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
};
package = mkOption {
description = "JSON formatter package";
type = package;
default = formats.${cfg.format.type}.package;
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
})
(mkIf cfg.lsp.enable {
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {
vim.formatter.conform-nvim = {
enable = true;
setupOpts.formatters_by_ft.json = [cfg.format.type];
setupOpts.formatters.${cfg.format.type} = {
command = getExe cfg.format.package;
};
};
})
]);
}

View file

@ -4,63 +4,82 @@
config,
...
}: let
inherit (builtins) attrNames isList;
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) either listOf package str enum bool nullOr;
inherit (lib.types) enum;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.strings) optionalString;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.dag) entryBefore;
defaultServer = "julials";
defaultServers = ["julials"];
servers = {
julials = {
package = pkgs.julia.withPackages ["LanguageServer"];
internalFormatter = true;
lspConfig = ''
lspconfig.julials.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''
{
"${optionalString (cfg.lsp.package != null) "${cfg.lsp.package}/bin/"}julia",
"--startup-file=no",
"--history-file=no",
"--eval",
[[
using LanguageServer
depot_path = get(ENV, "JULIA_DEPOT_PATH", "")
project_path = let
dirname(something(
## 1. Finds an explicitly set project (JULIA_PROJECT)
Base.load_path_expand((
p = get(ENV, "JULIA_PROJECT", nothing);
p === nothing ? nothing : isempty(p) ? nothing : p
)),
## 2. Look for a Project.toml file in the current working directory,
## or parent directories, with $HOME as an upper boundary
Base.current_project(),
## 3. First entry in the load path
get(Base.load_path(), 1, nothing),
## 4. Fallback to default global environment,
## this is more or less unreachable
Base.load_path_expand("@v#.#"),
))
end
@info "Running language server" VERSION pwd() project_path depot_path
server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path)
server.runlinter = true
run(server)
]]
}
''
}
}
'';
enable = true;
cmd =
mkLuaInline
/*
lua
*/
''
{
'${getExe (pkgs.julia.withPackages ["LanguageServer"])}',
'--startup-file=no',
'--history-file=no',
'-e',
[[
# Load LanguageServer.jl: attempt to load from ~/.julia/environments/nvim-lspconfig
# with the regular load path as a fallback
ls_install_path = joinpath(
get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")),
"environments", "nvim-lspconfig"
)
pushfirst!(LOAD_PATH, ls_install_path)
using LanguageServer
popfirst!(LOAD_PATH)
depot_path = get(ENV, "JULIA_DEPOT_PATH", "")
project_path = let
dirname(something(
## 1. Finds an explicitly set project (JULIA_PROJECT)
Base.load_path_expand((
p = get(ENV, "JULIA_PROJECT", nothing);
p === nothing ? nothing : isempty(p) ? nothing : p
)),
## 2. Look for a Project.toml file in the current working directory,
## or parent directories, with $HOME as an upper boundary
Base.current_project(),
## 3. First entry in the load path
get(Base.load_path(), 1, nothing),
## 4. Fallback to default global environment,
## this is more or less unreachable
Base.load_path_expand("@v#.#"),
))
end
@info "Running language server" VERSION pwd() project_path depot_path
server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path)
server.runlinter = true
run(server)
]],
}
'';
filetypes = ["julia"];
root_markers = ["Project.toml" "JuliaProject.toml"];
on_attach =
mkLuaInline
/*
lua
*/
''
function(_, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspJuliaActivateEnv', activate_julia_env, {
desc = 'Activate a Julia environment',
nargs = '?',
complete = 'file',
})
end
'';
};
};
@ -76,38 +95,26 @@ in {
};
lsp = {
enable = mkOption {
type = bool;
default = config.vim.lsp.enable;
enable = mkEnableOption "Julia LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = ''
Whether to enable Julia LSP support.
Julia LSP Server to Use
::: {.note}
The entirety of Julia is bundled with nvf, if you enable this
option, since there is no way to provide only the LSP server.
If you want to avoid that, you have to change
[](#opt-vim.languages.julia.lsp.package) to use the Julia binary
in {env}`PATH` (set it to `null`), and add the `LanguageServer` package to
Julia in your devshells.
[vim.lsp.servers.julials.cmd](#opt-vim.lsp.servers._name_.cmd) to use
the Julia binary in {env}`PATH`, and add the `LanguageServer`
package to Julia in your devshells.
Check the source file of this option for the full `cmd`.
:::
'';
};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
description = "Julia LSP server to use";
};
package = mkOption {
description = ''
Julia LSP server package, `null` to use the Julia binary in {env}`PATH`, or
the command to run as a list of strings.
'';
type = nullOr (either package (listOf str));
default = servers.${cfg.lsp.server}.package;
};
};
};
};
@ -119,8 +126,70 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.julia-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.luaConfigRC.julia-util =
entryBefore ["lsp-servers"]
/*
lua
*/
''
local function activate_julia_env(path)
assert(vim.fn.has 'nvim-0.10' == 1, 'requires Nvim 0.10 or newer')
local bufnr = vim.api.nvim_get_current_buf()
local julials_clients = vim.lsp.get_clients { bufnr = bufnr, name = 'julials' }
assert(
#julials_clients > 0,
'method julia/activateenvironment is not supported by any servers active on the current buffer'
)
local function _activate_env(environment)
if environment then
for _, julials_client in ipairs(julials_clients) do
julials_client:notify('julia/activateenvironment', { envPath = environment })
end
vim.notify('Julia environment activated: \n`' .. environment .. '`', vim.log.levels.INFO)
end
end
if path then
path = vim.fs.normalize(vim.fn.fnamemodify(vim.fn.expand(path), ':p'))
local found_env = false
for _, project_file in ipairs(root_files) do
local file = vim.uv.fs_stat(vim.fs.joinpath(path, project_file))
if file and file.type then
found_env = true
break
end
end
if not found_env then
vim.notify('Path is not a julia environment: \n`' .. path .. '`', vim.log.levels.WARN)
return
end
_activate_env(path)
else
local depot_paths = vim.env.JULIA_DEPOT_PATH
and vim.split(vim.env.JULIA_DEPOT_PATH, vim.fn.has 'win32' == 1 and ';' or ':')
or { vim.fn.expand '~/.julia' }
local environments = {}
vim.list_extend(environments, vim.fs.find(root_files, { type = 'file', upward = true, limit = math.huge }))
for _, depot_path in ipairs(depot_paths) do
local depot_env = vim.fs.joinpath(vim.fs.normalize(depot_path), 'environments')
vim.list_extend(
environments,
vim.fs.find(function(name, env_path)
return vim.tbl_contains(root_files, name) and string.sub(env_path, #depot_env + 1):match '^/[^/]*$'
end, { path = depot_env, type = 'file', limit = math.huge })
)
end
environments = vim.tbl_map(vim.fs.dirname, environments)
vim.ui.select(environments, { prompt = 'Select a Julia environment' }, _activate_env)
end
end
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -0,0 +1,64 @@
{
config,
lib,
pkgs,
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.types) enum listOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) mkGrammarOption;
cfg = config.vim.languages.just;
defaultServers = ["just-lsp"];
servers = {
just-lsp = {
enable = true;
cmd = [(getExe pkgs.just-lsp)];
filetypes = ["just"];
root_markers = [".git" "justfile"];
};
};
in {
options.vim.languages.just = {
enable = mkEnableOption "Just support";
treesitter = {
enable =
mkEnableOption "Just treesitter" // {default = config.vim.languages.enableTreesitter;};
package = mkGrammarOption pkgs "just";
};
lsp = {
enable =
mkEnableOption "Just LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Just LSP server to use";
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter = {
enable = true;
grammars = [cfg.treesitter.package];
};
})
(mkIf cfg.lsp.enable {
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -4,16 +4,47 @@
lib,
...
}: let
inherit (lib.options) mkEnableOption mkOption literalExpression;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.types) either package listOf str;
inherit (lib.meta) getExe' getExe;
inherit (builtins) attrNames;
inherit (lib.types) enum listOf;
inherit (lib.nvim.types) mkGrammarOption diagnostics;
inherit (lib.lists) isList;
inherit (lib.nvim.lua) expToLua;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.kotlin;
defaultServers = ["kotlin-language-server"];
servers = {
kotlin-language-server = {
enable = true;
cmd = [(getExe' pkgs.kotlin-language-server "kotlin-language-server")];
filetypes = ["kotlin"];
root_markers = [
"settings.gradle" # Gradle (multi-project)
"settings.gradle.kts" # Gradle (multi-project)
"build.xml" # Ant
"pom.xml" # Maven
"build.gradle" # Gradle
"build.gradle.kts" # gradle
];
init_options = {
storagePath = mkLuaInline "
vim.fs.root(vim.fn.expand '%:p:h',
{
'settings.gradle', -- Gradle (multi-project)
'settings.gradle.kts', -- Gradle (multi-project)
'build.xml', -- Ant
'pom.xml', -- Maven
'build.gradle', -- Gradle
'build.gradle.kts', -- Gradle
}
)";
};
};
};
defaultDiagnosticsProvider = ["ktlint"];
diagnosticsProviders = {
ktlint = {
@ -31,22 +62,10 @@ in {
lsp = {
enable = mkEnableOption "Kotlin LSP support" // {default = config.vim.lsp.enable;};
package = mkOption {
description = "kotlin_language_server package with Kotlin runtime";
type = either package (listOf str);
example = literalExpression ''
pkgs.symlinkJoin {
name = "kotlin-language-server-wrapped";
paths = [pkgs.kotlin-language-server];
nativeBuildInputs = [pkgs.makeBinaryWrapper];
postBuild = '''
wrapProgram $out/bin/kotlin-language-server \
--prefix PATH : ''${pkgs.kotlin}/bin
''';
};
'';
default = pkgs.kotlin-language-server;
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Kotlin LSP server to use";
};
};
@ -78,23 +97,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.kotlin_language_server = ''
lspconfig.kotlin_language_server.setup {
capabilities = capabilities,
root_dir = lspconfig.util.root_pattern("main.kt", ".git"),
on_attach=default_on_attach,
init_options = {
-- speeds up the startup time for the LSP
storagePath = vim.fn.stdpath('state') .. '/kotlin',
},
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/kotlin-language-server"}''
},
}
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,13 +8,32 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.lists) isList;
inherit (lib.types) bool either enum listOf package str;
inherit (lib.types) bool enum listOf package;
inherit (lib.nvim.types) diagnostics mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.dag) entryBefore;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.lua;
defaultServers = ["lua-language-server"];
servers = {
lua-language-server = {
enable = true;
cmd = [(getExe pkgs.lua-language-server)];
filetypes = ["lua"];
root_markers = [
".luarc.json"
".luarc.jsonc"
".luacheckrc"
".stylua.toml"
"stylua.toml"
"selene.toml"
"selene.yml"
".git"
];
};
};
defaultFormat = "stylua";
formats = {
stylua = {
@ -43,12 +62,11 @@ in {
};
lsp = {
enable = mkEnableOption "Lua LSP support via LuaLS" // {default = config.vim.lsp.enable;};
package = mkOption {
description = "LuaLS package, or the command to run as a list of strings";
type = either package (listOf str);
default = pkgs.lua-language-server;
enable = mkEnableOption "Lua LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Lua LSP server to use";
};
lazydev.enable = mkEnableOption "lazydev.nvim integration, useful for neovim plugin developers";
@ -91,23 +109,17 @@ in {
(mkIf cfg.enable (mkMerge [
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.lua-lsp = ''
lspconfig.lua_ls.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${getExe cfg.lsp.package}"}''
};
}
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.lsp.lazydev.enable {
vim.startPlugins = ["lazydev-nvim"];
vim.pluginRC.lazydev = entryBefore ["lua-lsp"] ''
vim.pluginRC.lazydev = entryBefore ["lsp-servers"] ''
require("lazydev").setup({
enabled = function(root_dir)
return not vim.uv.fs_stat(root_dir .. "/.luarc.json")

View file

@ -8,28 +8,20 @@
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.lists) isList;
inherit (lib.types) bool enum either package listOf str nullOr;
inherit (lib.nvim.lua) expToLua toLuaObject;
inherit (lib.nvim.types) diagnostics mkGrammarOption mkPluginSetupOption;
inherit (lib.types) bool enum package listOf str nullOr;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.types) diagnostics mkGrammarOption mkPluginSetupOption singleOrListOf;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.markdown;
defaultServer = "marksman";
defaultServers = ["marksman"];
servers = {
marksman = {
package = pkgs.marksman;
lspConfig = ''
lspconfig.marksman.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/marksman", "server"}''
},
}
'';
enable = true;
cmd = [(getExe pkgs.marksman) "server"];
filetypes = ["markdown" "markdown.mdx"];
root_markers = [".marksman.toml" ".git"];
};
};
@ -67,19 +59,12 @@ in {
};
lsp = {
enable = mkEnableOption "Enable Markdown LSP support" // {default = config.vim.lsp.enable;};
enable = mkEnableOption "Markdown LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
description = "Markdown LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
example = ''[lib.getExe pkgs.jdt-language-server " - data " " ~/.cache/jdtls/workspace "]'';
description = "Markdown LSP server package, or the command to run as a list of strings";
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
};
};
@ -161,8 +146,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.markdown-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -6,31 +6,34 @@
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe';
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.nim;
defaultServer = "nimlsp";
defaultServers = ["nimlsp"];
servers = {
nimlsp = {
package = pkgs.nimlsp;
lspConfig = ''
lspconfig.nimls.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''
{"${cfg.lsp.package}/bin/nimlsp"}
''
};
}
'';
enable = true;
cmd = [(getExe' pkgs.nimlsp "nimlsp")];
filetypes = ["nim"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(
util.root_pattern '*.nimble'(fname) or vim.fs.dirname(vim.fs.find('.git', { path = fname, upward = true })[1])
)
end
'';
};
};
@ -54,32 +57,26 @@ in {
lsp = {
enable = mkEnableOption "Nim LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
description = "Nim LSP server to use";
type = str;
default = defaultServer;
};
package = mkOption {
description = "Nim LSP server package, or the command to run as a list of strings";
example = ''[lib.getExe pkgs.nimlsp]'';
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Nim LSP server to use";
};
};
format = {
enable = mkEnableOption "Nim formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Nim formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Nim formatter to use";
};
package = mkOption {
description = "Nim formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Nim formatter package";
};
};
};
@ -100,8 +97,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.nim-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -9,90 +9,43 @@
inherit (lib.meta) getExe;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.strings) optionalString;
inherit (lib.types) anything attrsOf enum either listOf nullOr package str;
inherit (lib.nvim.types) mkGrammarOption diagnostics;
inherit (lib.nvim.lua) expToLua toLuaObject;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption diagnostics singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.nix;
useFormat = "on_attach = default_on_attach";
noFormat = "on_attach = attach_keymaps";
formattingCmd = mkIf (cfg.format.enable && cfg.lsp.enable) {
formatting = mkMerge [
(mkIf (cfg.format.type == "alejandra") {
command = ["${cfg.format.package}/bin/alejandra" "--quiet"];
})
(mkIf (cfg.format.type == "nixfmt") {
command = ["${cfg.format.package}/bin/nixfmt"];
})
];
};
defaultServer = "nil";
packageToCmd = package: defaultCmd:
if isList package
then expToLua package
else ''{"${package}/bin/${defaultCmd}"}'';
defaultServers = ["nil"];
servers = {
nil = {
package = pkgs.nil;
internalFormatter = true;
lspConfig = ''
lspconfig.nil_ls.setup{
capabilities = capabilities,
${
if cfg.format.enable
then useFormat
else noFormat
},
cmd = ${packageToCmd cfg.lsp.package "nil"},
${optionalString cfg.format.enable ''
settings = {
["nil"] = {
${optionalString (cfg.format.type == "alejandra")
''
formatting = {
command = {"${cfg.format.package}/bin/alejandra", "--quiet"},
},
''}
${optionalString (cfg.format.type == "nixfmt")
''
formatting = {
command = {"${cfg.format.package}/bin/nixfmt"},
},
''}
},
},
''}
}
'';
enable = true;
cmd = [(getExe pkgs.nil)];
settings = {
nil = formattingCmd;
};
filetypes = ["nix"];
root_markers = [".git" "flake.nix"];
};
nixd = {
package = pkgs.nixd;
internalFormatter = true;
lspConfig = ''
lspconfig.nixd.setup{
capabilities = capabilities,
${
if cfg.format.enable
then useFormat
else noFormat
},
cmd = ${packageToCmd cfg.lsp.package "nixd"},
${optionalString cfg.format.enable ''
settings = {
nixd = {
${optionalString (cfg.format.type == "alejandra")
''
formatting = {
command = {"${cfg.format.package}/bin/alejandra", "--quiet"},
},
''}
${optionalString (cfg.format.type == "nixfmt")
''
formatting = {
command = {"${cfg.format.package}/bin/nixfmt"},
},
''}
options = ${toLuaObject cfg.lsp.options},
},
},
''}
}
'';
enable = true;
cmd = [(getExe pkgs.nixd)];
settings = {
nixd = formattingCmd;
};
filetypes = ["nix"];
root_markers = [".git" "flake.nix"];
};
};
@ -144,23 +97,10 @@ in {
lsp = {
enable = mkEnableOption "Nix LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Nix LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Nix LSP server 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 = servers.${cfg.lsp.server}.package;
};
options = mkOption {
type = nullOr (attrsOf anything);
default = null;
description = "Options to pass to nixd LSP server";
};
};
@ -201,13 +141,6 @@ in {
${concatStringsSep ", " (attrNames formats)}
'';
}
{
assertion = cfg.lsp.server != "rnix";
message = ''
rnix-lsp has been archived upstream. Please use one of the following available language servers:
${concatStringsSep ", " (attrNames servers)}
'';
}
];
}
@ -217,11 +150,15 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.nix-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf (cfg.format.enable && (!cfg.lsp.enable || !servers.${cfg.lsp.server}.internalFormatter)) {
(mkIf (cfg.format.enable && !cfg.lsp.enable) {
vim.formatter.conform-nvim = {
enable = true;
setupOpts.formatters_by_ft.nix = [cfg.format.type];

View file

@ -5,27 +5,30 @@
...
}: let
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) str either package listOf;
inherit (lib.types) enum;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (builtins) isList;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.meta) getExe;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (builtins) attrNames;
defaultServer = "nushell";
defaultServers = ["nushell"];
servers = {
nushell = {
package = pkgs.nushell;
lspConfig = ''
lspconfig.nushell.setup{
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/nu", "--no-config-file", "--lsp"}''
}
}
'';
enable = true;
cmd = [(getExe pkgs.nushell) "--no-config-file" "--lsp"];
filetypes = ["nu"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
on_dir(vim.fs.root(bufnr, { '.git' }) or vim.fs.dirname(vim.api.nvim_buf_get_name(bufnr)))
end
'';
};
};
@ -41,17 +44,11 @@ in {
lsp = {
enable = mkEnableOption "Nu LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = str;
default = defaultServer;
description = "Nu LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
example = ''[(lib.getExe pkgs.nushell) "--lsp"]'';
description = "Nu LSP server package, or the command to run as a list of strings";
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Nu LSP server to use";
};
};
};
@ -63,8 +60,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.nu-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,28 +8,50 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.meta) getExe;
inherit (lib.lists) isList;
inherit (lib.types) either enum listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.ocaml;
defaultServer = "ocaml-lsp";
defaultServers = ["ocaml-lsp"];
servers = {
ocaml-lsp = {
package = pkgs.ocamlPackages.ocaml-lsp;
lspConfig = ''
lspconfig.ocamllsp.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${getExe cfg.lsp.package}"}''
};
}
'';
enable = true;
cmd = [(getExe pkgs.ocamlPackages.ocaml-lsp)];
filetypes = ["ocaml" "menhir" "ocamlinterface" "ocamllex" "reason" "dune"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern('*.opam', 'esy.json', 'package.json', '.git', 'dune-project', 'dune-workspace')(fname))
end
'';
get_language_id =
mkLuaInline
/*
lua
*/
''
function(_, ftype)
local language_id_of = {
menhir = 'ocaml.menhir',
ocaml = 'ocaml',
ocamlinterface = 'ocaml.interface',
ocamllex = 'ocaml.ocamllex',
reason = 'reason',
dune = 'dune',
}
return language_id_of[ftype]
end
'';
};
};
@ -49,38 +71,38 @@ in {
};
lsp = {
enable = mkEnableOption "OCaml LSP support (ocaml-lsp)" // {default = config.vim.lsp.enable;};
server = mkOption {
description = "OCaml LSP server to user";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "OCaml language server package, or the command to run as a list of strings";
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
enable = mkEnableOption "OCaml LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "OCaml LSP server to use";
};
};
format = {
enable = mkEnableOption "OCaml formatting support (ocamlformat)" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "OCaml formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "OCaml formatter to use";
};
package = mkOption {
description = "OCaml formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "OCaml formatter package";
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.ocaml-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.treesitter.enable {

View file

@ -7,26 +7,28 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) either listOf package str enum;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.types) enum;
inherit (lib.meta) getExe;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
defaultServer = "ols";
defaultServers = ["ols"];
servers = {
ols = {
package = pkgs.ols;
lspConfig = ''
lspconfig.ols.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/ols'}"
}
}
'';
enable = true;
cmd = [(getExe pkgs.ols)];
filetypes = ["odin"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
on_dir(util.root_pattern('ols.json', '.git', '*.odin')(fname))
end'';
};
};
@ -43,17 +45,11 @@ in {
lsp = {
enable = mkEnableOption "Odin LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Odin LSP server to use";
};
package = mkOption {
description = "Ols package, or the command to run as a list of strings";
type = either package (listOf str);
default = pkgs.ols;
};
};
};
@ -64,8 +60,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.odin-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,81 +8,60 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.php;
defaultServer = "phpactor";
defaultServers = ["phpactor"];
servers = {
phpactor = {
package = pkgs.phpactor;
lspConfig = ''
lspconfig.phpactor.setup{
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''
{
"${getExe cfg.lsp.package}",
"language-server"
},
''
}
}
'';
enable = true;
cmd = [(getExe pkgs.phpactor) "language-server"];
filetypes = ["php"];
root_markers = [".git" "composer.json" ".phpactor.json" ".phpactor.yml"];
workspace_required = true;
};
phan = {
package = pkgs.php81Packages.phan;
lspConfig = ''
lspconfig.phan.setup{
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''
{
"${getExe cfg.lsp.package}",
"-m",
"json",
"--no-color",
"--no-progress-bar",
"-x",
"-u",
"-S",
"--language-server-on-stdin",
"--allow-polyfill-parser"
},
''
}
}
'';
enable = true;
cmd = [
(getExe pkgs.php81Packages.phan)
"-m"
"json"
"--no-color"
"--no-progress-bar"
"-x"
"-u"
"-S"
"--language-server-on-stdin"
"--allow-polyfill-parser"
];
filetypes = ["php"];
root_dir =
mkLuaInline
/*
lua
*/
''
function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
local cwd = assert(vim.uv.cwd())
local root = vim.fs.root(fname, { 'composer.json', '.git' })
-- prefer cwd if root is a descendant
on_dir(root and vim.fs.relpath(cwd, root) and cwd)
end
'';
};
intelephense = {
package = pkgs.intelephense;
lspConfig = ''
lspconfig.intelephense.setup{
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''
{
"${getExe cfg.lsp.package}",
"--stdio"
},
''
}
}
'';
enable = true;
cmd = [(getExe pkgs.intelephense) "--stdio"];
filetypes = ["php"];
root_markers = ["composer.json" ".git"];
};
};
in {
@ -97,17 +76,10 @@ in {
lsp = {
enable = mkEnableOption "PHP LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "PHP LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "PHP LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
};
@ -117,11 +89,14 @@ in {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig = {
enable = true;
sources.php-lsp = servers.${cfg.lsp.server}.lspConfig;
};
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,57 +8,115 @@
inherit (lib.options) mkEnableOption mkOption literalExpression;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str bool;
inherit (lib.nvim.lua) expToLua;
inherit (lib.types) enum package bool;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) singleOrListOf;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.dag) entryBefore;
cfg = config.vim.languages.python;
defaultServer = "basedpyright";
defaultServers = ["basedpyright"];
servers = {
pyright = {
package = pkgs.pyright;
lspConfig = ''
lspconfig.pyright.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/pyright-langserver", "--stdio"}''
}
}
enable = true;
cmd = [(getExe pkgs.pyright) "--stdio"];
filetypes = ["python"];
root_markers = [
"pyproject.toml"
"setup.py"
"setup.cfg"
"requirements.txt"
"Pipfile"
"pyrightconfig.json"
".git"
];
settings = {
python = {
analysis = {
autoSearchPaths = true;
useLibraryCodeForTypes = true;
diagnosticMode = "openFilesOnly";
};
};
};
on_attach = mkLuaInline ''
function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
client:exec_cmd({
command = 'pyright.organizeimports',
arguments = { vim.uri_from_bufnr(bufnr) },
})
end, {
desc = 'Organize Imports',
})
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', function(opts)
set_python_path('pyright', opts.args)
end, {
desc = 'Reconfigure pyright with the provided python path',
nargs = 1,
complete = 'file',
})
end
'';
};
basedpyright = {
package = pkgs.basedpyright;
lspConfig = ''
lspconfig.basedpyright.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/basedpyright-langserver", "--stdio"}''
}
}
enable = true;
cmd = [(getExe pkgs.basedpyright) "--stdio"];
filetypes = ["python"];
root_markers = [
"pyproject.toml"
"setup.py"
"setup.cfg"
"requirements.txt"
"Pipfile"
"pyrightconfig.json"
".git"
];
settings = {
basedpyright = {
analysis = {
autoSearchPaths = true;
useLibraryCodeForTypes = true;
diagnosticMode = "openFilesOnly";
};
};
};
on_attach = mkLuaInline ''
function(client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
client:exec_cmd({
command = 'basedpyright.organizeimports',
arguments = { vim.uri_from_bufnr(bufnr) },
})
end, {
desc = 'Organize Imports',
})
vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', function(opts)
set_python_path('basedpyright', opts.args)
end, {
desc = 'Reconfigure basedpyright with the provided python path',
nargs = 1,
complete = 'file',
})
end
'';
};
python-lsp-server = {
package = pkgs.python3Packages.python-lsp-server;
lspConfig = ''
lspconfig.pylsp.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/pylsp"}''
}
}
'';
enable = true;
cmd = [(getExe pkgs.python3Packages.python-lsp-server)];
filetypes = ["python"];
root_markers = [
"pyproject.toml"
"setup.py"
"setup.cfg"
"requirements.txt"
"Pipfile"
".git"
];
};
};
@ -91,6 +149,16 @@
'';
};
};
ruff-check = {
package = pkgs.writeShellApplication {
name = "ruff-check";
runtimeInputs = [pkgs.ruff];
text = ''
ruff check --fix --exit-zero -
'';
};
};
};
defaultDebugger = "debugpy";
@ -171,17 +239,10 @@ in {
lsp = {
enable = mkEnableOption "Python LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Python LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "python LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -189,30 +250,30 @@ in {
enable = mkEnableOption "Python formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Python formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Python formatter to use";
};
package = mkOption {
description = "Python formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Python formatter package";
};
};
# TODO this implementation is very bare bones, I don't know enough python to implement everything
dap = {
enable = mkOption {
description = "Enable Python Debug Adapter";
type = bool;
default = config.vim.languages.enableDAP;
description = "Enable Python Debug Adapter";
};
debugger = mkOption {
description = "Python debugger to use";
type = enum (attrNames debuggers);
default = defaultDebugger;
description = "Python debugger to use";
};
package = mkOption {
@ -234,8 +295,34 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.python-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.luaConfigRC.python-util =
entryBefore ["lsp-servers"]
/*
lua
*/
''
local function set_python_path(server_name, path)
local clients = vim.lsp.get_clients {
bufnr = vim.api.nvim_get_current_buf(),
name = server_name,
}
for _, client in ipairs(clients) do
if client.settings then
client.settings.python = vim.tbl_deep_extend('force', client.settings.python or {}, { pythonPath = path })
else
client.config.settings = vim.tbl_deep_extend('force', client.config.settings, { python = { pythonPath = path } })
end
client.notify('workspace/didChangeConfiguration', { settings = nil })
end
end
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -0,0 +1,98 @@
{
config,
pkgs,
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.meta) getExe getExe';
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.qml;
qmlPackage = pkgs.kdePackages.qtdeclarative;
defaultServers = ["qmlls"];
servers = {
qmlls = {
cmd = [(getExe' qmlPackage "qmlls")];
filetypes = ["qml" "qmljs"];
rootmarkers = [".git"];
};
};
defaultFormat = "qmlformat";
formats = {
qmlformat = {
package = pkgs.writeShellApplication {
name = "qmlformat";
runtimeInputs = [qmlPackage];
text = "qmlformat -";
};
};
};
in {
options.vim.languages.qml = {
enable = mkEnableOption "QML language support";
treesitter = {
enable = mkEnableOption "QML treesitter support" // {default = config.vim.languages.enableTreesitter;};
package = mkGrammarOption pkgs "qmljs";
};
lsp = {
enable = mkEnableOption "QML LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "QML LSP server to use";
};
};
format = {
enable = mkEnableOption "QML formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
type = enum (attrNames formats);
default = defaultFormat;
description = "QML formatter to use";
};
package = mkOption {
type = package;
default = formats.${cfg.format.type}.package;
description = "QML formatter package";
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter = {
enable = true;
grammars = [cfg.treesitter.package];
};
})
(mkIf cfg.lsp.enable {
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf (cfg.format.enable && !cfg.lsp.enable) {
vim.formatter.conform-nvim = {
enable = true;
setupOpts.formatters_by_ft.qml = [cfg.format.type];
setupOpts.formatters.${cfg.format.type} = {
command = getExe cfg.format.package;
};
};
})
]);
}

View file

@ -5,12 +5,13 @@
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption literalExpression;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.types) enum package;
inherit (lib.meta) getExe;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.r;
@ -50,22 +51,16 @@
};
};
defaultServer = "r_language_server";
defaultServers = ["r_language_server"];
servers = {
r_language_server = {
package = pkgs.writeShellScriptBin "r_lsp" ''
${r-with-languageserver}/bin/R --slave -e "languageserver::run()"
'';
lspConfig = ''
lspconfig.r_language_server.setup{
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${lib.getExe cfg.lsp.package}"}''
}
}
enable = true;
cmd = [(getExe r-with-languageserver) "--no-echo" "-e" "languageserver::run()"];
filetypes = ["r" "rmd" "quarto"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
on_dir(vim.fs.root(bufnr, '.git') or vim.uv.os_homedir())
end
'';
};
};
@ -81,17 +76,10 @@ in {
lsp = {
enable = mkEnableOption "R LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "R LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "R LSP server package, or the command to run as a list of strings";
example = literalExpression "[ (lib.getExe pkgs.jdt-language-server) \"-data\" \"~/.cache/jdtls/workspace\" ]";
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
};
};
@ -127,8 +115,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.r-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -8,45 +8,42 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.types) mkGrammarOption diagnostics;
inherit (lib.nvim.lua) expToLua;
inherit (lib.lists) isList;
inherit (lib.types) either listOf package str enum;
inherit (lib.nvim.types) mkGrammarOption diagnostics singleOrListOf;
inherit (lib.types) package enum;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.ruby;
defaultServer = "rubyserver";
defaultServers = ["solargraph"];
servers = {
rubyserver = {
package = pkgs.rubyPackages.solargraph;
lspConfig = ''
lspconfig.solargraph.setup {
capabilities = capabilities,
on_attach = attach_keymaps,
flags = {
debounce_text_changes = 150,
},
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{ "${cfg.lsp.package}/bin/solargraph", "stdio" }''
}
}
'';
ruby_lsp = {
enable = true;
cmd = [(getExe pkgs.ruby-lsp)];
filetypes = ["ruby" "eruby"];
root_markers = ["Gemfile" ".git"];
init_options = {
formatter = "auto";
};
};
rubylsp = {
package = pkgs.ruby-lsp;
lspConfig = ''
lspconfig.ruby_lsp.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{ "${cfg.lsp.package}/bin/ruby-lsp" }''
}
}
'';
solargraph = {
enable = true;
cmd = [(getExe pkgs.rubyPackages.solargraph) "stdio"];
filetypes = ["ruby"];
root_markers = ["Gemfile" ".git"];
settings = {
solargraph = {
diagnostics = true;
};
};
flags = {
debounce_text_changes = 150;
};
init_options = {
formatting = true;
};
};
};
@ -79,17 +76,11 @@ in {
lsp = {
enable = mkEnableOption "Ruby LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Ruby LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
description = "Ruby LSP server package, or the command to run as a list of strings";
};
};
format = {
@ -128,8 +119,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.ruby-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -8,31 +8,27 @@
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) diagnostics;
inherit (lib.types) enum package str;
inherit (lib.nvim.types) diagnostics singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.sql;
sqlfluffDefault = pkgs.sqlfluff;
defaultServer = "sqls";
defaultServers = ["sqls"];
servers = {
sqls = {
package = pkgs.sqls;
lspConfig = ''
lspconfig.sqls.setup {
on_attach = function(client)
client.server_capabilities.execute_command = true
on_attach_keymaps(client, bufnr)
require'sqls'.setup{}
end,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{ "${cfg.lsp.package}/bin/sqls", "-config", string.format("%s/config.yml", vim.fn.getcwd()) }''
}
}
enable = true;
cmd = [(getExe pkgs.sqls)];
filetypes = ["sql" "mysql"];
root_markers = ["config.yml"];
settings = {};
on_attach = mkLuaInline ''
function(client, bufnr)
client.server_capabilities.execute_command = true
require'sqls'.setup{}
end
'';
};
};
@ -63,35 +59,28 @@ in {
enable = mkEnableOption "SQL language support";
dialect = mkOption {
description = "SQL dialect for sqlfluff (if used)";
type = str;
default = "ansi";
description = "SQL dialect for sqlfluff (if used)";
};
treesitter = {
enable = mkEnableOption "SQL treesitter" // {default = config.vim.languages.enableTreesitter;};
package = mkOption {
description = "SQL treesitter grammar to use";
type = package;
default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.sql;
description = "SQL treesitter grammar to use";
};
};
lsp = {
enable = mkEnableOption "SQL LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "SQL LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "SQL LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -99,15 +88,15 @@ in {
enable = mkEnableOption "SQL formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "SQL formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "SQL formatter to use";
};
package = mkOption {
description = "SQL formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "SQL formatter package";
};
};
@ -132,10 +121,12 @@ in {
vim = {
startPlugins = ["sqls-nvim"];
lsp.lspconfig = {
enable = true;
sources.sql-lsp = servers.${cfg.lsp.server}.lspConfig;
};
lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
};
})

View file

@ -7,28 +7,48 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.meta) getExe;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption diagnostics;
inherit (lib.types) enum package;
inherit (lib.nvim.types) mkGrammarOption diagnostics singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.svelte;
defaultServer = "svelte";
defaultServers = ["svelte"];
servers = {
svelte = {
package = pkgs.svelte-language-server;
lspConfig = ''
lspconfig.svelte.setup {
capabilities = capabilities;
on_attach = attach_keymaps,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/svelteserver", "--stdio"}''
}
}
enable = true;
cmd = [(getExe pkgs.svelte-language-server) "--stdio"];
filetypes = ["svelte"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local root_files = { 'package.json', '.git' }
local fname = vim.api.nvim_buf_get_name(bufnr)
-- Svelte LSP only supports file:// schema. https://github.com/sveltejs/language-tools/issues/2777
if vim.uv.fs_stat(fname) ~= nil then
on_dir(vim.fs.dirname(vim.fs.find(root_files, { path = fname, upward = true })[1]))
end
end
'';
on_attach = mkLuaInline ''
function(client, bufnr)
vim.api.nvim_create_autocmd('BufWritePost', {
pattern = { '*.js', '*.ts' },
group = vim.api.nvim_create_augroup('svelte_js_ts_file_watch', {}),
callback = function(ctx)
-- internal API to sync changes that have not yet been saved to the file system
client:notify('$/onDidChangeTsOrJsFile', { uri = ctx.match })
end,
})
vim.api.nvim_buf_create_user_command(bufnr, 'LspMigrateToSvelte5', function()
client:exec_cmd({
command = 'migrate_to_svelte_5',
arguments = { vim.uri_from_bufnr(bufnr) },
})
end, { desc = 'Migrate Component to Svelte 5 Syntax' })
end
'';
};
};
@ -78,17 +98,10 @@ in {
lsp = {
enable = mkEnableOption "Svelte LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Svelte LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Svelte LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -96,15 +109,15 @@ in {
enable = mkEnableOption "Svelte formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Svelte formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Svelte formatter to use";
};
package = mkOption {
description = "Svelte formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Svelte formatter package";
};
};
@ -126,8 +139,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.svelte-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
(mkIf cfg.format.enable {

View file

@ -7,26 +7,142 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.types) enum;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.types) singleOrListOf;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.tailwind;
defaultServer = "tailwindcss-language-server";
defaultServers = ["tailwindcss"];
servers = {
tailwindcss-language-server = {
package = pkgs.tailwindcss-language-server;
lspConfig = ''
lspconfig.tailwindcss.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/tailwindcss-language-server", "--stdio"}''
}
}
tailwindcss = {
enable = true;
cmd = [(getExe pkgs.tailwindcss-language-server) "--stdio"];
filetypes = [
# html
"aspnetcorerazor"
"astro"
"astro-markdown"
"blade"
"clojure"
"django-html"
"htmldjango"
"edge"
"eelixir"
"elixir"
"ejs"
"erb"
"eruby"
"gohtml"
"gohtmltmpl"
"haml"
"handlebars"
"hbs"
"html"
"htmlangular"
"html-eex"
"heex"
"jade"
"leaf"
"liquid"
"markdown"
"mdx"
"mustache"
"njk"
"nunjucks"
"php"
"razor"
"slim"
"twig"
# css
"css"
"less"
"postcss"
"sass"
"scss"
"stylus"
"sugarss"
# js
"javascript"
"javascriptreact"
"reason"
"rescript"
"typescript"
"typescriptreact"
# mixed
"vue"
"svelte"
"templ"
];
settings = {
tailwindCSS = {
validate = true;
lint = {
cssConflict = "warning";
invalidApply = "error";
invalidScreen = "error";
invalidVariant = "error";
invalidConfigPath = "error";
invalidTailwindDirective = "error";
recommendedVariantOrder = "warning";
};
classAttributes = [
"class"
"className"
"class:list"
"classList"
"ngClass"
];
includeLanguages = {
eelixir = "html-eex";
elixir = "phoenix-heex";
eruby = "erb";
heex = "phoenix-heex";
htmlangular = "html";
templ = "html";
};
};
};
before_init = mkLuaInline ''
function(_, config)
if not config.settings then
config.settings = {}
end
if not config.settings.editor then
config.settings.editor = {}
end
if not config.settings.editor.tabSize then
config.settings.editor.tabSize = vim.lsp.util.get_effective_tabstop()
end
end
'';
workspace_required = true;
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local root_files = {
-- Generic
'tailwind.config.js',
'tailwind.config.cjs',
'tailwind.config.mjs',
'tailwind.config.ts',
'postcss.config.js',
'postcss.config.cjs',
'postcss.config.mjs',
'postcss.config.ts',
-- Django
'theme/static_src/tailwind.config.js',
'theme/static_src/tailwind.config.cjs',
'theme/static_src/tailwind.config.mjs',
'theme/static_src/tailwind.config.ts',
'theme/static_src/postcss.config.js',
}
local fname = vim.api.nvim_buf_get_name(bufnr)
root_files = util.insert_package_json(root_files, 'tailwindcss', fname)
root_files = util.root_markers_with_field(root_files, { 'mix.lock', 'Gemfile.lock' }, 'tailwind', fname)
on_dir(vim.fs.dirname(vim.fs.find(root_files, { path = fname, upward = true })[1]))
end
'';
};
};
@ -37,25 +153,22 @@ in {
lsp = {
enable = mkEnableOption "Tailwindcss LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Tailwindcss LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Tailwindcss LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.tailwindcss-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -4,12 +4,25 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.types) package;
inherit (lib.meta) getExe;
inherit (lib.types) enum listOf;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.terraform;
defaultServers = ["terraformls"];
servers = {
terraformls = {
enable = true;
cmd = [(getExe pkgs.terraform-ls) "serve"];
filetypes = ["terraform" "terraform-vars"];
root_markers = [".terraform" ".git"];
};
};
in {
options.vim.languages.terraform = {
enable = mkEnableOption "Terraform/HCL support";
@ -22,10 +35,10 @@ in {
lsp = {
enable = mkEnableOption "Terraform LSP support (terraform-ls)" // {default = config.vim.lsp.enable;};
package = mkOption {
description = "terraform-ls package";
type = package;
default = pkgs.terraform-ls;
servers = mkOption {
type = listOf (enum (attrNames servers));
default = defaultServers;
description = "Terraform LSP server to use";
};
};
};
@ -36,14 +49,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.terraform-ls = ''
lspconfig.terraformls.setup {
capabilities = capabilities,
on_attach=default_on_attach,
cmd = {"${cfg.lsp.package}/bin/terraform-ls", "serve"},
}
'';
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -4,73 +4,177 @@
lib,
...
}: let
inherit (builtins) attrNames;
inherit (builtins) attrNames elem;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.meta) getExe;
inherit (lib.types) enum either listOf package str bool;
inherit (lib.nvim.lua) expToLua toLuaObject;
inherit (lib.nvim.types) mkGrammarOption diagnostics mkPluginSetupOption;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.types) enum package bool;
inherit (lib.generators) mkLuaInline;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.types) mkGrammarOption diagnostics mkPluginSetupOption singleOrListOf;
inherit (lib.nvim.dag) entryAnywhere entryBefore;
cfg = config.vim.languages.ts;
defaultServer = "ts_ls";
servers = {
defaultServers = ["ts_ls"];
servers = let
ts_ls = {
package = pkgs.typescript-language-server;
lspConfig = ''
lspconfig.ts_ls.setup {
capabilities = capabilities,
on_attach = function(client, bufnr)
attach_keymaps(client, bufnr);
client.server_capabilities.documentFormattingProvider = false;
end,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/typescript-language-server", "--stdio"}''
}
}
cmd = [(getExe pkgs.typescript-language-server) "--stdio"];
init_options = {hostInfo = "neovim";};
filetypes = [
"javascript"
"javascriptreact"
"javascript.jsx"
"typescript"
"typescriptreact"
"typescript.tsx"
];
root_markers = ["tsconfig.json" "jsconfig.json" "package.json" ".git"];
handlers = {
# handle rename request for certain code actions like extracting functions / types
"_typescript.rename" = mkLuaInline ''
function(_, result, ctx)
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
vim.lsp.util.show_document({
uri = result.textDocument.uri,
range = {
start = result.position,
['end'] = result.position,
},
}, client.offset_encoding)
vim.lsp.buf.rename()
return vim.NIL
end
'';
};
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr);
-- ts_ls provides `source.*` code actions that apply to the whole file. These only appear in
-- `vim.lsp.buf.code_action()` if specified in `context.only`.
vim.api.nvim_buf_create_user_command(0, 'LspTypescriptSourceAction', function()
local source_actions = vim.tbl_filter(function(action)
return vim.startswith(action, 'source.')
end, client.server_capabilities.codeActionProvider.codeActionKinds)
vim.lsp.buf.code_action({
context = {
only = source_actions,
},
})
end, {})
end
'';
};
denols = {
package = pkgs.deno;
lspConfig = ''
vim.g.markdown_fenced_languages = { "ts=typescript" }
lspconfig.denols.setup {
capabilities = capabilities;
on_attach = attach_keymaps,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/deno", "lsp"}''
}
}
'';
};
in {
inherit ts_ls;
# Here for backwards compatibility. Still consider tsserver a valid
# configuration in the enum, but assert if it's set to *properly*
# redirect the user to the correct server.
tsserver = {
package = pkgs.typescript-language-server;
lspConfig = ''
lspconfig.ts_ls.setup {
capabilities = capabilities;
on_attach = attach_keymaps,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/typescript-language-server", "--stdio"}''
}
}
tsserver = ts_ls;
denols = {
cmd = [(getExe pkgs.deno) "lsp"];
cmd_env = {NO_COLOR = true;};
filetypes = [
"javascript"
"javascriptreact"
"javascript.jsx"
"typescript"
"typescriptreact"
"typescript.tsx"
];
root_markers = ["deno.json" "deno.jsonc" ".git"];
settings = {
deno = {
enable = true;
suggest = {
imports = {
hosts = {
"https://deno.land" = true;
};
};
};
};
};
handlers = {
"textDocument/definition" = mkLuaInline "nvf_denols_handler";
"textDocument/typeDefinition" = mkLuaInline "nvf_denols_handler";
"textDocument/references" = mkLuaInline "nvf_denols_handler";
};
on_attach = mkLuaInline ''
function(client, bufnr)
default_on_attach(client, bufnr)
vim.api.nvim_buf_create_user_command(0, 'LspDenolsCache', function()
client:exec_cmd({
command = 'deno.cache',
arguments = { {}, vim.uri_from_bufnr(bufnr) },
}, { bufnr = bufnr }, function(err, _result, ctx)
if err then
local uri = ctx.params.arguments[2]
vim.api.nvim_err_writeln('cache command failed for ' .. vim.uri_to_fname(uri))
end
end)
end, {
desc = 'Cache a module and all of its dependencies.',
})
end
'';
};
};
denols_handlers = ''
local function nvf_denols_virtual_text_document_handler(uri, res, client)
if not res then
return nil
end
local lines = vim.split(res.result, '\n')
local bufnr = vim.uri_to_bufnr(uri)
local current_buf = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
if #current_buf ~= 0 then
return nil
end
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
vim.api.nvim_set_option_value('readonly', true, { buf = bufnr })
vim.api.nvim_set_option_value('modified', false, { buf = bufnr })
vim.api.nvim_set_option_value('modifiable', false, { buf = bufnr })
vim.lsp.buf_attach_client(bufnr, client.id)
end
local function nvf_denols_virtual_text_document(uri, client)
local params = {
textDocument = {
uri = uri,
},
}
local result = client.request_sync('deno/virtualTextDocument', params)
nvf_denols_virtual_text_document_handler(uri, result, client)
end
local function nvf_denols_handler(err, result, ctx, config)
if not result or vim.tbl_isempty(result) then
return nil
end
local client = vim.lsp.get_client_by_id(ctx.client_id)
for _, res in pairs(result) do
local uri = res.uri or res.targetUri
if uri:match '^deno:' then
nvf_denols_virtual_text_document(uri, client)
res['uri'] = uri
res['targetUri'] = uri
end
end
vim.lsp.handlers[ctx.method](err, result, ctx, config)
end
'';
# TODO: specify packages
defaultFormat = "prettier";
formats = {
@ -115,24 +219,18 @@ in {
treesitter = {
enable = mkEnableOption "Typescript/Javascript treesitter" // {default = config.vim.languages.enableTreesitter;};
tsPackage = mkGrammarOption pkgs "tsx";
tsPackage = mkGrammarOption pkgs "typescript";
tsxPackage = mkGrammarOption pkgs "tsx";
jsPackage = mkGrammarOption pkgs "javascript";
};
lsp = {
enable = mkEnableOption "Typescript/Javascript LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Typescript/Javascript LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Typescript/Javascript LSP server 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 = servers.${cfg.lsp.server}.package;
};
};
@ -186,12 +284,25 @@ in {
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.tsPackage cfg.treesitter.jsPackage];
vim.treesitter.grammars = [
cfg.treesitter.tsPackage
cfg.treesitter.tsxPackage
cfg.treesitter.jsPackage
];
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.ts-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (name: {
inherit name;
value = servers.${name};
})
cfg.lsp.servers;
})
(mkIf (cfg.lsp.enable && elem "denols" cfg.lsp.servers) {
vim.globals.markdown_fenced_languages = ["ts=typescript"];
vim.luaConfigRC.denols_handlers = entryBefore ["lsp-servers"] denols_handlers;
})
(mkIf cfg.format.enable {
@ -234,7 +345,7 @@ in {
{
assertions = [
{
assertion = cfg.lsp.enable -> cfg.lsp.server != "tsserver";
assertion = cfg.lsp.enable -> !(elem "tsserver" cfg.lsp.servers);
message = ''
As of a recent lspconfig update, the `tsserver` configuration has been renamed
to `ts_ls` to match upstream behaviour of `lspconfig`, and the name `tsserver`

View file

@ -6,52 +6,87 @@
}: let
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) nullOr enum either attrsOf listOf package str;
inherit (lib.types) nullOr enum attrsOf listOf package str;
inherit (lib.attrsets) attrNames;
inherit (lib.meta) getExe;
inherit (lib.nvim.lua) expToLua toLuaObject;
inherit (lib.nvim.types) mkGrammarOption mkPluginSetupOption;
inherit (lib.nvim.types) mkGrammarOption mkPluginSetupOption singleOrListOf;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.typst;
defaultServer = "tinymist";
defaultServers = ["tinymist"];
servers = {
typst-lsp = {
package = pkgs.typst-lsp;
lspConfig = ''
lspconfig.typst_lsp.setup {
capabilities = capabilities,
on_attach = function(client, bufnr)
-- Disable semantic tokens as a workaround for a semantic token error when using non-english characters
client.server_capabilities.semanticTokensProvider = nil
end,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/typst-lsp"}''
},
}
typst_lsp = {
enable = true;
cmd = [(getExe pkgs.typst-lsp)];
filetypes = ["typst"];
root_markers = [".git"];
on_attach = mkLuaInline ''
function(client, bufnr)
-- Disable semantic tokens as a workaround for a semantic token error when using non-english characters
client.server_capabilities.semanticTokensProvider = nil
end
'';
};
tinymist = {
package = pkgs.tinymist;
lspConfig = ''
lspconfig.tinymist.setup {
capabilities = capabilities,
single_file_support = true,
on_attach = function(client, bufnr)
-- Disable semantic tokens as a workaround for a semantic token error when using non-english characters
client.server_capabilities.semanticTokensProvider = nil
end,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/tinymist"}''
},
}
enable = true;
cmd = [(getExe pkgs.tinymist)];
filetypes = ["typst"];
root_markers = [".git"];
on_attach = mkLuaInline ''
function(client, bufnr)
local function create_tinymist_command(command_name, client, bufnr)
local export_type = command_name:match 'tinymist%.export(%w+)'
local info_type = command_name:match 'tinymist%.(%w+)'
if info_type and info_type:match '^get' then
info_type = info_type:gsub('^get', 'Get')
end
local cmd_display = export_type or info_type
local function run_tinymist_command()
local arguments = { vim.api.nvim_buf_get_name(bufnr) }
local title_str = export_type and ('Export ' .. cmd_display) or cmd_display
local function handler(err, res)
if err then
return vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
end
vim.notify(export_type and res or vim.inspect(res), vim.log.levels.INFO)
end
if vim.fn.has 'nvim-0.11' == 1 then
return client:exec_cmd({
title = title_str,
command = command_name,
arguments = arguments,
}, { bufnr = bufnr }, handler)
else
return vim.notify('Tinymist commands require Neovim 0.11+', vim.log.levels.WARN)
end
end
local cmd_name = export_type and ('LspTinymistExport' .. cmd_display) or ('LspTinymist' .. cmd_display)
local cmd_desc = export_type and ('Export to ' .. cmd_display) or ('Get ' .. cmd_display)
return run_tinymist_command, cmd_name, cmd_desc
end
for _, command in ipairs {
'tinymist.exportSvg',
'tinymist.exportPng',
'tinymist.exportPdf',
'tinymist.exportMarkdown',
'tinymist.exportText',
'tinymist.exportQuery',
'tinymist.exportAnsiHighlight',
'tinymist.getServerInfo',
'tinymist.getDocumentTrace',
'tinymist.getWorkspaceLabels',
'tinymist.getDocumentMetrics',
} do
local cmd_func, cmd_name, cmd_desc = create_tinymist_command(command, client, bufnr)
vim.api.nvim_buf_create_user_command(bufnr, cmd_name, cmd_func, { nargs = 0, desc = cmd_desc })
end
end
'';
};
};
@ -78,17 +113,10 @@ in {
lsp = {
enable = mkEnableOption "Typst LSP support (typst-lsp)" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Typst LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "typst-lsp 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 = servers.${cfg.lsp.server}.package;
};
};
@ -96,15 +124,15 @@ in {
enable = mkEnableOption "Typst document formatting" // {default = config.vim.languages.enableFormat;};
type = mkOption {
description = "Typst formatter to use";
type = enum (attrNames formats);
default = defaultFormat;
description = "Typst formatter to use";
};
package = mkOption {
description = "Typst formatter package";
type = package;
default = formats.${cfg.format.type}.package;
description = "Typst formatter package";
};
};
@ -131,7 +159,7 @@ in {
dependencies_bin = mkOption {
type = attrsOf str;
default = {
"tinymist" = getExe servers.tinymist.package;
"tinymist" = getExe pkgs.tinymist;
"websocat" = getExe pkgs.websocat;
};
@ -169,8 +197,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.typst-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
# Extensions

View file

@ -7,36 +7,57 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
inherit (lib.generators) mkLuaInline;
cfg = config.vim.languages.vala;
defaultServer = "vala_ls";
defaultServers = ["vala_ls"];
servers = {
vala_ls = {
package = pkgs.symlinkJoin {
name = "vala-language-server-wrapper";
paths = [pkgs.vala-language-server];
buildInputs = [pkgs.makeBinaryWrapper];
postBuild = ''
wrapProgram $out/bin/vala-language-server \
--prefix PATH : ${pkgs.uncrustify}/bin
'';
};
internalFormatter = true;
lspConfig = ''
lspconfig.vala_ls.setup {
capabilities = capabilities;
on_attach = default_on_attach;
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/vala-language-server"}''
},
}
enable = true;
cmd = [
(getExe (pkgs.symlinkJoin {
name = "vala-language-server-wrapper";
paths = [pkgs.vala-language-server];
buildInputs = [pkgs.makeBinaryWrapper];
postBuild = ''
wrapProgram $out/bin/vala-language-server \
--prefix PATH : ${pkgs.uncrustify}/bin
'';
}))
];
filetypes = ["vala" "genie"];
root_dir = mkLuaInline ''
function(bufnr, on_dir)
local meson_matcher = function(path)
local pattern = 'meson.build'
local f = vim.fn.glob(table.concat({ path, pattern }, '/'))
if f == ''' then
return nil
end
for line in io.lines(f) do
-- skip meson comments
if not line:match '^%s*#.*' then
local str = line:gsub('%s+', ''')
if str ~= ''' then
if str:match '^project%(' then
return path
else
break
end
end
end
end
end
local fname = vim.api.nvim_buf_get_name(bufnr)
local root = vim.iter(vim.fs.parents(fname)):find(meson_matcher)
on_dir(root or vim.fs.dirname(vim.fs.find('.git', { path = fname, upward = true })[1]))
end
'';
};
};
@ -51,16 +72,10 @@ in {
lsp = {
enable = mkEnableOption "Vala LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Vala LSP server to use";
type = enum (attrNames servers);
default = defaultServer;
};
package = mkOption {
description = "Vala LSP server package, or the command to run as a list of strings";
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
};
};
};
@ -72,8 +87,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.vala_ls = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -5,31 +5,23 @@
...
}: let
inherit (builtins) attrNames;
inherit (lib.lists) isList;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.options) literalExpression mkEnableOption mkOption;
inherit (lib.types) either enum listOf package str;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.types) enum;
inherit (lib.meta) getExe;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.wgsl;
defaultServer = "wgsl-analyzer";
defaultServers = ["wgsl-analyzer"];
servers = {
wgsl-analyzer = {
package = pkgs.wgsl-analyzer;
internalFormatter = true;
lspConfig = ''
lspconfig.wgsl_analyzer.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/wgsl-analyzer'}"
}
}
'';
enable = true;
cmd = [(getExe pkgs.wgsl-analyzer)];
filetypes = ["wgsl"];
root_markers = [".git"];
settings = {};
};
};
in {
@ -44,18 +36,11 @@ in {
lsp = {
enable = mkEnableOption "WGSL LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "WGSL LSP server to use";
};
package = mkOption {
description = "wgsl-analyzer package, or the command to run as a list of strings";
example = literalExpression "[(lib.getExe pkgs.wgsl-analyzer)]";
type = either package (listOf str);
default = pkgs.wgsl-analyzer;
};
};
};
@ -68,12 +53,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim = {
lsp.lspconfig = {
enable = true;
sources.wgsl_analyzer = servers.${cfg.lsp.server}.lspConfig;
};
};
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -7,10 +7,10 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.lists) isList;
inherit (lib.types) enum either listOf package str;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.nvim.lua) expToLua;
inherit (lib.meta) getExe;
inherit (lib.types) enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.yaml;
@ -25,23 +25,22 @@
end''
else "on_attach = default_on_attach";
defaultServer = "yaml-language-server";
defaultServers = ["yaml-language-server"];
servers = {
yaml-language-server = {
package = pkgs.yaml-language-server;
lspConfig = ''
lspconfig.yamlls.setup {
capabilities = capabilities,
${onAttach},
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else ''{"${cfg.lsp.package}/bin/yaml-language-server", "--stdio"}''
},
}
'';
enable = true;
cmd = [(getExe pkgs.yaml-language-server) "--stdio"];
filetypes = ["yaml" "yaml.docker-compose" "yaml.gitlab" "yaml.helm-values"];
root_markers = [".git"];
on_attach = onAttach;
# -- https://github.com/redhat-developer/vscode-redhat-telemetry#how-to-disable-telemetry-reporting
settings = {
redhat = {
telemetry = {
enabled = false;
};
};
};
};
};
in {
@ -55,18 +54,11 @@ in {
};
lsp = {
enable = mkEnableOption "YAML LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
description = "YAML LSP server to use";
};
package = mkOption {
type = either package (listOf str);
default = servers.${cfg.lsp.server}.package;
description = "YAML LSP server package";
enable = mkEnableOption "Yaml LSP support" // {default = config.vim.lsp.enable;};
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Yaml LSP server to use";
};
};
};
@ -78,8 +70,12 @@ in {
})
(mkIf cfg.lsp.enable {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.yaml-lsp = servers.${cfg.lsp.server}.lspConfig;
vim.lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
})
]);
}

View file

@ -7,29 +7,21 @@
inherit (builtins) attrNames;
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.modules) mkIf mkMerge mkDefault;
inherit (lib.lists) isList;
inherit (lib.types) bool either listOf package str enum;
inherit (lib.nvim.lua) expToLua;
inherit (lib.nvim.types) mkGrammarOption;
inherit (lib.types) bool package enum;
inherit (lib.nvim.types) mkGrammarOption singleOrListOf;
inherit (lib.meta) getExe;
inherit (lib.nvim.attrsets) mapListToAttrs;
cfg = config.vim.languages.zig;
defaultServer = "zls";
defaultServers = ["zls"];
servers = {
zls = {
package = pkgs.zls;
internalFormatter = true;
lspConfig = ''
lspconfig.zls.setup {
capabilities = capabilities,
on_attach = default_on_attach,
cmd = ${
if isList cfg.lsp.package
then expToLua cfg.lsp.package
else "{'${cfg.lsp.package}/bin/zls'}"
}
}
'';
enable = true;
cmd = [(getExe pkgs.zls)];
filetypes = ["zig" "zir"];
root_markers = ["zls.json" "build.zig" ".git"];
workspace_required = false;
};
};
@ -74,17 +66,11 @@ in {
lsp = {
enable = mkEnableOption "Zig LSP support" // {default = config.vim.lsp.enable;};
server = mkOption {
type = enum (attrNames servers);
default = defaultServer;
servers = mkOption {
type = singleOrListOf (enum (attrNames servers));
default = defaultServers;
description = "Zig LSP server to use";
};
package = mkOption {
description = "ZLS package, or the command to run as a list of strings";
type = either package (listOf str);
default = pkgs.zls;
};
};
dap = {
@ -118,10 +104,12 @@ in {
(mkIf cfg.lsp.enable {
vim = {
lsp.lspconfig = {
enable = true;
sources.zig-lsp = servers.${cfg.lsp.server}.lspConfig;
};
lsp.servers =
mapListToAttrs (n: {
name = n;
value = servers.${n};
})
cfg.lsp.servers;
# nvf handles autosaving already
globals.zig_fmt_autosave = mkDefault 0;

View file

@ -7,6 +7,7 @@
./lspconfig
./lspsaga
./null-ls
./harper-ls
# lsp plugins
./lspsaga

View file

@ -0,0 +1,19 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib.modules) mkIf;
inherit (lib.meta) getExe;
cfg = config.vim.lsp;
in {
config = mkIf (cfg.enable && cfg.harper-ls.enable) {
vim.lsp.servers.harper-ls = {
root_markers = [".git"];
cmd = [(getExe pkgs.harper) "--stdio"];
settings = {harper-ls = cfg.harper-ls.settings;};
};
};
}

View file

@ -0,0 +1,6 @@
{
imports = [
./harper-ls.nix
./config.nix
];
}

View file

@ -0,0 +1,35 @@
{lib, ...}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.types) anything attrsOf;
in {
options.vim.lsp.harper-ls = {
enable = mkEnableOption "Harper grammar checking LSP";
settings = mkOption {
type = attrsOf anything;
default = {};
example = {
userDictPath = "";
workspaceDictPath = "";
fileDictPath = "";
linters = {
BoringWords = true;
PossessiveNoun = true;
SentenceCapitalization = false;
SpellCheck = false;
};
codeActions = {
ForceStable = false;
};
markdown = {
IgnoreLinkTitle = false;
};
diagnosticSeverity = "hint";
isolateEnglish = false;
dialect = "American";
maxFileLength = 120000;
ignoredLintsPath = {};
};
description = "Settings to pass to harper-ls";
};
};
}

View file

@ -19,6 +19,7 @@
./oil-nvim
./outline
./preview
./qmk-nvim
./sleuth
./smart-splits
./snacks-nvim

View file

@ -3,18 +3,38 @@
lib,
...
}: let
inherit (lib.attrsets) optionalAttrs recursiveUpdate;
inherit (lib.lists) optionals;
inherit (lib.modules) mkIf;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.dag) entryAnywhere;
inherit (lib.nvim.dag) entryAfter entryAnywhere;
cfg = config.vim.utility.oil-nvim;
in {
config = mkIf cfg.enable {
vim = {
startPlugins = ["oil-nvim"];
pluginRC.oil-nvim = entryAnywhere ''
require("oil").setup(${toLuaObject cfg.setupOpts});
'';
startPlugins = ["oil-nvim"] ++ (optionals cfg.gitStatus.enable ["oil-git-status.nvim"]);
pluginRC.oil-nvim = let
gitStatusDefaultOpts = {
# https://github.com/refractalize/oil-git-status.nvim?tab=readme-ov-file#configuration
win_options = {
signcolumn = "yes:2";
};
};
setupOpts =
recursiveUpdate
(optionalAttrs cfg.gitStatus.enable gitStatusDefaultOpts)
cfg.setupOpts;
in
entryAnywhere ''
require("oil").setup(${toLuaObject setupOpts});
'';
pluginRC.oil-git-status-nvim = mkIf cfg.gitStatus.enable (entryAfter ["oil-nvim"] ''
require("oil-git-status").setup(${toLuaObject cfg.gitStatus.setupOpts})
'');
};
};
}

View file

@ -8,5 +8,13 @@ in {
'';
setupOpts = mkPluginSetupOption "oil-nvim" {};
gitStatus = {
enable = mkEnableOption ''
Git status on [oil-nvim] directory listings
'';
setupOpts = mkPluginSetupOption "oil-git-status-nvim" {};
};
};
}

View file

@ -0,0 +1,36 @@
{
config,
lib,
...
}: let
inherit (lib.modules) mkIf;
inherit (lib.nvim.lua) toLuaObject;
inherit (lib.nvim.dag) entryAfter;
cfg = config.vim.utility.qmk-nvim;
in {
config = mkIf cfg.enable {
vim = {
startPlugins = ["qmk-nvim"];
pluginRC.qmk-nvim = entryAfter ["nvim-notify"] ''
require('qmk').setup(${toLuaObject cfg.setupOpts})
'';
};
assertions = [
{
assertion = cfg.setupOpts.variant == "qmk" && cfg.setupOpts.comment_preview.position != "inside";
message = "comment_preview.position can only be set to inside when using the qmk layoyt";
}
{
assertion = cfg.setupOpts.name != null;
message = "qmk-nvim requires 'vim.utility.qmk.setupOpts.name' to be set.";
}
{
assertion = cfg.setupOpts.layout != null;
message = "qmk-nvim requires 'vim.utility.qmk.setupOpts.layout' to be set.";
}
];
};
}

View file

@ -0,0 +1,6 @@
{
imports = [
./config.nix
./qmk-nvim.nix
];
}

View file

@ -0,0 +1,49 @@
{lib, ...}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.types) attrsOf nullOr enum lines str;
inherit (lib.nvim.types) mkPluginSetupOption;
in {
options.vim.utility.qmk-nvim = {
enable = mkEnableOption "QMK and ZMK keymaps in nvim";
setupOpts = mkPluginSetupOption "qmk.nvim" {
name = mkOption {
type = nullOr str;
default = null;
description = "The name of the layout";
};
layout = mkOption {
type = nullOr lines;
default = null;
description = ''
The keyboard key layout
see <https://github.com/codethread/qmk.nvim?tab=readme-ov-file#Layout> for more details
'';
};
variant = mkOption {
type = enum ["qmk" "zmk"];
default = "qmk";
description = "Chooses the expected hardware target";
};
comment_preview = {
position = mkOption {
type = enum ["top" "bottom" "inside" "none"];
default = "top";
description = "Controls the position of the preview";
};
keymap_overrides = mkOption {
type = attrsOf str;
default = {};
description = ''
Key codes to text replacements
see <https://github.com/codethread/qmk.nvim/blob/main/lua/qmk/config/key_map.lua> for more details
'';
};
};
};
};
}

View file

@ -22,9 +22,7 @@
passthru.vimPlugin = false;
};
# build a vim plugin with the given name and arguments
# if the plugin is nvim-treesitter, warn the user to use buildTreesitterPlug
# instead
# Build a Vim plugin with the given name and arguments.
buildPlug = attrs: let
pin = getPin attrs.pname;
in
@ -36,6 +34,7 @@
// attrs
);
# Build a given Treesitter grammar.
buildTreesitterPlug = grammars: vimPlugins.nvim-treesitter.withPlugins (_: grammars);
pluginBuilders = {
@ -48,6 +47,9 @@
doCheck = false;
};
# Get plugins built from source from self.packages
# If adding a new plugin to be built from source, it must also be inherited
# here.
inherit (inputs.self.packages.${pkgs.stdenv.system}) blink-cmp avante-nvim;
};
@ -71,29 +73,38 @@
# Wrap the user's desired (unwrapped) Neovim package with arguments that'll be used to
# generate a wrapped Neovim package.
neovim-wrapped = inputs.mnw.lib.wrap {inherit pkgs;} {
appName = "nvf";
neovim = config.vim.package;
initLua = config.vim.builtLuaConfigRC;
luaFiles = config.vim.extraLuaFiles;
# Plugin configurations
plugins = {
start = buildConfigPlugins config.vim.startPlugins;
opt = buildConfigPlugins config.vim.optPlugins;
};
appName = "nvf";
extraBinPath = config.vim.extraPackages;
initLua = config.vim.builtLuaConfigRC;
luaFiles = config.vim.extraLuaFiles;
# Providers for Neovim
providers = {
ruby.enable = config.vim.withRuby;
nodeJs.enable = config.vim.withNodeJs;
python3 = {
enable = config.vim.withPython3;
extraPackages = ps: map (flip builtins.getAttr ps) config.vim.python3Packages;
};
ruby.enable = config.vim.withRuby;
nodeJs.enable = config.vim.withNodeJs;
};
# Aliases to link `nvim` to
aliases = lib.optional config.vim.viAlias "vi" ++ lib.optional config.vim.vimAlias "vim";
# Additional packages or Lua packages to be made available to Neovim
extraBinPath = config.vim.extraPackages;
extraLuaPackages = ps: map (flip builtins.getAttr ps) config.vim.luaPackages;
};
# A store path representing the built Lua configuration.
dummyInit = pkgs.writeText "nvf-init.lua" config.vim.builtLuaConfigRC;
# Additional helper scripts for printing and displaying nvf configuration
# in your commandline.
printConfig = pkgs.writers.writeDashBin "nvf-print-config" "cat ${dummyInit}";
@ -106,10 +117,20 @@
paths = [neovim-wrapped printConfig printConfigPath];
postBuild = "echo Helpers added";
# Allow evaluating config.vim, i.e., config.vim from the packages' passthru
# attribute. For example, packages.x86_64-linux.neovim.passthru.neovimConfig
# will return the configuration in full.
passthru.neovimConfig = config.vim;
passthru = {
# Allow evaluating config.vim, i.e., config.vim from the packages' passthru
# attribute. For example, packages.x86_64-linux.neovim.passthru.neovimConfig
# will return the configuration in full.
neovimConfig = config.vim;
# Also expose the helper scripts in passthru.
nvfPrintConfig = printConfig;
nvfPrintConfigPath = printConfigPath;
# In systems where we only have a package and no module, this can be used
# to access the built init.lua
initLua = dummyInit;
};
meta =
neovim-wrapped.meta

View file

@ -3,7 +3,7 @@
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption literalMD;
inherit (lib.options) mkOption mkEnableOption literalMD literalExpression;
inherit (lib.types) package bool str listOf attrsOf;
inherit (lib.nvim.types) pluginsOpt extraPluginType;
in {
@ -11,6 +11,7 @@ in {
package = mkOption {
type = package;
default = pkgs.neovim-unwrapped;
defaultText = literalExpression "pkgs.neovim-unwrapped";
description = ''
The neovim package to use for the wrapper. This
corresponds to the package that will be wrapped
@ -27,21 +28,20 @@ in {
viAlias = mkOption {
type = bool;
default = true;
example = false;
description = "Enable the `vi` alias for `nvim`";
};
vimAlias = mkOption {
type = bool;
default = true;
example = false;
description = "Enable the `vim` alias for `nvim`";
};
startPlugins = pluginsOpt {
default = ["plenary-nvim"];
example = ''
[pkgs.vimPlugins.telescope-nvim]
'';
example = literalExpression "[pkgs.vimPlugins.telescope-nvim]";
description = ''
List of plugins to load on startup. This is used
internally to add plugins to Neovim's runtime.
@ -54,9 +54,7 @@ in {
optPlugins = pluginsOpt {
default = [];
example = ''
[pkgs.vimPlugins.vim-ghost]
'';
example = literalExpression "[pkgs.vimPlugins.vim-ghost]";
description = ''
List of plugins to optionally load on startup.
@ -108,7 +106,7 @@ in {
'';
};
# this defaults to `true` in the wrapper
# This defaults to `true` in the wrapper
# and since we pass this value to the wrapper
# with an inherit, it should be `true` here as well
withRuby =
@ -120,14 +118,14 @@ in {
};
withNodeJs = mkEnableOption ''
NodeJs support in the Neovim wrapper
NodeJS support in the Neovim wrapper
'';
luaPackages = mkOption {
type = listOf str;
default = [];
example = ''["magick" "serpent"]'';
description = "List of lua packages to install";
description = "List of Lua packages to install";
};
withPython3 = mkEnableOption ''
@ -144,7 +142,7 @@ in {
pluginOverrides = mkOption {
type = attrsOf package;
default = {};
example = ''
example = literalExpression ''
{
lazydev-nvim = pkgs.fetchFromGitHub {
owner = "folke";

View file

@ -1,7 +1,7 @@
{lib, ...}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.types) enum listOf submodule nullOr str bool int attrsOf anything either oneOf lines;
inherit (lib.nvim.types) pluginType;
inherit (lib.nvim.types) pluginType luaInline;
inherit (lib.nvim.config) mkBool;
lznKeysSpec = submodule {
@ -98,7 +98,7 @@
# lz.n options
enabled = mkOption {
type = nullOr (either bool str);
type = nullOr (either bool luaInline);
default = null;
description = "When false, or if the lua function returns false, this plugin will not be included in the spec";
};

View file

@ -2088,6 +2088,19 @@
"url": "https://github.com/epwalsh/obsidian.nvim/archive/14e0427bef6c55da0d63f9a313fd9941be3a2479.tar.gz",
"hash": "15ycmhn48ryaqzch6w3w6llq2qgmjx8xwkb9dn0075z60dybpflr"
},
"oil-git-status.nvim": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "refractalize",
"repo": "oil-git-status.nvim"
},
"branch": "main",
"submodules": false,
"revision": "4b5cf53842c17a09420919e655a6a559da3112d7",
"url": "https://github.com/refractalize/oil-git-status.nvim/archive/4b5cf53842c17a09420919e655a6a559da3112d7.tar.gz",
"hash": "1jzw6lkvi9xxzqy8xz056xlb45byr1arklh87zmyf0nj9plm2nsp"
},
"oil-nvim": {
"type": "Git",
"repository": {
@ -2231,6 +2244,19 @@
"url": "https://github.com/kevinhwang91/promise-async/archive/119e8961014c9bfaf1487bf3c2a393d254f337e2.tar.gz",
"hash": "0q4a0rmy09hka6zvydzjj2gcm2j5mlbrhbxfcdjj33ngpblkmqzm"
},
"qmk-nvim": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "codethread",
"repo": "qmk.nvim"
},
"branch": "main",
"submodules": false,
"revision": "3c804c1480991e4837514900b22b9358cfd64fa1",
"url": "https://github.com/codethread/qmk.nvim/archive/3c804c1480991e4837514900b22b9358cfd64fa1.tar.gz",
"hash": "03fsx6qsn8b36jp5m0fkdla6gkkzdv2j18y378y3cqpjclgq995a"
},
"rainbow-delimiters-nvim": {
"type": "Git",
"repository": {