Skip to content

Commit 05e49aa

Browse files
authored
Allow Razor files to be additional documents in a misc files project (#78267)
Fixes a startup crash in VS Code if a .razor or .cshtml file is restored in the workspace. Part of dotnet/razor#11759
2 parents 42c13fd + 77b0cd9 commit 05e49aa

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ internal static ProjectInfo CreateMiscellaneousProjectInfoForDocument(
2727
var fileExtension = PathUtilities.GetExtension(filePath);
2828
var fileName = PathUtilities.GetFileName(filePath);
2929

30-
var languageServices = services.GetLanguageServices(languageInformation.LanguageName);
30+
// For Razor files we need to override the language name to C# as thats what code is generated
31+
var isRazor = languageInformation.LanguageName == "Razor";
32+
var languageName = isRazor ? LanguageNames.CSharp : languageInformation.LanguageName;
33+
34+
var languageServices = services.GetLanguageServices(languageName);
3135
var compilationOptions = languageServices.GetService<ICompilationFactoryService>()?.GetDefaultCompilationOptions();
3236

3337
// Use latest language version which is more permissive, as we cannot find out language version of the project which the file belongs to
@@ -63,15 +67,16 @@ internal static ProjectInfo CreateMiscellaneousProjectInfoForDocument(
6367
version: VersionStamp.Create(),
6468
name: FeaturesResources.Miscellaneous_Files,
6569
assemblyName: assemblyName,
66-
language: languageInformation.LanguageName,
70+
language: languageName,
6771
compilationOutputInfo: default,
6872
checksumAlgorithm: checksumAlgorithm,
6973
// Miscellaneous files projects are never fully loaded since, by definition, it won't know
7074
// what the full set of information is except when the file is script code.
7175
hasAllInformation: sourceCodeKind == SourceCodeKind.Script),
7276
compilationOptions: compilationOptions,
7377
parseOptions: parseOptions,
74-
documents: [documentInfo],
78+
documents: isRazor ? null : [documentInfo],
79+
additionalDocuments: isRazor ? [documentInfo] : null,
7580
metadataReferences: metadataReferences);
7681

7782
return projectInfo;

src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, I
3636
/// Calls to this method and <see cref="TryRemoveMiscellaneousDocument(Uri, bool)"/> are made
3737
/// from LSP text sync request handling which do not run concurrently.
3838
/// </summary>
39-
public Document? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger)
39+
public TextDocument? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger)
4040
{
4141
var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri);
4242

@@ -63,6 +63,12 @@ internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, I
6363
this, documentFilePath, sourceTextLoader, languageInformation, documentText.ChecksumAlgorithm, Services.SolutionServices, []);
6464
OnProjectAdded(projectInfo);
6565

66+
if (languageInformation.LanguageName == "Razor")
67+
{
68+
var docId = projectInfo.AdditionalDocuments.Single().Id;
69+
return CurrentSolution.GetRequiredAdditionalDocument(docId);
70+
}
71+
6672
var id = projectInfo.Documents.Single().Id;
6773
return CurrentSolution.GetRequiredDocument(id);
6874
}

src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,34 @@ void M()
180180
Assert.Null(GetMiscellaneousDocument(testLspServer));
181181
}
182182

183+
[Theory, CombinatorialData]
184+
public async Task TestLooseFile_RazorFile(bool mutatingLspWorkspace)
185+
{
186+
var source = "<div></div>";
187+
188+
// Create a server that supports LSP misc files and verify no misc files present.
189+
await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer });
190+
Assert.Null(GetMiscellaneousDocument(testLspServer));
191+
Assert.Null(GetMiscellaneousAdditionalDocument(testLspServer));
192+
193+
// Open an empty loose file and make a request to verify it gets added to the misc workspace.
194+
var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.razor");
195+
await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false);
196+
197+
// Trigger a request and assert we got a file in the misc workspace.
198+
await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false);
199+
Assert.Null(GetMiscellaneousDocument(testLspServer));
200+
Assert.NotNull(GetMiscellaneousAdditionalDocument(testLspServer));
201+
202+
// Trigger another request and assert we got a file in the misc workspace.
203+
await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false);
204+
Assert.NotNull(GetMiscellaneousAdditionalDocument(testLspServer));
205+
206+
await testLspServer.CloseDocumentAsync(looseFileUri).ConfigureAwait(false);
207+
Assert.Null(GetMiscellaneousDocument(testLspServer));
208+
Assert.Null(GetMiscellaneousAdditionalDocument(testLspServer));
209+
}
210+
183211
[Theory, CombinatorialData]
184212
public async Task TestLooseFile_RequestedTwiceAndClosed(bool mutatingLspWorkspace)
185213
{
@@ -306,7 +334,12 @@ private static async Task AssertFileInMainWorkspaceAsync(TestLspServer testLspSe
306334

307335
private static Document? GetMiscellaneousDocument(TestLspServer testLspServer)
308336
{
309-
return testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()!.CurrentSolution.Projects.SingleOrDefault()?.Documents.Single();
337+
return testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()!.CurrentSolution.Projects.SingleOrDefault()?.Documents.SingleOrDefault();
338+
}
339+
340+
private static TextDocument? GetMiscellaneousAdditionalDocument(TestLspServer testLspServer)
341+
{
342+
return testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()!.CurrentSolution.Projects.SingleOrDefault()?.AdditionalDocuments.SingleOrDefault();
310343
}
311344

312345
private static async Task<LSP.Hover> RunGetHoverAsync(TestLspServer testLspServer, LSP.Location caret)

0 commit comments

Comments
 (0)