nvim: Move LSP configuration to it's own LSP utils

This allows us to have all the language server configuration in one
place and only import relevant LSP server configuration to pass to
vim.lsp.start in after/ftplugin.

While at it, we also enable deno support.
This commit is contained in:
Sanchayan Maity 2023-02-27 19:48:55 +05:30
parent 6f8cf0bce5
commit 110a1643cb
Signed by: sanchayanmaity
GPG Key ID: 6F6A0609C12038F3
11 changed files with 325 additions and 177 deletions

View File

@ -1,22 +1,4 @@
local default_capabilities = { local lsp_utils = require('lsp-utils')
textDocument = { local clangd_config = lsp_utils.clangd_config()
completion = {
editsNearCursor = true,
},
},
offsetEncoding = { 'utf-8', 'utf-16' },
}
local root_files = { '.clangd', '.clang-tidy', '.clang-format', 'compile_commands.json', 'compile_flags.txt' } vim.lsp.start(clangd_config)
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,
})

View File

@ -1,9 +1,4 @@
local path = vim.fs.find({ 'go.mod', 'go.work', '.git' }, { type = "file" }) local lsp_utils = require('lsp-utils')
local root = vim.fs.dirname(path[1]) local gopls_config = lsp_utils.gopls_config()
vim.lsp.start({ vim.lsp.start(gopls_config)
name = "gopls",
cmd = { "gopls" },
root_dir = root,
filetypes = { 'go', 'gomod', 'gowork', 'gotmpl' },
})

View File

@ -1,12 +1,4 @@
local root_files = { 'hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml' } local lsp_utils = require('lsp-utils')
local path = vim.fs.find(root_files, { type = "file" }) local hls_config = lsp_utils.hls_config()
local root = vim.fs.dirname(path[1])
vim.lsp.start({ vim.lsp.start(hls_config)
name = "hls",
cmd = { 'haskell-language-server-wrapper', '--lsp' },
root_dir = root,
filetypes = { 'haskell' },
single_file_support = true,
settings = { haskell = { formattingProvider = 'ormolu' } },
})

View File

@ -1,37 +1,7 @@
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' } local lsp_utils = require('lsp-utils')
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' } local tsserver_config = lsp_utils.tsserver_config()
local path = vim.fs.find(root_files, { type = "file" })
vim.lsp.start({ vim.lsp.start(tsserver_config)
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,
}
}
}
})
vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 }) vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 })

View File

@ -1,26 +1,7 @@
local root_files = { 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', 'Pipfile' } local lsp_utils = require('lsp-utils')
local path = vim.fs.find(root_files, { type = "file" }) local jedi_config = lsp_utils.jedi_config()
local root = vim.fs.dirname(path[1])
vim.lsp.start({ vim.lsp.start(jedi_config)
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
},
},
},
})
vim.bo.textwidth = 0 vim.bo.textwidth = 0
vim.bo.formatprg = "black -q -" vim.bo.formatprg = "black -q -"

View File

@ -1,10 +1,4 @@
local path = vim.fs.find({ '.git' }, { type = "file" }) local lsp_utils = require('lsp-utils')
local root = vim.fs.dirname(path[1]) local scheme_config = lsp_utils.scheme_config()
vim.lsp.start({ vim.lsp.start(scheme_config)
name = "racket-langserver",
cmd = { 'racket', '--lib', 'racket-langserver' },
filetypes = { 'scheme', 'racket' },
root_dir = root,
single_file_support = true,
})

View File

@ -1,21 +1,7 @@
local path = vim.fs.find({ "Cargo.toml" }, { type = "file" }) local lsp_utils = require('lsp-utils')
local root = vim.fs.dirname(path[1]) local ra_config = lsp_utils.ra_config()
vim.lsp.start({ vim.lsp.start(ra_config)
name = "rust-analyzer",
cmd = { "rust-analyzer" },
root_dir = root,
settings = {
["rust-analyzer"] = {
procMacro = {
enable = true
},
checkOnSave = {
command = "clippy"
},
},
},
})
vim.cmd.compiler('cargo') vim.cmd.compiler('cargo')
vim.bo.makeprg = 'cargo build --all' vim.bo.makeprg = 'cargo build --all'

