提交 14c1c5fe 编写于 作者: A Allison Chou

To-do: fix streaming implementation

上级 ed030c6b
...@@ -95,9 +95,12 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext) ...@@ -95,9 +95,12 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext)
// Currently, 3rd party definitions = XAML definitions, and XAML will provide // Currently, 3rd party definitions = XAML definitions, and XAML will provide
// references via LSP instead of hooking into Roslyn. // references via LSP instead of hooking into Roslyn.
// This also means that we don't need to be on the UI thread. // This also means that we don't need to be on the UI thread.
var definitionTrackingContext = new DefinitionTrackingContext(context); if (context is FindUsagesContext findUsagesContext)
await FindLiteralOrSymbolReferencesAsync( {
document, position, definitionTrackingContext).ConfigureAwait(false); await FindLiteralOrSymbolReferencesAsync(
document, position, findUsagesContext).ConfigureAwait(true);
await findUsagesContext.OnCompletedAsync().ConfigureAwait(false);
}
} }
private async Task FindLiteralOrSymbolReferencesAsync( private async Task FindLiteralOrSymbolReferencesAsync(
......
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindSymbols.Finders;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Text.Adornments;
using Roslyn.Utilities;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.LanguageServer.CustomProtocol
{
internal class FindUsagesLSPContext : FindUsagesContext
{
private readonly object _gate = new object();
private const int MaxResultsChunkSize = 32;
private int _id = 0;
private readonly Dictionary<DefinitionItem, int> _definitionToId =
new Dictionary<DefinitionItem, int>();
private readonly List<VSReferenceItem> _resultsChunk =
new List<VSReferenceItem>();
private readonly IProgress<object[]> _progress;
private readonly Document _document;
private readonly int _position;
private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;
public override CancellationToken CancellationToken { get; }
public FindUsagesLSPContext(
IProgress<object[]> progress,
Document document,
int position,
IMetadataAsSourceFileService metadataAsSourceFileService,
CancellationToken cancellationToken)
{
_progress = progress;
_document = document;
_position = position;
_metadataAsSourceFileService = metadataAsSourceFileService;
CancellationToken = cancellationToken;
}
public string? Message { get; private set; }
public string? SearchTitle { get; private set; }
public override Task ReportMessageAsync(string message)
{
Message = message;
return Task.CompletedTask;
}
public override Task SetSearchTitleAsync(string title)
{
SearchTitle = title;
return Task.CompletedTask;
}
public override Task OnCompletedAsync()
{
lock (_gate)
{
if (!_resultsChunk.IsEmpty())
{
_progress.Report(_resultsChunk.ToArray());
_resultsChunk.Clear();
}
}
return Task.CompletedTask;
}
public async override Task OnDefinitionFoundAsync(DefinitionItem definition)
{
if (!_definitionToId.ContainsKey(definition))
{
// Assinging a new id to the definition
_definitionToId.Add(definition, _id);
// Creating a new VSReferenceItem for the definition
var definitionItem = await GenerateVSReferenceItemAsync(
_id, definitionId: _id, _document, _position, definition.SourceSpans.FirstOrDefault(),
definition.DisplayableProperties, _metadataAsSourceFileService, definition.GetClassifiedText(),
symbolUsageInfo: null, CancellationToken).ConfigureAwait(false);
if (definitionItem.Location != null)
{
AddAndReportResultsIfAtMax(definitionItem);
_id++;
}
}
}
public async override Task OnReferenceFoundAsync(SourceReferenceItem reference)
{
if (_definitionToId.TryGetValue(reference.Definition, out var definitionId))
{
// Creating a new VSReferenceItem for the reference
var referenceItem = await GenerateVSReferenceItemAsync(
_id, definitionId, _document, _position, reference.SourceSpan,
reference.AdditionalProperties, _metadataAsSourceFileService, definitionText: null,
reference.SymbolUsageInfo, CancellationToken).ConfigureAwait(false);
if (referenceItem.Location != null)
{
AddAndReportResultsIfAtMax(referenceItem);
_id++;
}
}
}
private void AddAndReportResultsIfAtMax(VSReferenceItem item)
{
lock (_gate)
{
_resultsChunk.Add(item);
if (_resultsChunk.Count >= MaxResultsChunkSize)
{
_progress.Report(_resultsChunk.ToArray());
_resultsChunk.Clear();
}
}
}
private static async Task<LSP.VSReferenceItem> GenerateVSReferenceItemAsync(
int id,
int? definitionId,
Document document,
int position,
DocumentSpan documentSpan,
ImmutableDictionary<string, string> properties,
IMetadataAsSourceFileService metadataAsSourceFileService,
ClassifiedTextElement? definitionText,
SymbolUsageInfo? symbolUsageInfo,
CancellationToken cancellationToken)
{
LSP.Location? location = null;
// If we have no source span, our location may be in metadata.
if (documentSpan == default)
{
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);
if (symbol != null && symbol.Locations != null && !symbol.Locations.IsEmpty && symbol.Locations.First().IsInMetadata)
{
var declarationFile = await metadataAsSourceFileService.GetGeneratedFileAsync(
document.Project, symbol, allowDecompilation: false, cancellationToken).ConfigureAwait(false);
var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
location = new LSP.Location
{
Uri = new Uri(declarationFile.FilePath),
Range = ProtocolConversions.LinePositionToRange(linePosSpan),
};
}
}
else
{
location = await ProtocolConversions.DocumentSpanToLocationAsync(documentSpan, cancellationToken).ConfigureAwait(false);
}
// TO-DO: The Origin property should be added once Rich-Nav is completed.
// https://github.com/dotnet/roslyn/issues/42847
var result = new LSP.VSReferenceItem
{
ContainingMember = properties.TryGetValue(
AbstractReferenceFinder.ContainingMemberInfoPropertyName, out var referenceContainingMember) ? referenceContainingMember : null,
ContainingType = properties.TryGetValue(
AbstractReferenceFinder.ContainingTypeInfoPropertyName, out var referenceContainingType) ? referenceContainingType : null,
DefinitionId = definitionId,
DefinitionText = definitionText, // Only definitions should have a non-null DefinitionText
DisplayPath = location?.Uri.LocalPath,
DocumentName = documentSpan == default ? null : documentSpan.Document.Name,
Id = id,
Kind = symbolUsageInfo.HasValue ? ProtocolConversions.SymbolUsageInfoToReferenceKinds(symbolUsageInfo.Value) : new ReferenceKind[] { },
Location = location,
ProjectName = documentSpan == default ? null : documentSpan.Document.Project.Name,
ResolutionStatus = ResolutionStatusKind.ConfirmedAsReference,
};
// Properly assigning the text property.
if (id == definitionId)
{
result.Text = definitionText;
}
else if (documentSpan != default)
{
var classifiedSpansAndHighlightSpan = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(
documentSpan, cancellationToken).ConfigureAwait(false);
var classifiedSpans = classifiedSpansAndHighlightSpan.ClassifiedSpans;
var docText = await documentSpan.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);
result.Text = new ClassifiedTextElement(
classifiedSpans.Select(cspan => new ClassifiedTextRun(cspan.ClassificationType, docText.ToString(cspan.TextSpan))));
}
return result;
}
}
}
...@@ -5,27 +5,16 @@ ...@@ -5,27 +5,16 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition; using System.Composition;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindSymbols.Finders;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Text.Adornments;
using Roslyn.Utilities;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.LanguageServer.Handler namespace Microsoft.CodeAnalysis.LanguageServer.Handler
...@@ -33,14 +22,12 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler ...@@ -33,14 +22,12 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
[ExportLspMethod(LSP.Methods.TextDocumentReferencesName), Shared] [ExportLspMethod(LSP.Methods.TextDocumentReferencesName), Shared]
internal class FindAllReferencesHandler : IRequestHandler<LSP.ReferenceParams, LSP.VSReferenceItem[]> internal class FindAllReferencesHandler : IRequestHandler<LSP.ReferenceParams, LSP.VSReferenceItem[]>
{ {
private readonly IThreadingContext _threadingContext;
private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;
[ImportingConstructor] [ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public FindAllReferencesHandler(IThreadingContext threadingContext, IMetadataAsSourceFileService metadataAsSourceFileService) public FindAllReferencesHandler(IMetadataAsSourceFileService metadataAsSourceFileService)
{ {
_threadingContext = threadingContext;
_metadataAsSourceFileService = metadataAsSourceFileService; _metadataAsSourceFileService = metadataAsSourceFileService;
} }
...@@ -61,148 +48,15 @@ public FindAllReferencesHandler(IThreadingContext threadingContext, IMetadataAsS ...@@ -61,148 +48,15 @@ public FindAllReferencesHandler(IThreadingContext threadingContext, IMetadataAsS
var findUsagesService = document.GetRequiredLanguageService<IFindUsagesLSPService>(); var findUsagesService = document.GetRequiredLanguageService<IFindUsagesLSPService>();
var position = await document.GetPositionFromLinePositionAsync( var position = await document.GetPositionFromLinePositionAsync(
ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false); ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false);
var context = new SimpleFindUsagesContext(cancellationToken);
// Finds the references for the symbol at the specific position in the document, pushing the results to the context instance. var context = new FindUsagesLSPContext(
await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false); referenceParams.PartialResultToken, document, position, _metadataAsSourceFileService, cancellationToken);
return await GetReferenceItemsAsync(document, position, context, cancellationToken).ConfigureAwait(false);
}
private async Task<LSP.VSReferenceItem[]> GetReferenceItemsAsync(
Document document,
int position,
SimpleFindUsagesContext context,
CancellationToken cancellationToken)
{
// Mapping each reference to its definition
var definitionMap = new Dictionary<DefinitionItem, List<SourceReferenceItem>>();
foreach (var reference in context.GetReferences())
{
if (!definitionMap.ContainsKey(reference.Definition))
{
definitionMap.Add(reference.Definition, new List<SourceReferenceItem>());
}
definitionMap[reference.Definition].Add(reference);
}
// NOTE: Parts of FAR currently do not display correctly due to a bug in LSP.VSReferenceItem.
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1088938/
using var _ = ArrayBuilder<LSP.VSReferenceItem>.GetInstance(out var referenceItems);
// Each reference is assigned its own unique id
var id = 0;
foreach (var (definition, references) in definitionMap)
{
// Creating the reference item that corresponds to the definition.
var definitionItem = await GenerateReferenceItem(
id, definitionId: id, document, position, definition.SourceSpans.FirstOrDefault(), context, definition.DisplayableProperties,
definition.GetClassifiedText(), symbolUsageInfo: null, cancellationToken).ConfigureAwait(false);
// If we have an empty location, skip this definition and its references.
if (definitionItem.Location == null)
{
continue;
}
referenceItems.Add(definitionItem);
var definitionId = id;
id++;
// Creating a reference item for each reference. // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client.
foreach (var reference in references) await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false);
{
var referenceItem = await GenerateReferenceItem(
id, definitionId, document, position, reference.SourceSpan, context, reference.AdditionalProperties,
definitionText: null, reference.SymbolUsageInfo, cancellationToken).ConfigureAwait(false);
// If we have an empty location, skip this reference.
if (referenceItem.Location == null)
{
continue;
}
referenceItems.Add(referenceItem);
id++;
};
}
return referenceItems.ToArray();
async Task<LSP.VSReferenceItem> GenerateReferenceItem(
int id,
int? definitionId,
Document originalDocument,
int originalPosition,
DocumentSpan documentSpan,
SimpleFindUsagesContext context,
ImmutableDictionary<string, string> properties,
ClassifiedTextElement? definitionText,
SymbolUsageInfo? symbolUsageInfo,
CancellationToken cancellationToken)
{
LSP.Location? location = null;
// If we have no source span, our location may be in metadata.
if (documentSpan == default)
{
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(originalDocument, originalPosition, cancellationToken).ConfigureAwait(false);
if (symbol != null && symbol.Locations != null && !symbol.Locations.IsEmpty && symbol.Locations.First().IsInMetadata)
{
var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(
originalDocument.Project, symbol, allowDecompilation: false, cancellationToken).ConfigureAwait(false);
var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
location = new LSP.Location
{
Uri = new Uri(declarationFile.FilePath),
Range = ProtocolConversions.LinePositionToRange(linePosSpan),
};
}
}
else
{
location = await ProtocolConversions.DocumentSpanToLocationAsync(documentSpan, cancellationToken).ConfigureAwait(false);
}
// TO-DO: The Origin property should be added once Rich-Nav is completed.
// https://github.com/dotnet/roslyn/issues/42847
var result = new LSP.VSReferenceItem
{
ContainingMember = properties.TryGetValue(
AbstractReferenceFinder.ContainingMemberInfoPropertyName, out var referenceContainingMember) ? referenceContainingMember : null,
ContainingType = properties.TryGetValue(
AbstractReferenceFinder.ContainingTypeInfoPropertyName, out var referenceContainingType) ? referenceContainingType : null,
DefinitionId = definitionId,
DefinitionText = definitionText, // Only definitions should have a non-null DefinitionText
DisplayPath = location?.Uri.LocalPath,
DocumentName = documentSpan == default ? null : documentSpan.Document.Name,
Id = id,
Kind = symbolUsageInfo.HasValue ? ProtocolConversions.SymbolUsageInfoToReferenceKinds(symbolUsageInfo.Value) : new ReferenceKind[] { },
Location = location,
ProjectName = documentSpan == default ? null : documentSpan.Document.Project.Name,
ResolutionStatus = ResolutionStatusKind.ConfirmedAsReference,
};
// Properly assigning the text property.
if (id == definitionId)
{
result.Text = definitionText;
}
else if (documentSpan != default)
{
var classifiedSpansAndHighlightSpan = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(
documentSpan, cancellationToken).ConfigureAwait(false);
var classifiedSpans = classifiedSpansAndHighlightSpan.ClassifiedSpans;
var docText = await documentSpan.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);
result.Text = new ClassifiedTextElement(
classifiedSpans.Select(cspan => new ClassifiedTextRun(cspan.ClassificationType, docText.ToString(cspan.TextSpan))));
}
return result; // The results have already been reported to the client, so we don't need to return anything here.
} return Array.Empty<LSP.VSReferenceItem>();
} }
} }
} }
...@@ -41,24 +41,6 @@ internal class InProcLanguageServer ...@@ -41,24 +41,6 @@ internal class InProcLanguageServer
private readonly LanguageServerProtocol _protocol; private readonly LanguageServerProtocol _protocol;
private readonly CodeAnalysis.Workspace _workspace; private readonly CodeAnalysis.Workspace _workspace;
// The VS LSP client supports streaming using IProgress<T> on various requests.
// However, this is not yet supported through Live Share, so deserialization fails on the IProgress<T> property.
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1043376 tracks Live Share support for this (committed for 16.6).
// Additionally, the VS LSP client will be changing the type of 'tagSupport' from bool to an object in future LSP package versions.
// Since updating our package versions is extraordinarily difficult, add this workaround so we aren't broken when they change the type.
// https://github.com/dotnet/roslyn/issues/40829 tracks updating our package versions to remove this workaround.
internal static readonly JsonSerializer JsonSerializer = JsonSerializer.Create(new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (object.Equals(args.ErrorContext.Member, "partialResultToken")
|| (object.Equals(args.ErrorContext.Member, "tagSupport") && args.ErrorContext.OriginalObject.GetType() == typeof(PublishDiagnosticsSetting)))
{
args.ErrorContext.Handled = true;
}
}
});
private VSClientCapabilities _clientCapabilities; private VSClientCapabilities _clientCapabilities;
public InProcLanguageServer(Stream inputStream, Stream outputStream, LanguageServerProtocol protocol, public InProcLanguageServer(Stream inputStream, Stream outputStream, LanguageServerProtocol protocol,
...@@ -88,8 +70,8 @@ public Task<InitializeResult> InitializeAsync(JToken input, CancellationToken ca ...@@ -88,8 +70,8 @@ public Task<InitializeResult> InitializeAsync(JToken input, CancellationToken ca
// InitializeParams only references ClientCapabilities, but the VS LSP client // InitializeParams only references ClientCapabilities, but the VS LSP client
// sends additional VS specific capabilities, so directly deserialize them into the VSClientCapabilities // sends additional VS specific capabilities, so directly deserialize them into the VSClientCapabilities
// to avoid losing them. // to avoid losing them.
_clientCapabilities = input["capabilities"].ToObject<VSClientCapabilities>(JsonSerializer); _clientCapabilities = input["capabilities"].ToObject<VSClientCapabilities>();
return _protocol.InitializeAsync(_workspace.CurrentSolution, input.ToObject<InitializeParams>(JsonSerializer), _clientCapabilities, cancellationToken); return _protocol.InitializeAsync(_workspace.CurrentSolution, input.ToObject<InitializeParams>(), _clientCapabilities, cancellationToken);
} }
[JsonRpcMethod(Methods.InitializedName)] [JsonRpcMethod(Methods.InitializedName)]
...@@ -116,96 +98,57 @@ public void Exit() ...@@ -116,96 +98,57 @@ public void Exit()
{ {
} }
[JsonRpcMethod(Methods.TextDocumentDefinitionName)] [JsonRpcMethod(Methods.TextDocumentDefinitionName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentDefinitionAsync(JToken input, CancellationToken cancellationToken) public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentDefinitionAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
{ => _protocol.GoToDefinitionAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.GoToDefinitionAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentRenameName)] [JsonRpcMethod(Methods.TextDocumentRenameName, UseSingleObjectParameterDeserialization = true)]
public Task<WorkspaceEdit> GetTextDocumentRenameAsync(JToken input, CancellationToken cancellationToken) public Task<WorkspaceEdit> GetTextDocumentRenameAsync(RenameParams renameParams, CancellationToken cancellationToken)
{ => _protocol.RenameAsync(_workspace.CurrentSolution, renameParams, _clientCapabilities, cancellationToken);
var renameParams = input.ToObject<RenameParams>(JsonSerializer);
return _protocol.RenameAsync(_workspace.CurrentSolution, renameParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentReferencesName)] [JsonRpcMethod(Methods.TextDocumentReferencesName, UseSingleObjectParameterDeserialization = true)]
public Task<VSReferenceItem[]> GetTextDocumentReferencesAsync(JToken input, CancellationToken cancellationToken) public Task<VSReferenceItem[]> GetTextDocumentReferencesAsync(ReferenceParams referencesParams, CancellationToken cancellationToken)
{ => _protocol.GetDocumentReferencesAsync(_workspace.CurrentSolution, referencesParams, _clientCapabilities, cancellationToken);
var referencesParams = input.ToObject<ReferenceParams>(JsonSerializer);
return _protocol.GetDocumentReferencesAsync(_workspace.CurrentSolution, referencesParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionName)] [JsonRpcMethod(Methods.TextDocumentCompletionName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<CompletionItem[], CompletionList>?> GetTextDocumentCompletionAsync(JToken input, CancellationToken cancellationToken) public Task<SumType<CompletionItem[], CompletionList>?> GetTextDocumentCompletionAsync(CompletionParams completionParams, CancellationToken cancellationToken)
{ => _protocol.GetCompletionsAsync(_workspace.CurrentSolution, completionParams, _clientCapabilities, cancellationToken);
var completionParams = input.ToObject<CompletionParams>(JsonSerializer);
return _protocol.GetCompletionsAsync(_workspace.CurrentSolution, completionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionResolveName)] [JsonRpcMethod(Methods.TextDocumentCompletionResolveName, UseSingleObjectParameterDeserialization = true)]
public Task<CompletionItem> ResolveCompletionItemAsync(JToken input, CancellationToken cancellationToken) public Task<CompletionItem> ResolveCompletionItemAsync(CompletionItem completionItem, CancellationToken cancellationToken)
{ => _protocol.ResolveCompletionItemAsync(_workspace.CurrentSolution, completionItem, _clientCapabilities, cancellationToken);
var completionItem = input.ToObject<CompletionItem>(JsonSerializer);
return _protocol.ResolveCompletionItemAsync(_workspace.CurrentSolution, completionItem, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentHighlightName)] [JsonRpcMethod(Methods.TextDocumentDocumentHighlightName, UseSingleObjectParameterDeserialization = true)]
public Task<DocumentHighlight[]> GetTextDocumentDocumentHighlightsAsync(JToken input, CancellationToken cancellationToken) public Task<DocumentHighlight[]> GetTextDocumentDocumentHighlightsAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
{ => _protocol.GetDocumentHighlightAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.GetDocumentHighlightAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentSymbolName)] [JsonRpcMethod(Methods.TextDocumentDocumentSymbolName, UseSingleObjectParameterDeserialization = true)]
public Task<object[]> GetTextDocumentDocumentSymbolsAsync(JToken input, CancellationToken cancellationToken) public Task<object[]> GetTextDocumentDocumentSymbolsAsync(DocumentSymbolParams documentSymbolParams, CancellationToken cancellationToken)
{ => _protocol.GetDocumentSymbolsAsync(_workspace.CurrentSolution, documentSymbolParams, _clientCapabilities, cancellationToken);
var documentSymbolParams = input.ToObject<DocumentSymbolParams>(JsonSerializer);
return _protocol.GetDocumentSymbolsAsync(_workspace.CurrentSolution, documentSymbolParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentFormattingName)] [JsonRpcMethod(Methods.TextDocumentFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentFormattingAsync(JToken input, CancellationToken cancellationToken) public Task<TextEdit[]> GetTextDocumentFormattingAsync(DocumentFormattingParams documentFormattingParams, CancellationToken cancellationToken)
{ => _protocol.FormatDocumentAsync(_workspace.CurrentSolution, documentFormattingParams, _clientCapabilities, cancellationToken);
var documentFormattingParams = input.ToObject<DocumentFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentAsync(_workspace.CurrentSolution, documentFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName)] [JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentFormattingOnTypeAsync(JToken input, CancellationToken cancellationToken) public Task<TextEdit[]> GetTextDocumentFormattingOnTypeAsync(DocumentOnTypeFormattingParams documentOnTypeFormattingParams, CancellationToken cancellationToken)
{ => _protocol.FormatDocumentOnTypeAsync(_workspace.CurrentSolution, documentOnTypeFormattingParams, _clientCapabilities, cancellationToken);
var documentOnTypeFormattingParams = input.ToObject<DocumentOnTypeFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentOnTypeAsync(_workspace.CurrentSolution, documentOnTypeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentImplementationName)] [JsonRpcMethod(Methods.TextDocumentImplementationName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentImplementationsAsync(JToken input, CancellationToken cancellationToken) public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentImplementationsAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
{ => _protocol.FindImplementationsAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.FindImplementationsAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentRangeFormattingName)] [JsonRpcMethod(Methods.TextDocumentRangeFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentRangeFormattingAsync(JToken input, CancellationToken cancellationToken) public Task<TextEdit[]> GetTextDocumentRangeFormattingAsync(DocumentRangeFormattingParams documentRangeFormattingParams, CancellationToken cancellationToken)
{ => _protocol.FormatDocumentRangeAsync(_workspace.CurrentSolution, documentRangeFormattingParams, _clientCapabilities, cancellationToken);
var documentRangeFormattingParams = input.ToObject<DocumentRangeFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentRangeAsync(_workspace.CurrentSolution, documentRangeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentSignatureHelpName)] [JsonRpcMethod(Methods.TextDocumentSignatureHelpName, UseSingleObjectParameterDeserialization = true)]
public async Task<SignatureHelp> GetTextDocumentSignatureHelpAsync(JToken input, CancellationToken cancellationToken) public async Task<SignatureHelp> GetTextDocumentSignatureHelpAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
{ => await _protocol.GetSignatureHelpAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return await _protocol.GetSignatureHelpAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
[JsonRpcMethod(Methods.WorkspaceSymbolName)] [JsonRpcMethod(Methods.WorkspaceSymbolName, UseSingleObjectParameterDeserialization = true)]
public async Task<SymbolInformation[]> GetWorkspaceSymbolsAsync(JToken input, CancellationToken cancellationToken) public async Task<SymbolInformation[]> GetWorkspaceSymbolsAsync(WorkspaceSymbolParams workspaceSymbolParams, CancellationToken cancellationToken)
{ => await _protocol.GetWorkspaceSymbolsAsync(_workspace.CurrentSolution, workspaceSymbolParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
var workspaceSymbolParams = input.ToObject<WorkspaceSymbolParams>(JsonSerializer);
return await _protocol.GetWorkspaceSymbolsAsync(_workspace.CurrentSolution, workspaceSymbolParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
#pragma warning disable VSTHRD100 // Avoid async void methods #pragma warning disable VSTHRD100 // Avoid async void methods
private async void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) private async void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
......
...@@ -14,7 +14,7 @@ public static class LspRequestExtensions ...@@ -14,7 +14,7 @@ public static class LspRequestExtensions
=> new LS.LspRequest<TIn, TOut>(lspRequest.Name); => new LS.LspRequest<TIn, TOut>(lspRequest.Name);
public static LSP.ClientCapabilities GetClientCapabilities(this LS.RequestContext requestContext) public static LSP.ClientCapabilities GetClientCapabilities(this LS.RequestContext requestContext)
=> requestContext.ClientCapabilities?.ToObject<LSP.ClientCapabilities>(InProcLanguageServer.JsonSerializer) ?? new LSP.VSClientCapabilities(); => requestContext.ClientCapabilities?.ToObject<LSP.ClientCapabilities>() ?? new LSP.VSClientCapabilities();
} }
} }
...@@ -21,16 +21,15 @@ ...@@ -21,16 +21,15 @@
using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.SignatureHelp;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol; using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol; using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.LiveShare.LanguageServices; using Microsoft.VisualStudio.LiveShare.LanguageServices;
using Newtonsoft.Json.Linq; using StreamJsonRpc;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare namespace Microsoft.VisualStudio.LanguageServices.LiveShare
{ {
[ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.TextDocumentCompletionName)] [ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.TextDocumentCompletionName)]
internal class TypeScriptCompletionHandlerShim : CompletionHandler, ILspRequestHandler<object, object?, Solution> internal class TypeScriptCompletionHandlerShim : CompletionHandler, ILspRequestHandler<CompletionParams, object?, Solution>
{ {
[ImportingConstructor] [ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
...@@ -38,12 +37,9 @@ public TypeScriptCompletionHandlerShim() ...@@ -38,12 +37,9 @@ public TypeScriptCompletionHandlerShim()
{ {
} }
public async Task<object?> HandleAsync(object input, RequestContext<Solution> requestContext, CancellationToken cancellationToken) [JsonRpcMethod(UseSingleObjectParameterDeserialization = true)]
public async Task<object?> HandleAsync(CompletionParams request, RequestContext<Solution> requestContext, CancellationToken cancellationToken)
{ {
// The VS LSP client supports streaming using IProgress<T> on various requests.
// However, this is not yet supported through Live Share, so deserialization fails on the IProgress<T> property.
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1043376 tracks Live Share support for this (committed for 16.6).
var request = ((JObject)input).ToObject<CompletionParams>(InProcLanguageServer.JsonSerializer);
// The return definition for TextDocumentCompletionName is SumType<CompletionItem[], CompletionList>. // The return definition for TextDocumentCompletionName is SumType<CompletionItem[], CompletionList>.
// However Live Share is unable to handle a SumType return when using ILspRequestHandler. // However Live Share is unable to handle a SumType return when using ILspRequestHandler.
// So instead we just return the actual value from the SumType. // So instead we just return the actual value from the SumType.
...@@ -246,7 +242,7 @@ public Task<WorkspaceEdit> HandleAsync(RenameParams param, RequestContext<Soluti ...@@ -246,7 +242,7 @@ public Task<WorkspaceEdit> HandleAsync(RenameParams param, RequestContext<Soluti
} }
[ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.WorkspaceSymbolName)] [ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.WorkspaceSymbolName)]
internal class TypeScriptWorkspaceSymbolsHandlerShim : WorkspaceSymbolsHandler, ILspRequestHandler<object, SymbolInformation[], Solution> internal class TypeScriptWorkspaceSymbolsHandlerShim : WorkspaceSymbolsHandler, ILspRequestHandler<WorkspaceSymbolParams, SymbolInformation[], Solution>
{ {
[ImportingConstructor] [ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
...@@ -254,13 +250,8 @@ public TypeScriptWorkspaceSymbolsHandlerShim() ...@@ -254,13 +250,8 @@ public TypeScriptWorkspaceSymbolsHandlerShim()
{ {
} }
public Task<SymbolInformation[]> HandleAsync(object input, RequestContext<Solution> requestContext, CancellationToken cancellationToken) [JsonRpcMethod(UseSingleObjectParameterDeserialization = true)]
{ public Task<SymbolInformation[]> HandleAsync(WorkspaceSymbolParams request, RequestContext<Solution> requestContext, CancellationToken cancellationToken)
// The VS LSP client supports streaming using IProgress<T> on various requests. => base.HandleRequestAsync(requestContext.Context, request, requestContext.GetClientCapabilities(), cancellationToken);
// However, this is not yet supported through Live Share, so deserialization fails on the IProgress<T> property.
// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1043376 tracks Live Share support for this (committed for 16.6).
var request = ((JObject)input).ToObject<WorkspaceSymbolParams>(InProcLanguageServer.JsonSerializer);
return base.HandleRequestAsync(requestContext.Context, request, requestContext.GetClientCapabilities(), cancellationToken);
}
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册