Skip to content

Commit

Permalink
Merge pull request #74978 from davidwengier/CohostImplemenationAndSpe…
Browse files Browse the repository at this point in the history
…llCheck

Expose Go To Impl and Spell Check to Razor
  • Loading branch information
davidwengier authored Sep 4, 2024
2 parents 3bd322d + 5b1d55d commit 077642f
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 13 deletions.
10 changes: 10 additions & 0 deletions src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,26 +34,32 @@ public FindImplementationsHandler(IGlobalOptionService globalOptions)

public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.TextDocumentPositionParams request) => request.TextDocument;

public async Task<LSP.Location[]> HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
public Task<LSP.Location[]> 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<LSP.Location[]> FindImplementationsAsync(Document document, LinePosition linePosition, OptionsProvider<ClassificationOptions> classificationOptions, bool supportsVisualStudioExtensions, CancellationToken cancellationToken)
{
var locations = ArrayBuilder<LSP.Location>.GetInstance();

var findUsagesService = document.GetRequiredLanguageService<IFindUsagesLSPService>();
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())
{
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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ private async IAsyncEnumerable<TReport> 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
Expand Down Expand Up @@ -186,13 +185,7 @@ private async IAsyncEnumerable<TReport> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ImmutableArray<SpellCheckSpan>> GetSpellCheckSpansAsync(Document document, CancellationToken cancellationToken)
{
var service = document.GetLanguageService<ISpellCheckSpanService>();
if (service is null)
{
return [];
}

var spans = await service.GetSpansAsync(document, cancellationToken).ConfigureAwait(false);

using var _ = ArrayBuilder<SpellCheckSpan>.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();
}
}
Original file line number Diff line number Diff line change
@@ -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<Location[]> FindImplementationsAsync(Document document, LinePosition linePosition, bool supportsVisualStudioExtensions, CancellationToken cancellationToken)
{
var globalOptions = document.Project.Solution.Services.ExportProvider.GetService<IGlobalOptionService>();
var classificationOptions = globalOptions.GetClassificationOptionsProvider();

return FindImplementationsHandler.FindImplementationsAsync(document, linePosition, classificationOptions, supportsVisualStudioExtensions, cancellationToken);
}
}

0 comments on commit 077642f

Please sign in to comment.