2023-02-27 15:18:55 +01:00
|
|
|
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,
|
2023-03-06 17:35:55 +01:00
|
|
|
settings = {
|
|
|
|
haskell = {
|
|
|
|
formattingProvider = 'ormolu' ,
|
|
|
|
cabalFormattingProvider = 'cabalfmt',
|
|
|
|
}
|
|
|
|
},
|
2023-02-27 15:18:55 +01:00
|
|
|
}
|
|
|
|
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
|