Skip to content

Add Support for Roslyn LSP (Csharp Language Server) - #11

Merged
reflectronic merged 15 commits into
zed-extensions:mainfrom
Digni:main
Dec 10, 2025
Merged

reflectronic merged 15 commits into
zed-extensions:mainfrom
Digni:main

Conversation

@Digni

@Digni Digni commented May 26, 2025 •

Copy link
Copy Markdown
Contributor

This adds support for the (newer) Roslyn LSP from Microsoft (Microsoft.CodeAnalysis.LanguageServer).

The current Implementation is using a wrapper provided by: https://github.com/SofusA/csharp-language-server.
This is because the Roslyn LSP expects one of the following notifications after "initialize":

{
  "method": "solution/open",
  "params": {
    "solution" : "filepathUri_to_solution" (.sln, .slnx)
  }
}

{
  "method": "project/open",
  "params": {
    "projects" : [ "filePathUri_to_Project" ,  ....] (list of .csproj files)
  }
}

The csharp-language-server reacts on the initialize notification to get the working directory and then scans it for solution and project files.
If it finds a solution file it picks the first one it finds, this could lead to some unintended reference issues if there are more than one solution file in the working directory.
The VsCode Extension handles this by asking the user which solution should be opened.

I would like to implement something similar and run the roslyn lsp directly (dotnet Microsoft.CodeAnalysis.LanguageServer.dll).
But for that to work I need to be able to send these notifications to the lsp server (and if possible ask the user which solution he wants to open) and I currently don't know how this would be possible with the extension api.

Maybe someone could help me with that.

Update

Added Workspace Configuration Options for Roslyn lsp.
Server expects the following format:

{language}|{grouping}.name for language specific options or {grouping}.{name} for general options.

Example

"csharp|inlay_hints.csharp_enable_inlay_hints_for_implicit_object_creation": true,
"csharp|inlay_hints.csharp_enable_inlay_hints_for_implicit_variable_types": true,

In the settings json I made it nested:

  "lsp": {
    "roslyn": {
      "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
        }
      }
    }
  }

This will get translated to the valid format described above.
Which leads to something like this (configured inlay_hints):

image


Fixes #1
Fixes #7
Fixes #8
Fixes #9
Fixes #10
Fixes #13
Fixes #14
Fixes #20
Fixes #29
Fixes zed-industries/zed#8352
Fixes zed-industries/zed#11104
Fixes zed-industries/zed#22002
Fixes zed-industries/zed#31014
Fixes zed-industries/zed#33135

@cla-bot

This comment was marked as resolved.

@cla-bot

This comment was marked as resolved.

@Digni

This comment was marked as resolved.

@cla-bot cla-bot Bot added the cla-signed label May 26, 2025
@cla-bot

This comment was marked as resolved.

@Vlaaaaaaad

Copy link
Copy Markdown

CC @fminkowski, @dibarbet, @CyrusNajmabadi, and @maxbrunsfeld since they were involved in the initial implementation of the Zed C# extension and thus might or might not have thoughts

@Digni

Digni commented May 29, 2025 •

Copy link
Copy Markdown
Contributor Author

Seems like I made that PR to early... I did try Completion, Code Action etc.
But I missed a really crucial part.
The diagnostics are not working, even with that hack of @SofusA. (Force Diagnostics Pull)
I did try the hack that is used in nvim:

    capabilities = {
        textDocument = {
            -- HACK: Doesn't show any diagnostics if we do not set this to true
            diagnostic = {
                dynamicRegistration = true,
            },
        },
    },

Via intercepting the notification and adding it, but that did not work.

So I think here we need the support from the Zed Team.

@SofusA

SofusA commented May 29, 2025

Copy link
Copy Markdown

I also get no diagnostics. A simple way to reproduce is overriding the path for omnisharp:

"lsp": {
    "omnisharp": {
      "binary": {
        "path": "csharp-language-server"
      }
    }
  }

Do you know if zed supports pull diagnostics?

@Digni

Digni commented May 29, 2025

Copy link
Copy Markdown
Contributor Author

I do not, but my guess at the moment seems no.

Just tried dotrush to see if the diagnostics are working with that, but its the same. No Diagnostics