View File

@ -1,10 +1,4 @@
local path = vim.fs.find({ '.git' }, { type = "file" }) local lsp_utils = require('lsp-utils')
local root = vim.fs.dirname(path[1]) local scheme_config = lsp_utils.scheme_config()
vim.lsp.start({ vim.lsp.start(scheme_config)
name = "racket-langserver",
cmd = { 'racket', '--lib', 'racket-langserver' },
filetypes = { 'scheme', 'racket' },
root_dir = root,
single_file_support = true,
})

View File

@ -1,14 +1,4 @@
vim.lsp.start({ local lsp_utils = require('lsp-utils')
name = "bashls", local bashls_config = lsp_utils.bashls_config()
cmd = { 'bash-language-server', 'start' },
root_dir = vim.fn.getcwd(), vim.lsp.start(bashls_config)
filetypes = { 'sh' },
single_file_support = true,
cmd_env = {
-- Prevent recursive scanning which will cause issues when opening a file
-- directly in the home directory (e.g. ~/foo.sh).
--
-- Default upstream pattern is "**/*@(.sh|.inc|.bash|.command)".
GLOB_PATTERN = vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)',
},
})

View File

@ -1,37 +1,7 @@
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' } local lsp_utils = require('lsp-utils')
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' } local typescript_config = lsp_utils.typescript_config()
local path = vim.fs.find(root_files, { type = "file" })
vim.lsp.start({ vim.lsp.start(typescript_config)
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,
}
}
}
})
vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 }) vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 })

View File

