Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Cohost feature branch into main #9786

Merged
merged 32 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5819e8c
Use constructor injection
davidwengier Dec 23, 2023
93f886d
Use primary constructor
davidwengier Dec 23, 2023
c44a260
Move logic from endpoint into service
davidwengier Dec 23, 2023
de081ab
Move IClientConnection to a parameter to prepare for cohosting
davidwengier Dec 23, 2023
0755188
Use primary constructor
davidwengier Dec 23, 2023
d216f26
Create cohost endpoint
davidwengier Dec 23, 2023
0e6bd17
Disable semantic tokens in regular server
davidwengier Dec 23, 2023
16615ce
Move options retreival code out into the endpoints
davidwengier Dec 23, 2023
0e9d0b3
Update tests and benchmarks
davidwengier Dec 23, 2023
b80e428
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Dec 24, 2023
7f258ab
Merge branch 'features/cohost' into dev/dawengie/SemanticTokensCohost
davidwengier Dec 24, 2023
bf504f3
Updates after merge
davidwengier Dec 24, 2023
b9e9532
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Dec 25, 2023
ad2fe27
Merge branch 'features/cohost' into dev/dawengie/SemanticTokensCohost
davidwengier Dec 25, 2023
18bc37c
Do code generation as soon as a document opens or changes in cohosting
davidwengier Dec 27, 2023
4398c6a
Don't publish document changes from the LSP server when cohosting is on
davidwengier Dec 27, 2023
34f01cd
Prevent accidental regressions
davidwengier Dec 27, 2023
78ad08f
Regenerate open documents when the project changes
davidwengier Dec 27, 2023
350f67d
Add feature flag to disable the non-cohost server
davidwengier Dec 24, 2023
fb37276
Don't start the language server if the feature flag is off
davidwengier Dec 27, 2023
be23375
Port semantic tokens range endpoint to cohost server (#9761)
davidwengier Dec 27, 2023
f922bc1
Missed PR feedback
davidwengier Dec 27, 2023
ed7eb9b
Add feature flag to disable the Razor LSP, leaving only cohosting (#9…
davidwengier Dec 27, 2023
9f1a342
Missed PR feedback from Semantic Tokens PR (#9769)
davidwengier Dec 27, 2023
8f51c5e
PR Feedback
davidwengier Dec 28, 2023
a5d1c6f
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Dec 28, 2023
2ded3ad
Move C# and Html document generation (ie, compilation) to the Cohost …
davidwengier Dec 28, 2023
50911ca
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Jan 1, 2024
dd99886
Typo
davidwengier Jan 3, 2024
8214697
Fix typo (#9779)
davidwengier Jan 3, 2024
90fe324
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Jan 4, 2024
1f6d05d
Merge remote-tracking branch 'upstream/main' into features/cohost
davidwengier Jan 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ public class RazorSemanticTokensBenchmark : RazorLanguageServerBenchmarkBase

private ProjectSnapshotManagerDispatcher ProjectSnapshotManagerDispatcher { get; set; }

private RazorSemanticTokensLegend SemanticTokensLegend { get; set; }

private string PagesDirectory { get; set; }

private string ProjectFilePath { get; set; }
Expand Down Expand Up @@ -81,8 +79,6 @@ public async Task InitializeRazorSemanticAsync()
Character = text.Lines.Last().Span.Length - 1
}
};

SemanticTokensLegend = new RazorSemanticTokensLegend(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });
}

[Benchmark(Description = "Razor Semantic Tokens Range Handling")]
Expand All @@ -94,11 +90,12 @@ public async Task RazorSemanticTokensRangeAsync()
};
var cancellationToken = CancellationToken.None;
var documentVersion = 1;
var correlationId = Guid.Empty;

await UpdateDocumentAsync(documentVersion, DocumentSnapshot, cancellationToken).ConfigureAwait(false);

var clientConnection = RazorLanguageServer.GetRequiredService<IClientConnection>();
await RazorSemanticTokenService.GetSemanticTokensAsync(
textDocumentIdentifier, Range, DocumentContext, SemanticTokensLegend, correlationId, cancellationToken).ConfigureAwait(false);
clientConnection, textDocumentIdentifier, Range, DocumentContext, colorBackground: false, cancellationToken).ConfigureAwait(false);
}

private async Task UpdateDocumentAsync(int newVersion, IDocumentSnapshot documentSnapshot, CancellationToken cancellationToken)
Expand All @@ -124,28 +121,29 @@ private void EnsureServicesInitialized()
{
var languageServer = RazorLanguageServer.GetInnerLanguageServerForTesting();
RazorSemanticTokenService = languageServer.GetRequiredService<IRazorSemanticTokensInfoService>();
RazorSemanticTokenService.ApplyCapabilities(new(), new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true });
VersionCache = languageServer.GetRequiredService<IDocumentVersionCache>();
ProjectSnapshotManagerDispatcher = languageServer.GetRequiredService<ProjectSnapshotManagerDispatcher>();
}