@SofusA

SofusA commented May 30, 2025

Copy link
Copy Markdown

ruby configuration states that pull diagnostics are not supported, under setting up ruby-lsp

@Digni

Digni commented May 30, 2025

Copy link
Copy Markdown
Contributor Author

You are right, here is the issue tracking that: zed-industries/zed#13107
Roslyn switched to only pull diagnostics some time ago, so it seems we need to wait on that for working rolyn support.

Comment thread src/language_servers/roslyn.rs Outdated
dylhack

This comment was marked as resolved.

@SofusA

SofusA commented Jun 3, 2025

Copy link
Copy Markdown

Thanks to @MoaidHathot for pointing this out. It looks like utilizing csharp-language-server outside of Visual Studio Code goes against the Dev Kit license making this usage illegal in Zed.

The tool only utilises code from Roslyn which is licensed under MIT Licence. It does do use anything from C# DevKit.

C# DevKit utilises the same underlying language server from Roslyn, Microsoft.CodeAnalysis.LanguageServer, but csharp-language-server has nothing to do with C# DevKit.

@Digni

Digni commented Jun 3, 2025

Copy link
Copy Markdown
Contributor Author

@SofusA was quicker to respond. And that is true, the server uses the Microsoft.CodeAnalysis.LanguageServer. This can be found here: https://github.com/dotnet/roslyn.
And that is MIT License, so no DevKit is used.

Co-authored-by: Dylan Hackworth <drhackworth@pm.me>
@dylhack

dylhack commented Jun 3, 2025 •

Copy link
Copy Markdown
Contributor

Ah okay looks like a misinterpretation of csharp-language-server and the DevKit license. Love it so far! Great work.

@julionav

julionav commented Jun 3, 2025

Copy link
Copy Markdown

@Digni any chance that this can be run alongside omnisharp? to have the diagnostics. Right now the omnisharp ls doesn't work when decompiling sources (go to definition)

@Digni

Digni commented Jun 3, 2025

Copy link
Copy Markdown
Contributor Author

@Digni any chance that this can be run alongside omnisharp? to have the diagnostics. Right now the omnisharp ls doesn't work when decompiling sources (go to definition)

Yeah, Zed supports running several lsp's for one language.
https://zed.dev/docs/configuring-languages

  "languages": {
    "CSharp": {
      "language_servers": ["roslyn", "omnisharp", "..."]
    }
  }

