diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 13a3bffdbdaaf..79b5ab45911ba 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.SpellCheck; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Text.Adornments; @@ -583,6 +584,15 @@ public static LSP.DocumentHighlightKind HighlightSpanKindToDocumentHighlightKind } } + public static LSP.VSInternalSpellCheckableRangeKind SpellCheckSpanKindToSpellCheckableRangeKind(SpellCheckKind kind) + => kind switch + { + SpellCheckKind.Identifier => LSP.VSInternalSpellCheckableRangeKind.Identifier, + SpellCheckKind.Comment => LSP.VSInternalSpellCheckableRangeKind.Comment, + SpellCheckKind.String => LSP.VSInternalSpellCheckableRangeKind.String, + _ => throw ExceptionUtilities.UnexpectedValue(kind), + }; + public static Glyph SymbolKindToGlyph(LSP.SymbolKind kind) { switch (kind) diff --git a/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs index 343299bec39e4..edc18420b5433 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler @@ -33,18 +34,24 @@ public FindImplementationsHandler(IGlobalOptionService globalOptions) public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.TextDocumentPositionParams request) => request.TextDocument; - public async Task HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); - var clientCapabilities = context.GetRequiredClientCapabilities(); + var supportsVisualStudioExtensions = context.GetRequiredClientCapabilities().HasVisualStudioLspCapability(); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); + + return FindImplementationsAsync(document, linePosition, classificationOptions, supportsVisualStudioExtensions, cancellationToken); + } + internal static async Task FindImplementationsAsync(Document document, LinePosition linePosition, OptionsProvider classificationOptions, bool supportsVisualStudioExtensions, CancellationToken cancellationToken) + { var locations = ArrayBuilder.GetInstance(); var findUsagesService = document.GetRequiredLanguageService(); - var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); + var position = await document.GetPositionFromLinePositionAsync(linePosition, cancellationToken).ConfigureAwait(false); var findUsagesContext = new SimpleFindUsagesContext(); - var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); await findUsagesService.FindImplementationsAsync(findUsagesContext, document, position, classificationOptions, cancellationToken).ConfigureAwait(false); foreach (var definition in findUsagesContext.GetDefinitions()) @@ -52,7 +59,7 @@ public FindImplementationsHandler(IGlobalOptionService globalOptions) var text = definition.GetClassifiedText(); foreach (var sourceSpan in definition.SourceSpans) { - if (clientCapabilities.HasVisualStudioLspCapability() == true) + if (supportsVisualStudioExtensions) { locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false)); } diff --git a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs index f63aed313296e..d7fe19248adff 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs @@ -156,7 +156,6 @@ private async IAsyncEnumerable ComputeAndReportCurrentSpansAsync( { var textDocumentIdentifier = ProtocolConversions.DocumentToTextDocumentIdentifier(document); - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); var spans = await service.GetSpansAsync(document, cancellationToken).ConfigureAwait(false); // protocol requires the results be in sorted order @@ -186,13 +185,7 @@ private async IAsyncEnumerable ComputeAndReportCurrentSpansAsync( { var span = spans[i]; - var kind = span.Kind switch - { - SpellCheckKind.Identifier => VSInternalSpellCheckableRangeKind.Identifier, - SpellCheckKind.Comment => VSInternalSpellCheckableRangeKind.Comment, - SpellCheckKind.String => VSInternalSpellCheckableRangeKind.String, - _ => throw ExceptionUtilities.UnexpectedValue(span.Kind), - }; + var kind = ProtocolConversions.SpellCheckSpanKindToSpellCheckableRangeKind(span.Kind); triples[triplesIndex++] = (int)kind; triples[triplesIndex++] = span.TextSpan.Start - lastSpanEnd; diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs new file mode 100644 index 0000000000000..c1d9310d3cd6a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.SpellCheck; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class SpellCheck +{ + public readonly record struct SpellCheckSpan(int StartIndex, int Length, VSInternalSpellCheckableRangeKind Kind); + + public static async Task> GetSpellCheckSpansAsync(Document document, CancellationToken cancellationToken) + { + var service = document.GetLanguageService(); + if (service is null) + { + return []; + } + + var spans = await service.GetSpansAsync(document, cancellationToken).ConfigureAwait(false); + + using var _ = ArrayBuilder.GetInstance(spans.Length, out var razorSpans); + foreach (var span in spans) + { + var kind = ProtocolConversions.SpellCheckSpanKindToSpellCheckableRangeKind(span.Kind); + razorSpans.Add(new SpellCheckSpan(span.TextSpan.Start, span.TextSpan.Length, kind)); + } + + return razorSpans.ToImmutable(); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs new file mode 100644 index 0000000000000..6124fb821981a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +using Location = Roslyn.LanguageServer.Protocol.Location; + +internal static class GoToImplementation +{ + public static Task FindImplementationsAsync(Document document, LinePosition linePosition, bool supportsVisualStudioExtensions, CancellationToken cancellationToken) + { + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + var classificationOptions = globalOptions.GetClassificationOptionsProvider(); + + return FindImplementationsHandler.FindImplementationsAsync(document, linePosition, classificationOptions, supportsVisualStudioExtensions, cancellationToken); + } +}