Hi everyone,
it’s a pleasure to join this discourse.
I would need your precious help.
So, I want to definitely abandon the all-time Neovim’s rival (the unmentionable )
I already quite got used to (Neo-)Vim built-in motions and custom remappings.
I’m now only missing a good (and minimalist) LSP integration.
I had firstly started with packer, but suffered very high startup times (around 5sec). And that was already a discouraging signal.
Then, I decided to move completely to Lazy package manager. There, starting with a minimal configuration, startup started to feel much smoother (though I still feel it hangs sometimes, specially at the very first launch after I shut down the machine).
Now, I cannot get the LSP to work properly.
As soon as I open the first buffer in a new Neovim session, I see the LSP init message appearing, meaning that the client rightly ataches to the buffer.
But then, none of the functionalities seem to work:
- If I introduce an error (whatever it is) the LSP doesn’t signal it (it used to in the past)
- The local buffer keymaps related to LSP do not work (i.e. if pressing ‘gd’ for going to the definition, it does not work, if not in the same file)
Here is my lazy.lua LSP config:
-- LSP config
{"neovim/nvim-lspconfig",
event = {"BufReadPre", "BufNewFile"},
lazy = true,
dependencies = {
{"williamboman/mason.nvim"},
{"williamboman/mason-lspconfig.nvim"},
{"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"saadparwaiz1/cmp_luasnip",
"L3MON4D3/LuaSnip",
}
}
},
opts = {
autoformat = false, -- Automatically format on save
format = {
formatting_options = nil,
timeout_ms = nil
},
-- LSP Server Settings
servers = {
fortls = {},
clangd = {},
},
},
config = function(_, opts)
local luasnip = require("luasnip");
local cmp = require'cmp'
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
window = {
completion = cmp.config.window.bordered(),
documentation = cmp.config.window.bordered(),
},
mapping = cmp.mapping.preset.insert({
['<C-n>'] = cmp.mapping.select_next_item(),
['<C-b>'] = cmp.mapping.select_prev_item(),
['<C-u>'] = cmp.mapping.scroll_docs(-2),
['<C-d>'] = cmp.mapping.scroll_docs(2),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.abort(),
['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { 'i', 's' }),
['<S-Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.locally_jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { 'i', 's' }),
}),
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'luasnip' },
{ name = "buffer" },
{ name = "path" },
})
})
local servers = opts.servers
local keymap_set = vim.keymap.set;
local on_attach = function(_, bufnr)
-- [[ Configure LSP ]]
-- This function gets run when an LSP connects to a particular buffer.
local nnoremap = function(keys, func, desc)
if desc then
desc = 'LSP: ' .. desc
end
keymap_set('n', keys, func, { buffer = bufnr, noremap = true, desc = desc });
end
nnoreamp('<leader>dm', vim.diagnostic.open_float, 'Open floating [d]iagnostic [m]essage' )
nnoreamp("gp", vim.diagnostic.goto_prev, '[G]o to [p]revious diagnostic message' )
nnoreamp("gn", vim.diagnostic.goto_next, '[G]o to [n]ext diagnostic message' )
nnoreamp('<leader>dl', vim.diagnostic.setloclist, 'Open [d]iagnostics [l]ist' )
nnoremap('gd', vim.lsp.buf.definition, '[G]oto [d]efinition')
nnoremap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
nnoremap('gi', vim.lsp.buf.implementation, '[G]oto [I]mplementation')
nnoremap('gr', vim.lsp.buf.references, '[G]oto [R]eferences')
nnoremap('K', vim.lsp.buf.hover, 'Hover documentation')
nnoremap('<C-k>', vim.lsp.buf.signature_help, 'Signature Documentation')
nnoremap('<space>wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder')
nnoremap('<space>wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder')
nnoremap('<space>wl', function()
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
end, 'List [W]orkspace [F]olders')
nnoremap('<leader>rn', vim.lsp.buf.rename, '[R]e[n]ame')
nnoremap('<leader>D', vim.lsp.buf.type_definition, 'Type [D]efinition')
nnoremap('<leader>f', function()
vim.lsp.buf.format { async = true }
end, 'Format current buffer')
vim.keymap.set({ 'n', 'v' }, '<leader>ca', vim.lsp.buf.code_action,
{buffer = bufnr, noremap = true, desc = 'LSP: [C]ode [A]ction'})
end
local lspconfig = require("lspconfig");
local capabilities = require("cmp_nvim_lsp").default_capabilities(vim.lsp.protocol.make_client_capabilities())
local function setup(server_name)
local server_opts = {
capabilities = capabilities,
on_attach = on_attach,
-- filetypes = (servers[server] or {}).filetypes,
}
lspconfig[server_name].setup(server_opts)
end
local mlsp = require("mason-lspconfig")
local available = mlsp.get_available_servers()
local ensure_installed = {}
for server, server_opts in pairs(servers) do
if server_opts then
server_opts = server_opts == true and {} or server_opts
-- run manual setup if mason=false or if this is a server that cannot be installed with mason-lspconfig
if server_opts.mason == false or not vim.tbl_contains(available, server) then
setup(server)
else
ensure_installed[#ensure_installed + 1] = server
end
end
end
require("mason").setup()
require("mason-lspconfig").setup({
ensure_installed = ensure_installed,
automatic_installation = true
})
require("mason-lspconfig").setup_handlers({setup})
end
},
Any suggestion is more than welcome.
Cheers