|
| 1 | +---@brief |
| 2 | +--- |
| 3 | +--- https://github.com/dotnet/roslyn |
| 4 | +-- |
| 5 | +-- To install the server, compile from source or download as nuget package. |
| 6 | +-- Go to `https://dev.azure.com/azure-public/vside/_artifacts/feed/vs-impl/NuGet/Microsoft.CodeAnalysis.LanguageServer.<platform>/overview` |
| 7 | +-- 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). |
| 8 | +-- Download and extract it (nuget's are zip files). |
| 9 | +-- - if you chose `neutral` nuget version, then you have to change the `cmd` like so: |
| 10 | +-- cmd = { |
| 11 | +-- 'dotnet', |
| 12 | +-- '<my_folder>/Microsoft.CodeAnalysis.LanguageServer.dll', |
| 13 | +-- '--logLevel', -- this property is required by the server |
| 14 | +-- 'Information', |
| 15 | +-- '--extensionLogDirectory', -- this property is required by the server |
| 16 | +-- fs.joinpath(uv.os_tmpdir(), 'roslyn_ls/logs'), |
| 17 | +-- '--stdio', |
| 18 | +-- }, |
| 19 | +-- where `<my_folder>` has to be the folder you extracted the nuget package to. |
| 20 | +-- - for all other platforms put the extracted folder to neovim's PATH (`vim.env.PATH`) |
| 21 | + |
| 22 | +local uv = vim.uv |
| 23 | +local fs = vim.fs |
| 24 | + |
| 25 | +---@param client vim.lsp.Client |
| 26 | +---@param target string |
| 27 | +local function on_init_sln(client, target) |
| 28 | + vim.notify('Initializing: ' .. target, vim.log.levels.INFO, { title = 'roslyn_ls' }) |
| 29 | + ---@diagnostic disable-next-line: param-type-mismatch |
| 30 | + client:notify('solution/open', { |
| 31 | + solution = vim.uri_from_fname(target), |
| 32 | + }) |
| 33 | +end |
| 34 | + |
| 35 | +---@param client vim.lsp.Client |
| 36 | +---@param project_files string[] |
| 37 | +local function on_init_project(client, project_files) |
| 38 | + vim.notify('Initializing: projects', vim.log.levels.INFO, { title = 'roslyn_ls' }) |
| 39 | + ---@diagnostic disable-next-line: param-type-mismatch |
| 40 | + client:notify('project/open', { |
| 41 | + projects = vim.tbl_map(function(file) |
| 42 | + return vim.uri_from_fname(file) |
| 43 | + end, project_files), |
| 44 | + }) |
| 45 | +end |
| 46 | + |
| 47 | +local function roslyn_handlers() |
| 48 | + return { |
| 49 | + ['workspace/projectInitializationComplete'] = function(_, _, ctx) |
| 50 | + vim.notify('Roslyn project initialization complete', vim.log.levels.INFO, { title = 'roslyn_ls' }) |
| 51 | + |
| 52 | + local buffers = vim.lsp.get_buffers_by_client_id(ctx.client_id) |
| 53 | + for _, buf in ipairs(buffers) do |
| 54 | + vim.lsp.util._refresh('textDocument/diagnostic', { bufnr = buf }) |
| 55 | + end |
| 56 | + end, |
| 57 | + ['workspace/_roslyn_projectHasUnresolvedDependencies'] = function() |
| 58 | + vim.notify('Detected missing dependencies. Run `dotnet restore` command.', vim.log.levels.ERROR, { |
| 59 | + title = 'roslyn_ls', |
| 60 | + }) |
| 61 | + return vim.NIL |
| 62 | + end, |
| 63 | + ['workspace/_roslyn_projectNeedsRestore'] = function(_, result, ctx) |
| 64 | + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) |
| 65 | + |
| 66 | + ---@diagnostic disable-next-line: param-type-mismatch |
| 67 | + client:request('workspace/_roslyn_restore', result, function(err, response) |
| 68 | + if err then |
| 69 | + vim.notify(err.message, vim.log.levels.ERROR, { title = 'roslyn_ls' }) |
| 70 | + end |
| 71 | + if response then |
| 72 | + for _, v in ipairs(response) do |
| 73 | + vim.notify(v.message, vim.log.levels.INFO, { title = 'roslyn_ls' }) |
| 74 | + end |
| 75 | + end |
| 76 | + end) |
| 77 | + |
| 78 | + return vim.NIL |
| 79 | + end, |
| 80 | + ['razor/provideDynamicFileInfo'] = function(_, _, _) |
| 81 | + vim.notify( |
| 82 | + 'Razor is not supported.\nPlease use https://github.com/tris203/rzls.nvim', |
| 83 | + vim.log.levels.WARN, |
| 84 | + { title = 'roslyn_ls' } |
| 85 | + ) |
| 86 | + return vim.NIL |
| 87 | + end, |
| 88 | + } |
| 89 | +end |
| 90 | + |
| 91 | +---@type vim.lsp.ClientConfig |
| 92 | +return { |
| 93 | + name = 'roslyn_ls', |
| 94 | + offset_encoding = 'utf-8', |
| 95 | + cmd = { |
| 96 | + 'Microsoft.CodeAnalysis.LanguageServer', |
| 97 | + '--logLevel', |
| 98 | + 'Information', |
| 99 | + '--extensionLogDirectory', |
| 100 | + fs.joinpath(uv.os_tmpdir(), 'roslyn_ls/logs'), |
| 101 | + '--stdio', |
| 102 | + }, |
| 103 | + filetypes = { 'cs' }, |
| 104 | + handlers = roslyn_handlers(), |
| 105 | + root_dir = function(bufnr, cb) |
| 106 | + local bufname = vim.api.nvim_buf_get_name(bufnr) |
| 107 | + -- don't try to find sln or csproj for files from libraries |
| 108 | + -- outside of the project |
| 109 | + if not bufname:match('^' .. fs.joinpath('/tmp/MetadataAsSource/')) then |
| 110 | + -- try find solutions root first |
| 111 | + local root_dir = fs.root(bufnr, function(fname, _) |
| 112 | + return fname:match('%.sln$') ~= nil |
| 113 | + end) |
| 114 | + |
| 115 | + if not root_dir then |
| 116 | + -- try find projects root |
| 117 | + root_dir = fs.root(bufnr, function(fname, _) |
| 118 | + return fname:match('%.csproj$') ~= nil |
| 119 | + end) |
| 120 | + end |
| 121 | + |
| 122 | + if root_dir then |
| 123 | + cb(root_dir) |
| 124 | + end |
| 125 | + end |
| 126 | + end, |
| 127 | + on_init = { |
| 128 | + function(client) |
| 129 | + local root_dir = client.config.root_dir |
| 130 | + |
| 131 | + -- try load first solution we find |
| 132 | + for entry, type in vim.fs.dir(root_dir) do |
| 133 | + if type == 'file' and vim.endswith(entry, '.sln') then |
| 134 | + on_init_sln(client, entry) |
| 135 | + return |
| 136 | + end |
| 137 | + end |
| 138 | + |
| 139 | + -- if no solution is found load project |
| 140 | + for entry, type in vim.fs.dir(root_dir) do |
| 141 | + if type == 'file' and vim.endswith(entry, '.csproj') then |
| 142 | + on_init_project(client, { entry }) |
| 143 | + end |
| 144 | + end |
| 145 | + end, |
| 146 | + }, |
| 147 | + capabilities = { |
| 148 | + -- HACK: Doesn't show any diagnostics if we do not set this to true |
| 149 | + textDocument = { |
| 150 | + diagnostic = { |
| 151 | + dynamicRegistration = true, |
| 152 | + }, |
| 153 | + }, |
| 154 | + }, |
| 155 | + settings = { |
| 156 | + ['csharp|background_analysis'] = { |
| 157 | + dotnet_analyzer_diagnostics_scope = 'fullSolution', |
| 158 | + dotnet_compiler_diagnostics_scope = 'fullSolution', |
| 159 | + }, |
| 160 | + ['csharp|inlay_hints'] = { |
| 161 | + csharp_enable_inlay_hints_for_implicit_object_creation = true, |
| 162 | + csharp_enable_inlay_hints_for_implicit_variable_types = true, |
| 163 | + csharp_enable_inlay_hints_for_lambda_parameter_types = true, |
| 164 | + csharp_enable_inlay_hints_for_types = true, |
| 165 | + dotnet_enable_inlay_hints_for_indexer_parameters = true, |
| 166 | + dotnet_enable_inlay_hints_for_literal_parameters = true, |
| 167 | + dotnet_enable_inlay_hints_for_object_creation_parameters = true, |
| 168 | + dotnet_enable_inlay_hints_for_other_parameters = true, |
| 169 | + dotnet_enable_inlay_hints_for_parameters = true, |
| 170 | + dotnet_suppress_inlay_hints_for_parameters_that_differ_only_by_suffix = true, |
| 171 | + dotnet_suppress_inlay_hints_for_parameters_that_match_argument_name = true, |
| 172 | + dotnet_suppress_inlay_hints_for_parameters_that_match_method_intent = true, |
| 173 | + }, |
| 174 | + ['csharp|symbol_search'] = { |
| 175 | + dotnet_search_reference_assemblies = true, |
| 176 | + }, |
| 177 | + ['csharp|completion'] = { |
| 178 | + dotnet_show_name_completion_suggestions = true, |
| 179 | + dotnet_show_completion_items_from_unimported_namespaces = true, |
| 180 | + dotnet_provide_regex_completions = true, |
| 181 | + }, |
| 182 | + ['csharp|code_lens'] = { |
| 183 | + dotnet_enable_references_code_lens = true, |
| 184 | + }, |
| 185 | + }, |
| 186 | +} |
0 commit comments