lua/custom/lsp/** configs This commit removes the need for nvim-lspconfig which is replaced by the vim.lsp API. The lsp/ folder is a copy of nvim-lspconfig's lsp/ folder as it makes it easy to modify LSP configurations on the fly. Conform: biome has been replaced with oxfmt
260 lines
8.6 KiB
Lua
260 lines
8.6 KiB
Lua
---@brief
|
|
---
|
|
--- https://github.com/dotnet/roslyn
|
|
--
|
|
-- To install the server, compile from source or download as nuget package.
|
|
-- Go to `https://dev.azure.com/azure-public/vside/_artifacts/feed/vs-impl/NuGet/Microsoft.CodeAnalysis.LanguageServer.<platform>/overview`
|
|
-- replace `<platform>` with one of the following `linux-x64`, `osx-x64`, `win-x64`, `neutral` (for more info on the download location see https://github.com/dotnet/roslyn/issues/71474#issuecomment-2177303207).
|
|
-- Download and extract it (nuget's are zip files).
|
|
-- - if you chose `neutral` nuget version, then you have to change the `cmd` like so:
|
|
-- ```lua
|
|
-- cmd = {
|
|
-- 'dotnet',
|
|
-- '<my_folder>/Microsoft.CodeAnalysis.LanguageServer.dll',
|
|
-- '--logLevel', -- this property is required by the server
|
|
-- 'Information',
|
|
-- '--extensionLogDirectory', -- this property is required by the server
|
|
-- fs.joinpath(uv.os_tmpdir(), 'roslyn_ls/logs'),
|
|
-- '--stdio',
|
|
-- },
|
|
-- ```
|
|
-- where `<my_folder>` has to be the folder you extracted the nuget package to.
|
|
-- - for all other platforms put the extracted folder to neovim's PATH (`vim.env.PATH`)
|
|
|
|
local uv = vim.uv
|
|
local fs = vim.fs
|
|
|
|
local group = vim.api.nvim_create_augroup('lspconfig.roslyn_ls', { clear = true })
|
|
|
|
---@param client vim.lsp.Client
|
|
---@param target string
|
|
local function on_init_sln(client, target)
|
|
vim.notify('Initializing: ' .. target, vim.log.levels.TRACE, { title = 'roslyn_ls' })
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
client:notify('solution/open', {
|
|
solution = vim.uri_from_fname(target),
|
|
})
|
|
end
|
|
|
|
---@param client vim.lsp.Client
|
|
---@param project_files string[]
|
|
local function on_init_project(client, project_files)
|
|
vim.notify('Initializing: projects', vim.log.levels.TRACE, { title = 'roslyn_ls' })
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
client:notify('project/open', {
|
|
projects = vim.tbl_map(function(file)
|
|
return vim.uri_from_fname(file)
|
|
end, project_files),
|
|
})
|
|
end
|
|
|
|
---@param client vim.lsp.Client
|
|
local function refresh_diagnostics(client)
|
|
for buf, _ in pairs(vim.lsp.get_client_by_id(client.id).attached_buffers) do
|
|
if vim.api.nvim_buf_is_loaded(buf) then
|
|
client:request(
|
|
vim.lsp.protocol.Methods.textDocument_diagnostic,
|
|
{ textDocument = vim.lsp.util.make_text_document_params(buf) },
|
|
nil,
|
|
buf
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function roslyn_handlers()
|
|
return {
|
|
['workspace/projectInitializationComplete'] = function(_, _, ctx)
|
|
vim.notify('Roslyn project initialization complete', vim.log.levels.INFO, { title = 'roslyn_ls' })
|
|
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
|
|
refresh_diagnostics(client)
|
|
return vim.NIL
|
|
end,
|
|
['workspace/_roslyn_projectNeedsRestore'] = function(_, result, ctx)
|
|
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
|
|
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
client:request('workspace/_roslyn_restore', result, function(err, response)
|
|
if err then
|
|
vim.notify(err.message, vim.log.levels.ERROR, { title = 'roslyn_ls' })
|
|
end
|
|
if response then
|
|
for _, v in ipairs(response) do
|
|
vim.notify(v.message, vim.log.levels.INFO, { title = 'roslyn_ls' })
|
|
end
|
|
end
|
|
end)
|
|
|
|
return vim.NIL
|
|
end,
|
|
['razor/provideDynamicFileInfo'] = function(_, _, _)
|
|
vim.notify(
|
|
'Razor is not supported.\nPlease use https://github.com/tris203/rzls.nvim',
|
|
vim.log.levels.WARN,
|
|
{ title = 'roslyn_ls' }
|
|
)
|
|
return vim.NIL
|
|
end,
|
|
}
|
|
end
|
|
|
|
---@param bufname string
|
|
---@return boolean
|
|
local function is_decompiled(bufname)
|
|
local _, endpos = bufname:find('[/\\]MetadataAsSource[/\\]')
|
|
if endpos == nil then
|
|
return false
|
|
end
|
|
return vim.fn.finddir(bufname:sub(1, endpos), uv.os_tmpdir()) ~= ''
|
|
end
|
|
|
|
---@type vim.lsp.Config
|
|
return {
|
|
name = 'roslyn_ls',
|
|
offset_encoding = 'utf-8',
|
|
cmd = {
|
|
'Microsoft.CodeAnalysis.LanguageServer',
|
|
'--logLevel',
|
|
'Information',
|
|
'--extensionLogDirectory',
|
|
fs.joinpath(uv.os_tmpdir(), 'roslyn_ls/logs'),
|
|
'--stdio',
|
|
},
|
|
filetypes = { 'cs' },
|
|
handlers = roslyn_handlers(),
|
|
|
|
commands = {
|
|
['roslyn.client.completionComplexEdit'] = function(command, ctx)
|
|
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
|
|
local args = command.arguments or {}
|
|
local uri, edit = args[1], args[2]
|
|
|
|
---@diagnostic disable: undefined-field
|
|
if uri and edit and edit.newText and edit.range then
|
|
local workspace_edit = {
|
|
changes = {
|
|
[uri.uri] = {
|
|
{
|
|
range = edit.range,
|
|
newText = edit.newText,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
vim.lsp.util.apply_workspace_edit(workspace_edit, client.offset_encoding)
|
|
---@diagnostic enable: undefined-field
|
|
else
|
|
vim.notify('roslyn_ls: completionComplexEdit args not understood: ' .. vim.inspect(args), vim.log.levels.WARN)
|
|
end
|
|
end,
|
|
},
|
|
|
|
root_dir = function(bufnr, cb)
|
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
|
-- don't try to find sln or csproj for files from libraries
|
|
-- outside of the project
|
|
if not is_decompiled(bufname) then
|
|
-- try find solutions root first
|
|
local root_dir = fs.root(bufnr, function(fname, _)
|
|
return fname:match('%.sln[x]?$') ~= nil
|
|
end)
|
|
|
|
if not root_dir then
|
|
-- try find projects root
|
|
root_dir = fs.root(bufnr, function(fname, _)
|
|
return fname:match('%.csproj$') ~= nil
|
|
end)
|
|
end
|
|
|
|
if root_dir then
|
|
cb(root_dir)
|
|
end
|
|
else
|
|
-- Decompiled code (example: "/tmp/MetadataAsSource/f2bfba/DecompilationMetadataAsSourceFileProvider/d5782a/Console.cs")
|
|
local prev_buf = vim.fn.bufnr('#')
|
|
local client = vim.lsp.get_clients({
|
|
name = 'roslyn_ls',
|
|
bufnr = prev_buf ~= 1 and prev_buf or nil,
|
|
})[1]
|
|
if client then
|
|
cb(client.config.root_dir)
|
|
end
|
|
end
|
|
end,
|
|
on_init = {
|
|
function(client)
|
|
local root_dir = client.config.root_dir
|
|
|
|
-- try load first solution we find
|
|
for entry, type in fs.dir(root_dir) do
|
|
if type == 'file' and (vim.endswith(entry, '.sln') or vim.endswith(entry, '.slnx')) then
|
|
on_init_sln(client, fs.joinpath(root_dir, entry))
|
|
return
|
|
end
|
|
end
|
|
|
|
-- if no solution is found load project
|
|
for entry, type in fs.dir(root_dir) do
|
|
if type == 'file' and vim.endswith(entry, '.csproj') then
|
|
on_init_project(client, { fs.joinpath(root_dir, entry) })
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
on_attach = function(client, bufnr)
|
|
-- avoid duplicate autocmds for same buffer
|
|
if vim.api.nvim_get_autocmds({ buffer = bufnr, group = group })[1] then
|
|
return
|
|
end
|
|
|
|
vim.api.nvim_create_autocmd({ 'BufWritePost', 'InsertLeave' }, {
|
|
group = group,
|
|
buffer = bufnr,
|
|
callback = function()
|
|
refresh_diagnostics(client)
|
|
end,
|
|
desc = 'roslyn_ls: refresh diagnostics',
|
|
})
|
|
end,
|
|
|
|
capabilities = {
|
|
-- HACK: Doesn't show any diagnostics if we do not set this to true
|
|
textDocument = {
|
|
diagnostic = {
|
|
dynamicRegistration = true,
|
|
},
|
|
},
|
|
},
|
|
settings = {
|
|
['csharp|background_analysis'] = {
|
|
dotnet_analyzer_diagnostics_scope = 'fullSolution',
|
|
dotnet_compiler_diagnostics_scope = 'fullSolution',
|
|
},
|
|
['csharp|inlay_hints'] = {
|
|
csharp_enable_inlay_hints_for_implicit_object_creation = true,
|
|
csharp_enable_inlay_hints_for_implicit_variable_types = true,
|
|
csharp_enable_inlay_hints_for_lambda_parameter_types = true,
|
|
csharp_enable_inlay_hints_for_types = true,
|
|
dotnet_enable_inlay_hints_for_indexer_parameters = true,
|
|
dotnet_enable_inlay_hints_for_literal_parameters = true,
|
|
dotnet_enable_inlay_hints_for_object_creation_parameters = true,
|
|
dotnet_enable_inlay_hints_for_other_parameters = true,
|
|
dotnet_enable_inlay_hints_for_parameters = true,
|
|
dotnet_suppress_inlay_hints_for_parameters_that_differ_only_by_suffix = true,
|
|
dotnet_suppress_inlay_hints_for_parameters_that_match_argument_name = true,
|
|
dotnet_suppress_inlay_hints_for_parameters_that_match_method_intent = true,
|
|
},
|
|
['csharp|symbol_search'] = {
|
|
dotnet_search_reference_assemblies = true,
|
|
},
|
|
['csharp|completion'] = {
|
|
dotnet_show_name_completion_suggestions = true,
|
|
dotnet_show_completion_items_from_unimported_namespaces = true,
|
|
dotnet_provide_regex_completions = true,
|
|
},
|
|
['csharp|code_lens'] = {
|
|
dotnet_enable_references_code_lens = true,
|
|
},
|
|
},
|
|
}
|