diff --git a/configuration.nix b/configuration.nix index 832bf95c..cbab23e6 100644 --- a/configuration.nix +++ b/configuration.nix @@ -75,6 +75,7 @@ isMaximal: { enable = isMaximal; crates.enable = isMaximal; }; + csharp.enable = isMaximal; }; visuals = { diff --git a/docs/release-notes/rl-0.7.md b/docs/release-notes/rl-0.7.md index d5f050ab..0d560f82 100644 --- a/docs/release-notes/rl-0.7.md +++ b/docs/release-notes/rl-0.7.md @@ -189,6 +189,9 @@ To migrate to `nixfmt`, simply change `vim.languages.nix.format.type` to - Add sorting function options for completion sources under [](#opt-vim.autocomplete.nvim-cmp.setupOpts.sorting.comparators) +- Add C# support under `vim.languages.csharp`, with support for both + omnisharp-roslyn and csharp-language-server. + [Neovim documentation on `vim.cmd`]: https://neovim.io/doc/user/lua.html#vim.cmd() - Make Neovim's configuration file entirely Lua based. This comes with a few @@ -230,7 +233,8 @@ To migrate to `nixfmt`, simply change `vim.languages.nix.format.type` to `vim.languages.ts.extensions.ts-error-translator` to aid with Typescript development. -- Add [neo-tree.nvim] as an alternative file-tree plugin. It will be available under `vim.filetree.neo-tree`, similar to nvimtree. +- Add [neo-tree.nvim] as an alternative file-tree plugin. It will be available + under `vim.filetree.neo-tree`, similar to nvimtree. - Add `nvf-print-config` & `nvf-print-config-path` helper scripts to Neovim closure. Both of those scripts have been automatically added to your PATH upon @@ -298,5 +302,9 @@ To migrate to `nixfmt`, simply change `vim.languages.nix.format.type` to [nezia1](https://github.com/nezia1): -- Add [biome](https://github.com/biomejs/biome) support for Typescript, CSS and Svelte. Enable them via [](#opt-vim.languages.ts.format.type), [](#opt-vim.languages.css.format.type) and [](#opt-vim.languages.svelte.format.type) respectively. -- Replace [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt) with [nixfmt](https://github.com/NixOS/nixfmt) (nixfmt-rfc-style). +- Add [biome](https://github.com/biomejs/biome) support for Typescript, CSS and + Svelte. Enable them via [](#opt-vim.languages.ts.format.type), + [](#opt-vim.languages.css.format.type) and + [](#opt-vim.languages.svelte.format.type) respectively. +- Replace [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt) with + [nixfmt](https://github.com/NixOS/nixfmt) (nixfmt-rfc-style). diff --git a/flake.lock b/flake.lock index 34a22430..4e5ec65c 100644 --- a/flake.lock +++ b/flake.lock @@ -460,6 +460,22 @@ "type": "github" } }, + "plugin-csharpls-extended": { + "flake": false, + "locked": { + "lastModified": 1728438370, + "narHash": "sha256-sOLPV5IhOvQ0+u7CDAfG3X0ZbRCicz18QyYXQ0dxpwQ=", + "owner": "Decodetalkers", + "repo": "csharpls-extended-lsp.nvim", + "rev": "b647e1bd1f9c0410f5ef4a1517a331cbac322d9a", + "type": "github" + }, + "original": { + "owner": "Decodetalkers", + "repo": "csharpls-extended-lsp.nvim", + "type": "github" + } + }, "plugin-dashboard-nvim": { "flake": false, "locked": { @@ -1453,6 +1469,22 @@ "type": "github" } }, + "plugin-omnisharp-extended": { + "flake": false, + "locked": { + "lastModified": 1719701797, + "narHash": "sha256-P1ZCaW8w+e3H3oBhbEjDc7vuR+XuxJmb/7IbPL3KWi4=", + "owner": "Hoffs", + "repo": "omnisharp-extended-lsp.nvim", + "rev": "aad7bf06b4ca0de816b919d475a75b30f5f62b61", + "type": "github" + }, + "original": { + "owner": "Hoffs", + "repo": "omnisharp-extended-lsp.nvim", + "type": "github" + } + }, "plugin-onedark": { "flake": false, "locked": { @@ -1932,6 +1964,7 @@ "plugin-copilot-cmp": "plugin-copilot-cmp", "plugin-copilot-lua": "plugin-copilot-lua", "plugin-crates-nvim": "plugin-crates-nvim", + "plugin-csharpls-extended": "plugin-csharpls-extended", "plugin-dashboard-nvim": "plugin-dashboard-nvim", "plugin-diffview-nvim": "plugin-diffview-nvim", "plugin-dracula": "plugin-dracula", @@ -1994,6 +2027,7 @@ "plugin-nvim-ts-autotag": "plugin-nvim-ts-autotag", "plugin-nvim-web-devicons": "plugin-nvim-web-devicons", "plugin-obsidian-nvim": "plugin-obsidian-nvim", + "plugin-omnisharp-extended": "plugin-omnisharp-extended", "plugin-onedark": "plugin-onedark", "plugin-orgmode-nvim": "plugin-orgmode-nvim", "plugin-otter-nvim": "plugin-otter-nvim", diff --git a/flake.nix b/flake.nix index d12bdc57..00b56c51 100644 --- a/flake.nix +++ b/flake.nix @@ -211,6 +211,16 @@ flake = false; }; + plugin-omnisharp-extended = { + url = "github:Hoffs/omnisharp-extended-lsp.nvim"; + flake = false; + }; + + plugin-csharpls-extended = { + url = "github:Decodetalkers/csharpls-extended-lsp.nvim"; + flake = false; + }; + # Copying/Registers plugin-registers = { url = "github:tversteeg/registers.nvim"; diff --git a/modules/plugins/languages/csharp.nix b/modules/plugins/languages/csharp.nix new file mode 100644 index 00000000..5011c5cc --- /dev/null +++ b/modules/plugins/languages/csharp.nix @@ -0,0 +1,122 @@ +{ + lib, + pkgs, + config, + options, + ... +}: let + inherit (builtins) attrNames; + inherit (lib.options) mkEnableOption mkOption; + inherit (lib.types) either listOf package str enum; + inherit (lib.modules) mkIf mkMerge; + inherit (lib.lists) isList; + inherit (lib.strings) optionalString; + inherit (lib.nvim.types) mkGrammarOption; + inherit (lib.nvim.lua) expToLua; + + lspKeyConfig = config.vim.lsp.mappings; + lspKeyOptions = options.vim.lsp.mappings; + mkLspBinding = optionName: action: let + key = lspKeyConfig.${optionName}; + desc = lspKeyOptions.${optionName}.description; + 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. + defaultServer = "csharp_ls"; + servers = { + omnisharp = { + package = pkgs.omnisharp-roslyn; + internalFormatter = true; + lspConfig = '' + lspconfig.omnisharp.setup { + capabilities = capabilities, + on_attach = function(client, bufnr) + default_on_attach(client, bufnr) + + local oe = require("omnisharp_extended") + ${mkLspBinding "goToDefinition" "oe.lsp_definition"} + ${mkLspBinding "goToType" "oe.lsp_type_definition"} + ${mkLspBinding "listReferences" "oe.lsp_references"} + ${mkLspBinding "listImplementations" "oe.lsp_implementation"} + end, + cmd = ${ + if isList cfg.lsp.package + then expToLua cfg.lsp.package + else "{'${cfg.lsp.package}/bin/OmniSharp'}" + } + } + ''; + }; + + csharp_ls = { + package = pkgs.csharp-ls; + internalFormatter = true; + lspConfig = '' + local extended_handler = require("csharpls_extended").handler + + lspconfig.csharp_ls.setup { + capabilities = capabilities, + on_attach = default_on_attach, + handlers = { + ["textDocument/definition"] = extended_handler, + ["textDocument/typeDefinition"] = extended_handler + }, + cmd = ${ + if isList cfg.lsp.package + then expToLua cfg.lsp.package + else "{'${cfg.lsp.package}/bin/csharp-ls'}" + } + } + ''; + }; + }; + + extraServerPlugins = { + omnisharp = ["omnisharp-extended"]; + csharp_ls = ["csharpls-extended"]; + }; + + cfg = config.vim.languages.csharp; +in { + options = { + vim.languages.csharp = { + enable = mkEnableOption "C# language support"; + + treesitter = { + enable = mkEnableOption "C# treesitter" // {default = config.vim.languages.enableTreesitter;}; + package = mkGrammarOption pkgs "c-sharp"; + }; + + lsp = { + enable = mkEnableOption "C# LSP support" // {default = config.vim.languages.enableLSP;}; + server = mkOption { + description = "C# LSP server to use"; + type = enum (attrNames servers); + default = defaultServer; + }; + + package = mkOption { + description = "C# LSP server package, or the command to run as a list of strings"; + type = either package (listOf str); + default = servers.${cfg.lsp.server}.package; + }; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf cfg.treesitter.enable { + vim.treesitter.enable = true; + vim.treesitter.grammars = [cfg.treesitter.package]; + }) + + (mkIf cfg.lsp.enable { + vim.startPlugins = extraServerPlugins.${cfg.lsp.server} or []; + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.csharp-lsp = servers.${cfg.lsp.server}.lspConfig; + }) + ]); +} diff --git a/modules/plugins/languages/default.nix b/modules/plugins/languages/default.nix index 54a9e1c4..9dec325b 100644 --- a/modules/plugins/languages/default.nix +++ b/modules/plugins/languages/default.nix @@ -28,6 +28,7 @@ in { ./ts.nix ./typst.nix ./zig.nix + ./csharp.nix ]; options.vim.languages = {