diff --git a/extra.nix b/extra.nix index 02ee01c..5fba36b 100644 --- a/extra.nix +++ b/extra.nix @@ -25,25 +25,23 @@ inputs: let }; }; - vim.lsp = { - enable = true; - formatOnSave = true; - lightbulb.enable = true; - lspsaga.enable = false; - nvimCodeActionMenu.enable = true; - trouble.enable = true; - lspSignature.enable = true; - rust.enable = isMaximal; - python = isMaximal; + vim.languages = { + enableLSP = true; + enableFormat = true; + enableTreesitter = true; + enableExtraDiagnostics = true; + + nix.enable = true; clang.enable = isMaximal; - sql = isMaximal; - ts = isMaximal; - go = isMaximal; - zig.enable = isMaximal; - nix = { - enable = true; - formatter = "alejandra"; + sql.enable = isMaximal; + rust = { + enable = isMaximal; + crates.enable = true; }; + ts.enable = isMaximal; + go.enable = isMaximal; + zig.enable = isMaximal; + python.enable = isMaximal; }; vim.visuals = { @@ -101,24 +99,14 @@ inputs: let nvimBufferline.enable = true; }; - vim.treesitter = { - enable = true; - context.enable = true; - }; + vim.treesitter.context.enable = true; vim.binds = { whichKey.enable = true; cheatsheet.enable = true; }; - vim.telescope = { - enable = true; - }; - - vim.markdown = { - enable = true; - glow.enable = true; - }; + vim.telescope.enable = true; vim.git = { enable = true; diff --git a/flake.nix b/flake.nix index 78f77b6..6e7d363 100644 --- a/flake.nix +++ b/flake.nix @@ -49,7 +49,6 @@ ... }: { devShells.default = pkgs.mkShell {nativeBuildInputs = [config.packages.nix];}; - }; }; diff --git a/lib/default.nix b/lib/default.nix index 873f31b..e7b721b 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -2,4 +2,5 @@ dag = import ./dag.nix {inherit lib;}; booleans = import ./booleans.nix {inherit lib;}; types = import ./types {inherit lib;}; + languages = import ./languages.nix {inherit lib;}; } diff --git a/lib/languages.nix b/lib/languages.nix new file mode 100644 index 0000000..18d678d --- /dev/null +++ b/lib/languages.nix @@ -0,0 +1,25 @@ +# From home-manager: https://github.com/nix-community/home-manager/blob/master/modules/lib/booleans.nix +{lib}: { + # Converts a boolean to a yes/no string. This is used in lots of + # configuration formats. + diagnosticsToLua = { + lang, + config, + diagnostics, + }: + lib.listToAttrs + (map (v: let + type = + if builtins.isString v + then v + else builtins.getAttr v.type; + package = + if builtins.isString v + then diagnostics.${type}.package + else v.package; + in { + name = "${lang}-diagnostics-${type}"; + value = diagnostics.${type}.nullConfig package; + }) + config); +} diff --git a/lib/types/default.nix b/lib/types/default.nix index fca45ba..6317160 100644 --- a/lib/types/default.nix +++ b/lib/types/default.nix @@ -1,7 +1,9 @@ {lib}: let typesDag = import ./dag.nix {inherit lib;}; typesPlugin = import ./plugins.nix {inherit lib;}; + typesLanguage = import ./languages.nix {inherit lib;}; in { inherit (typesDag) dagOf; inherit (typesPlugin) pluginsOpt; + inherit (typesLanguage) diagnostics; } diff --git a/lib/types/languages.nix b/lib/types/languages.nix new file mode 100644 index 0000000..7dc57af --- /dev/null +++ b/lib/types/languages.nix @@ -0,0 +1,26 @@ +{lib}: +with lib; let + diagnosticSubmodule = {...}: { + options = { + type = mkOption { + description = "Type of diagnostic to enable"; + type = attrNames diagnostics; + }; + package = mkOption { + description = "Diagnostics package"; + type = types.package; + }; + }; + }; +in { + diagnostics = { + langDesc, + diagnostics, + defaultDiagnostics, + }: + mkOption { + description = "List of ${langDesc} diagnostics to enable"; + type = with types; listOf (either (enum (attrNames diagnostics)) (submodule diagnosticSubmodule)); + default = defaultDiagnostics; + }; +} diff --git a/modules/completion/nvim-cmp/config.nix b/modules/completion/nvim-cmp/config.nix index a502358..4495243 100644 --- a/modules/completion/nvim-cmp/config.nix +++ b/modules/completion/nvim-cmp/config.nix @@ -1,4 +1,5 @@ { + pkgs, lib, config, ... @@ -6,15 +7,22 @@ with lib; with builtins; let cfg = config.vim.autocomplete; + builtSources = + concatMapStringsSep "\n" (x: "{ name = '${x}'},") cfg.sources; in { config = mkIf cfg.enable { vim.startPlugins = [ - "vim-vsnip" "nvim-cmp" "cmp-buffer" "cmp-vsnip" "cmp-path" - "cmp-treesitter" + ]; + + vim.autocomplete.sources = [ + "nvim-cmp" + "vsnip" + "buffer" + "path" ]; vim.luaConfigRC.completion = mkIf (cfg.type == "nvim-cmp") (nvim.dag.entryAnywhere '' @@ -35,12 +43,7 @@ in { end, }, sources = { - ${optionalString (config.vim.lsp.enable) "{ name = 'nvim_lsp' },"} - ${optionalString (config.vim.lsp.rust.enable) "{ name = 'crates' },"} - { name = 'vsnip' }, - { name = 'treesitter' }, - { name = 'path' }, - { name = 'buffer' }, + ${builtSources} }, mapping = { [''] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }), diff --git a/modules/completion/nvim-cmp/nvim-cmp.nix b/modules/completion/nvim-cmp/nvim-cmp.nix index 5938525..6585218 100644 --- a/modules/completion/nvim-cmp/nvim-cmp.nix +++ b/modules/completion/nvim-cmp/nvim-cmp.nix @@ -1,16 +1,21 @@ { + pkgs, lib, config, ... }: with lib; -with builtins; { +with builtins; let + cfg = config.vim.autocomplete; + builtSources = + concatMapStringsSep "\n" (x: "{ name = '${x}'},") cfg.sources; +in { options.vim = { autocomplete = { enable = mkOption { type = types.bool; default = false; - description = "Enable autocomplete via nvim-cmp"; + description = "enable autocomplete"; }; type = mkOption { @@ -18,6 +23,12 @@ with builtins; { default = "nvim-cmp"; description = "Set the autocomplete plugin. Options: [nvim-cmp]"; }; + + sources = mkOption { + description = "List of source names for nvim-cmp"; + type = with types; listOf str; + default = []; + }; }; }; } diff --git a/modules/languages/clang.nix b/modules/languages/clang.nix new file mode 100644 index 0000000..4514329 --- /dev/null +++ b/modules/languages/clang.nix @@ -0,0 +1,96 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.clang; + + defaultServer = "ccls"; + servers = { + ccls = { + package = pkgs.ccls; + lspConfig = '' + lspconfig.ccls.setup{ + capabilities = capabilities; + on_attach=default_on_attach; + cmd = {"${pkgs.ccls}/bin/ccls"}; + ${optionalString (cfg.lsp.opts != null) "init_options = ${cfg.lsp.cclsOpts}"} + } + ''; + }; + }; +in { + options.vim.languages.clang = { + enable = mkEnableOption "C/C++ language support"; + + cHeader = mkOption { + description = '' + C syntax for headers. Can fix treesitter errors, see: + https://www.reddit.com/r/neovim/comments/orfpcd/question_does_the_c_parser_from_nvimtreesitter/ + ''; + type = types.bool; + default = false; + }; + + treesitter = { + enable = mkOption { + description = "Enable C/C++ treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + cPackage = mkOption { + description = "C treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.c; + }; + cppPackage = mkOption { + description = "C++ treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.cpp; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable clang LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "The clang LSP server to use"; + type = with types; enum (attrNames servers); + default = defaultServer; + }; + package = mkOption { + description = "clang LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.package; + }; + opts = mkOption { + description = "Options to pass to clang LSP server"; + type = with types; nullOr str; + default = null; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf cfg.cHeader { + vim.configRC.c-header = nvim.dag.entryAnywhere "let g:c_syntax_for_h = 1"; + }) + + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.cPackage cfg.treesitter.cppPackage]; + }) + + (mkIf cfg.lsp.enable { + vim.lsp.lspconfig.enable = true; + + vim.lsp.lspconfig.sources.clang-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + ]); +} diff --git a/modules/languages/default.nix b/modules/languages/default.nix new file mode 100644 index 0000000..3b26e35 --- /dev/null +++ b/modules/languages/default.nix @@ -0,0 +1,27 @@ +{lib, ...}: +with lib; let + mkEnable = desc: + mkOption { + description = "Turn on ${desc} for enabled langauges by default"; + type = types.bool; + default = false; + }; +in { + imports = [ + ./clang.nix + ./go.nix + ./nix.nix + ./python.nix + ./rust.nix + ./sql.nix + ./ts.nix + ./zig.nix + ]; + + options.vim.languages = { + enableLSP = mkEnable "LSP"; + enableTreesitter = mkEnable "treesitter"; + enableFormat = mkEnable "formatting"; + enableExtraDiagnostics = mkEnable "extra diagnostics"; + }; +} diff --git a/modules/languages/go.nix b/modules/languages/go.nix new file mode 100644 index 0000000..0ceb111 --- /dev/null +++ b/modules/languages/go.nix @@ -0,0 +1,71 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.go; + + defaultServer = "gopls"; + servers = { + gopls = { + package = pkgs.gopls; + lspConfig = '' + lspconfig.gopls.setup { + capabilities = capabilities; + on_attach = default_on_attach; + cmd = {"${cfg.lsp.package}/bin/gopls", "serve"}, + } + ''; + }; + }; +in { + options.vim.languages.go = { + enable = mkEnableOption "Go language support"; + + treesitter = { + enable = mkOption { + description = "Enable Go treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "Go treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.go; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable Go LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "Go LSP server to use"; + type = with types; enum (attrNames servers); + default = defaultServer; + }; + package = mkOption { + description = "Go LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.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.lspconfig.enable = true; + vim.lsp.lspconfig.sources.go-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + ]); +} diff --git a/modules/languages/nix.nix b/modules/languages/nix.nix new file mode 100644 index 0000000..5063f6b --- /dev/null +++ b/modules/languages/nix.nix @@ -0,0 +1,161 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.nix; + + useFormat = "on_attach = default_on_attatch"; + noFormat = "on_attach = attach_keymaps"; + + defaultServer = "nil"; + servers = { + rnix = { + package = pkgs.rnix-lsp; + internalFormatter = true; + lspConfig = '' + lspconfig.rnix.setup{ + capabilities = capabilities, + ${ + if (cfg.format.enable && cfg.format.type == "nixpkgs-fmt") + then useFormat + else noFormat + }, + cmd = {"${cfg.lsp.package}/bin/rnix-lsp"}, + } + ''; + }; + + nil = { + package = pkgs.nil; + internalFormatter = cfg.format.type != "nixpkgs-fmt"; + lspConfig = '' + lspconfig.nil_ls.setup{ + capabilities = capabilities, + ${ + if cfg.format.enable + then useFormat + else noFormat + }, + cmd = {"${cfg.lsp.package}/bin/nil"}, + ${optionalString cfg.format.enable '' + settings = { + ["nil"] = { + ${optionalString (cfg.format.type == "alejandra") + '' + formatting = { + command = {"${cfg.format.package}/bin/alejandra", "--quiet"}, + }, + ''} + ${optionalString (cfg.format.type == "nixpkgs-fmt") + '' + formatting = { + command = {"${cfg.format.package}/bin/nixpkgs-fmt"}, + }, + ''} + ''} + }, + }; + } + ''; + }; + }; + + defaultFormat = "alejandra"; + formats = { + alejandra = { + package = pkgs.alejandra; + nullConfig = '' + table.insert( + ls_sources, + null_ls.builtins.formatting.alejandra.with({ + command = "${cfg.format.package}/bin/alejandra" + }) + ) + ''; + }; + nixpkgs-fmt = { + package = pkgs.nixpkgs-fmt; + # Never need to use null-ls for nixpkgs-fmt + }; + }; +in { + options.vim.languages.nix = { + enable = mkEnableOption "Nix language support"; + + treesitter = { + enable = mkOption { + description = "Enable Nix treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "Nix treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.nix; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable Nix LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "Nix LSP server to use"; + type = types.str; + default = defaultServer; + }; + package = mkOption { + description = "Nix LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.package; + }; + }; + + format = { + enable = mkOption { + description = "Enable Nix formatting"; + type = types.bool; + default = config.vim.languages.enableFormat; + }; + type = mkOption { + description = "Nix formatter to use"; + type = with types; enum (attrNames formats); + default = defaultFormat; + }; + package = mkOption { + description = "Nix formatter package"; + type = types.package; + default = formats.${cfg.format.type}.package; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { + vim.configRC.nix = nvim.dag.entryAnywhere '' + autocmd filetype nix setlocal tabstop=2 shiftwidth=2 softtabstop=2 + ''; + } + + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.package]; + }) + + (mkIf cfg.lsp.enable { + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.nix-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + + (mkIf (cfg.format.enable && !servers.${cfg.lsp.server}.internalFormatter) { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources.nix-format = formats.${cfg.format.type}.nullConfig; + }) + ]); +} diff --git a/modules/languages/python.nix b/modules/languages/python.nix new file mode 100644 index 0000000..c2cabda --- /dev/null +++ b/modules/languages/python.nix @@ -0,0 +1,108 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.python; + + defaultServer = "pyright"; + servers = { + pyright = { + package = pkgs.nodePackages.pyright; + lspConfig = '' + lspconfig.pyright.setup{ + capabilities = capabilities; + on_attach = default_on_attach; + cmd = {"${cfg.lsp.package}/bin/pyright-langserver", "--stdio"} + } + ''; + }; + }; + + defaultFormat = "black"; + formats = { + black = { + package = pkgs.black; + nullConfig = '' + table.insert( + ls_sources, + null_ls.builtins.formatting.black.with({ + command = "${cfg.format.package}/bin/black", + }) + ) + ''; + }; + }; +in { + options.vim.languages.python = { + enable = mkEnableOption "Python language support"; + + treesitter = { + enable = mkOption { + description = "Enable Python treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "Python treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.python; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable Python LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "Python LSP server to use"; + type = with types; enum (attrNames servers); + default = defaultServer; + }; + package = mkOption { + description = "Python LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.package; + }; + }; + + format = { + enable = mkOption { + description = "Enable Python formatting"; + type = types.bool; + default = config.vim.languages.enableFormat; + }; + type = mkOption { + description = "Python formatter to use"; + type = with types; enum (attrNames formats); + default = defaultFormat; + }; + package = mkOption { + description = "Python formatter package"; + type = types.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.lspconfig.enable = true; + vim.lsp.lspconfig.sources.python-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + + (mkIf cfg.format.enable { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources.python-format = formats.${cfg.format.type}.nullConfig; + }) + ]); +} diff --git a/modules/languages/rust.nix b/modules/languages/rust.nix new file mode 100644 index 0000000..b58d885 --- /dev/null +++ b/modules/languages/rust.nix @@ -0,0 +1,113 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.rust; +in { + options.vim.languages.rust = { + enable = mkEnableOption "Rust language support"; + + treesitter = { + enable = mkOption { + description = "Enable Rust treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "Rust treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.rust; + }; + }; + + crates = { + enable = mkEnableOption "crates-nvim, tools for managing dependencies"; + codeActions = mkOption { + description = "Enable code actions through null-ls"; + type = types.bool; + default = true; + }; + }; + + lsp = { + enable = mkOption { + description = "Rust LSP support (rust-analyzer with extra tools)"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + package = mkOption { + description = "rust-analyzer package"; + type = types.package; + default = pkgs.rust-analyzer; + }; + opts = mkOption { + description = "Options to pass to rust analyzer"; + type = types.str; + default = ""; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf cfg.crates.enable { + vim.lsp.null-ls.enable = mkIf cfg.crates.codeActions true; + + vim.startPlugins = ["crates-nvim"]; + + vim.autocomplete.sources = ["crates"]; + vim.luaConfigRC.rust-crates = nvim.dag.entryAnywhere '' + require('crates').setup { + null_ls = { + enabled = ${boolToString cfg.crates.codeActions}, + name = "crates.nvim", + } + } + ''; + }) + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.package]; + }) + (mkIf cfg.lsp.enable { + vim.startPlugins = ["rust-tools"]; + + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.rust-lsp = '' + local rt = require('rust-tools') + rust_on_attach = function(client, bufnr) + default_on_attach(client, bufnr) + local opts = { noremap=true, silent=true, buffer = bufnr } + vim.keymap.set("n", "ris", rt.inlay_hints.set, opts) + vim.keymap.set("n", "riu", rt.inlay_hints.unset, opts) + vim.keymap.set("n", "rr", rt.runnables.runnables, opts) + vim.keymap.set("n", "rp", rt.parent_module.parent_module, opts) + vim.keymap.set("n", "rm", rt.expand_macro.expand_macro, opts) + vim.keymap.set("n", "rc", rt.open_cargo_toml.open_cargo_toml, opts) + vim.keymap.set("n", "rg", function() rt.crate_graph.view_crate_graph("x11", nil) end, opts) + end + local rustopts = { + tools = { + autoSetHints = true, + hover_with_actions = false, + inlay_hints = { + only_current_line = false, + } + }, + server = { + capabilities = capabilities, + on_attach = rust_on_attach, + cmd = {"${cfg.lsp.package}/bin/rust-analyzer"}, + settings = { + ${cfg.lsp.opts} + } + } + } + rt.setup(rustopts) + ''; + }) + ]); +} diff --git a/modules/languages/sql.nix b/modules/languages/sql.nix new file mode 100644 index 0000000..0b03cbc --- /dev/null +++ b/modules/languages/sql.nix @@ -0,0 +1,160 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.sql; + sqlfluffDefault = pkgs.sqlfluff; + + defaultServer = "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 = { "${cfg.lsp.package}/bin/sqls", "-config", string.format("%s/config.yml", vim.fn.getcwd()) } + } + ''; + }; + }; + + defaultFormat = "sqlfluff"; + formats = { + sqlfluff = { + package = sqlfluffDefault; + nullConfig = '' + table.insert( + ls_sources, + null_ls.builtins.formatting.sqlfluff.with({ + command = "${cfg.format.package}/bin/sqlfluff", + extra_args = {"--dialect", "${cfg.dialect}"} + }) + ) + ''; + }; + }; + + defaultDiagnostics = ["sqlfluff"]; + diagnostics = { + sqlfluff = { + package = sqlfluffDefault; + nullConfig = pkg: '' + table.insert( + ls_sources, + null_ls.builtins.diagnostics.sqlfluff.with({ + command = "${pkg}/bin/sqlfluff", + extra_args = {"--dialect", "${cfg.dialect}"} + }) + ) + ''; + }; + }; +in { + options.vim.languages.sql = { + enable = mkEnableOption "SQL language support"; + + dialect = mkOption { + description = "SQL dialect for sqlfluff (if used)"; + type = types.str; + default = "ansi"; + }; + + treesitter = { + enable = mkOption { + description = "Enable SQL treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "SQL treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.sql; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable SQL LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "SQL LSP server to use"; + type = with types; enum (attrNames servers); + default = defaultServer; + }; + package = mkOption { + description = "SQL LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.package; + }; + }; + + format = { + enable = mkOption { + description = "Enable SQL formatting"; + type = types.bool; + default = config.vim.languages.enableFormat; + }; + type = mkOption { + description = "SQL formatter to use"; + type = with types; enum (attrNames formats); + default = defaultFormat; + }; + package = mkOption { + description = "SQL formatter package"; + type = types.package; + default = formats.${cfg.format.type}.package; + }; + }; + + extraDiagnostics = { + enable = mkOption { + description = "Enable extra SQL diagnostics"; + type = types.bool; + default = config.vim.languages.enableExtraDiagnostics; + }; + types = lib.nvim.types.diagnostics { + langDesc = "SQL"; + inherit diagnostics; + inherit defaultDiagnostics; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.package]; + }) + + (mkIf cfg.lsp.enable { + vim.startPlugins = ["sqls-nvim"]; + + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.sql-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + + (mkIf cfg.format.enable { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources."sql-format" = formats.${cfg.format.type}.nullConfig; + }) + + (mkIf cfg.extraDiagnostics.enable { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources = lib.nvim.languages.diagnosticsToLua { + lang = "sql"; + config = cfg.extraDiagnostics.types; + inherit diagnostics; + }; + }) + ]); +} diff --git a/modules/languages/ts.nix b/modules/languages/ts.nix new file mode 100644 index 0000000..318b623 --- /dev/null +++ b/modules/languages/ts.nix @@ -0,0 +1,153 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.ts; + + defaultServer = "tsserver"; + servers = { + tsserver = { + package = pkgs.nodePackages.typescript-language-server; + lspConfig = '' + lspconfig.tsserver.setup { + capabilities = capabilities; + on_attach = attach_keymaps, + cmd = { "${cfg.lsp.package}/bin/typescript-language-server", "--stdio" } + } + ''; + }; + }; + + # TODO: specify packages + defaultFormat = "prettier"; + formats = { + prettier = { + package = pkgs.nodePackages.prettier; + nullConfig = '' + table.insert( + ls_sources, + null_ls.builtins.formatting.prettier.with({ + command = "${cfg.format.package}/bin/prettier", + }) + ) + ''; + }; + }; + + # TODO: specify packages + defaultDiagnostics = ["eslint"]; + diagnostics = { + eslint = { + package = pkgs.nodePackages.eslint; + nullConfig = pkg: '' + table.insert( + ls_sources, + null_ls.builtins.diagnostics.eslint.with({ + command = "${pkg}/bin/eslint", + }) + ) + ''; + }; + }; +in { + options.vim.languages.ts = { + enable = mkEnableOption "SQL language support"; + + treesitter = { + enable = mkOption { + description = "Enable Typescript/Javascript treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + tsPackage = mkOption { + description = "Typescript treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.tsx; + }; + jsPackage = mkOption { + description = "Javascript treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.javascript; + }; + }; + + lsp = { + enable = mkOption { + description = "Enable Typescript/Javascript LSP support"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + server = mkOption { + description = "Typescript/Javascript LSP server to use"; + type = with types; enum (attrNames servers); + default = defaultServer; + }; + package = mkOption { + description = "Typescript/Javascript LSP server package"; + type = types.package; + default = servers.${cfg.lsp.server}.package; + }; + }; + + format = { + enable = mkOption { + description = "Enable Typescript/Javascript formatting"; + type = types.bool; + default = config.vim.languages.enableFormat; + }; + type = mkOption { + description = "Typescript/Javascript formatter to use"; + type = with types; enum (attrNames formats); + default = defaultFormat; + }; + package = mkOption { + description = "Typescript/Javascript formatter package"; + type = types.package; + default = formats.${cfg.format.type}.package; + }; + }; + + extraDiagnostics = { + enable = mkOption { + description = "Enable extra Typescript/Javascript diagnostics"; + type = types.bool; + default = config.vim.languages.enableExtraDiagnostics; + }; + types = lib.nvim.types.diagnostics { + langDesc = "Typescript/Javascript"; + inherit diagnostics; + inherit defaultDiagnostics; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.tsPackage cfg.treesitter.jsPackage]; + }) + + (mkIf cfg.lsp.enable { + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.ts-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + + (mkIf cfg.format.enable { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources.ts-format = formats.${cfg.format.type}.nullConfig; + }) + + (mkIf cfg.extraDiagnostics.enable { + vim.lsp.null-ls.enable = true; + vim.lsp.null-ls.sources = lib.nvim.languages.diagnosticsToLua { + lang = "ts"; + config = cfg.extraDiagnostics.types; + inherit diagnostics; + }; + }) + ]); +} diff --git a/modules/languages/zig.nix b/modules/languages/zig.nix new file mode 100644 index 0000000..8dbcb7f --- /dev/null +++ b/modules/languages/zig.nix @@ -0,0 +1,68 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.languages.zig; +in { + options.vim.languages.zig = { + enable = mkEnableOption "SQL language support"; + + treesitter = { + enable = mkOption { + description = "Enable Zig treesitter"; + type = types.bool; + default = config.vim.languages.enableTreesitter; + }; + package = mkOption { + description = "Zig treesitter grammar to use"; + type = types.package; + default = pkgs.vimPlugins.nvim-treesitter.builtGrammars.zig; + }; + }; + lsp = { + enable = mkOption { + description = "Zig LSP support (zls)"; + type = types.bool; + default = config.vim.languages.enableLSP; + }; + package = mkOption { + description = "ZLS package"; + type = types.package; + default = pkgs.nodePackages.pyright; + }; + zigPackage = mkOption { + description = "Zig package used by ZLS"; + type = types.package; + default = pkgs.zig; + }; + }; + }; + + 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.lspconfig.enable = true; + vim.lsp.lspconfig.sources.zig-lsp = '' + lspconfig.zls.setup { + capabilities = capabilities, + on_attach=default_on_attach, + cmd = {"${cfg.lsp.package}/bin/zls"}, + settings = { + ["zls"] = { + zig_exe_path = "${cfg.lsp.zigPackage}/bin/zig", + zig_lib_path = "${cfg.lsp.zigPackage}/lib/zig", + } + } + } + ''; + }) + ]); +} diff --git a/modules/lsp/config.nix b/modules/lsp/config.nix index 581556e..a90bd02 100644 --- a/modules/lsp/config.nix +++ b/modules/lsp/config.nix @@ -1,352 +1,63 @@ { - pkgs, config, lib, + pkgs, ... }: with lib; with builtins; let cfg = config.vim.lsp; + usingNvimCmp = config.vim.autocomplete.enable && config.vim.autocomplete.type == "nvim-cmp"; in { - config = mkIf cfg.enable ( - let - writeIf = cond: msg: - if cond - then msg - else ""; - in { - vim.startPlugins = - [ - "nvim-lspconfig" - "null-ls" - ( - if (config.vim.autocomplete.enable && (config.vim.autocomplete.type == "nvim-cmp")) - then "cmp-nvim-lsp" - else null - ) - ( - if cfg.sql - then "sqls-nvim" - else null - ) - ] - ++ ( - if cfg.rust.enable - then [ - "crates-nvim" - "rust-tools" - ] - else [] - ); + config = mkIf cfg.enable { + vim.startPlugins = optional usingNvimCmp "cmp-nvim-lsp"; - vim.configRC.lsp = nvim.dag.entryAnywhere '' - ${ - if cfg.nix.enable - then '' - autocmd filetype nix setlocal tabstop=2 shiftwidth=2 softtabstop=2 - '' - else "" - } + vim.autocomplete.sources = ["nvim_lsp"]; - ${ - if cfg.clang.c_header - then '' - " c syntax for header (otherwise breaks treesitter highlighting) - " https://www.reddit.com/r/neovim/comments/orfpcd/question_does_the_c_parser_from_nvimtreesitter/ - let g:c_syntax_for_h = 1 - '' - else "" - } - ''; - vim.luaConfigRC.lsp = nvim.dag.entryAnywhere '' + vim.luaConfigRC.lsp-setup = '' + vim.g.formatsave = ${boolToString cfg.formatOnSave}; - local attach_keymaps = function(client, bufnr) - local opts = { noremap=true, silent=true } + local attach_keymaps = function(client, bufnr) + local opts = { noremap=true, silent=true } - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgD', 'lua vim.lsp.buf.declaration()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgd', 'lua vim.lsp.buf.definition()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgt', 'lua vim.lsp.buf.type_definition()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgn', 'lua vim.diagnostic.goto_next()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgp', 'lua vim.diagnostic.goto_prev()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgD', 'lua vim.lsp.buf.declaration()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgd', 'lua vim.lsp.buf.definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgt', 'lua vim.lsp.buf.type_definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgn', 'lua vim.diagnostic.goto_next()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lgp', 'lua vim.diagnostic.goto_prev()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwa', 'lua vim.lsp.buf.add_workspace_folder()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwr', 'lua vim.lsp.buf.remove_workspace_folder()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwl', 'lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwa', 'lua vim.lsp.buf.add_workspace_folder()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwr', 'lua vim.lsp.buf.remove_workspace_folder()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lwl', 'lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lh', 'lua vim.lsp.buf.hover()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ls', 'lua vim.lsp.buf.signature_help()', opts) - vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ln', 'lua vim.lsp.buf.rename()', opts) - end + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'lh', 'lua vim.lsp.buf.hover()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ls', 'lua vim.lsp.buf.signature_help()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ln', 'lua vim.lsp.buf.rename()', opts) + end - local null_ls = require("null-ls") - local null_helpers = require("null-ls.helpers") - local null_methods = require("null-ls.methods") - - local ls_sources = { - ${writeIf cfg.python - '' - null_ls.builtins.formatting.black.with({ - command = "${pkgs.black}/bin/black", - }), - ''} - - -- Commented out for now - --${writeIf (config.vim.git.enable && config.vim.git.gitsigns.enable) '' - -- null_ls.builtins.code_actions.gitsigns, - --''} - - ${writeIf cfg.sql - '' - null_helpers.make_builtin({ - method = null_methods.internal.FORMATTING, - filetypes = { "sql" }, - generator_opts = { - to_stdin = true, - ignore_stderr = true, - suppress_errors = true, - command = "${pkgs.sqlfluff}/bin/sqlfluff", - args = { - "fix", - "-", - }, - }, - factory = null_helpers.formatter_factory, - }), - - null_ls.builtins.diagnostics.sqlfluff.with({ - command = "${pkgs.sqlfluff}/bin/sqlfluff", - extra_args = {"--dialect", "postgres"} - }), - ''} - - ${writeIf - (cfg.nix.enable - && cfg.nix.server == "rnix" - && cfg.nix.formatter == "alejandra") - '' - null_ls.builtins.formatting.alejandra.with({ - command = "${pkgs.alejandra}/bin/alejandra" - }), - ''} - - ${writeIf cfg.ts - '' - null_ls.builtins.diagnostics.eslint, - null_ls.builtins.formatting.prettier, - ''} - } - - vim.g.formatsave = ${ - if cfg.formatOnSave - then "true" - else "false" - }; - - -- Enable formatting - format_callback = function(client, bufnr) - vim.api.nvim_create_autocmd("BufWritePre", { - group = augroup, - buffer = bufnr, - callback = function() - if vim.g.formatsave then - if client.supports_method("textDocument/formatting") then - local params = require'vim.lsp.util'.make_formatting_params({}) - client.request('textDocument/formatting', params, nil, bufnr) - end + -- Enable formatting + format_callback = function(client, bufnr) + vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup, + buffer = bufnr, + callback = function() + if vim.g.formatsave then + if client.supports_method("textDocument/formatting") then + local params = require'vim.lsp.util'.make_formatting_params({}) + client.request('textDocument/formatting', params, nil, bufnr) end end - }) - end - - default_on_attach = function(client, bufnr) - attach_keymaps(client, bufnr) - format_callback(client, bufnr) - end - - -- Enable null-ls - require('null-ls').setup({ - diagnostics_format = "[#{m}] #{s} (#{c})", - debounce = 250, - default_timeout = 5000, - sources = ls_sources, - on_attach=default_on_attach - }) - - -- Enable lspconfig - local lspconfig = require('lspconfig') - - local capabilities = vim.lsp.protocol.make_client_capabilities() - ${ - let - cfg = config.vim.autocomplete; - in - writeIf cfg.enable ( - if cfg.type == "nvim-cmp" - then '' - capabilities = require('cmp_nvim_lsp').default_capabilities() - '' - else "" - ) - } - - ${writeIf cfg.rust.enable '' - -- Rust config - local rt = require('rust-tools') - - rust_on_attach = function(client, bufnr) - default_on_attach(client, bufnr) - local opts = { noremap=true, silent=true, buffer = bufnr } - vim.keymap.set("n", "ris", rt.inlay_hints.set, opts) - vim.keymap.set("n", "riu", rt.inlay_hints.unset, opts) - vim.keymap.set("n", "rr", rt.runnables.runnables, opts) - vim.keymap.set("n", "rp", rt.parent_module.parent_module, opts) - vim.keymap.set("n", "rm", rt.expand_macro.expand_macro, opts) - vim.keymap.set("n", "rc", rt.open_cargo_toml.open_cargo_toml, opts) - vim.keymap.set("n", "rg", function() rt.crate_graph.view_crate_graph("x11", nil) end, opts) end + }) + end - local rustopts = { - tools = { - autoSetHints = true, - hover_with_actions = false, - inlay_hints = { - only_current_line = false, - } - }, - server = { - capabilities = capabilities, - on_attach = rust_on_attach, - cmd = {"${pkgs.rust-analyzer}/bin/rust-analyzer"}, - settings = { - ${cfg.rust.rustAnalyzerOpts} - } - } - } + default_on_attach = function(client, bufnr) + attach_keymaps(client, bufnr) + format_callback(client, bufnr) + end - require('crates').setup { - null_ls = { - enabled = true, - name = "crates.nvim", - } - } - rt.setup(rustopts) - ''} - - ${optionalString cfg.zig.enable '' - -- Zig config - lspconfig.zls.setup { - capabilities = capabilities, - on_attach=default_on_attach, - cmd = {"${pkgs.zls}/bin/zls"}, - settings = { - ["zls"] = { - zig_exe_path = "${pkgs.zig}/bin/zig", - zig_lib_path = "${pkgs.zig}/lib/zig", - } - } - } - ''} - - ${writeIf cfg.python '' - -- Python config - lspconfig.pyright.setup{ - capabilities = capabilities; - on_attach=default_on_attach; - cmd = {"${pkgs.nodePackages.pyright}/bin/pyright-langserver", "--stdio"} - } - ''} - - ${writeIf cfg.nix.enable ( - (writeIf (cfg.nix.server == "rnix") '' - -- Nix (rnix) config - lspconfig.rnix.setup{ - capabilities = capabilities, - ${writeIf (cfg.nix.formatter == "alejandra") - '' - on_attach = function(client, bufnr) - attach_keymaps(client, bufnr) - end, - ''} - ${writeIf (cfg.nix.formatter == "nixpkgs-fmt") - '' - on_attach = default_on_attach, - ''} - cmd = {"${cfg.nix.pkg}/bin/rnix-lsp"}, - } - '') - + (writeIf (cfg.nix.server == "nil") '' - -- Nix (nil) config - lspconfig.nil_ls.setup{ - capabilities = capabilities, - on_attach=default_on_attach, - cmd = {"${cfg.nix.pkg}/bin/nil"}, - settings = { - ["nil"] = { - ${writeIf (cfg.nix.formatter == "alejandra") - '' - formatting = { - command = {"${pkgs.alejandra}/bin/alejandra", "--quiet"}, - }, - ''} - ${writeIf (cfg.nix.formatter == "nixpkgs-fmt") - '' - formatting = { - command = {"${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt"}, - }, - ''} - }, - }; - } - '') - )} - - - ${writeIf cfg.clang.enable '' - -- CCLS (clang) config - lspconfig.ccls.setup{ - capabilities = capabilities; - on_attach=default_on_attach; - cmd = {"${pkgs.ccls}/bin/ccls"}; - ${ - if cfg.clang.cclsOpts == "" - then "" - else "init_options = ${cfg.clang.cclsOpts}" - } - } - ''} - - ${writeIf cfg.sql '' - -- SQLS config - lspconfig.sqls.setup { - on_attach = function(client) - client.server_capabilities.execute_command = true - on_attach_keymaps(client, bufnr) - require'sqls'.setup{} - end, - cmd = {"${pkgs.sqls}/bin/sqls", "-config", string.format("%s/config.yml", vim.fn.getcwd()) } - } - ''} - - ${writeIf cfg.go '' - -- Go config - lspconfig.gopls.setup { - capabilities = capabilities; - on_attach = default_on_attach; - cmd = {"${pkgs.gopls}/bin/gopls", "serve"}, - } - ''} - - ${writeIf cfg.ts '' - -- TS config - lspconfig.tsserver.setup { - capabilities = capabilities; - on_attach = function(client, bufnr) - attach_keymaps(client, bufnr) - end, - cmd = { "${pkgs.nodePackages.typescript-language-server}/bin/typescript-language-server", "--stdio" } - } - ''} - ''; - } - ); + local capabilities = vim.lsp.protocol.make_client_capabilities() + ${optionalString usingNvimCmp "capabilities = require('cmp_nvim_lsp').default_capabilities()"} + ''; + }; } diff --git a/modules/lsp/default.nix b/modules/lsp/default.nix index db4f027..cd18221 100644 --- a/modules/lsp/default.nix +++ b/modules/lsp/default.nix @@ -4,6 +4,10 @@ ./config.nix ./module.nix + ./lspconfig + ./lspsaga + ./null-ls + # lsp plugins ./lspsaga ./nvim-code-action-menu diff --git a/modules/lsp/flutter-tools-nvim/flutter-tools.nix b/modules/lsp/flutter-tools-nvim/flutter-tools.nix index 2f87c31..9bd460b 100644 --- a/modules/lsp/flutter-tools-nvim/flutter-tools.nix +++ b/modules/lsp/flutter-tools-nvim/flutter-tools.nix @@ -6,6 +6,8 @@ with lib; with builtins; { options.vim.lsp.dart.flutter-tools = { + enable = mkEnableOption "Enable flutter-tools for flutter support"; + color = { enable = mkEnableOption "Whether or mot to highlight color variables at all"; diff --git a/modules/lsp/lspconfig/config.nix b/modules/lsp/lspconfig/config.nix new file mode 100644 index 0000000..70485be --- /dev/null +++ b/modules/lsp/lspconfig/config.nix @@ -0,0 +1,25 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.lsp; +in { + config = mkIf cfg.lspconfig.enable (mkMerge [ + { + vim.lsp.enable = true; + + vim.startPlugins = ["nvim-lspconfig"]; + + vim.luaConfigRC.lspconfig = nvim.dag.entryAfter ["lsp-setup"] '' + local lspconfig = require('lspconfig') + ''; + } + { + vim.luaConfigRC = mapAttrs (_: v: (nvim.dag.entryAfter ["lspconfig"] v)) cfg.lspconfig.sources; + } + ]); +} diff --git a/modules/lsp/lspconfig/default.nix b/modules/lsp/lspconfig/default.nix new file mode 100644 index 0000000..117e4d4 --- /dev/null +++ b/modules/lsp/lspconfig/default.nix @@ -0,0 +1,6 @@ +_: { + imports = [ + ./config.nix + ./lspconfig.nix + ]; +} diff --git a/modules/lsp/lspconfig/lspconfig.nix b/modules/lsp/lspconfig/lspconfig.nix new file mode 100644 index 0000000..7bc3dab --- /dev/null +++ b/modules/lsp/lspconfig/lspconfig.nix @@ -0,0 +1,18 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; { + options.vim.lsp.lspconfig = { + enable = mkEnableOption "nvim-lspconfig, also enabled automatically"; + + sources = mkOption { + description = "nvim-lspconfig sources"; + type = with types; attrsOf str; + default = {}; + }; + }; +} diff --git a/modules/lsp/module.nix b/modules/lsp/module.nix index a6b95d9..88a2811 100644 --- a/modules/lsp/module.nix +++ b/modules/lsp/module.nix @@ -1,73 +1,13 @@ { - pkgs, config, lib, + pkgs, ... }: with lib; -with builtins; let - cfg = config.vim.lsp; -in { +with builtins; { options.vim.lsp = { - enable = mkEnableOption "Enable neovim LSP support. Requires language specific LSPs to be anabled to take effect"; - formatOnSave = mkEnableOption "Format on save"; - nix = { - enable = mkEnableOption "Nix LSP"; - server = mkOption { - type = with types; enum ["rnix" "nil"]; - default = "nil"; - description = "Which LSP to use"; - }; - - pkg = mkOption { - type = types.package; - default = - if (cfg.nix.server == "rnix") - then pkgs.rnix-lsp - else pkgs.nil; - description = "The LSP package to use"; - }; - - formatter = mkOption { - type = with types; enum ["nixpkgs-fmt" "alejandra"]; - default = "alejandra"; - description = "Which nix formatter to use"; - }; - }; - rust = { - enable = mkEnableOption "Rust LSP"; - rustAnalyzerOpts = mkOption { - type = types.str; - default = '' - ["rust-analyzer"] = { - experimental = { - procAttrMacros = true, - }, - }, - ''; - description = "Options to pass to rust analyzer"; - }; - }; - python = mkEnableOption "Python LSP"; - clang = { - enable = mkEnableOption "C language LSP"; - c_header = mkEnableOption "C syntax header files"; - cclsOpts = mkOption { - type = types.str; - default = ""; - }; - }; - - dart = { - enable = mkEnableOption "Dart Language LSP"; - flutter-tools = { - enable = mkEnableOption ""; - }; - }; - - sql = mkEnableOption "SQL Language LSP"; - go = mkEnableOption "Go language LSP"; - ts = mkEnableOption "TS language LSP"; - zig.enable = mkEnableOption "Zig language LSP"; + enable = mkEnableOption "LSP, also enabled automatically through null-ls and lspconfig options"; + formatOnSave = mkEnableOption "format on save"; }; } diff --git a/modules/lsp/null-ls/config.nix b/modules/lsp/null-ls/config.nix new file mode 100644 index 0000000..7f1289a --- /dev/null +++ b/modules/lsp/null-ls/config.nix @@ -0,0 +1,36 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.lsp; +in { + config = mkIf cfg.null-ls.enable (mkMerge [ + { + vim.lsp.enable = true; + vim.startPlugins = ["null-ls"]; + + vim.luaConfigRC.null_ls-setup = nvim.dag.entryAnywhere '' + local null_ls = require("null-ls") + local null_helpers = require("null-ls.helpers") + local null_methods = require("null-ls.methods") + local ls_sources = {} + ''; + vim.luaConfigRC.null_ls = nvim.dag.entryAfter ["null_ls-setup" "lsp-setup"] '' + require('null-ls').setup({ + diagnostics_format = "[#{m}] #{s} (#{c})", + debounce = 250, + default_timeout = 5000, + sources = ls_sources, + on_attach=default_on_attach + }) + ''; + } + { + vim.luaConfigRC = mapAttrs (_: v: (nvim.dag.entryBetween ["null_ls"] ["null_ls-setup"] v)) cfg.null-ls.sources; + } + ]); +} diff --git a/modules/lsp/null-ls/default.nix b/modules/lsp/null-ls/default.nix new file mode 100644 index 0000000..01e6e59 --- /dev/null +++ b/modules/lsp/null-ls/default.nix @@ -0,0 +1,6 @@ +_: { + imports = [ + ./config.nix + ./null-ls.nix + ]; +} diff --git a/modules/lsp/null-ls/null-ls.nix b/modules/lsp/null-ls/null-ls.nix new file mode 100644 index 0000000..b8b661c --- /dev/null +++ b/modules/lsp/null-ls/null-ls.nix @@ -0,0 +1,20 @@ +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.lsp; +in { + options.vim.lsp.null-ls = { + enable = mkEnableOption "null-ls, also enabled automatically"; + + sources = mkOption { + description = "null-ls sources"; + type = with types; attrsOf str; + default = {}; + }; + }; +} diff --git a/modules/modules.nix b/modules/modules.nix index 47e9eb8..86d137f 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -30,6 +30,7 @@ ./session ./comments ./projects + ./languages ]; pkgsModule = {config, ...}: { diff --git a/modules/treesitter/config.nix b/modules/treesitter/config.nix index 08acaa0..c38b2b9 100644 --- a/modules/treesitter/config.nix +++ b/modules/treesitter/config.nix @@ -1,4 +1,5 @@ { + pkgs, config, lib, ... @@ -6,59 +7,49 @@ with lib; with builtins; let cfg = config.vim.treesitter; + usingNvimCmp = config.vim.autocomplete.enable && config.vim.autocomplete.type == "nvim-cmp"; in { - config = mkIf cfg.enable ( - let - writeIf = cond: msg: - if cond - then msg - else ""; - in { - vim.startPlugins = [ - "nvim-treesitter" - ( - if cfg.autotagHtml - then "nvim-ts-autotag" - else null - ) - ]; + config = mkIf cfg.enable { + vim.startPlugins = + ["nvim-treesitter"] + ++ optional cfg.autotagHtml "nvim-ts-autotag" + ++ optional usingNvimCmp "cmp-treesitter"; - # For some reason treesitter highlighting does not work on start if this is set before syntax on - vim.configRC.treesitter = writeIf cfg.fold (nvim.dag.entryBefore ["basic"] '' - " Tree-sitter based folding - set foldmethod=expr - set foldexpr=nvim_treesitter#foldexpr() - set nofoldenable - ''); + vim.autocomplete.sources = ["treesitter"]; - vim.luaConfigRC.treesitter = nvim.dag.entryAnywhere '' - -- Treesitter config - require'nvim-treesitter.configs'.setup { - highlight = { - enable = true, - disable = {}, + # For some reason treesitter highlighting does not work on start if this is set before syntax on + vim.configRC.treesitter-fold = mkIf cfg.fold (nvim.dag.entryBefore ["basic"] '' + set foldmethod=expr + set foldexpr=nvim_treesitter#foldexpr() + set nofoldenable + ''); + + vim.luaConfigRC.treesitter = nvim.dag.entryAnywhere '' + require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + disable = {}, + }, + + auto_install = false, + ensure_installed = {}, + + incremental_selection = { + enable = true, + keymaps = { + init_selection = "gnn", + node_incremental = "grn", + scope_incremental = "grc", + node_decremental = "grm", }, + }, - auto_install = false, - ensure_installed = {}, - - incremental_selection = { - enable = true, - keymaps = { - init_selection = "gnn", - node_incremental = "grn", - scope_incremental = "grc", - node_decremental = "grm", - }, - }, - - ${writeIf cfg.autotagHtml '' - autotag = { - enable = true, - }, - ''} - } - ''; - } - ); + ${optionalString cfg.autotagHtml '' + autotag = { + enable = true, + }, + ''} + } + ''; + }; } diff --git a/modules/treesitter/treesitter.nix b/modules/treesitter/treesitter.nix index ab3cea6..a1928a5 100644 --- a/modules/treesitter/treesitter.nix +++ b/modules/treesitter/treesitter.nix @@ -5,51 +5,23 @@ ... }: with lib; -with builtins; { +with builtins; let + cfg = config.vim.treesitter; + usingNvimCmp = config.vim.autocomplete.enable && config.vim.autocomplete.type == "nvim-cmp"; +in { options.vim.treesitter = { - enable = mkOption { - default = false; - type = types.bool; - description = "Enable tree-sitter [nvim-treesitter]"; - }; + enable = mkEnableOption "treesitter, also enabled automatically through language options"; - fold = mkOption { - default = false; - type = types.bool; - description = "Enable fold with tree-sitter"; - }; + fold = mkEnableOption "fold with treesitter"; - autotagHtml = mkOption { - default = false; - type = types.bool; - description = "Enable autoclose and rename html tag [nvim-ts-autotag]"; - }; + autotagHtml = mkEnableOption "autoclose and rename html tag"; grammars = mkOption { type = with types; listOf package; - default = with (pkgs.vimPlugins.nvim-treesitter.builtGrammars); - [ - c - cpp - nix - python - rust - markdown - comment - toml - make - tsx - html - javascript - css - graphql - json - zig - ] - ++ (optional config.vim.notes.orgmode.enable org); # add orgmode grammar if enabled + default = []; description = '' - List of treesitter grammars to install. - When enabling a language, its treesitter grammar is added for you. + List of treesitter grammars to install. For supported languages + use the `vim.language..treesitter` option ''; }; };