What happened?
Description
When opening a projectless directory in VS Code (like an empty folder or the Desktop) and subsequently creating/opening a .cs file, SharpLsp fails to provide any language features (autocomplete, diagnostics, etc.).
Root Cause
When a folder is opened in VS Code, the Rust host eagerly sends a workspace/open request to the sidecars with the directory path. The C# sidecar attempts to find a .sln or .csproj. Upon finding nothing, it delegates to OpenProjectlessAsync(path) in an attempt to load it as a single-file app.
However, because the path is a directory and not a .cs file, OpenProjectlessAsync correctly rejects it and returns a Failure. Because the workspace/open initialization failed, the Rust host skips starting the health monitor for the sidecar, and the C# sidecar gets stuck in a permanent uninitialized state (_solution = null).
Any .cs files opened afterwards have their edits stashed infinitely in UpdateDocumentTextAsync, rendering the extension broken for that session.
Solution
This can be fixed cleanly inside the C# sidecar without requiring changes to the Rust host's eager-loading logic:
- Defer Initialization on Directories: In
WorkspaceManager.OpenCoreAsync, if target is null but the path is a directory, set a flag (_isProjectlessDirectory = true) and return Success. This allows the Rust host to successfully boot the sidecar and start the health monitor.
- Lazy Load on First File: In
WorkspaceManager.UpdateDocumentTextAsync, check if _isProjectlessDirectory is true. If it is, intercept the first .cs file opened, clear the flag, and invoke OpenProjectlessAsync(filePath) with the precise file path before acquiring the _solutionMutationLock.
This restores the single-file mode logic exactly as originally designed, building the ad-hoc workspace around the .cs file as soon as the user opens it.
Steps to reproduce
- Install the SharpLsp extension in VS Code.
- Go to File -> Open Folder... and select a completely empty directory (e.g., a new folder on your Desktop) that does not contain any
.csproj or .sln files.
- Once the folder is open, create a new file named
test.cs.
- Type some C# code into the file (e.g.,
Console.WriteLine();).
- Expected behavior: The extension provides autocomplete, IntelliSense, and diagnostics for the single file.
- Actual behavior: No suggestions or diagnostics appear, and the extension fails to parse the file because the sidecar initialization has died silently in the background.
Component
C# sidecar (Roslyn)
Language
C#
SharpLsp version
0.16.0
Editor & OS
VS Code, Windows
Relevant logs
What happened?
Description
When opening a projectless directory in VS Code (like an empty folder or the Desktop) and subsequently creating/opening a
.csfile, SharpLsp fails to provide any language features (autocomplete, diagnostics, etc.).Root Cause
When a folder is opened in VS Code, the Rust host eagerly sends a
workspace/openrequest to the sidecars with the directory path. The C# sidecar attempts to find a.slnor.csproj. Upon finding nothing, it delegates toOpenProjectlessAsync(path)in an attempt to load it as a single-file app.However, because the
pathis a directory and not a.csfile,OpenProjectlessAsynccorrectly rejects it and returns aFailure. Because theworkspace/openinitialization failed, the Rust host skips starting the health monitor for the sidecar, and the C# sidecar gets stuck in a permanent uninitialized state (_solution = null).Any
.csfiles opened afterwards have their edits stashed infinitely inUpdateDocumentTextAsync, rendering the extension broken for that session.Solution
This can be fixed cleanly inside the C# sidecar without requiring changes to the Rust host's eager-loading logic:
WorkspaceManager.OpenCoreAsync, iftarget is nullbut the path is a directory, set a flag (_isProjectlessDirectory = true) and returnSuccess. This allows the Rust host to successfully boot the sidecar and start the health monitor.WorkspaceManager.UpdateDocumentTextAsync, check if_isProjectlessDirectoryis true. If it is, intercept the first.csfile opened, clear the flag, and invokeOpenProjectlessAsync(filePath)with the precise file path before acquiring the_solutionMutationLock.This restores the single-file mode logic exactly as originally designed, building the ad-hoc workspace around the
.csfile as soon as the user opens it.Steps to reproduce
.csprojor.slnfiles.test.cs.Console.WriteLine();).Component
C# sidecar (Roslyn)
Language
C#
SharpLsp version
0.16.0
Editor & OS
VS Code, Windows
Relevant logs