Skip to content

Commit 5025403

Browse files
authored
Make cohosting win over legacy editor (#11959)
Fixes #11941 This change means that if cohosting is on, we'll always use LSP, except for .NET Framework projects which will fall back to the really really legacy legacy editor. That editor has no interaction with any of our code, except the VS editor does send us a couple of LSP methods (because dynamic registration is by file extension, not content type) so we have to be a tiny bit defensive.
2 parents 1212a45 + 5280119 commit 5025403

File tree

8 files changed

+68
-23
lines changed

8 files changed

+68
-23
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/DocumentSymbol/CohostDocumentSymbolEndpoint.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Composition;
66
using System.Threading;
77
using System.Threading.Tasks;
8-
using Microsoft.AspNetCore.Razor;
8+
using Microsoft.AspNetCore.Razor.Threading;
99
using Microsoft.CodeAnalysis;
1010
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
1111
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
@@ -50,7 +50,16 @@ public ImmutableArray<Registration> GetRegistrations(VSInternalClientCapabilitie
5050
=> request.TextDocument.ToRazorTextDocumentIdentifier();
5151

5252
protected override Task<SumType<DocumentSymbol[], SymbolInformation[]>?> HandleRequestAsync(DocumentSymbolParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
53-
=> HandleRequestAsync(context.TextDocument.AssumeNotNull(), _useHierarchicalSymbols, cancellationToken);
53+
{
54+
// The editor can send us a document symbol request in a .NET Framework project for some reason, so we have to be
55+
// a little defensive here.
56+
if (context.TextDocument is null)
57+
{
58+
return SpecializedTasks.Default<SumType<DocumentSymbol[], SymbolInformation[]>?>();
59+
}
60+
61+
return HandleRequestAsync(context.TextDocument, _useHierarchicalSymbols, cancellationToken);
62+
}
5463

5564
private async Task<SumType<DocumentSymbol[], SymbolInformation[]>?> HandleRequestAsync(TextDocument razorDocument, bool useHierarchicalSymbols, CancellationToken cancellationToken)
5665
{

src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/LinkedEditingRange/CohostLinkedEditingRangeEndpoint.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Composition;
66
using System.Threading;
77
using System.Threading.Tasks;
8-
using Microsoft.AspNetCore.Razor;
8+
using Microsoft.AspNetCore.Razor.Threading;
99
using Microsoft.CodeAnalysis;
1010
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
1111
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
@@ -50,7 +50,16 @@ public ImmutableArray<Registration> GetRegistrations(VSInternalClientCapabilitie
5050
=> request.TextDocument.ToRazorTextDocumentIdentifier();
5151

5252
protected override Task<LinkedEditingRanges?> HandleRequestAsync(LinkedEditingRangeParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
53-
=> HandleRequestAsync(request, context.TextDocument.AssumeNotNull(), cancellationToken);
53+
{
54+
// The editor can send us a linked editing range request in a .NET Framework project for some reason, so we have to be
55+
// a little defensive here.
56+
if (context.TextDocument is null)
57+
{
58+
return SpecializedTasks.Null<LinkedEditingRanges>();
59+
}
60+
61+
return HandleRequestAsync(request, context.TextDocument, cancellationToken);
62+
}
5463

5564
private async Task<LinkedEditingRanges?> HandleRequestAsync(LinkedEditingRangeParams request, TextDocument razorDocument, CancellationToken cancellationToken)
5665
{

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ILspEditorFeatureDetector.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ internal interface ILspEditorFeatureDetector
1616
/// </summary>
1717
bool IsLspEditorSupported(string documentFilePath);
1818

19+
/// <summary>
20+
/// Determines whether the project containing the given document is a .NET Core project.
21+
/// </summary>
22+
bool IsDotNetCoreProject(string documentFilePath);
23+
1924
/// <summary>
2025
/// A remote client is a LiveShare guest or a Codespaces instance
2126
/// </summary>

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSHTMLFilePathToContentTypeProvider.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

44
using System.ComponentModel.Composition;
5+
using Microsoft.CodeAnalysis.Razor.Workspaces;
56
using Microsoft.VisualStudio.Utilities;
67

78
namespace Microsoft.VisualStudio.Razor.LanguageClient;
@@ -12,7 +13,8 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient;
1213
[method: ImportingConstructor]
1314
internal class CSHTMLFilePathToContentTypeProvider(
1415
IContentTypeRegistryService contentTypeRegistryService,
15-
ILspEditorFeatureDetector lspEditorFeatureDetector)
16-
: RazorFilePathToContentTypeProviderBase(contentTypeRegistryService, lspEditorFeatureDetector)
16+
ILspEditorFeatureDetector lspEditorFeatureDetector,
17+
LanguageServerFeatureOptions options)
18+
: RazorFilePathToContentTypeProviderBase(contentTypeRegistryService, lspEditorFeatureDetector, options)
1719
{
1820
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorFilePathToContentTypeProvider.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

44
using System.ComponentModel.Composition;
5+
using Microsoft.CodeAnalysis.Razor.Workspaces;
56
using Microsoft.VisualStudio.Utilities;
67

78
namespace Microsoft.VisualStudio.Razor.LanguageClient;
@@ -12,7 +13,8 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient;
1213
[method: ImportingConstructor]
1314
internal class RazorFilePathToContentTypeProvider(
1415
IContentTypeRegistryService contentTypeRegistryService,
15-
ILspEditorFeatureDetector lspEditorFeatureDetector)
16-
: RazorFilePathToContentTypeProviderBase(contentTypeRegistryService, lspEditorFeatureDetector)
16+
ILspEditorFeatureDetector lspEditorFeatureDetector,
17+
LanguageServerFeatureOptions options)
18+
: RazorFilePathToContentTypeProviderBase(contentTypeRegistryService, lspEditorFeatureDetector, options)
1719
{
1820
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorFilePathToContentTypeProviderBase.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,49 @@
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

44
using System.Diagnostics.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.Razor.Workspaces;
56
using Microsoft.VisualStudio.Utilities;
67

78
namespace Microsoft.VisualStudio.Razor.LanguageClient;
89

9-
internal abstract class RazorFilePathToContentTypeProviderBase : IFilePathToContentTypeProvider
10+
internal abstract class RazorFilePathToContentTypeProviderBase(
11+
IContentTypeRegistryService contentTypeRegistryService,
12+
ILspEditorFeatureDetector lspEditorFeatureDetector,
13+
LanguageServerFeatureOptions options) : IFilePathToContentTypeProvider
1014
{
11-
private readonly IContentTypeRegistryService _contentTypeRegistryService;
12-
private readonly ILspEditorFeatureDetector _lspEditorFeatureDetector;
15+
private readonly IContentTypeRegistryService _contentTypeRegistryService = contentTypeRegistryService;
16+
private readonly ILspEditorFeatureDetector _lspEditorFeatureDetector = lspEditorFeatureDetector;
17+
private readonly LanguageServerFeatureOptions _options = options;
1318

14-
public RazorFilePathToContentTypeProviderBase(
15-
IContentTypeRegistryService contentTypeRegistryService,
16-
ILspEditorFeatureDetector lspEditorFeatureDetector)
19+
public bool TryGetContentTypeForFilePath(string filePath, [NotNullWhen(true)] out IContentType? contentType)
1720
{
18-
_contentTypeRegistryService = contentTypeRegistryService;
19-
_lspEditorFeatureDetector = lspEditorFeatureDetector;
21+
if (UseLSPEditor(filePath))
22+
{
23+
contentType = _contentTypeRegistryService.GetContentType(RazorConstants.RazorLSPContentTypeName);
24+
return true;
25+
}
26+
27+
contentType = null;
28+
return false;
2029
}
2130

22-
public bool TryGetContentTypeForFilePath(string filePath, [NotNullWhen(true)] out IContentType? contentType)
31+
private bool UseLSPEditor(string filePath)
2332
{
33+
// When cohosting is on, it's on for all non .NET Framework projects, regardless of feature flags or
34+
// project capabilities.
35+
if (_options.UseRazorCohostServer &&
36+
_lspEditorFeatureDetector.IsDotNetCoreProject(filePath))
37+
{
38+
return true;
39+
}
40+
41+
// Otherwise, we just check for the lack of feature flag feature or project capability.
2442
if (_lspEditorFeatureDetector.IsLspEditorEnabled() &&
2543
_lspEditorFeatureDetector.IsLspEditorSupported(filePath))
2644
{
27-
contentType = _contentTypeRegistryService.GetContentType(RazorConstants.RazorLSPContentTypeName);
2845
return true;
2946
}
3047

31-
contentType = null;
3248
return false;
3349
}
3450
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LspEditorFeatureDetector.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,19 @@ public bool IsLspEditorSupported(string documentFilePath)
103103
return false;
104104
}
105105

106-
var supportsRazor = _projectCapabilityResolver.ResolveCapability(WellKnownProjectCapabilities.DotNetCoreCSharp, documentFilePath);
107-
108-
if (!supportsRazor)
106+
if (!IsDotNetCoreProject(documentFilePath))
109107
{
110108
_activityLog.LogInfo($"'{documentFilePath}' does not support the LSP editor because it is not associated with the '{WellKnownProjectCapabilities.DotNetCoreCSharp}' capability.");
111109
return false;
112110
}
113111

114112
_activityLog.LogInfo($"LSP editor is supported for '{documentFilePath}'.");
115-
return supportsRazor;
113+
return true;
116114
}
117115

116+
public bool IsDotNetCoreProject(string documentFilePath)
117+
=> _projectCapabilityResolver.ResolveCapability(WellKnownProjectCapabilities.DotNetCoreCSharp, documentFilePath);
118+
118119
public bool IsRemoteClient()
119120
=> _uiContextService.IsActive(Guids.LiveShareGuestUIContextGuid) ||
120121
_uiContextService.IsActive(VSConstants.UICONTEXT.CloudEnvironmentConnected_guid);

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ private class TestLspEditorFeatureDetector : ILspEditorFeatureDetector
166166
public bool IsLiveShareHost() => throw new NotImplementedException();
167167
public bool IsLspEditorEnabled() => throw new NotImplementedException();
168168
public bool IsLspEditorSupported(string documentFilePath) => throw new NotImplementedException();
169+
public bool IsDotNetCoreProject(string documentFilePath) => throw new NotImplementedException();
169170
public bool IsRemoteClient() => throw new NotImplementedException();
170171
}
171172

0 commit comments

Comments
 (0)