-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rejig semantic tokens service to not take VS protocol types, and extr…
…act C# functionality to a separate service
- Loading branch information
1 parent
3d36512
commit 166c9e1
Showing
11 changed files
with
226 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
...rosoft.AspNetCore.Razor.LanguageServer/Semantic/Services/ICSharpSemanticTokensProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// 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.Collections.Immutable; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; | ||
|
||
internal interface ICSharpSemanticTokensProvider | ||
{ | ||
Task<int[]?> GetCSharpSemanticTokensResponseAsync( | ||
VersionedDocumentContext documentContext, | ||
ImmutableArray<LinePositionSpan> csharpSpans, | ||
bool usePreciseSemanticTokenRanges, | ||
Guid correlationId, | ||
CancellationToken cancellationToken); | ||
} |
5 changes: 3 additions & 2 deletions
5
...osoft.AspNetCore.Razor.LanguageServer/Semantic/Services/IRazorSemanticTokenInfoService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
// 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; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; | ||
|
||
internal interface IRazorSemanticTokensInfoService | ||
{ | ||
Task<SemanticTokens?> GetSemanticTokensAsync(IClientConnection clientConnection, TextDocumentIdentifier textDocumentIdentifier, Range range, VersionedDocumentContext documentContext, bool colorBackground, CancellationToken cancellationToken); | ||
Task<int[]?> GetSemanticTokensAsync(VersionedDocumentContext documentContext, LinePositionSpan range, bool colorBackground, Guid correlationId, CancellationToken cancellationToken); | ||
} |
106 changes: 106 additions & 0 deletions
106
...soft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// 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.Collections.Immutable; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Razor.LanguageServer.Common; | ||
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; | ||
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models; | ||
using Microsoft.AspNetCore.Razor.PooledObjects; | ||
using Microsoft.CodeAnalysis.Razor.Logging; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; | ||
|
||
internal class LSPCSharpSemanticTokensProvider(IClientConnection clientConnection, IRazorLoggerFactory loggerFactory) : ICSharpSemanticTokensProvider | ||
{ | ||
private readonly IClientConnection _clientConnection = clientConnection; | ||
private readonly ILogger _logger = loggerFactory.CreateLogger<LSPCSharpSemanticTokensProvider>(); | ||
|
||
public async Task<int[]?> GetCSharpSemanticTokensResponseAsync( | ||
VersionedDocumentContext documentContext, | ||
ImmutableArray<LinePositionSpan> csharpSpans, | ||
bool usePreciseSemanticTokenRanges, | ||
Guid correlationId, | ||
CancellationToken cancellationToken) | ||
{ | ||
var documentVersion = documentContext.Version; | ||
|
||
using var _ = ListPool<Range>.GetPooledObject(out var csharpRangeList); | ||
foreach (var span in csharpSpans) | ||
{ | ||
csharpRangeList.Add(span.ToRange()); | ||
} | ||
|
||
var csharpRanges = csharpRangeList.ToArray(); | ||
|
||
var parameter = new ProvideSemanticTokensRangesParams(documentContext.Identifier.TextDocumentIdentifier, documentVersion, csharpRanges, correlationId); | ||
ProvideSemanticTokensResponse? csharpResponse; | ||
if (usePreciseSemanticTokenRanges) | ||
{ | ||
csharpResponse = await GetCsharpResponseAsync(_clientConnection, parameter, CustomMessageNames.RazorProvidePreciseRangeSemanticTokensEndpoint, cancellationToken).ConfigureAwait(false); | ||
|
||
// Likely the server doesn't support the new endpoint, fallback to the original one | ||
if (csharpResponse?.Tokens is null && csharpRanges.Length > 1) | ||
{ | ||
var minimalRange = new Range | ||
{ | ||
Start = csharpRanges[0].Start, | ||
End = csharpRanges[^1].End | ||
}; | ||
|
||
var newParams = new ProvideSemanticTokensRangesParams( | ||
parameter.TextDocument, | ||
parameter.RequiredHostDocumentVersion, | ||
[minimalRange], | ||
parameter.CorrelationId); | ||
|
||
csharpResponse = await GetCsharpResponseAsync(_clientConnection, newParams, CustomMessageNames.RazorProvideSemanticTokensRangeEndpoint, cancellationToken).ConfigureAwait(false); | ||
} | ||
} | ||
else | ||
{ | ||
csharpResponse = await GetCsharpResponseAsync(_clientConnection, parameter, CustomMessageNames.RazorProvideSemanticTokensRangeEndpoint, cancellationToken).ConfigureAwait(false); | ||
} | ||
|
||
if (csharpResponse is null) | ||
{ | ||
// C# isn't ready yet, don't make Razor wait for it. Once C# is ready they'll send a refresh notification. | ||
return []; | ||
} | ||
|
||
var csharpVersion = csharpResponse.HostDocumentSyncVersion; | ||
if (csharpVersion != documentVersion) | ||
{ | ||
// No C# response or C# is out of sync with us. Unrecoverable, return null to indicate no change. | ||
// Once C# syncs up they'll send a refresh notification. | ||
if (csharpVersion == -1) | ||
{ | ||
_logger.LogWarning("Didn't get C# tokens because the virtual document wasn't found, or other problem. We were wanting {documentVersion} but C# could not get any version.", documentVersion); | ||
} | ||
else if (csharpVersion < documentVersion) | ||
{ | ||
_logger.LogDebug("Didn't wait for Roslyn to get the C# version we were expecting. We are wanting {documentVersion} but C# is at {csharpVersion}.", documentVersion, csharpVersion); | ||
} | ||
else | ||
{ | ||
_logger.LogWarning("We are behind the C# version which is surprising. Could be an old request that wasn't cancelled, but if not, expect most future requests to fail. We were wanting {documentVersion} but C# is at {csharpVersion}.", documentVersion, csharpVersion); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
return csharpResponse.Tokens ?? []; | ||
} | ||
|
||
private static Task<ProvideSemanticTokensResponse?> GetCsharpResponseAsync(IClientConnection clientConnection, ProvideSemanticTokensRangesParams parameter, string lspMethodName, CancellationToken cancellationToken) | ||
{ | ||
return clientConnection.SendRequestAsync<ProvideSemanticTokensRangesParams, ProvideSemanticTokensResponse?>( | ||
lspMethodName, | ||
parameter, | ||
cancellationToken); | ||
} | ||
} |
Oops, something went wrong.