Skip to content

Commit d8406d5

Browse files
committed
languages/csharp: add razor support
Adds razor support for `roslyn` and `csharp_ls` servers
1 parent 92854bd commit d8406d5

3 files changed

Lines changed: 105 additions & 24 deletions

File tree

docs/manual/release-notes/rl-0.9.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
allow valid options. `default` is no longer valid. `inline` and `split` are
3232
two new valid options.
3333

34+
[CaueAnjos](https://github.com/caueanjos)
35+
36+
- Rename `roslyn_ls` to `roslyn` (required by roslyn-nvim).
37+
3438
## Changelog {#sec-release-0-9-changelog}
3539

3640
[taylrfnt](https://github.com/taylrfnt)
@@ -185,4 +189,8 @@ https://github.com/gorbit99/codewindow.nvim
185189
- Fix non-functional `vim.keymaps.*.noremap`. Now, setting it to false is
186190
equivalent to `:lua vim.keymap.set(..., { remap = true })`
187191
192+
[CaueAnjos](https://github.com/caueanjos)
193+
194+
- Add razor support for `roslyn` and `csharp_ls`
195+
188196
<!-- vim: set textwidth=80: -->

modules/plugins/languages/csharp.nix

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
in
2525
optionalString (key != null) "vim.keymap.set('n', '${key}', ${action}, {buffer=bufnr, noremap=true, silent=true, desc='${desc}'})";
2626

27-
# Omnisharp doesn't have colors in popup docs for some reason, and I've also
28-
# seen mentions of it being way slower, so until someone finds missing
29-
# functionality, this will be the default.
30-
defaultServers = ["csharp_ls"];
27+
# NOTE: roslyn is the most feature-rich option, and its Razor integration is better than csharp-ls (which only supports .cshtml).
28+
defaultServers = ["roslyn"];
3129
servers = {
3230
omnisharp = {
3331
cmd = mkLuaInline ''
@@ -118,8 +116,8 @@
118116
};
119117

120118
csharp_ls = {
121-
cmd = [(lib.getExe pkgs.csharp-ls)];
122-
filetypes = ["cs"];
119+
cmd = [(lib.getExe pkgs.csharp-ls) "--features" "razor-support"];
120+
filetypes = ["cs" "razor"];
123121
root_dir = mkLuaInline ''
124122
function(bufnr, on_dir)
125123
local function find_root_pattern(fname, lua_pattern)
@@ -137,17 +135,28 @@
137135
};
138136
};
139137

140-
roslyn_ls = {
138+
roslyn = let
139+
pkg = pkgs.vscode-extensions.ms-dotnettools.csharp;
140+
pluginRoot = "${pkg}/share/vscode/extensions/ms-dotnettools.csharp";
141+
exe = "${pluginRoot}/.roslyn/Microsoft.CodeAnalysis.LanguageServer";
142+
razorSourceGenerator = "${pluginRoot}/.razorExtension/Microsoft.CodeAnalysis.LanguageServer";
143+
razorDesignTimePath = "${pluginRoot}/.razorExtension/Targets/Microsoft.NET.Sdk.Razor.DesignTime.targets";
144+
razorExtension = "${pluginRoot}/.razorExtension/Microsoft.VisualStudioCode.RazorExtension.dll";
145+
in {
141146
cmd = mkLuaInline ''
142147
{
143-
${toLuaObject (getExe pkgs.roslyn-ls)},
144-
'--logLevel=Warning',
145-
'--extensionLogDirectory=' .. vim.fs.dirname(vim.lsp.get_log_path()),
146-
'--stdio',
148+
"dotnet",
149+
"${exe}.dll",
150+
"--stdio",
151+
"--logLevel=Information",
152+
"--extensionLogDirectory=" .. vim.fs.dirname(vim.lsp.get_log_path()),
153+
"--razorSourceGenerator=${razorSourceGenerator}",
154+
"--razorDesignTimePath=${razorDesignTimePath}",
155+
"--extension=${razorExtension}",
147156
}
148157
'';
149158

150-
filetypes = ["cs"];
159+
filetypes = ["cs" "razor"];
151160
root_dir = mkLuaInline ''
152161
function(bufnr, on_dir)
153162
local function find_root_pattern(fname, lua_pattern)
@@ -167,22 +176,58 @@
167176
extraServerPlugins = {
168177
omnisharp = ["omnisharp-extended-lsp-nvim"];
169178
csharp_ls = ["csharpls-extended-lsp-nvim"];
170-
roslyn_ls = [];
179+
roslyn = ["roslyn-nvim"];
171180
};
172181

173182
cfg = config.vim.languages.csharp;
174183
in {
175184
options = {
176185
vim.languages.csharp = {
177-
enable = mkEnableOption "C# language support";
186+
enable = mkEnableOption ''
187+
C# language support.
188+
189+
::: {.note}
190+
This feature will not work if the .NET SDK is not installed.
191+
Both `roslyn` and `csharp_ls` require the .NET SDK 10 to work properly with Razor.
192+
Using the most recent SDK version is strongly recommended.
193+
:::
194+
195+
:::{.tip}
196+
There is a way to avoid always specifying _dotnet-sdk_10_ inside devshells, even when a project targets _dotnet-sdk_8_. You can achieve this by adding the following **Lua** configuration to your **NVF** setup (for example, via `luaConfigRC`):
197+
198+
```lua
199+
vim.lsp.config('roslyn', {
200+
cmd = vim.list_extend(
201+
{ "$${pkgs.lib.getExe (with pkgs.dotnetCorePackages;
202+
combinePackages [
203+
sdk_10_0
204+
sdk_9_0
205+
sdk_8_0
206+
])}" },
207+
vim.list_slice(vim.lsp.config.roslyn.cmd, 2)
208+
)
209+
})
210+
```
211+
This configuration overrides only the first argument of the Roslyn LSP command (the `dotnet` executable), replacing it with a `dotnet` binary built from a combined package that includes SDK versions 10, 9, and 8. Additional SDK versions can be added if needed.
212+
213+
This approach is not a perfect solution. You may encounter issues if your project requires a specific patch version (for example, `8.0.433`) but the combined package only provides an earlier version (such as `8.0.300`). While this usually does not cause major problems, it is something to be aware of when using this setup.
214+
:::
215+
216+
::: {.warning}
217+
At the moment, only `roslyn` provides full Razor support.
218+
`csharp_ls` is limited to `.cshtml` files.
219+
:::
220+
'';
178221

179222
treesitter = {
180223
enable = mkEnableOption "C# treesitter" // {default = config.vim.languages.enableTreesitter;};
181-
package = mkGrammarOption pkgs "c_sharp";
224+
csPackage = mkGrammarOption pkgs "c_sharp";
225+
razorPackage = mkGrammarOption pkgs "razor";
182226
};
183227

184228
lsp = {
185-
enable = mkEnableOption "C# LSP support" // {default = config.vim.lsp.enable;};
229+
enable =
230+
mkEnableOption "C# language support" // {default = config.vim.lsp.enable;};
186231
servers = mkOption {
187232
description = "C# LSP server to use";
188233
type = deprecatedSingleOrListOf "vim.language.csharp.lsp.servers" (enum (attrNames servers));
@@ -195,17 +240,32 @@ in {
195240
config = mkIf cfg.enable (mkMerge [
196241
(mkIf cfg.treesitter.enable {
197242
vim.treesitter.enable = true;
198-
vim.treesitter.grammars = [cfg.treesitter.package];
243+
vim.treesitter.grammars = with cfg.treesitter; [csPackage razorPackage];
199244
})
200245

201246
(mkIf cfg.lsp.enable {
202-
vim.startPlugins = concatMap (server: extraServerPlugins.${server}) cfg.lsp.servers;
203-
vim.lsp.servers =
204-
mapListToAttrs (name: {
205-
inherit name;
206-
value = servers.${name};
207-
})
208-
cfg.lsp.servers;
247+
vim = {
248+
startPlugins = concatMap (server: extraServerPlugins.${server}) cfg.lsp.servers;
249+
luaConfigRC.razorFileTypes =
250+
/*
251+
lua
252+
*/
253+
''
254+
-- Set unkown file types!
255+
vim.filetype.add {
256+
extension = {
257+
razor = "razor",
258+
cshtml = "razor",
259+
},
260+
}
261+
'';
262+
lsp.servers =
263+
mapListToAttrs (name: {
264+
inherit name;
265+
value = servers.${name};
266+
})
267+
cfg.lsp.servers;
268+
};
209269
})
210270
]);
211271
}

npins/sources.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,19 @@
23892389
"url": "https://github.com/rose-pine/neovim/archive/72a04c4065345b51b56aed4859ea1d884f734097.tar.gz",
23902390
"hash": "sha256-CAPZaKFR/WcLW/NW9FNG3jJDnNgzLuwJP+I43ppzkpA="
23912391
},
2392+
"roslyn-nvim": {
2393+
"type": "Git",
2394+
"repository": {
2395+
"type": "GitHub",
2396+
"owner": "seblyng",
2397+
"repo": "roslyn.nvim"
2398+
},
2399+
"branch": "main",
2400+
"submodules": false,
2401+
"revision": "24f7c91ee5e09c63104deaab68f932620f25c24a",
2402+
"url": "https://github.com/seblyng/roslyn.nvim/archive/24f7c91ee5e09c63104deaab68f932620f25c24a.tar.gz",
2403+
"hash": "sha256-a/Slmkrz/4P/rfRhPa1W5kGV7joQNTN0Un7bbncCnk0="
2404+
},
23922405
"rtp-nvim": {
23932406
"type": "Git",
23942407
"repository": {

0 commit comments

Comments
 (0)