diff --git a/nvim/.config/nvim/after/ftplugin/c.lua b/nvim/.config/nvim/after/ftplugin/c.lua new file mode 100644 index 0000000..87717f2 --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/c.lua @@ -0,0 +1,22 @@ +local default_capabilities = { + textDocument = { + completion = { + editsNearCursor = true, + }, + }, + offsetEncoding = { 'utf-8', 'utf-16' }, +} + +local root_files = { '.clangd', '.clang-tidy', '.clang-format', 'compile_commands.json', 'compile_flags.txt' } +local clangd_cmd = { "clangd", "--background-index", "--pch-storage=memory", "--clang-tidy", "--header-insertion=never" } +local path = vim.fs.find(root_files, { type = "file" }) +local root = vim.fs.dirname(path[1]) + +vim.lsp.start({ + name = "clangd", + cmd = clangd_cmd, + root_dir = root, + filetypes = { 'c', 'cpp' }, + single_file_support = true, + capabilities = default_capabilities, +}) diff --git a/nvim/.config/nvim/after/ftplugin/haskell.lua b/nvim/.config/nvim/after/ftplugin/haskell.lua new file mode 100644 index 0000000..23fcbab --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/haskell.lua @@ -0,0 +1,12 @@ +local root_files = { 'hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml' } +local path = vim.fs.find(root_files, { type = "file" }) +local root = vim.fs.dirname(path[1]) + +vim.lsp.start({ + name = "hls", + cmd = { 'haskell-language-server-wrapper', '--lsp' }, + root_dir = root, + filetypes = { 'haskell' }, + single_file_support = true, + settings = { haskell = { formattingProvider = 'ormolu' } }, +}) diff --git a/nvim/.config/nvim/after/ftplugin/javascript.lua b/nvim/.config/nvim/after/ftplugin/javascript.lua new file mode 100644 index 0000000..ccd00eb --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/javascript.lua @@ -0,0 +1,34 @@ +local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' } +local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' } +local path = vim.fs.find(root_files, { type = "file" }) + +vim.lsp.start({ + name = "tsserver", + cmd = { "typescript-language-server", "--stdio" }, + root_dir = vim.fs.dirname(path[1]), + filetypes = file_types, + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = 'all', + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + } + }, + javascript = { + inlayHints = { + includeInlayParameterNameHints = 'all', + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + } + } + } +}) diff --git a/nvim/.config/nvim/after/ftplugin/python.lua b/nvim/.config/nvim/after/ftplugin/python.lua new file mode 100644 index 0000000..a2a5996 --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/python.lua @@ -0,0 +1,23 @@ +local root_files = { 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', 'Pipfile' } +local path = vim.fs.find(root_files, { type = "file" }) +local root = vim.fs.dirname(path[1]) + +vim.lsp.start({ + name = "jedi-language-server", + cmd = { "jedi-language-server" }, + filetypes = { 'python' }, + root_dir = root, + init_options = { + completion = { + resolveEagerly = true, + }, + jediSettings = { + caseInsensitiveCompletion = false, + }, + workspace = { + symbols = { + maxSymbols = 50 + }, + }, + }, +}) diff --git a/nvim/.config/nvim/after/ftplugin/rust.lua b/nvim/.config/nvim/after/ftplugin/rust.lua new file mode 100644 index 0000000..256d2ab --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/rust.lua @@ -0,0 +1,18 @@ +local path = vim.fs.find({ "Cargo.toml" }, { type = "file" }) +local root = vim.fs.dirname(path[1]) + +vim.lsp.start({ + name = "rust-analyzer", + cmd = { "rust-analyzer" }, + root_dir = root, + settings = { + ["rust-analyzer"] = { + procMacro = { + enable = true + }, + checkOnSave = { + command = "clippy" + }, + }, + }, +}) diff --git a/nvim/.config/nvim/after/ftplugin/typescript.lua b/nvim/.config/nvim/after/ftplugin/typescript.lua new file mode 100644 index 0000000..ccd00eb --- /dev/null +++ b/nvim/.config/nvim/after/ftplugin/typescript.lua @@ -0,0 +1,34 @@ +local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' } +local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' } +local path = vim.fs.find(root_files, { type = "file" }) + +vim.lsp.start({ + name = "tsserver", + cmd = { "typescript-language-server", "--stdio" }, + root_dir = vim.fs.dirname(path[1]), + filetypes = file_types, + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = 'all', + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + } + }, + javascript = { + inlayHints = { + includeInlayParameterNameHints = 'all', + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + } + } + } +}) diff --git a/nvim/.config/nvim/lua/lsp.lua b/nvim/.config/nvim/lua/lsp.lua index ec51679..dcfe170 100644 --- a/nvim/.config/nvim/lua/lsp.lua +++ b/nvim/.config/nvim/lua/lsp.lua @@ -1,6 +1,4 @@ -local nvim_lsp = require 'lspconfig' local protocol = require 'vim.lsp.protocol' -local util = require 'lspconfig/util' local lightbulb = require 'nvim-lightbulb' local inlay_hint = require 'lsp-inlayhints' @@ -65,6 +63,8 @@ protocol.CompletionItemKind = { ' TypeParameter'; } +local lsp_augroup_id = vim.api.nvim_create_augroup("LSP", { clear = true }) + local lsp_key_mappings = { { "definitionProvider" , 'n', 'pd' , 'lua PeekDefinition()' }, { "definitionProvider" , 'n', 'gd' , 'lua vim.lsp.buf.definition()' }, @@ -95,6 +95,49 @@ local tsserver_setup = function(client) end end +local get_active_client_by_name = function(bufnr, servername) + for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do + if client.name == servername then + return client + end + end +end + +local switch_source_header = function() + local clangd_client = get_active_client_by_name(0, 'clangd') + local params = { uri = vim.uri_from_bufnr(0) } + + if clangd_client then + clangd_client.request('textDocument/switchSourceHeader', params, function(err, result) + if err then + print 'Error dane' + error(tostring(err)) + end + + if not result then + print 'Corresponding file cannot be determined' + return + end + + vim.api.nvim_command('edit ' .. vim.uri_to_fname(result)) + end, 0) + else + print 'Method switchSourceHeader is not supported by server active on the current buffer' + end +end + +local clangd_setup = function(client) + if client.name == 'clangd' then + vim.api.nvim_create_user_command("ClangdSwitchSourceHeader", switch_source_header, {desc = 'Switch between source/header'}) + end +end + +local clangd_cleanup = function(client) + if client.name == 'clangd' then + vim.api.nvim_del_user_command("ClangdSwitchSourceHeader") + end +end + local on_attach = function(client, bufnr) vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') vim.lsp.set_log_level('warn') @@ -110,6 +153,8 @@ local on_attach = function(client, bufnr) -- actually checking it below. tsserver_setup(client) + clangd_setup(client) + for _, mappings in pairs(lsp_key_mappings) do local capability, mode, lhs, rhs = unpack(mappings) if client.server_capabilities[capability] then @@ -118,8 +163,6 @@ local on_attach = function(client, bufnr) end if client.server_capabilities.codeLensProvider or client.server_capabilities.documentHighlightProvider then - local lsp_augroup_id = vim.api.nvim_create_augroup("LSP", {clear = true}) - if client.server_capabilities.codeLensProvider then vim.api.nvim_buf_set_keymap(bufnr, "n", "l", "lua vim.lsp.codelens.run()", opts) vim.api.nvim_create_autocmd({"CursorHold", "CursorHoldI", "InsertLeave"}, { @@ -159,97 +202,37 @@ local on_attach = function(client, bufnr) inlay_hint.on_attach(client, bufnr) end -local on_init = function(client) - if client.config.settings then - client.notify('workspace/didChangeConfiguration', { settings = client.config.settings }) - end -end +vim.api.nvim_create_autocmd("LspAttach", { + group = lsp_augroup_id, + callback = function(args) + local bufnr = args.buf + local client = vim.lsp.get_client_by_id(args.data.client_id) + local opts = { noremap=true, silent=true } -local capabilities = vim.lsp.protocol.make_client_capabilities() -capabilities.workspace.configuration = true -capabilities.textDocument.completion.completionItem.snippetSupport = true -capabilities.textDocument.completion.completionItem.resolveSupport = { - properties = { 'documentation', 'detail', 'additionalTextEdits', } -} + for _, mappings in pairs(lsp_key_mappings) do + local capability, mode, lhs, rhs = unpack(mappings) + if client.server_capabilities[capability] then + vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts) + end + end -local servers = { - clangd = { - default_config = { - cmd = { "clangd", "--background-index", "--pch-storage=memory", "--clang-tidy", "--header-insertion=never" }, - filetypes = { 'c', 'cpp' }, - root_dir = function(fname) - -- We specify build/compile_commands.json as that is where the compile_commands.json - -- gets generated automatically for meson projects. - local root_pattern = util.root_pattern('build/compile_commands.json', 'compile_commands.json', 'compile_flags.txt', '.git') - local filename = util.path.is_absolute(fname) and fname or util.path.join(vim.loop.cwd(), fname) - return root_pattern(filename) or util.path.dirname(filename) - end, - } - }, - eslint = {}, - hls = {}, - jedi_language_server = { - init_options = { - completion = { - resolveEagerly = true, - }, - jediSettings = { - caseInsensitiveCompletion = false, - }, - workspace = { - symbols = { - maxSymbols = 50 - }, - }, - }, - }, - rust_analyzer = { - settings = { - ["rust-analyzer"] = { - procMacro = { - enable = true - }, - checkOnSave = { - command = "clippy" - }, - } - } - }, - tsserver = { - settings = { - typescript = { - inlayHints = { - includeInlayParameterNameHints = 'all', - includeInlayParameterNameHintsWhenArgumentMatchesName = false, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - } - }, - javascript = { - inlayHints = { - includeInlayParameterNameHints = 'all', - includeInlayParameterNameHintsWhenArgumentMatchesName = false, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - } - } - } - }, -} + on_attach(client, bufnr) + end, +}) -for client, config in pairs(servers) do - config.on_init = on_init - config.on_attach = on_attach - config.capabilities = vim.tbl_deep_extend( - 'keep', - config.capabilities or {}, - capabilities - ) - nvim_lsp[client].setup(config) -end +vim.api.nvim_create_autocmd("LspDetach", { + group = lsp_augroup_id, + callback = function(args) + local bufnr = args.buf + local client = vim.lsp.get_client_by_id(args.data.client_id) + + for _, mappings in pairs(lsp_key_mappings) do + local capability, mode, lhs, _ = unpack(mappings) + if client.server_capabilities[capability] then + vim.api.nvim_buf_del_keymap(bufnr, mode, lhs) + end + end + + clangd_cleanup(client) + end, +}) diff --git a/nvim/.config/nvim/lua/plugins.lua b/nvim/.config/nvim/lua/plugins.lua index 2aec0e8..ceb38b2 100644 --- a/nvim/.config/nvim/lua/plugins.lua +++ b/nvim/.config/nvim/lua/plugins.lua @@ -63,10 +63,7 @@ local init = function () use 'junegunn/vim-easy-align' use 'nvim-lua/plenary.nvim' -- LSP - use { - 'neovim/nvim-lspconfig', - 'kosayoda/nvim-lightbulb', - } + use 'kosayoda/nvim-lightbulb' -- Language support & syntax highlighting use 'mfussenegger/nvim-lint' use 'lvimuser/lsp-inlayhints.nvim'