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+ # roslyn is the official language server and the most feature-rich
28+ defaultServers = [ "roslyn" ] ;
3129 servers = {
3230 omnisharp = {
3331 cmd = mkLuaInline ''
4341 }
4442 '' ;
4543 filetypes = [ "cs" "vb" ] ;
46- root_dir = mkLuaInline ''
47- function(bufnr, on_dir)
48- local function find_root_pattern(fname, lua_pattern)
49- return vim.fs.root(0, function(name, path)
50- return name:match(lua_pattern)
51- end)
52- end
53-
54- local fname = vim.api.nvim_buf_get_name(bufnr)
55- on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
56- end
57- '' ;
58- init_options = { } ;
44+ root_marks = [ ".sln" ".csproj" ] ;
5945 capabilities = {
6046 workspace = {
6147 workspaceFolders = false ; # https://github.com/OmniSharp/omnisharp-roslyn/issues/909
120106 csharp_ls = {
121107 cmd = [ ( lib . getExe pkgs . csharp-ls ) ] ;
122108 filetypes = [ "cs" ] ;
123- root_dir = mkLuaInline ''
124- function(bufnr, on_dir)
125- local function find_root_pattern(fname, lua_pattern)
126- return vim.fs.root(0, function(name, path)
127- return name:match(lua_pattern)
128- end)
129- end
130-
131- local fname = vim.api.nvim_buf_get_name(bufnr)
132- on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
133- end
134- '' ;
109+ root_marks = [ ".sln" ".csproj" ] ;
135110 init_options = {
136111 AutomaticWorkspaceInit = true ;
137112 } ;
138113 } ;
139114
140- roslyn_ls = {
141- cmd = mkLuaInline ''
142- {
143- ${ toLuaObject ( getExe pkgs . roslyn-ls ) } ,
144- '--logLevel=Warning',
145- '--extensionLogDirectory=' .. vim.fs.dirname(vim.lsp.get_log_path()),
146- '--stdio',
147- }
148- '' ;
149-
150- filetypes = [ "cs" ] ;
151- root_dir = mkLuaInline ''
152- function(bufnr, on_dir)
153- local function find_root_pattern(fname, lua_pattern)
154- return vim.fs.root(0, function(name, path)
155- return name:match(lua_pattern)
156- end)
157- end
158-
159- local fname = vim.api.nvim_buf_get_name(bufnr)
160- on_dir(find_root_pattern(fname, "%.sln$") or find_root_pattern(fname, "%.csproj$"))
161- end
162- '' ;
163- init_options = { } ;
115+ roslyn = {
116+ # NOTE: cmd is set by roslyn-nvim!
117+ filetypes = [ "cs" "razor" "cshtml" ] ;
118+ root_marks = [ ".sln" ".csproj" ] ;
164119 } ;
165120 } ;
166121
167122 extraServerPlugins = {
168123 omnisharp = [ "omnisharp-extended-lsp-nvim" ] ;
169124 csharp_ls = [ "csharpls-extended-lsp-nvim" ] ;
170- roslyn_ls = [ ] ;
125+ roslyn = [ "roslyn-nvim" ] ;
171126 } ;
172127
173128 cfg = config . vim . languages . csharp ;
174129in {
175130 options = {
176131 vim . languages . csharp = {
177- enable = mkEnableOption "C# language support" ;
132+ enable = mkEnableOption "C# language support. It requires .NET sdk 10 " ;
178133
179134 treesitter = {
180- enable = mkEnableOption "C# treesitter" // { default = config . vim . languages . enableTreesitter ; } ;
181- package = mkGrammarOption pkgs "c-sharp" ;
135+ enable = mkEnableOption "C#/razor treesitter" // { default = config . vim . languages . enableTreesitter ; } ;
136+ csPackage = mkGrammarOption pkgs "c-sharp" ;
137+ razorPackage = mkGrammarOption pkgs "razor" ;
182138 } ;
183139
184140 lsp = {
@@ -195,11 +151,81 @@ in {
195151 config = mkIf cfg . enable ( mkMerge [
196152 ( mkIf cfg . treesitter . enable {
197153 vim . treesitter . enable = true ;
198- vim . treesitter . grammars = [ cfg . treesitter . package ] ;
154+ vim . treesitter . grammars = [ cfg . treesitter . csPackage cfg . treesitter . razorPackage ] ;
155+ } )
156+
157+ ( mkIf ( cfg . lsp . enable && lib . elem "roslyn" cfg . lsp . servers ) {
158+ vim . luaConfigRC . roslyn-path = ''
159+ -- NOTE: this is required by roslyn-nvim to find roslyn
160+ vim.env.PATH = vim.env.PATH .. ":${ pkgs . roslyn-ls } /bin"
161+
162+ -- NOTE: this is required by roslyn-nvim to find .razorExtension folder
163+ -- roslyn-nvim looks for .razorExtension folder using this logic!
164+ -- take a look at https://github.com/seblyng/roslyn.nvim/blob/main/lua/roslyn/health.lua
165+ local razor_extensions_path = "${ pkgs . vscode-extensions . ms-dotnettools . csharp } /share/vscode/extensions/ms-dotnettools.csharp/.razorExtension"
166+
167+ -- Function to check if path exists (including symlinks)
168+ local function path_exists(path)
169+ local stat = vim.uv.fs_lstat(path)
170+ return stat ~= nil
171+ end
172+
173+ -- Function to create symlink
174+ local function create_razor_symlink()
175+ if not razor_extensions_path or razor_extensions_path == "" then
176+ vim.notify("razor_extensions_path is not set", vim.log.levels.WARN)
177+ return
178+ end
179+
180+ -- Check if source path exists
181+ if vim.fn.isdirectory(razor_extensions_path) == 0 then
182+ vim.notify("Source path does not exist: " .. razor_extensions_path, vim.log.levels.ERROR)
183+ return
184+ end
185+
186+ -- Get mason path
187+ vim.env.MASON = vim.fn.expand("~/.local/share/nvf/mason")
188+ local expanded_mason = vim.fn.expand("$MASON")
189+ local mason = expanded_mason == "$MASON"
190+ and vim.fs.joinpath(vim.fn.stdpath("data"), "mason")
191+ or expanded_mason
192+ local mason_packages = vim.fs.joinpath(mason, "packages")
193+
194+ -- Define target paths
195+ local targets = {
196+ vim.fs.joinpath(mason_packages, "roslyn", "libexec", ".razorExtension"),
197+ vim.fs.joinpath(mason_packages, "roslyn-unstable", "libexec", ".razorExtension"),
198+ }
199+
200+ -- Create symlinks for each target
201+ for _, target in ipairs(targets) do
202+ local parent_dir = vim.fn.fnamemodify(target, ":h")
203+
204+ -- Check if parent directory exists
205+ if vim.fn.isdirectory(parent_dir) == 1 then
206+ -- Remove existing symlink or directory
207+ if path_exists(target) then
208+ vim.fn.delete(target, "rf")
209+ end
210+
211+ -- Create symlink
212+ local success = vim.uv.fs_symlink(razor_extensions_path, target, { dir = true })
213+
214+ if not success then
215+ vim.notify("Failed to create symlink for .razorExtension: " .. target, vim.log.levels.ERROR)
216+ end
217+ end
218+ end
219+ end
220+
221+ -- Run the function
222+ create_razor_symlink()
223+ '' ;
199224 } )
200225
201226 ( mkIf cfg . lsp . enable {
202227 vim . startPlugins = concatMap ( server : extraServerPlugins . ${ server } ) cfg . lsp . servers ;
228+
203229 vim . lsp . servers =
204230 mapListToAttrs ( name : {
205231 inherit name ;
0 commit comments