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:
parent
6f8cf0bce5
commit
110a1643cb
11 changed files with 325 additions and 177 deletions
|
@ -1,22 +1,4 @@
|
|||
local default_capabilities = {
|
||||
textDocument = {
|
||||
completion = {
|
||||
editsNearCursor = true,
|
||||
},
|
||||
},
|
||||
offsetEncoding = { 'utf-8', 'utf-16' },
|
||||
}
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local clangd_config = lsp_utils.clangd_config()
|
||||
|
||||
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 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,
|
||||
})
|
||||
vim.lsp.start(clangd_config)
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
local path = vim.fs.find({ 'go.mod', 'go.work', '.git' }, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local gopls_config = lsp_utils.gopls_config()
|
||||
|
||||
vim.lsp.start({
|
||||
name = "gopls",
|
||||
cmd = { "gopls" },
|
||||
root_dir = root,
|
||||
filetypes = { 'go', 'gomod', 'gowork', 'gotmpl' },
|
||||
})
|
||||
vim.lsp.start(gopls_config)
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
local root_files = { 'hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml' }
|
||||
local path = vim.fs.find(root_files, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local hls_config = lsp_utils.hls_config()
|
||||
|
||||
vim.lsp.start({
|
||||
name = "hls",
|
||||
cmd = { 'haskell-language-server-wrapper', '--lsp' },
|
||||
root_dir = root,
|
||||
filetypes = { 'haskell' },
|
||||
single_file_support = true,
|
||||
settings = { haskell = { formattingProvider = 'ormolu' } },
|
||||
})
|
||||
vim.lsp.start(hls_config)
|
||||
|
|
|
@ -1,37 +1,7 @@
|
|||
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' }
|
||||
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' }
|
||||
local path = vim.fs.find(root_files, { type = "file" })
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local tsserver_config = lsp_utils.tsserver_config()
|
||||
|
||||
vim.lsp.start({
|
||||
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.lsp.start(tsserver_config)
|
||||
|
||||
vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 })
|
||||
|
||||
|
|
|
@ -1,26 +1,7 @@
|
|||
local root_files = { 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', 'Pipfile' }
|
||||
local path = vim.fs.find(root_files, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local jedi_config = lsp_utils.jedi_config()
|
||||
|
||||
vim.lsp.start({
|
||||
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.lsp.start(jedi_config)
|
||||
|
||||
vim.bo.textwidth = 0
|
||||
vim.bo.formatprg = "black -q -"
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
local path = vim.fs.find({ '.git' }, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local scheme_config = lsp_utils.scheme_config()
|
||||
|
||||
vim.lsp.start({
|
||||
name = "racket-langserver",
|
||||
cmd = { 'racket', '--lib', 'racket-langserver' },
|
||||
filetypes = { 'scheme', 'racket' },
|
||||
root_dir = root,
|
||||
single_file_support = true,
|
||||
})
|
||||
vim.lsp.start(scheme_config)
|
||||
|
|
|
@ -1,21 +1,7 @@
|
|||
local path = vim.fs.find({ "Cargo.toml" }, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local ra_config = lsp_utils.ra_config()
|
||||
|
||||
vim.lsp.start({
|
||||
name = "rust-analyzer",
|
||||
cmd = { "rust-analyzer" },
|
||||
root_dir = root,
|
||||
settings = {
|
||||
["rust-analyzer"] = {
|
||||
procMacro = {
|
||||
enable = true
|
||||
},
|
||||
checkOnSave = {
|
||||
command = "clippy"
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
vim.lsp.start(ra_config)
|
||||
|
||||
vim.cmd.compiler('cargo')
|
||||
vim.bo.makeprg = 'cargo build --all'
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
local path = vim.fs.find({ '.git' }, { type = "file" })
|
||||
local root = vim.fs.dirname(path[1])
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local scheme_config = lsp_utils.scheme_config()
|
||||
|
||||
vim.lsp.start({
|
||||
name = "racket-langserver",
|
||||
cmd = { 'racket', '--lib', 'racket-langserver' },
|
||||
filetypes = { 'scheme', 'racket' },
|
||||
root_dir = root,
|
||||
single_file_support = true,
|
||||
})
|
||||
vim.lsp.start(scheme_config)
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
vim.lsp.start({
|
||||
name = "bashls",
|
||||
cmd = { 'bash-language-server', 'start' },
|
||||
root_dir = vim.fn.getcwd(),
|
||||
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)',
|
||||
},
|
||||
})
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local bashls_config = lsp_utils.bashls_config()
|
||||
|
||||
vim.lsp.start(bashls_config)
|
||||
|
|
|
@ -1,37 +1,7 @@
|
|||
local root_files = { 'jsconfig.json', 'tsconfig.json', 'package.json' }
|
||||
local file_types = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx' }
|
||||
local path = vim.fs.find(root_files, { type = "file" })
|
||||
local lsp_utils = require('lsp-utils')
|
||||
local typescript_config = lsp_utils.typescript_config()
|
||||
|
||||
vim.lsp.start({
|
||||
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.lsp.start(typescript_config)
|
||||
|
||||
vim.keymap.set('n', 'gq', "<cmd>!npx prettier --write %:p<CR>:e<CR>", { noremap=true, silent=true, buffer=0 })
|
||||
|
||||
|
|
294
nvim/.config/nvim/lua/lsp-utils.lua
Normal file
294
nvim/.config/nvim/lua/lsp-utils.lua
Normal 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
|
Loading…
Reference in a new issue