internal class TestRazorSemanticTokensInfoService : RazorSemanticTokensInfoService
{
public TestRazorSemanticTokensInfoService(
IClientConnection clientConnection,
LanguageServerFeatureOptions languageServerFeatureOptions,
IRazorDocumentMappingService documentMappingService,
RazorLSPOptionsMonitor razorLSPOptionsMonitor,
IRazorLoggerFactory loggerFactory)
: base(clientConnection, documentMappingService, razorLSPOptionsMonitor, languageServerFeatureOptions, loggerFactory)
: base(documentMappingService, languageServerFeatureOptions, loggerFactory, telemetryReporter: null)
{
}

// We can't get C# responses without significant amounts of extra work, so let's just shim it for now, any non-Null result is fine.
internal override Task<ImmutableArray<SemanticRange>?> GetCSharpSemanticRangesAsync(
IClientConnection clientConnection,
RazorCodeDocument codeDocument,
TextDocumentIdentifier textDocumentIdentifier,
Range razorRange,
RazorSemanticTokensLegend razorSemanticTokensLegend,
bool colorBackground,
long documentVersion,
Guid correlationId,
CancellationToken cancellationToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ public async Task InitializeRazorSemanticAsync()
var documentSnapshot = GetDocumentSnapshot(ProjectFilePath, filePath, TargetPath);
var version = 1;
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version);
SemanticTokensRangeEndpoint = new SemanticTokensRangeEndpoint(loggerFactory, telemetryReporter: null);

var razorOptionsMonitor = RazorLanguageServer.GetRequiredService<RazorLSPOptionsMonitor>();
var clientConnection = RazorLanguageServer.GetRequiredService<IClientConnection>();
SemanticTokensRangeEndpoint = new SemanticTokensRangeEndpoint(RazorSemanticTokenService, razorOptionsMonitor, clientConnection);
SemanticTokensRangeEndpoint.ApplyCapabilities(new(), new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });

var text = await DocumentContext.GetSourceTextAsync(CancellationToken.None).ConfigureAwait(false);
Expand Down Expand Up @@ -150,21 +153,21 @@ private void EnsureServicesInitialized()
internal class TestCustomizableRazorSemanticTokensInfoService : RazorSemanticTokensInfoService
{
public TestCustomizableRazorSemanticTokensInfoService(
IClientConnection clientConnection,
LanguageServerFeatureOptions languageServerFeatureOptions,
IRazorDocumentMappingService documentMappingService,
RazorLSPOptionsMonitor razorLSPOptionsMonitor,
IRazorLoggerFactory loggerFactory)
: base(clientConnection, documentMappingService, razorLSPOptionsMonitor, languageServerFeatureOptions, loggerFactory)
: base(documentMappingService, languageServerFeatureOptions, loggerFactory, telemetryReporter: null)
{
}

// We can't get C# responses without significant amounts of extra work, so let's just shim it for now, any non-Null result is fine.
internal override Task<ImmutableArray<SemanticRange>?> GetCSharpSemanticRangesAsync(
IClientConnection clientConnection,
RazorCodeDocument codeDocument,
TextDocumentIdentifier textDocumentIdentifier,
Range razorRange,
RazorSemanticTokensLegend razorSemanticTokensLegend,
bool colorBackground,
long documentVersion,
Guid correlationId,
CancellationToken cancellationToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public async Task InitializeRazorSemanticAsync()
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version: 1);

SemanticTokensLegend = new RazorSemanticTokensLegend(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });
RazorSemanticTokenService.ApplyCapabilities(new(), new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });

var text = await DocumentSnapshot.GetTextAsync().ConfigureAwait(false);
Range = new Range
Expand Down Expand Up @@ -85,13 +86,14 @@ public async Task RazorSemanticTokensRangeScrollingAsync()
Uri = DocumentUri
};
var cancellationToken = CancellationToken.None;
var correlationId = Guid.Empty;
var documentVersion = 1;

await UpdateDocumentAsync(documentVersion, DocumentSnapshot).ConfigureAwait(false);

var documentLineCount = Range.End.Line;

var clientConnection = RazorLanguageServer.GetRequiredService<IClientConnection>();

var lineCount = 0;
while (lineCount != documentLineCount)
{
Expand All @@ -102,11 +104,11 @@ public async Task RazorSemanticTokensRangeScrollingAsync()
End = new Position(newLineCount, 0)
};
await RazorSemanticTokenService!.GetSemanticTokensAsync(
clientConnection,
textDocumentIdentifier,
range,
DocumentContext,
SemanticTokensLegend,
correlationId,
colorBackground: false,
cancellationToken);