But as written in the ruby extension (https://zed.dev/docs/languages/ruby) they would provide similar functionality. So we probably need to turn off autocompletion, code-actions from omnisharp.

https://github.com/OmniSharp/omnisharp-roslyn/wiki/Configuration-Options

I did not look into that yet.

@AleksaBajat

Copy link
Copy Markdown

@SofusA @Digni It seems that Zed closed this PR. Let me know if I can help out in pursuing this LSP.

@Digni

Digni commented Jun 12, 2025

Copy link
Copy Markdown
Contributor Author

I just did a quick check on Zed Preview and diagnostics seems to be working now.

image

@julionav

Copy link
Copy Markdown

@Digni i tried this but I couldn't make the go to definition with decompiling work. Do you know if that should work? E.g go to the definition of a installed package

@SofusA

SofusA commented Jun 19, 2025

Copy link
Copy Markdown

@Digni i tried this but I couldn't make the go to definition with decompiling work. Do you know if that should work? E.g go to the definition of a installed package

I get working decompiling using the the config mentioned in my previous comment.

@fallenwood

Copy link
Copy Markdown
Contributor

I am able to make diagnostic work on my fork(?) with an workaround, to enrich the textDocument/diagnostic request in the wrapper with range

image

@moheladwy

Copy link
Copy Markdown

any updates on this PR?

@reflectronic

Copy link
Copy Markdown
Contributor

I am planning on tackling the Zed bugs that are blocking this PR next week

@reflectronic

Copy link
Copy Markdown
Contributor

We have a patch that fixes the diagnostics: zed-industries/zed@main...pull-diagnostics-registrations

It requires some cleanup before we merge it, but it's working reliably:
image

@vavans

vavans commented Nov 15, 2025 •

Copy link
Copy Markdown

So close guys... I have like 10 friends of mine waiting for this PR to be merged to drop the lagy vscode for .net core dev ! 🥳

@reflectronic

Copy link
Copy Markdown
Contributor

Roslyn issues with LSP specification conformance have been resolved: dotnet/roslyn#81174

I will try to get the Zed fixes merged this week.

@reflectronic reflectronic left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zed-industries/zed#43703 has fixed the issue with diagnostics in Zed. As such, I think this PR is good to go.

v0.217 (the preview that'll be released on Wednesday) will be the first version with these fixes. We'll change the default settings in Zed so that versions without the fix will use OmniSharp and versions with the fix will use Roslyn.

Additionally, a new release of csharp-language-server which has the latest Roslyn fixes will need to be released before we can publish a new version of the extension.

@SofusA

SofusA commented Dec 9, 2025

Copy link
Copy Markdown

zed-industries/zed#43703 has fixed the issue with diagnostics in Zed. As such, I think this PR is good to go.

v0.217 (the preview that'll be released on Wednesday) will be the first version with these fixes. We'll change the default settings in Zed so that versions without the fix will use OmniSharp and versions with the fix will use Roslyn.

Additionally, a new release of csharp-language-server which has the latest Roslyn fixes will need to be released before we can publish a new version of the extension.

Great work!
How would you prefer updates to and releases of sofusa/csharp-language-server?

Currently I update and do manual tests every months before releasing. Simple automatic tests is on the way.

I have considered that the server version should be a cli argument or to follow the version of the vscode extension.

I personally don’t have any preferences, I am happy to follow requests. Only that we can share as much as possible between editors (mainly helix and zed).

@reflectronic
reflectronic merged commit a39a06b into zed-extensions:main Dec 10, 2025
1 check passed
reflectronic pushed a commit to zed-industries/zed that referenced this pull request Dec 10, 2025
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
reflectronic pushed a commit to zed-industries/zed that referenced this pull request Dec 10, 2025
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
nrbnlulu pushed a commit to nrbnlulu/zed that referenced this pull request Dec 14, 2025
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
CherryWorm pushed a commit to CherryWorm/zed that referenced this pull request Dec 16, 2025
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
@reflectronic

Copy link
Copy Markdown
Contributor

We found an issue with the Zed fixes that were causing stale diagnostics with other language servers. We had to revert the patch, so the stable release for v0.217 won't support Roslyn. v0.218 will support Roslyn. Sorry for any inconvenience

someone13574 pushed a commit to someone13574/zed that referenced this pull request Dec 16, 2025
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
jasonsmithio pushed a commit to paddleboarddev/paddleboard that referenced this pull request May 31, 2026
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
MrSubidubi added a commit that referenced this pull request Jun 4, 2026
Adds [csharp-ls](https://github.com/razzmatazz/csharp-language-server)
as a third language server option alongside OmniSharp and Roslyn.
csharp-ls is an F#-based C# language server distributed as a `dotnet
tool` NuGet package; it is unrelated to the deprecated
`SofusA/csharp-language-server` wrapper referenced by
[#11](#11) and
[#57](#57). The naming
overlap is unfortunate: the upstream project markets itself as
`csharp-ls` precisely to reduce that confusion.

The use case is different from Roslyn. csharp-ls is a leaner
alternative: cold start is faster, memory footprint is lower, and it
stays responsive on small projects or quick edits where spinning up a
full Roslyn workspace is overkill. Roslyn remains the right choice for
the deepest Microsoft tooling; csharp-ls is for the case when you want
something snappy.

To use it:

```json
{
  "languages": {
    "CSharp": {
      "language_servers": ["csharp-ls", "!omnisharp", "!roslyn"]
    }
  }
}
```

It partially addresses
#62, it is running better
on my own M3 mac for smaller projects.

---------

Co-authored-by: MrSubidubi <dev@bahn.sh>
Co-authored-by: Finn Evers <finn@zed.dev>
jonx pushed a commit to jonx/zed-aros that referenced this pull request Jul 17, 2026
In preparation for zed-extensions/csharp#11. Do
not merge before that PR is published.

Release Notes:

- Added support for Roslyn in C# files. Roslyn will now be the default
language server for C#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment