{ pkgs, config, lib, ... }: with lib; with builtins; let cfg = config.vim.lsp; in { config = mkIf cfg.enable ( let writeIf = cond: msg: if cond then msg else ""; in { vim.startPlugins = [ "nvim-lspconfig" "null-ls" ] ++ optionals (cfg.rust.enable) [ "crates-nvim" "rust-tools" ] ++ optionals (cfg.elixir.enable) [ "elixir-ls" ] ++ optionals ((config.vim.autocomplete.enable) && (config.vim.autocomplete.type == "nvim-cmp")) [ "cmp-nvim-lsp" ] ++ optionals (cfg.sql) [ "sqls-nvim" ]; vim.configRC.lsp = nvim.dag.entryAnywhere '' ${ if cfg.nix.enable then '' autocmd filetype nix setlocal tabstop=2 shiftwidth=2 softtabstop=2 '' else "" } ${ 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 '' 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', '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 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 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 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} } } } 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" } } ''} ${writeIf cfg.elixir.enable '' lspconfig.elixirls.setup { cmd = { "${pkgs.elixir-ls}/language_server.sh" }, on_attach = on_attach } ''} ''; } ); }