lineCount = newLineCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal class ConfigurableLanguageServerFeatureOptions : LanguageServerFeatureO
private readonly bool? _includeProjectKeyInGeneratedFilePath;
private readonly bool? _monitorWorkspaceFolderForConfigurationFiles;
private readonly bool? _useRazorCohostServer;
private readonly bool? _disableRazorLanguageServer;

public override bool SupportsFileManipulation => _supportsFileManipulation ?? _defaults.SupportsFileManipulation;
public override string ProjectConfigurationFileName => _projectConfigurationFileName ?? _defaults.ProjectConfigurationFileName;
Expand All @@ -39,6 +40,7 @@ internal class ConfigurableLanguageServerFeatureOptions : LanguageServerFeatureO
public override bool IncludeProjectKeyInGeneratedFilePath => _includeProjectKeyInGeneratedFilePath ?? _defaults.IncludeProjectKeyInGeneratedFilePath;
public override bool MonitorWorkspaceFolderForConfigurationFiles => _monitorWorkspaceFolderForConfigurationFiles ?? _defaults.MonitorWorkspaceFolderForConfigurationFiles;
public override bool UseRazorCohostServer => _useRazorCohostServer ?? _defaults.UseRazorCohostServer;
public override bool DisableRazorLanguageServer => _disableRazorLanguageServer ?? _defaults.DisableRazorLanguageServer;

public ConfigurableLanguageServerFeatureOptions(string[] args)
{
Expand All @@ -63,6 +65,7 @@ public ConfigurableLanguageServerFeatureOptions(string[] args)
TryProcessBoolOption(nameof(IncludeProjectKeyInGeneratedFilePath), ref _includeProjectKeyInGeneratedFilePath, option, args, i);
TryProcessBoolOption(nameof(MonitorWorkspaceFolderForConfigurationFiles), ref _monitorWorkspaceFolderForConfigurationFiles, option, args, i);
TryProcessBoolOption(nameof(UseRazorCohostServer), ref _useRazorCohostServer, option, args, i);
TryProcessBoolOption(nameof(DisableRazorLanguageServer), ref _disableRazorLanguageServer, option, args, i);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash
public override bool MonitorWorkspaceFolderForConfigurationFiles => true;

public override bool UseRazorCohostServer => false;

public override bool DisableRazorLanguageServer => false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,19 @@ public static void AddHoverServices(this IServiceCollection services)
services.AddSingleton<IHoverInfoService, HoverInfoService>();
}

public static void AddSemanticTokensServices(this IServiceCollection services)
public static void AddSemanticTokensServices(this IServiceCollection services, LanguageServerFeatureOptions featureOptions)
{
services.AddHandlerWithCapabilities<SemanticTokensRangeEndpoint>();
if (!featureOptions.UseRazorCohostServer)
{
services.AddHandlerWithCapabilities<SemanticTokensRangeEndpoint>();
// Ensure that we don't add the default service if something else has added one.
services.TryAddSingleton<IRazorSemanticTokensInfoService, RazorSemanticTokensInfoService>();
}

services.AddHandler<RazorSemanticTokensRefreshEndpoint>();

services.AddSingleton<WorkspaceSemanticTokensRefreshPublisher, DefaultWorkspaceSemanticTokensRefreshPublisher>();
services.AddSingleton<IProjectSnapshotChangeTrigger, DefaultWorkspaceSemanticTokensRefreshTrigger>();

// Ensure that we don't add the default service if something else has added one.
services.TryAddSingleton<IRazorSemanticTokensInfoService, RazorSemanticTokensInfoService>();
}

public static void AddCodeActionsServices(this IServiceCollection services)
Expand Down Expand Up @@ -228,7 +231,12 @@ public static void AddDocumentManagementServices(this IServiceCollection service
services.AddSingleton<DocumentProcessedListener, RazorDiagnosticsPublisher>();
}

services.AddSingleton<DocumentProcessedListener, GeneratedDocumentSynchronizer>();
// Don't generate documents in the language server if cohost is enabled, let cohost do it.
if (!featureOptions.UseRazorCohostServer)
{
services.AddSingleton<DocumentProcessedListener, GeneratedDocumentSynchronizer>();
}

services.AddSingleton<DocumentProcessedListener, CodeDocumentReferenceHolder>();

services.AddSingleton<ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ protected override ILspServices ConstructLspServices()
services.AddLifeCycleServices(this, _clientConnection, _lspServerActivationTracker);

services.AddDiagnosticServices();
services.AddSemanticTokensServices();
services.AddSemanticTokensServices(featureOptions);
services.AddDocumentManagementServices(featureOptions);
services.AddCompletionServices(featureOptions);
services.AddFormattingServices();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,30 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic;

[LanguageServerEndpoint(LspEndpointName)]
internal sealed class SemanticTokensRangeEndpoint(IRazorLoggerFactory loggerFactory, ITelemetryReporter? telemetryReporter)
[LanguageServerEndpoint(Methods.TextDocumentSemanticTokensRangeName)]
internal sealed class SemanticTokensRangeEndpoint(
IRazorSemanticTokensInfoService semanticTokensInfoService,
RazorLSPOptionsMonitor razorLSPOptionsMonitor,
IClientConnection clientConnection)
: IRazorRequestHandler<SemanticTokensRangeParams, SemanticTokens?>, ICapabilitiesProvider
{
private const string LspEndpointName = Methods.TextDocumentSemanticTokensRangeName;

private readonly ILogger _logger = loggerFactory.CreateLogger<SemanticTokensRangeEndpoint>();
private readonly ITelemetryReporter? _telemetryReporter = telemetryReporter;

private RazorSemanticTokensLegend? _razorSemanticTokensLegend;
private readonly IRazorSemanticTokensInfoService _semanticTokensInfoService = semanticTokensInfoService;
private readonly RazorLSPOptionsMonitor _razorLSPOptionsMonitor = razorLSPOptionsMonitor;
private readonly IClientConnection _clientConnection = clientConnection;

public bool MutatesSolutionState { get; } = false;

public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
{
_razorSemanticTokensLegend = new RazorSemanticTokensLegend(clientCapabilities);

serverCapabilities.SemanticTokensOptions = new SemanticTokensOptions
{
Full = false,
Legend = _razorSemanticTokensLegend.Legend,
Range = true,
};
_semanticTokensInfoService.ApplyCapabilities(serverCapabilities, clientCapabilities);
}

public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParams request)
Expand All @@ -47,26 +34,10 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParam

public async Task<SemanticTokens?> HandleRequestAsync(SemanticTokensRangeParams request, RazorRequestContext requestContext, CancellationToken cancellationToken)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}

var documentContext = requestContext.GetRequiredDocumentContext();
var semanticTokensInfoService = requestContext.GetRequiredService<IRazorSemanticTokensInfoService>();

var correlationId = Guid.NewGuid();
using var _ = _telemetryReporter?.TrackLspRequest(LspEndpointName, LanguageServerConstants.RazorLanguageServerName, correlationId);
var semanticTokens = await semanticTokensInfoService.GetSemanticTokensAsync(request.TextDocument, request.Range, documentContext, _razorSemanticTokensLegend.AssumeNotNull(), correlationId, cancellationToken).ConfigureAwait(false);
var amount = semanticTokens is null ? "no" : (semanticTokens.Data.Length / 5).ToString(Thread.CurrentThread.CurrentCulture);

_logger.LogInformation("Returned {amount} semantic tokens for range ({startLine},{startChar})-({endLine},{endChar}) in {request.TextDocument.Uri}.", amount, request.Range.Start.Line, request.Range.Start.Character, request.Range.End.Line, request.Range.End.Character, request.TextDocument.Uri);
var colorBackground = _razorLSPOptionsMonitor.CurrentValue.ColorBackground;

if (semanticTokens is not null)
{
Debug.Assert(semanticTokens.Data.Length % 5 == 0, $"Number of semantic token-ints should be divisible by 5. Actual number: {semanticTokens.Data.Length}");
Debug.Assert(semanticTokens.Data.Length == 0 || semanticTokens.Data[0] >= 0, $"Line offset should not be negative.");
}
var semanticTokens = await _semanticTokensInfoService.GetSemanticTokensAsync(_clientConnection, request.TextDocument, request.Range, documentContext, colorBackground, cancellationToken).ConfigureAwait(false);

return semanticTokens;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic;

internal interface IRazorSemanticTokensInfoService
internal interface IRazorSemanticTokensInfoService : ICapabilitiesProvider
{
Task<SemanticTokens?> GetSemanticTokensAsync(TextDocumentIdentifier textDocumentIdentifier, Range range, VersionedDocumentContext documentContext, RazorSemanticTokensLegend razorSemanticTokensLegend, Guid correlationId, CancellationToken cancellationToken);
Task<SemanticTokens?> GetSemanticTokensAsync(IClientConnection clientConnection, TextDocumentIdentifier textDocumentIdentifier, Range range, VersionedDocumentContext documentContext, bool colorBackground, CancellationToken cancellationToken);
}
Loading