dotfiles/nvim/.config/nvim/lua/lsp.lua
Sanchayan Maity 068dfcd4b9 nvim: lsp/keymappings: Move the diagnostic key mappings outside of LSP
vim.diagnostic framework is now available and can be used outside of
LSP. This means the same functions can now work for plugins providing
diagnostics via this framework like nvim-lint and null-ls.
2021-10-02 18:29:57 +05:30

309 lines
10 KiB
Lua

local nvim_lsp = require 'lspconfig'
local protocol = require 'vim.lsp.protocol'
local signature = require 'lsp_signature'
local ts_utils = require 'nvim-lsp-ts-utils'
local null_ls = require 'null-ls'
local util = require 'lspconfig/util'
local cmp = require 'cmp_nvim_lsp'
-- https://github.com/neovim/nvim-lspconfig/wiki/User-contributed-tips
function format_range_operator()
local old_func = vim.go.operatorfunc
_G.op_func_formatting = function()
local start = vim.api.nvim_buf_get_mark(0, '[')
local finish = vim.api.nvim_buf_get_mark(0, ']')
vim.lsp.buf.range_formatting({}, start, finish)
vim.go.operatorfunc = old_func
_G.op_func_formatting = nil
end
vim.go.operatorfunc = 'v:lua.op_func_formatting'
vim.api.nvim_feedkeys('g@', 'n', false)
end
local function preview_location_callback(_, result)
if result == nil or vim.tbl_isempty(result) then
return nil
end
vim.lsp.util.preview_location(result[1])
end
function PeekDefinition()
local params = vim.lsp.util.make_position_params()
return vim.lsp.buf_request(0, 'textDocument/definition', params, preview_location_callback)
end
-- This should be called only once, so cannot be in on_attach as earlier.
-- See https://github.com/jose-elias-alvarez/null-ls.nvim/issues/38
-- Required by nvim-lsp-ts-utils to provide ESLint code actions, diagnostics
-- and formatting.
null_ls.config {}
nvim_lsp["null-ls"].setup {}
local ts_utils_setup = function(client, bufnr, opts)
if client.name == 'tsserver' then
-- Disable tsserver formatting as we plan on formatting via null-ls
client.resolved_capabilities.document_formatting = false
client.resolved_capabilities.document_range_formatting = false
ts_utils.setup {
debug = false,
disable_commands = false,
enable_import_on_completion = false,
import_all_timeout = 5000,
import_all_scan_buffers = 100,
import_all_select_source = false,
import_all_priorities = {
buffers = 4, -- loaded buffer names
buffer_content = 3, -- loaded buffer content
local_files = 2, -- git files or files with relative path markers
same_file = 1, -- add to existing import statement
},
eslint_enable_code_actions = true,
eslint_bin = "eslint",
eslint_enable_disable_comments = true,
eslint_enable_diagnostics = true,
eslint_config_fallback = nil,
eslint_show_rule_id = false,
enable_formatting = true,
formatter = "prettier",
formatter_config_fallback = nil,
update_imports_on_move = false,
require_confirmation_on_move = false,
watch_dir = nil,
filter_out_diagnostics_by_severity = {},
filter_out_diagnostics_by_code = {},
}
ts_utils.setup_client(client)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'go', ':TSLspOrganize<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gf', ':TSLspFixCurrent<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gI', ':TSLspImportAll<CR>' , opts)
end
end
local on_attach = function(client, bufnr)
signature.on_attach({
bind = true,
hint_enable = true,
hint_prefix = "🐼 ",
hint_scheme = "String",
handler_opts = { border = "single" },
decorator = {"`", "`"}
})
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
vim.lsp.set_log_level('warn')
if client.config.flags then
client.config.flags.allow_incremental_sync = true
client.config.flags.debounce_text_changes = 500
end
local opts = { noremap=true, silent=true }
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gd' , '<cmd>lua vim.lsp.buf.definition()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gD' , '<cmd>lua vim.lsp.buf.declaration()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<Leader>k', '<cmd>lua vim.lsp.buf.hover()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gr' , '<cmd>lua vim.lsp.buf.references()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ga' , '<cmd>lua vim.lsp.buf.code_action()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gi' , '<cmd>lua vim.lsp.buf.implementation()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<C-k>' , '<cmd>lua vim.lsp.buf.type_definition()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '1gd' , '<cmd>lua vim.lsp.buf.document_symbol()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '1gD' , '<cmd>lua vim.lsp.buf.workspace_symbol()<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gR' , '<cmd>lua vim.lsp.buf.rename()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'pd' , '<cmd>lua PeekDefinition()<CR>' , opts)
if client.resolved_capabilities.document_range_formatting then
vim.api.nvim_buf_set_keymap(bufnr, 'x', 'gq', '<cmd>lua format_range_operator()<CR>', opts)
end
if client.resolved_capabilities.document_formatting then
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gq', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end
if client.resolved_capabilities.code_lens then
vim.api.nvim_buf_set_keymap(bufnr, "n", "gl", "<cmd>lua vim.lsp.codelens.run()<CR>", opts)
vim.api.nvim_command [[autocmd CursorHold,CursorHoldI,InsertLeave <buffer> lua vim.lsp.codelens.refresh()]]
end
protocol.CompletionItemKind = {
''; -- text
''; -- method
''; -- function
''; -- ctor
''; -- field
''; -- variable
''; -- class
''; -- interface
''; -- module
''; -- property
''; -- unit
''; -- value
''; -- enum
''; -- keyword
''; -- snippet
''; -- color
''; -- file
''; -- reference
''; -- folder
''; -- enum member
''; -- constant
''; -- struct
''; -- event
''; -- operator
''; -- type parameter
}
ts_utils_setup(client, bufnr, opts)
vim.cmd [[autocmd CursorHold,CursorHoldI <buffer> lua require'nvim-lightbulb'.update_lightbulb()]]
end
-- See https://github.com/sumneko/lua-language-server/wiki/Setting-without-VSCode#neovim-with-built-in-lsp-client
-- on why we do this library thing
-- Idea taken from https://gist.github.com/folke/fe5d28423ea5380929c3f7ce674c41d8
local determine_setup_lua = function ()
local library = {}
local cwd = vim.fn.getcwd()
local add_to_library = function(lib_path)
for _, p in pairs(vim.fn.expand(lib_path, false, true)) do
p = vim.loop.fs_realpath(p)
library[p] = true
end
end
if string.find(cwd, "neovim") then
add_to_library("$VIMRUNTIME")
elseif string.find(cwd, "dotfiles") then
add_to_library("$VIMRUNTIME")
add_to_library("~/.config/nvim")
add_to_library("~/.local/share/nvim/site/pack/packer/opt/*")
add_to_library("~/.local/share/nvim/site/pack/packer/start/*")
else
add_to_library(cwd .. "/*")
end
local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, "lua/?.lua")
table.insert(runtime_path, "lua/?/init.lua")
local lua_version = function()
if string.find(cwd, "neovim") or string.find(cwd, "dotfiles") then
return "LuaJIT"
else
return "Lua 5.4"
end
end
return library, runtime_path, lua_version()
end
local get_snippet_capabilities = function()
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.resolveSupport = {
properties = {
'documentation',
'detail',
'additionalTextEdits',
}
}
return cmp.update_capabilities(capabilities)
end
local rust_tool_opts = {
tools = {
autoSetHints = true,
hover_with_actions = false,
runnables = { use_telescope = false },
debuggables = { use_telescope = false },
inlay_hints = {
only_current_line = false,
only_current_line_autocmd = "CursorHold",
show_parameter_hints = true,
parameter_hints_prefix = "<- ",
other_hints_prefix = "=> ",
other_hints_prefix = "",
highlight = "Hint",
},
hover_actions = {
auto_focus = true
},
crate_graph = {
backend = "svg",
output = "crates_graph.svg",
full = false,
}
},
server = {
on_attach = on_attach,
capabilities = get_snippet_capabilities(),
settings = {
["rust-analyzer"] = {
checkOnSave = {
command = "clippy"
},
}
}
},
}
local servers = { 'hls', 'pylsp', 'tsserver' }
for _, lsp in ipairs(servers) do
nvim_lsp[lsp].setup {
on_attach = on_attach,
capabilities = get_snippet_capabilities(),
}
end
nvim_lsp.clangd.setup {
on_attach = on_attach,
capabilities = get_snippet_capabilities(),
default_config = {
cmd = { "clangd", "--background-index", "--pch-storage=memory", "--clang-tidy", "--suggest-missing-includes" },
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,
}
}
require('rust-tools').setup(rust_tool_opts)
library, runtime_path, lua_version = determine_setup_lua()
nvim_lsp.sumneko_lua.setup {
cmd = { "/usr/bin/lua-language-server" };
on_attach = on_attach,
capabilities = get_snippet_capabilities(),
settings = {
Lua = {
runtime = {
version = lua_version,
path = runtime_path,
},
completion = { callSnippet = "Both" },
diagnostics = {
globals = {'vim'},
},
workspace = {
library = library,
maxPreload = 2000,
preloadFileSize = 50000
},
telemetry = {
enable = false,
},
},
},
}