csharp-language-server icon indicating copy to clipboard operation
csharp-language-server copied to clipboard

Hot Reload package for Unity causes csharp-ls to stop working due to recreated solution files

Open midsbie opened this issue 1 year ago • 2 comments

I'm seeing an issue where using the Hot Reload package for Unity causes csharp-ls to stop working for a workspace.

This issue is caused by the Hot Reload package re-creating the workspace's sln and csproj files under <root>/Library/com.singularitygroup.hotreload/Solution, resulting in these files being duplicated since they normally exist in the workspace's root directory. This results in csharp-ls picking up the newly generated files, integrating them and starting to malfunction. Here are some of the JSON-RPC logs after it starts malfunctioning:

[jsonrpc] e[14:15:22.983] <-- textDocument/inlayHint[5] {"jsonrpc":"2.0","id":5,"result":null}
[jsonrpc] e[14:15:22.983] <-- textDocument/signatureHelp[4] {"jsonrpc":"2.0","id":4,"result":null}
[jsonrpc] e[14:15:22.983] <-- textDocument/hover[2] {"jsonrpc":"2.0","id":2,"result":null}

I've looked at the csharp-ls codebase but couldn't find any configuration options that would allow me to ignore specific directories or files. Is there a way to configure csharp-ls to exclude these directories, or is such functionality not yet implemented?

midsbie avatar Oct 06 '24 13:10 midsbie

The diff below works. It makes it so csharp-ls ignores the duplicate solution and project files normally found under a com.singularitygroup.hotreload directory. A better solution would be to read this from a configuration file though.

modified   src/CSharpLanguageServer/RoslynHelpers.fs
@@ -463,14 +463,15 @@ let findAndLoadSolutionOnDir
         (logger: ILog)
         dir =
     async {
-        let fileNotOnNodeModules (filename: string) =
+        let ignoredDirectories = ["node_modules"; "com.singularitygroup.hotreload"]
+
+        let fileNotInIgnoredDirectories (filename: string) =
             filename.Split(Path.DirectorySeparatorChar)
-            |> Seq.contains "node_modules"
-            |> not
+            |> Seq.forall (fun segment -> not (List.contains segment ignoredDirectories))
 
         let solutionFiles =
             Directory.GetFiles(dir, "*.sln", SearchOption.AllDirectories)
-            |> Seq.filter fileNotOnNodeModules
+            |> Seq.filter fileNotInIgnoredDirectories
             |> Seq.toList
 
         let showMessage m =
@@ -496,7 +497,7 @@ let findAndLoadSolutionOnDir
                 let fsprojFiles = Directory.GetFiles(dir, "*.fsproj", SearchOption.AllDirectories)
 
                 [ csprojFiles; fsprojFiles ] |> Seq.concat
-                                                |> Seq.filter fileNotOnNodeModules
+                                                |> Seq.filter fileNotInIgnoredDirectories
                                                 |> Seq.toList
 
             if projFiles.Length = 0 then

midsbie avatar Oct 14 '24 10:10 midsbie

I wouldn't mind improving on the above to make it configurable but would need to know what an acceptable path might be to achieve this, @razzmatazz .

midsbie avatar Oct 14 '24 10:10 midsbie