@ -0,0 +1,294 @@
local M = {}
-- All configuration is taken from nvim-lspconfig except for may be minor changes
--
-- Deno specific functions
local buf_cache = function(bufnr, client)
local params = {}
params['referrer'] = { uri = vim.uri_from_bufnr(bufnr) }
params['uris'] = {}
client.request_sync('deno/cache', params)
end
local virtual_text_document_handler = function(uri, res, client)
if not res then
return nil
end
local lines = vim.split(res.result, '\n')
local bufnr = vim.uri_to_bufnr(uri)
local current_buf = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
if #current_buf ~= 0 then
return nil
end
vim.api.nvim_buf_set_lines(bufnr, 0, -1, nil, lines)
vim.api.nvim_buf_set_option(bufnr, 'readonly' , true)
vim.api.nvim_buf_set_option(bufnr, 'modified' , false)
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
vim.lsp.buf_attach_client(bufnr, client.id)
end
local virtual_text_document = function(uri, client)
local params = {
textDocument = {
uri = uri,
},
}
local result = client.request_sync('deno/virtualTextDocument', params)
virtual_text_document_handler(uri, result, client)
end
local denols_handler = function(err, result, ctx)
if not result or vim.tbl_isempty(result) then
return nil
end
local client = vim.lsp.get_client_by_id(ctx.client_id)
for _, res in pairs(result) do
local uri = res.uri or res.targetUri
if uri:match '^deno:' then
virtual_text_document(uri, client)
res['uri'] = uri
res['targetUri'] = uri
end
end
vim.lsp.handlers[ctx.method](err, result, ctx)
end
-- End of deno specific functions
local get_root_directory = function(root_files)
local path = vim.fs.find(root_files, { type = "file" })
return vim.fs.dirname(path[1])
end
function M.bashls_config()
local root_directory = vim.fn.getcwd()
return {
name = "bashls",
cmd = { 'bash-language-server', 'start' },
root_dir = root_directory,
filetypes = { 'sh' },
single_file_support = true,
cmd_env = {
-- Prevent recursive scanning which will cause issues when opening a file
-- directly in the home directory (e.g. ~/foo.sh).
--
-- Default upstream pattern is "**/*@(.sh|.inc|.bash|.command)".
GLOB_PATTERN = vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)',
},
}
end
function M.clangd_config()
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 root_directory = get_root_directory(root_files)
return {
name = "clangd",
cmd = clangd_cmd,
root_dir = root_directory,
filetypes = { 'c', 'cpp' },
single_file_support = true,
capabilities = default_capabilities,
}
end
function M.deno_config()
local root_files = { 'deno.json', 'deno.jsonc' }
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' }
local root_directory = get_root_directory(root_files)
return {
cmd = { 'deno', 'lsp' },
filetypes = file_types,
root_dir = root_directory,
init_options = {
enable = true,
unstable = false,
},
handlers = {
['textDocument/definition'] = denols_handler,
['textDocument/typeDefinition'] = denols_handler,
['textDocument/references'] = denols_handler,
['workspace/executeCommand'] = function(err, result, context)
if context.params.command == 'deno.cache' then
buf_cache(context.bufnr, vim.lsp.get_client_by_id(context.client_id))
else
vim.lsp.handlers[context.method](err, result, context)
end
end,
},
commands = {
DenolsCache = {
function()
local clients = vim.lsp.get_active_clients()
for _, client in ipairs(clients) do
if client.name == 'denols' then
buf_cache(0, client)
break
end
end
end,
description = 'Cache a module and all of its dependencies.',
},
}
}
end
function M.gopls_config()
local root_files = { 'go.mod', 'go.work', '.git' }
local root_directory = get_root_directory(root_files)
return {
name = "gopls",
cmd = { "gopls" },
root_dir = root_directory,
filetypes = { 'go', 'gomod', 'gowork', 'gotmpl' },
}
end
function M.hls_config()
local root_files = { 'hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml' }
local root_directory = get_root_directory(root_files)
return {
name = "hls",
cmd = { 'haskell-language-server-wrapper', '--lsp' },
root_dir = root_directory,
filetypes = { 'haskell' },
single_file_support = true,
settings = { haskell = { formattingProvider = 'ormolu' } },
}
end
function M.jedi_config()
local root_files = { 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', 'Pipfile' }
local root_directory = get_root_directory(root_files)
return {
name = "jedi-language-server",
cmd = { "jedi-language-server" },
filetypes = { 'python' },
root_dir = root_directory,
init_options = {
completion = {
resolveEagerly = true,
},
jediSettings = {
caseInsensitiveCompletion = false,
},
workspace = {
symbols = {
maxSymbols = 50
},
},
},
}
end
function M.ra_config()
local root_files = { "Cargo.toml" }
local root_directory = get_root_directory(root_files)
return {
name = "rust-analyzer",
cmd = { "rust-analyzer" },
root_dir = root_directory,
settings = {
["rust-analyzer"] = {
procMacro = {
enable = true
},
checkOnSave = {
command = "clippy"
},
},
},
}
end
function M.scheme_config()
local root_files = { '.git' }
local root_directory = get_root_directory(root_files)
return {
name = "racket-langserver",
cmd = { 'racket', '--lib', 'racket-langserver' },
filetypes = { 'scheme', 'racket' },
root_dir = root_directory,
single_file_support = true,
}
end
function M.tsserver_config()
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' }
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' }
local root_directory = get_root_directory(root_files)
return {
name = "tsserver",
cmd = { "typescript-language-server", "--stdio" },
root_dir = root_directory,
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,
}
}
}
}
end
function M.typescript_config()
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' }
local root_dir = get_root_directory(root_files)
-- Look for npm based typescript files first and if found return tsserver
-- configuration, else return deno configuration. This allows us to work
-- with both npm and deno based typescript projects.
if root_dir then
return M.tsserver_config()
else
return M.deno_config()
end
end
return M