From 3e377ce6370e26028b04b82e5e036ceb295b23d0 Mon Sep 17 00:00:00 2001 From: hektor Date: Tue, 3 Nov 2026 23:48:58 +0100 Subject: [PATCH] feat(nvim): add nixCats-backed language options --- home/hosts/andromache/default.nix | 1 + home/hosts/astyanax/default.nix | 1 + home/hosts/work/default.nix | 8 + home/modules/3d/modeling.nix | 1 - home/modules/go/default.nix | 5 +- .../nvim/config/after/plugin/conform.lua | 68 +++-- .../nvim/config/after/plugin/lspconfig.lua | 261 ++++++++++-------- .../nvim/config/after/plugin/nvim-lint.lua | 75 +++-- .../after/plugin/tailwind-fold.nvim.lua | 4 + home/modules/nvim/config/flake.nix | 35 +-- home/modules/nvim/config/languages.nix | 133 +++++++++ home/modules/nvim/default.nix | 17 +- 12 files changed, 410 insertions(+), 199 deletions(-) create mode 100644 home/modules/nvim/config/languages.nix diff --git a/home/hosts/andromache/default.nix b/home/hosts/andromache/default.nix index 050e904..f5da9fe 100644 --- a/home/hosts/andromache/default.nix +++ b/home/hosts/andromache/default.nix @@ -31,6 +31,7 @@ desktop.niri.enable = true; devenv.enable = true; direnv.enable = true; + docker.enable = true; gaming.enable = true; git = { enable = true; diff --git a/home/hosts/astyanax/default.nix b/home/hosts/astyanax/default.nix index 229a899..aff4e3e 100644 --- a/home/hosts/astyanax/default.nix +++ b/home/hosts/astyanax/default.nix @@ -30,6 +30,7 @@ desktop.niri.enable = true; devenv.enable = true; direnv.enable = true; + docker.enable = true; git = { enable = true; gitea.enable = true; diff --git a/home/hosts/work/default.nix b/home/hosts/work/default.nix index 0a7adb0..c302531 100644 --- a/home/hosts/work/default.nix +++ b/home/hosts/work/default.nix @@ -72,6 +72,14 @@ nvim = { enable = true; colorscheme = "vscode"; + # note: non-exhaustive (these are the ones that are not inferred from home + # module options atm) + languages = { + css = true; + html = true; + json = true; + tailwind = true; + }; }; pandoc.enable = true; shell.enable = true; diff --git a/home/modules/3d/modeling.nix b/home/modules/3d/modeling.nix index 9207635..9330468 100644 --- a/home/modules/3d/modeling.nix +++ b/home/modules/3d/modeling.nix @@ -13,7 +13,6 @@ blender ] ++ lib.optionals config.modules."3d".modeling.openscad.enable [ - openscad-lsp openscad-unstable ]; }; diff --git a/home/modules/go/default.nix b/home/modules/go/default.nix index 49a4816..a2f1ffc 100644 --- a/home/modules/go/default.nix +++ b/home/modules/go/default.nix @@ -13,10 +13,7 @@ config = lib.mkIf config.go.enable { home = { sessionVariables.GOPATH = "${config.xdg.dataHome}/go"; - packages = with pkgs; [ - go - gopls - ]; + packages = with pkgs; [ go ]; }; }; } diff --git a/home/modules/nvim/config/after/plugin/conform.lua b/home/modules/nvim/config/after/plugin/conform.lua index 1fbadfb..b31ffb8 100644 --- a/home/modules/nvim/config/after/plugin/conform.lua +++ b/home/modules/nvim/config/after/plugin/conform.lua @@ -1,29 +1,51 @@ +local nixCatsUtils = require("nixCatsUtils") + +local formatters = { + general = { + awk = { "awk" }, + html = { "prettierd", "prettier", stop_after_first = true }, + json = { "prettierd", "prettier", stop_after_first = true }, + jsonc = { "prettierd", "prettier", stop_after_first = true }, + markdown = { "prettierd", "prettier", stop_after_first = true }, + }, + c = { + c = { "clang-format" }, + cpp = { "clang-format" }, + }, + css = { css = { "prettierd", "prettier", stop_after_first = true } }, + gdscript = { gdscript = { "gdformat" } }, + go = { go = { "gofmt" } }, + haskell = { haskell = { "ormolu" } }, + lua = { lua = { "stylua" } }, -- configured in stylua.toml + nix = { nix = { "nixfmt" } }, + python = { python = { "isort", "black" } }, + rust = { rust = { "rustfmt", lsp_format = "fallback" } }, + shell = { bash = { "shellcheck" } }, + svelte = { svelte = { "eslint_d", "prettierd", "prettier", stop_after_first = true } }, + typescript = { + javascript = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, + javascriptreact = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, + typescript = { "eslint_d", "prettierd", "prettier", stop_after_first = true }, + typescriptreact = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, + }, + yaml = { + -- yaml = { "prettierd", "prettier", stop_after_first = true }, + }, +} + +local formatters_by_ft = {} +for language, language_formatters in pairs(formatters) do + if language == "general" or nixCatsUtils.enableForCategory("languages." .. language) then + for ft, ft_formatters in pairs(language_formatters) do + formatters_by_ft[ft] = ft_formatters + end + end +end + require("conform").setup({ format_after_save = { lsp_format = "never", timeout_ms = 500, }, - formatters_by_ft = { - awk = { "awk" }, - bash = { "shellcheck" }, - c = { "clang-format" }, - cpp = { "clang-format" }, - css = { "prettierd", "prettier", stop_after_first = true }, - gdscript = { "gdformat" }, - haskell = { "ormolu" }, - html = { "prettierd", "prettier", stop_after_first = true }, - javascript = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, - javascriptreact = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, - json = { "prettierd", "prettier", stop_after_first = true }, - jsonc = { "prettierd", "prettier", stop_after_first = true }, - lua = { "stylua" }, -- configured in stylua.toml - markdown = { "prettierd", "prettier", stop_after_first = true }, - nix = { "nixfmt" }, - python = { "isort", "black" }, - rust = { "rustfmt", lsp_format = "fallback" }, - svelte = { "eslint_d", "prettierd", "prettier", stop_after_first = true }, - typescript = { "eslint_d", "prettierd", "prettier", stop_after_first = true }, - typescriptreact = { "eslint_d", "eslint", "prettierd", "prettier", stop_after_first = true }, - -- yaml = { "prettierd", "prettier", stop_after_first = true }, - }, + formatters_by_ft = formatters_by_ft, }) diff --git a/home/modules/nvim/config/after/plugin/lspconfig.lua b/home/modules/nvim/config/after/plugin/lspconfig.lua index 92fce1d..cf3bf9e 100644 --- a/home/modules/nvim/config/after/plugin/lspconfig.lua +++ b/home/modules/nvim/config/after/plugin/lspconfig.lua @@ -4,159 +4,186 @@ local cmp_nvim_lsp = require("cmp_nvim_lsp") local capabilities = cmp_nvim_lsp.default_capabilities() local servers = { - bashls = {}, - eslint = { - settings = { - --Assuming prettier/prettierd will handle formatting, we don't need to see these errors - rulesCustomizations = { - { rule = "prettier/prettier", severity = "off" }, - }, - format = false, + c = { clangd = {} }, + css = { cssls = {} }, + docker = { dockerls = {} }, + gdscript = { gdscript = {} }, + go = { gopls = {} }, + haskell = { hls = { filetypes = { "haskell", "lhaskell", "cabal" } } }, + helm = { + helm_ls = { + filetypes = { "helm", "yaml.helm-values" }, }, }, - emmet_language_server = {}, - gdscript = {}, - helm_ls = { - filetypes = { "helm", "yaml.helm-values" }, + html = { + emmet_language_server = {}, + html = {}, }, - hls = { filetypes = { "haskell", "lhaskell", "cabal" } }, - html = {}, - jsonls = { - settings = { - json = { - schemas = require("schemastore").json.schemas(), - validate = { enable = true }, + json = { + jsonls = { + settings = { + json = { + schemas = require("schemastore").json.schemas(), + validate = { enable = true }, + }, }, }, }, - lua_ls = { - on_init = function(client) - if client.workspace_folders then - local path = client.workspace_folders[1].name - if - path ~= vim.fn.stdpath("config") - and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc")) - then - return + lua = { + lua_ls = { + on_init = function(client) + if client.workspace_folders then + local path = client.workspace_folders[1].name + if + path ~= vim.fn.stdpath("config") + and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc")) + then + return + end end - end - client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, { - runtime = { - version = "LuaJIT", - path = { - "lua/?.lua", - "lua/?/init.lua", + client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, { + runtime = { + version = "LuaJIT", + path = { + "lua/?.lua", + "lua/?/init.lua", + }, }, - }, - workspace = { - checkThirdParty = false, - library = { - vim.env.VIMRUNTIME, + workspace = { + checkThirdParty = false, + library = { + vim.env.VIMRUNTIME, + }, }, - }, - }) - end, - settings = { - Lua = {}, + }) + end, + settings = { + Lua = {}, + }, }, }, - nixd = { - settings = { - nixd = { - nixpkgs = { - expr = "import { }", - expr = 'import (builtins.getFlake ("git+file://" + toString ../../../../../.)).inputs.nixpkgs { }', + nix = { + nixd = { + settings = { + nixd = { + nixpkgs = { + expr = "import { }", + expr = 'import (builtins.getFlake ("git+file://" + toString ../../../../../.)).inputs.nixpkgs { }', + }, }, - }, - options = { - nixos = { - expr = '(builtins.getFlake ("git+file://" + toString ../../../../../.)).nixosConfigurations."' - .. vim.fn.hostname() - .. '".options', - }, - home_manager = { - expr = '(builtins.getFlake ("git+file://" + toString ../../../../../.)).homeConfigurations."' - .. vim.fn.expand("$USER") - .. "@" - .. vim.fn.hostname() - .. '".options', + options = { + nixos = { + expr = '(builtins.getFlake ("git+file://" + toString ../../../../../.)).nixosConfigurations."' + .. vim.fn.hostname() + .. '".options', + }, + home_manager = { + expr = '(builtins.getFlake ("git+file://" + toString ../../../../../.)).homeConfigurations."' + .. vim.fn.expand("$USER") + .. "@" + .. vim.fn.hostname() + .. '".options', + }, }, }, }, }, - openscad_ls = {}, - pyright = {}, + openscad = { openscad_ls = {} }, + python = { pyright = {} }, + shell = { bashls = {} }, svelte = { - plugin = { - svelte = { - defaultScriptLanguage = "ts", + svelte = { + plugin = { + svelte = { + defaultScriptLanguage = "ts", + }, }, }, }, - tailwindcss = {}, - ts_ls = {}, - vtsls = { - filetypes = { - "javascript", - "javascriptreact", - "javascript.jsx", - "typescript", - "typescriptreact", - "typescript.tsx", + tailwind = { tailwindcss = {} }, + typescript = { + eslint = { + settings = { + --Assuming prettier/prettierd will handle formatting, we don't need to see these errors + rulesCustomizations = { + { rule = "prettier/prettier", severity = "off" }, + }, + format = false, + }, }, - settings = { - vtsls = { - enableMoveToFileCodeAction = true, - autoUseWorkspaceTsdk = true, - experimental = { - completion = { - enableServerSideFuzzyMatch = true, + ts_ls = {}, + vtsls = { + filetypes = { + "javascript", + "javascriptreact", + "javascript.jsx", + "typescript", + "typescriptreact", + "typescript.tsx", + }, + settings = { + vtsls = { + enableMoveToFileCodeAction = true, + autoUseWorkspaceTsdk = true, + experimental = { + completion = { + enableServerSideFuzzyMatch = true, + }, + }, + }, + typescript = { + updateImportsOnFileMove = { enabled = "always" }, + tsserver = { maxTsServerMemory = 16384 }, + suggest = { + completeFunctionCalls = true, + }, + inlayHints = { + enumMemberValues = { enabled = true }, + functionLikeReturnTypes = { enabled = true }, + parameterNames = { enabled = "literals" }, + parameterTypes = { enabled = true }, + propertyDeclarationTypes = { enabled = true }, + variableTypes = { enabled = false }, }, }, }, - typescript = { - updateImportsOnFileMove = { enabled = "always" }, - tsserver = { maxTsServerMemory = 16384 }, - suggest = { - completeFunctionCalls = true, - }, - inlayHints = { - enumMemberValues = { enabled = true }, - functionLikeReturnTypes = { enabled = true }, - parameterNames = { enabled = "literals" }, - parameterTypes = { enabled = true }, - propertyDeclarationTypes = { enabled = true }, - variableTypes = { enabled = false }, - }, - }, }, }, - yamlls = { - settings = { - yaml = { - schemaStore = { - -- You must disable built-in schemaStore support if you want to use - -- this plugin and its advanced options like `ignore`. - enable = false, - -- Avoid TypeError: Cannot read properties of undefined (reading 'length') - url = "", + yaml = { + yamlls = { + settings = { + yaml = { + schemaStore = { + -- You must disable built-in schemaStore support if you want to use + -- this plugin and its advanced options like `ignore`. + enable = false, + -- Avoid TypeError: Cannot read properties of undefined (reading 'length') + url = "", + }, + schemas = require("schemastore").yaml.schemas(), }, - schemas = require("schemastore").yaml.schemas(), }, }, }, } -local typescript_server = require("nixCatsUtils").getCatOrDefault("typescriptServer", "ts_ls") -servers[typescript_server == "vtsls" and "ts_ls" or "vtsls"] = nil +local nixCatsUtils = require("nixCatsUtils") +local typescript_server = nixCatsUtils.getCatOrDefault("typescriptServer", "ts_ls") +servers.typescript[typescript_server == "vtsls" and "ts_ls" or "vtsls"] = nil -for server, config in pairs(servers) do - config.capabilities = capabilities - vim.lsp.config(server, config) +local enabled = {} +for language, language_servers in pairs(servers) do + if nixCatsUtils.enableForCategory("languages." .. language) then + for server, config in pairs(language_servers) do + config.capabilities = capabilities + vim.lsp.config(server, config) + table.insert(enabled, server) + end + end end -vim.lsp.enable(vim.tbl_keys(servers)) +vim.lsp.enable(enabled) vim.api.nvim_create_autocmd("LspAttach", { callback = function(e) diff --git a/home/modules/nvim/config/after/plugin/nvim-lint.lua b/home/modules/nvim/config/after/plugin/nvim-lint.lua index 14b9c91..d23517d 100644 --- a/home/modules/nvim/config/after/plugin/nvim-lint.lua +++ b/home/modules/nvim/config/after/plugin/nvim-lint.lua @@ -1,33 +1,60 @@ +local nixCatsUtils = require("nixCatsUtils") + vim.env.ESLINT_D_PPID = vim.fn.getpid() local eslint_linter = "eslint_d" -require("lint").linters_by_ft = { - bash = { "shellcheck" }, - c = { "clangtidy", "flawfinder" }, - cmake = { "cmakelint" }, - cpp = { "clangtidy", "flawfinder" }, -- "cpplint", "cppcheck", "flawfinder" - css = { "stylelint" }, - dockerfile = { "hadolint" }, - editorconfig = { "editorconfig-checker" }, - haskell = { "hlint" }, - -- html = { "htmlhint" }, - -- javascript = { eslint_linter }, - -- javascriptreact = { eslint_linter }, - gdscript = { "gdlint" }, - latex = { "chktex" }, - -- lua = { "luacheck", "selene" }, - make = { "checkmake" }, - -- pandoc = { "proselint", "woke" }, - -- python = { "pylint" }, - sh = { "shellcheck" }, - svelte = { eslint_linter }, - systemd = { "systemdlint" }, - -- typescript = { eslint_linter }, - -- typescriptreact = { eslint_linter }, - yaml = { "yamllint" }, +local linters = { + general = { + cmake = { "cmakelint" }, + editorconfig = { "editorconfig-checker" }, + latex = { "chktex" }, + make = { "checkmake" }, + -- pandoc = { "proselint", "woke" }, + systemd = { "systemdlint" }, + }, + c = { + c = { "clangtidy", "flawfinder" }, + cpp = { "clangtidy", "flawfinder" }, -- "cpplint", "cppcheck", "flawfinder" + }, + css = { css = { "stylelint" } }, + docker = { dockerfile = { "hadolint" } }, + gdscript = { gdscript = { "gdlint" } }, + haskell = { haskell = { "hlint" } }, + html = { + -- html = { "htmlhint" }, + }, + lua = { + -- lua = { "luacheck", "selene" }, + }, + python = { + -- python = { "pylint" }, + }, + shell = { + bash = { "shellcheck" }, + sh = { "shellcheck" }, + }, + svelte = { svelte = { eslint_linter } }, + typescript = { + -- javascript = { eslint_linter }, + -- javascriptreact = { eslint_linter }, + -- typescript = { eslint_linter }, + -- typescriptreact = { eslint_linter }, + }, + yaml = { yaml = { "yamllint" } }, } +local linters_by_ft = {} +for language, language_linters in pairs(linters) do + if language == "general" or nixCatsUtils.enableForCategory("languages." .. language) then + for ft, ft_linters in pairs(language_linters) do + linters_by_ft[ft] = ft_linters + end + end +end + +require("lint").linters_by_ft = linters_by_ft + local function has_yamllint_config(buf) return vim.fs.root(buf, { ".yamllint", ".yamllint.yaml", ".yamllint.yml" }) ~= nil end diff --git a/home/modules/nvim/config/after/plugin/tailwind-fold.nvim.lua b/home/modules/nvim/config/after/plugin/tailwind-fold.nvim.lua index 83d1e46..d1f668a 100644 --- a/home/modules/nvim/config/after/plugin/tailwind-fold.nvim.lua +++ b/home/modules/nvim/config/after/plugin/tailwind-fold.nvim.lua @@ -1 +1,5 @@ +if not require("nixCatsUtils").enableForCategory("languages.tailwind") then + return +end + require("tailwind-fold").setup({ ft = { "html", "svelte", "tsx" } }) diff --git a/home/modules/nvim/config/flake.nix b/home/modules/nvim/config/flake.nix index bd769c7..e93402b 100644 --- a/home/modules/nvim/config/flake.nix +++ b/home/modules/nvim/config/flake.nix @@ -34,6 +34,7 @@ }@inputs: let inherit (nixCats) utils; + inherit (nixpkgs) lib; luaPath = ./.; forEachSystem = utils.eachSystem nixpkgs.lib.platforms.all; extra_pkg_config = { @@ -75,44 +76,23 @@ }: let themes = import ./themes.nix pkgs; + languages = import ./languages.nix { inherit pkgs categories; }; in { lspsAndRuntimeDeps = with pkgs; { general = [ nodejs_24 - black - clang - clang-tools curl # → plenary-nvim delta - emmet-language-server - eslint_d fd gawk - gdtoolkit_4 - hadolint - helm-ls inotify-tools - isort - lua-language-server - nixd - nixfmt prettier - ormolu prettierd - rust-analyzer - rustfmt - shellcheck-minimal - stylelint - stylua tree-sitter - tailwindcss-language-server - (if (categories.typescriptServer or "ts_ls") == "vtsls" then vtsls else typescript-language-server) - vscode-langservers-extracted - yaml-language-server - yamllint ]; github = [ gh ]; + languages = lib.mapAttrs (_: language: language.packages) languages; }; startupPlugins = { @@ -137,9 +117,7 @@ # TODO: tidalcycles/vim-tidal vim-glsl # TODO: timtro/glslView-nvim - # TODO: sirtaj/vim-openscad jupytext-nvim - vim-openscad ## paq eyeliner-nvim fzf-lua @@ -172,21 +150,19 @@ gitsigns-nvim pkgs.neovimPlugins.atlas-nvim nvim-highlight-colors - pkgs.neovimPlugins.tailwind-fold-nvim auto-session nvim-dbee image-nvim pkgs.neovimPlugins.beancount-nvim codecompanion-nvim - helm-ls-nvim kitty-scrollback-nvim fidget-nvim - rustaceanvim # pkgs.neovimPlugins.m-taskwarrior-d-nvim claudecode-nvim snacks-nvim ] ++ themes.${categories.colorscheme or "zenwritten"}; + languages = lib.mapAttrs (_: language: language.plugins or [ ]) languages; }; optionalPlugins = { @@ -202,7 +178,7 @@ }; packageDefinitions = { - nvim = _: { + nvim = { pkgs, ... }: { settings = { suffix-path = true; suffix-LD = true; @@ -214,6 +190,7 @@ github = false; colorscheme = "zenwritten"; typescriptServer = "ts_ls"; + languages = lib.mapAttrs (_: language: language.enable) (import ./languages.nix { inherit pkgs; }); }; }; }; diff --git a/home/modules/nvim/config/languages.nix b/home/modules/nvim/config/languages.nix new file mode 100644 index 0000000..ff2311c --- /dev/null +++ b/home/modules/nvim/config/languages.nix @@ -0,0 +1,133 @@ +{ + pkgs, + categories ? { }, +}: + +with pkgs; +{ + c = { + enable = false; + packages = [ + clang + clang-tools + ]; + }; + css = { + enable = false; + packages = [ + stylelint + vscode-langservers-extracted + ]; + }; + docker = { + enable = false; + packages = [ + dockerfile-language-server + hadolint + ]; + }; + gdscript = { + enable = false; + packages = [ gdtoolkit_4 ]; + }; + go = { + enable = false; + packages = [ + go + gopls + ]; + }; + haskell = { + enable = false; + packages = [ + haskell-language-server + hlint + ormolu + ]; + }; + helm = { + enable = false; + packages = [ helm-ls ]; + plugins = [ vimPlugins.helm-ls-nvim ]; + }; + html = { + enable = false; + packages = [ + emmet-language-server + vscode-langservers-extracted + ]; + }; + json = { + enable = false; + packages = [ vscode-langservers-extracted ]; + }; + lua = { + enable = true; + packages = [ + lua-language-server + stylua + ]; + }; + nix = { + enable = true; + packages = [ + nixd + nixfmt + ]; + }; + openscad = { + enable = false; + packages = [ openscad-lsp ]; + plugins = [ vimPlugins.vim-openscad ]; + }; + python = { + enable = false; + packages = [ + black + isort + pyright + ]; + }; + rust = { + enable = false; + packages = [ + rust-analyzer + rustfmt + ]; + plugins = [ vimPlugins.rustaceanvim ]; + }; + shell = { + enable = true; + packages = [ + bash-language-server + shellcheck-minimal + ]; + }; + svelte = { + enable = false; + packages = [ + eslint_d + svelte-language-server + ]; + }; + tailwind = { + enable = false; + packages = [ tailwindcss-language-server ]; + plugins = [ neovimPlugins.tailwind-fold-nvim ]; + }; + typescript = { + enable = false; + packages = [ + eslint_d + (if (categories.typescriptServer or "ts_ls") == "vtsls" then vtsls else typescript-language-server) + vscode-langservers-extracted + ]; + }; + yaml = { + enable = false; + packages = [ + yaml-language-server + yamllint + ]; + }; +} diff --git a/home/modules/nvim/default.nix b/home/modules/nvim/default.nix index c98470e..590b332 100644 --- a/home/modules/nvim/default.nix +++ b/home/modules/nvim/default.nix @@ -25,14 +25,29 @@ in "vtsls" ]; }; + languages = lib.mapAttrs ( + _: language: + lib.mkOption { + default = language.enable; + type = lib.types.bool; + } + ) (import "${inputs.nvim}/languages.nix" { inherit pkgs; }); }; config = lib.mkIf config.nvim.enable { + nvim.languages = { + docker = lib.mkDefault config.docker.enable; + go = lib.mkDefault config.go.enable; + helm = lib.mkDefault config.k8s.helm.enable; + openscad = lib.mkDefault config.modules."3d".modeling.openscad.enable; + typescript = lib.mkDefault config.nodejs.enable; + }; + nvim.packageDefinitions.merge.nvim = _: { categories = { colorscheme = config.nvim.colorscheme; github = config.git.github.enable; - inherit (config.nvim) typescriptServer; + inherit (config.nvim) languages typescriptServer; }; };