diff --git a/docs/manual/release-notes/rl-0.9.md b/docs/manual/release-notes/rl-0.9.md index 651f9f4e..607ad42f 100644 --- a/docs/manual/release-notes/rl-0.9.md +++ b/docs/manual/release-notes/rl-0.9.md @@ -185,4 +185,9 @@ https://github.com/gorbit99/codewindow.nvim - Fix non-functional `vim.keymaps.*.noremap`. Now, setting it to false is equivalent to `:lua vim.keymap.set(..., { remap = true })` +[CaueAnjos](https://github.com/caueanjos) + +- Rename `roslyn_ls` to `roslyn` (required by roslyn-nvim). +- Add razor support for `roslyn` and `csharp_ls` + diff --git a/modules/neovim/init/lsp.nix b/modules/neovim/init/lsp.nix index b17c5554..654f9ba1 100644 --- a/modules/neovim/init/lsp.nix +++ b/modules/neovim/init/lsp.nix @@ -16,6 +16,36 @@ cfg = config.vim.lsp; + # NOTE: Used to notify and redirect deprecated lsp servers + mkDeprecated = { + old, + new ? null, + message ? ( + if new == null + then "${old} is deprecated." + else "${old} was renamed to ${new}. Please update it accordingly." + ), + }: ( + lib.warnIf + (cfg.servers.${old} + != {}) + message + { + ${old}.enable = false; + } + // (mkIf (new != null) { + ${new} = cfg.servers.${old}; + }) + ); + + servers = + cfg.servers + # Deprecated lsp servers + // (mkDeprecated { + old = "roslyn_ls"; + new = "roslyn"; + }); + # TODO: lspConfigurations filter on enabledServers instead of cfg.servers? lspConfigurations = mapAttrsToList ( @@ -23,9 +53,9 @@ vim.lsp.config["${name}"] = ${toLuaObject value} '' ) - cfg.servers; + servers; - enabledServers = filterAttrs (_: u: u.enable) cfg.servers; + enabledServers = filterAttrs (_: u: u.enable) servers; in { options = { vim.lsp = { diff --git a/modules/plugins/languages/csharp.nix b/modules/plugins/languages/csharp.nix index ef973301..583a14d2 100644 --- a/modules/plugins/languages/csharp.nix +++ b/modules/plugins/languages/csharp.nix @@ -24,10 +24,8 @@ in optionalString (key != null) "vim.keymap.set('n', '${key}', ${action}, {buffer=bufnr, noremap=true, silent=true, desc='${desc}'})"; - # Omnisharp doesn't have colors in popup docs for some reason, and I've also - # seen mentions of it being way slower, so until someone finds missing - # functionality, this will be the default. - defaultServers = ["csharp_ls"]; + # NOTE: roslyn is the most feature-rich option, and its Razor integration is better than csharp-ls (which only supports .cshtml). + defaultServers = ["roslyn"]; servers = { omnisharp = { cmd = mkLuaInline '' @@ -118,8 +116,8 @@ }; csharp_ls = { - cmd = [(lib.getExe pkgs.csharp-ls)]; - filetypes = ["cs"]; + cmd = [(lib.getExe pkgs.csharp-ls) "--features" "razor-support"]; + filetypes = ["cs" "razor"]; root_dir = mkLuaInline '' function(bufnr, on_dir) local function find_root_pattern(fname, lua_pattern) @@ -137,17 +135,28 @@ }; }; - roslyn_ls = { + roslyn = let + pkg = pkgs.vscode-extensions.ms-dotnettools.csharp; + pluginRoot = "${pkg}/share/vscode/extensions/ms-dotnettools.csharp"; + exe = "${pluginRoot}/.roslyn/Microsoft.CodeAnalysis.LanguageServer"; + razorSourceGenerator = "${pluginRoot}/.razorExtension/Microsoft.CodeAnalysis.LanguageServer"; + razorDesignTimePath = "${pluginRoot}/.razorExtension/Targets/Microsoft.NET.Sdk.Razor.DesignTime.targets"; + razorExtension = "${pluginRoot}/.razorExtension/Microsoft.VisualStudioCode.RazorExtension.dll"; + in { cmd = mkLuaInline '' { - ${toLuaObject (getExe pkgs.roslyn-ls)}, - '--logLevel=Warning', - '--extensionLogDirectory=' .. vim.fs.dirname(vim.lsp.get_log_path()), - '--stdio', + "dotnet", + "${exe}.dll", + "--stdio", + "--logLevel=Information", + "--extensionLogDirectory=" .. vim.fs.dirname(vim.lsp.get_log_path()), + "--razorSourceGenerator=${razorSourceGenerator}", + "--razorDesignTimePath=${razorDesignTimePath}", + "--extension=${razorExtension}", } ''; - filetypes = ["cs"]; + filetypes = ["cs" "razor"]; root_dir = mkLuaInline '' function(bufnr, on_dir) local function find_root_pattern(fname, lua_pattern) @@ -167,22 +176,58 @@ extraServerPlugins = { omnisharp = ["omnisharp-extended-lsp-nvim"]; csharp_ls = ["csharpls-extended-lsp-nvim"]; - roslyn_ls = []; + roslyn = ["roslyn-nvim"]; }; cfg = config.vim.languages.csharp; in { options = { vim.languages.csharp = { - enable = mkEnableOption "C# language support"; + enable = mkEnableOption '' + C# language support. + + ::: {.note} + This feature will not work if the .NET SDK is not installed. + Both `roslyn` and `csharp_ls` require the .NET SDK 10 to work properly with Razor. + Using the most recent SDK version is strongly recommended. + ::: + + :::{.tip} + 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`): + + ```lua + vim.lsp.config('roslyn', { + cmd = vim.list_extend( + { "$${pkgs.lib.getExe (with pkgs.dotnetCorePackages; + combinePackages [ + sdk_10_0 + sdk_9_0 + sdk_8_0 + ])}" }, + vim.list_slice(vim.lsp.config.roslyn.cmd, 2) + ) + }) + ``` + 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. + + 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. + ::: + + ::: {.warning} + At the moment, only `roslyn` provides full Razor support. + `csharp_ls` is limited to `.cshtml` files. + ::: + ''; treesitter = { enable = mkEnableOption "C# treesitter" // {default = config.vim.languages.enableTreesitter;}; - package = mkGrammarOption pkgs "c_sharp"; + csPackage = mkGrammarOption pkgs "c_sharp"; + razorPackage = mkGrammarOption pkgs "razor"; }; lsp = { - enable = mkEnableOption "C# LSP support" // {default = config.vim.lsp.enable;}; + enable = + mkEnableOption "C# language support" // {default = config.vim.lsp.enable;}; servers = mkOption { description = "C# LSP server to use"; type = deprecatedSingleOrListOf "vim.language.csharp.lsp.servers" (enum (attrNames servers)); @@ -195,17 +240,32 @@ in { config = mkIf cfg.enable (mkMerge [ (mkIf cfg.treesitter.enable { vim.treesitter.enable = true; - vim.treesitter.grammars = [cfg.treesitter.package]; + vim.treesitter.grammars = with cfg.treesitter; [csPackage razorPackage]; }) (mkIf cfg.lsp.enable { - vim.startPlugins = concatMap (server: extraServerPlugins.${server}) cfg.lsp.servers; - vim.lsp.servers = - mapListToAttrs (name: { - inherit name; - value = servers.${name}; - }) - cfg.lsp.servers; + vim = { + startPlugins = concatMap (server: extraServerPlugins.${server}) cfg.lsp.servers; + luaConfigRC.razorFileTypes = + /* + lua + */ + '' + -- Set unkown file types! + vim.filetype.add { + extension = { + razor = "razor", + cshtml = "razor", + }, + } + ''; + lsp.servers = + mapListToAttrs (name: { + inherit name; + value = servers.${name}; + }) + cfg.lsp.servers; + }; }) ]); } diff --git a/npins/sources.json b/npins/sources.json index d9d1f9cc..26052bc2 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -2389,6 +2389,19 @@ "url": "https://github.com/rose-pine/neovim/archive/72a04c4065345b51b56aed4859ea1d884f734097.tar.gz", "hash": "sha256-CAPZaKFR/WcLW/NW9FNG3jJDnNgzLuwJP+I43ppzkpA=" }, + "roslyn-nvim": { + "type": "Git", + "repository": { + "type": "GitHub", + "owner": "seblyng", + "repo": "roslyn.nvim" + }, + "branch": "main", + "submodules": false, + "revision": "24f7c91ee5e09c63104deaab68f932620f25c24a", + "url": "https://github.com/seblyng/roslyn.nvim/archive/24f7c91ee5e09c63104deaab68f932620f25c24a.tar.gz", + "hash": "sha256-a/Slmkrz/4P/rfRhPa1W5kGV7joQNTN0Un7bbncCnk0=" + }, "rtp-nvim": { "type": "Git", "repository": {