This is an actively maintained & upgraded fork that interacts with the improved & open-source C# Roslyn language server, meant to replace the old and discontinued OmniSharp. This language server is currently used in the Visual Studio Code C# Extension, which is shipped with the standard C# Dev Kit.
This standalone plugin was necessary because Roslyn uses a non-standard method of initializing communication with the client and requires additional custom integrations, unlike typical LSP setups in Neovim.
- Neovim >= 0.10.0
- Roslyn language server downloaded locally
- .NET SDK installed and
dotnet
command available
roslyn_demo.mp4
Mason
roslyn
is not in the mason core registry, so a custom registry is used. This is automatically setup if you have mason installed.
This registry provides two binaries
roslyn
(To be used with this repo)rzls
(To be used with rzls.nvim)
IMPORTANT
If you are setting up mason with custom registries, make sure that you are either setting it up before roslyn.nvim
is setup, or also include github:Crashdummyy/mason-registry
in your registries
config
NOTE
There's currently an open pull request to add the Roslyn server to mason, which would greatly improve the experience. If you are interested in this, please react to the original comment, but don't spam the thread with unnecessary comments.
Manually
- Navigate to this feed, search for
Microsoft.CodeAnalysis.LanguageServer
and download the version matching your OS and architecture.For nix users, install roslyn-ls and then you can config this plugin right away.
- Unzip the downloaded
.nupkg
and copy the contents of<zip root>/content/LanguageServer/<yourArch>
inside:- Linux:
~/.local/share/nvim/roslyn
- Windows:
%LOCALAPPDATA%\nvim-data\roslyn
TIP: You can also specify a custom path to the roslyn folder in the setup function.
- Linux:
- Check if it's working by running
dotnet Microsoft.CodeAnalysis.LanguageServer.dll --version
in theroslyn
directory.
Tip
For server compatibility check the roslyn repo
Install the plugin with your preferred package manager:
{
"seblj/roslyn.nvim",
ft = "cs",
opts = {
-- your configuration comes here; leave empty for default settings
}
}
The plugin comes with the following defaults:
{
config = {
-- Here you can pass in any options that that you would like to pass to `vim.lsp.start`.
-- Use `:h vim.lsp.ClientConfig` to see all possible options.
-- The only options that are overwritten and won't have any effect by setting here:
-- - `name`
-- - `cmd`
-- - `root_dir`
},
--[[
-- if you installed `roslyn-ls` by nix, use the following:
exe = 'Microsoft.CodeAnalysis.LanguageServer',
]]
exe = {
"dotnet",
vim.fs.joinpath(vim.fn.stdpath("data"), "roslyn", "Microsoft.CodeAnalysis.LanguageServer.dll"),
},
args = {
"--logLevel=Information", "--extensionLogDirectory=" .. vim.fs.dirname(vim.lsp.get_log_path())
},
--[[
-- args can be used to pass additional flags to the language server
]]
-- NOTE: Set `filewatching` to false if you experience performance problems.
-- Defaults to true, since turning it off is a hack.
-- If you notice that the server is _super_ slow, it is probably because of file watching
-- Neovim becomes super unresponsive on some large codebases, because it schedules the file watching on the event loop.
-- This issue goes away by disabling this capability, but roslyn will fallback to its own file watching,
-- which can make the server super slow to initialize.
-- Setting this option to false will indicate to the server that neovim will do the file watching.
-- However, in `hacks.lua` I will also just don't start off any watchers, which seems to make the server
-- a lot faster to initialize.
filewatching = true,
-- Optional function that takes an array of solutions as the only argument. Return the solution you
-- want to use. If it returns `nil`, then it falls back to guessing the solution like normal
-- Example:
--
-- choose_sln = function(sln)
-- return vim.iter(sln):find(function(item)
-- if string.match(item, "Foo.sln") then
-- return item
-- end
-- end)
-- end
choose_sln = nil,
-- Optional function that takes the selected solution as the only argument.
-- Returns a boolean of whether it should be ignored to attach to or not
--
-- I am for example using this to disable a solution with a lot of .NET Framework code on mac
-- Example:
--
-- ignore_sln = function(sln)
-- return string.match(sln, "Foo.sln") ~= nil
-- end
ignore_sln = nil,
-- Whether or not to look for solution files in the child of the (root).
-- Set this to true if you have some projects that are not a child of the
-- directory with the solution file
broad_search = false,
-- Whether or not to lock the solution target after the first attach.
-- This will always attach to the target in `vim.g.roslyn_nvim_selected_solution`.
-- NOTE: You can use `:Roslyn target` to change the target
lock_target = false,
})
To configure language server specific settings sent to the server, you can modify the config.settings
map.
Note
These settings are not guaranteed to be up-to-date and new ones can appear in the future. Aditionally, not not all settings are shown here, but only the most relevant ones for Neovim. For a full list, visit this unit test from the vscode extension and look especially for the ones which don't have vsCodeConfiguration: null
.
csharp|background_analysis
These settings control the scope of background diagnostics.
-
background_analysis.dotnet_analyzer_diagnostics_scope
Scope of the background analysis for .NET analyzer diagnostics.
Expected values:openFiles
,fullSolution
,none
-
background_analysis.dotnet_compiler_diagnostics_scope
Scope of the background analysis for .NET compiler diagnostics.
Expected values:openFiles
,fullSolution
,none
csharp|code_lens
These settings control the LSP code lens.
-
dotnet_enable_references_code_lens
Enable code lens references.
Expected values:true
,false
-
dotnet_enable_tests_code_lens
Enable tests code lens.
Expected values:true
,false
Tip
You must refresh the code lens yourself. Check :h vim.lsp.codelens.refresh()
and the example autocmd.
csharp|completion
These settings control how the completions behave.
-
dotnet_provide_regex_completions
Show regular expressions in completion list.
Expected values:true
,false
-
dotnet_show_completion_items_from_unimported_namespaces
Enables support for showing unimported types and unimported extension methods in completion lists.
Expected values:true
,false
-
dotnet_show_name_completion_suggestions
Perform automatic object name completion for the members that you have recently selected.
Expected values:true
,false
csharp|inlay_hints
These settings control what inlay hints should be displayed.
-
csharp_enable_inlay_hints_for_implicit_object_creation
Show hints for implicit object creation.
Expected values:true
,false
-
csharp_enable_inlay_hints_for_implicit_variable_types
Show hints for variables with inferred types.
Expected values:true
,false
-
csharp_enable_inlay_hints_for_lambda_parameter_types
Show hints for lambda parameter types.
Expected values:true
,false
-
csharp_enable_inlay_hints_for_types
Display inline type hints.
Expected values:true
,false
-
dotnet_enable_inlay_hints_for_indexer_parameters
Show hints for indexers.
Expected values:true
,false
-
dotnet_enable_inlay_hints_for_literal_parameters
Show hints for literals.
Expected values:true
,false
-
dotnet_enable_inlay_hints_for_object_creation_parameters
Show hints for 'new' expressions.
Expected values:true
,false
-
dotnet_enable_inlay_hints_for_other_parameters
Show hints for everything else.
Expected values:true
,false
-
dotnet_enable_inlay_hints_for_parameters
Display inline parameter name hints.
Expected values:true
,false
-
dotnet_suppress_inlay_hints_for_parameters_that_differ_only_by_suffix
Suppress hints when parameter names differ only by suffix.
Expected values:true
,false
-
dotnet_suppress_inlay_hints_for_parameters_that_match_argument_name
Suppress hints when argument matches parameter name.
Expected values:true
,false
-
dotnet_suppress_inlay_hints_for_parameters_that_match_method_intent
Suppress hints when parameter name matches the method's intent.
Expected values:true
,false
Tip
These won't have any effect if you don't enable inlay hints in your config. Check :h vim.lsp.inlay_hint.enable()
.
csharp|symbol_search
This setting controls how the language server should search for symbols.
dotnet_search_reference_assemblies
Search symbols in reference assemblies.
Expected values:true
,false
Example:
opts = {
config = {
settings = {
["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|code_lens"] = {
dotnet_enable_references_code_lens = true,
},
},
},
}
:Roslyn restart
restarts the server:Roslyn stop
stops the server:Roslyn target
chooses a solution if there are multiple to chose from
- If you have multiple solutions, this plugin tries to guess which one to use. You can change the target with the
:Roslyn target
command. - The current solution is always stored in
vim.g.roslyn_nvim_selected_solution
. You can use this, for example, to display the current solution in your statusline.