dotfiles/nvim/.config/nvim/lua/lsp.lua
Sanchayan Maity 47b157805d nvim: lsp: Fix enabling of range format support
If range formatting is supported we should check that first to enable
it else since most LSP servers support formatting, without range
formatting check being first, it would never be enabled.
2021-09-25 18:21:51 +05:30

266 lines
9.6 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")
-- 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
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')
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)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev { wrap = false }<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next { wrap = false }<CR>', opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', '[D', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', ']D', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'do', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>' , opts)
vim.api.nvim_buf_set_keymap(bufnr, 'n', ',d', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>' , opts)
if client.resolved_capabilities.document_range_formatting then
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gq', '<cmd>lua format_range_operator()<CR>', opts)
elseif 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
}
if client.name == 'tsserver' then
-- Disable tsserver formatting as we plan on formatting via null-ls
client.resolved_capabilities.document_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>', { silent = true })
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gf', ':TSLspFixCurrent<CR>', { silent = true })
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gI', ':TSLspImportAll<CR>', { silent = true })
end
vim.cmd [[autocmd CursorHold,CursorHoldI <buffer> lua require'nvim-lightbulb'.update_lightbulb()]]
end
function set_snippet_capabilities()
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.resolveSupport = {
properties = {
'documentation',
'detail',
'additionalTextEdits',
}
}
return capabilities
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 servers = { 'hls', 'rust_analyzer', 'pylsp', 'tsserver' }
for _, lsp in ipairs(servers) do
nvim_lsp[lsp].setup {
on_attach = on_attach,
capabilities = set_snippet_capabilities(),
}
end
nvim_lsp.clangd.setup {
on_attach = on_attach,
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,
}
}
-- 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 library = {}
local function add_to_library(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
local function add_libraries()
local cwd = vim.fn.getcwd()
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
end
local function determine_lua_version()
local cwd = vim.fn.getcwd()
if string.find(cwd, "neovim") or string.find(cwd, "dotfiles") then
return "LuaJIT"
else
return "Lua 5.4"
end
end
add_libraries()
local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, "lua/?.lua")
table.insert(runtime_path, "lua/?/init.lua")
nvim_lsp.sumneko_lua.setup {
cmd = { "/usr/bin/lua-language-server" };
on_attach = on_attach,
settings = {
Lua = {
runtime = {
version = determine_lua_version(),
path = runtime_path,
},
completion = { callSnippet = "Both" },
diagnostics = {
globals = {'vim'},
},
workspace = {
library = library,
maxPreload = 2000,
preloadFileSize = 50000
},
telemetry = {
enable = false,
},
},
},
}