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

To-do: fix streaming implementation

上级 ed030c6b
......@@ -95,9 +95,12 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext)
// Currently, 3rd party definitions = XAML definitions, and XAML will provide
// references via LSP instead of hooking into Roslyn.
// This also means that we don't need to be on the UI thread.
var definitionTrackingContext = new DefinitionTrackingContext(context);
await FindLiteralOrSymbolReferencesAsync(
document, position, definitionTrackingContext).ConfigureAwait(false);
if (context is FindUsagesContext findUsagesContext)
{
await FindLiteralOrSymbolReferencesAsync(
document, position, findUsagesContext).ConfigureAwait(true);
await findUsagesContext.OnCompletedAsync().ConfigureAwait(false);
}
}
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 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor;
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.PooledObjects;
using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Text.Adornments;
using Roslyn.Utilities;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.LanguageServer.Handler
......@@ -33,14 +22,12 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
[ExportLspMethod(LSP.Methods.TextDocumentReferencesName), Shared]
internal class FindAllReferencesHandler : IRequestHandler<LSP.ReferenceParams, LSP.VSReferenceItem[]>
{
private readonly IThreadingContext _threadingContext;
private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public FindAllReferencesHandler(IThreadingContext threadingContext, IMetadataAsSourceFileService metadataAsSourceFileService)
public FindAllReferencesHandler(IMetadataAsSourceFileService metadataAsSourceFileService)
{
_threadingContext = threadingContext;
_metadataAsSourceFileService = metadataAsSourceFileService;
}
......@@ -61,148 +48,15 @@ public FindAllReferencesHandler(IThreadingContext threadingContext, IMetadataAsS
var findUsagesService = document.GetRequiredLanguageService<IFindUsagesLSPService>();
var position = await document.GetPositionFromLinePositionAsync(
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.
await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false);
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++;
var context = new FindUsagesLSPContext(
referenceParams.PartialResultToken, document, position, _metadataAsSourceFileService, cancellationToken);
// Creating a reference item for each reference.
foreach (var reference in references)
{
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))));
}
// Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client.
await findUsagesService.FindReferencesAsync(document, position, context).ConfigureAwait(false);
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
private readonly LanguageServerProtocol _protocol;
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;
public InProcLanguageServer(Stream inputStream, Stream outputStream, LanguageServerProtocol protocol,
......@@ -88,8 +70,8 @@ public Task<InitializeResult> InitializeAsync(JToken input, CancellationToken ca
// InitializeParams only references ClientCapabilities, but the VS LSP client
// sends additional VS specific capabilities, so directly deserialize them into the VSClientCapabilities
// to avoid losing them.
_clientCapabilities = input["capabilities"].ToObject<VSClientCapabilities>(JsonSerializer);
return _protocol.InitializeAsync(_workspace.CurrentSolution, input.ToObject<InitializeParams>(JsonSerializer), _clientCapabilities, cancellationToken);
_clientCapabilities = input["capabilities"].ToObject<VSClientCapabilities>();
return _protocol.InitializeAsync(_workspace.CurrentSolution, input.ToObject<InitializeParams>(), _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.InitializedName)]
......@@ -116,96 +98,57 @@ public void Exit()
{
}
[JsonRpcMethod(Methods.TextDocumentDefinitionName)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentDefinitionAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.GoToDefinitionAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDefinitionName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentDefinitionAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
=> _protocol.GoToDefinitionAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentRenameName)]
public Task<WorkspaceEdit> GetTextDocumentRenameAsync(JToken input, CancellationToken cancellationToken)
{
var renameParams = input.ToObject<RenameParams>(JsonSerializer);
return _protocol.RenameAsync(_workspace.CurrentSolution, renameParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentRenameName, UseSingleObjectParameterDeserialization = true)]
public Task<WorkspaceEdit> GetTextDocumentRenameAsync(RenameParams renameParams, CancellationToken cancellationToken)
=> _protocol.RenameAsync(_workspace.CurrentSolution, renameParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentReferencesName)]
public Task<VSReferenceItem[]> GetTextDocumentReferencesAsync(JToken input, CancellationToken cancellationToken)
{
var referencesParams = input.ToObject<ReferenceParams>(JsonSerializer);
return _protocol.GetDocumentReferencesAsync(_workspace.CurrentSolution, referencesParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentReferencesName, UseSingleObjectParameterDeserialization = true)]
public Task<VSReferenceItem[]> GetTextDocumentReferencesAsync(ReferenceParams referencesParams, CancellationToken cancellationToken)
=> _protocol.GetDocumentReferencesAsync(_workspace.CurrentSolution, referencesParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentCompletionName)]
public Task<SumType<CompletionItem[], CompletionList>?> GetTextDocumentCompletionAsync(JToken input, CancellationToken cancellationToken)
{
var completionParams = input.ToObject<CompletionParams>(JsonSerializer);
return _protocol.GetCompletionsAsync(_workspace.CurrentSolution, completionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<CompletionItem[], CompletionList>?> GetTextDocumentCompletionAsync(CompletionParams completionParams, CancellationToken cancellationToken)
=> _protocol.GetCompletionsAsync(_workspace.CurrentSolution, completionParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentCompletionResolveName)]
public Task<CompletionItem> ResolveCompletionItemAsync(JToken input, CancellationToken cancellationToken)
{
var completionItem = input.ToObject<CompletionItem>(JsonSerializer);
return _protocol.ResolveCompletionItemAsync(_workspace.CurrentSolution, completionItem, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionResolveName, UseSingleObjectParameterDeserialization = true)]
public Task<CompletionItem> ResolveCompletionItemAsync(CompletionItem completionItem, CancellationToken cancellationToken)
=> _protocol.ResolveCompletionItemAsync(_workspace.CurrentSolution, completionItem, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentDocumentHighlightName)]
public Task<DocumentHighlight[]> GetTextDocumentDocumentHighlightsAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.GetDocumentHighlightAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentHighlightName, UseSingleObjectParameterDeserialization = true)]
public Task<DocumentHighlight[]> GetTextDocumentDocumentHighlightsAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
=> _protocol.GetDocumentHighlightAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentDocumentSymbolName)]
public Task<object[]> GetTextDocumentDocumentSymbolsAsync(JToken input, CancellationToken cancellationToken)
{
var documentSymbolParams = input.ToObject<DocumentSymbolParams>(JsonSerializer);
return _protocol.GetDocumentSymbolsAsync(_workspace.CurrentSolution, documentSymbolParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentSymbolName, UseSingleObjectParameterDeserialization = true)]
public Task<object[]> GetTextDocumentDocumentSymbolsAsync(DocumentSymbolParams documentSymbolParams, CancellationToken cancellationToken)
=> _protocol.GetDocumentSymbolsAsync(_workspace.CurrentSolution, documentSymbolParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentFormattingName)]
public Task<TextEdit[]> GetTextDocumentFormattingAsync(JToken input, CancellationToken cancellationToken)
{
var documentFormattingParams = input.ToObject<DocumentFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentAsync(_workspace.CurrentSolution, documentFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentFormattingAsync(DocumentFormattingParams documentFormattingParams, CancellationToken cancellationToken)
=> _protocol.FormatDocumentAsync(_workspace.CurrentSolution, documentFormattingParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName)]
public Task<TextEdit[]> GetTextDocumentFormattingOnTypeAsync(JToken input, CancellationToken cancellationToken)
{
var documentOnTypeFormattingParams = input.ToObject<DocumentOnTypeFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentOnTypeAsync(_workspace.CurrentSolution, documentOnTypeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentFormattingOnTypeAsync(DocumentOnTypeFormattingParams documentOnTypeFormattingParams, CancellationToken cancellationToken)
=> _protocol.FormatDocumentOnTypeAsync(_workspace.CurrentSolution, documentOnTypeFormattingParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentImplementationName)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentImplementationsAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return _protocol.FindImplementationsAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentImplementationName, UseSingleObjectParameterDeserialization = true)]
public Task<SumType<LSP.Location, LSP.Location[]>?> GetTextDocumentImplementationsAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
=> _protocol.FindImplementationsAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentRangeFormattingName)]
public Task<TextEdit[]> GetTextDocumentRangeFormattingAsync(JToken input, CancellationToken cancellationToken)
{
var documentRangeFormattingParams = input.ToObject<DocumentRangeFormattingParams>(JsonSerializer);
return _protocol.FormatDocumentRangeAsync(_workspace.CurrentSolution, documentRangeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentRangeFormattingName, UseSingleObjectParameterDeserialization = true)]
public Task<TextEdit[]> GetTextDocumentRangeFormattingAsync(DocumentRangeFormattingParams documentRangeFormattingParams, CancellationToken cancellationToken)
=> _protocol.FormatDocumentRangeAsync(_workspace.CurrentSolution, documentRangeFormattingParams, _clientCapabilities, cancellationToken);
[JsonRpcMethod(Methods.TextDocumentSignatureHelpName)]
public async Task<SignatureHelp> GetTextDocumentSignatureHelpAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>(JsonSerializer);
return await _protocol.GetSignatureHelpAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
[JsonRpcMethod(Methods.TextDocumentSignatureHelpName, UseSingleObjectParameterDeserialization = true)]
public async Task<SignatureHelp> GetTextDocumentSignatureHelpAsync(TextDocumentPositionParams textDocumentPositionParams, CancellationToken cancellationToken)
=> await _protocol.GetSignatureHelpAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
[JsonRpcMethod(Methods.WorkspaceSymbolName)]
public async Task<SymbolInformation[]> GetWorkspaceSymbolsAsync(JToken input, CancellationToken cancellationToken)
{
var workspaceSymbolParams = input.ToObject<WorkspaceSymbolParams>(JsonSerializer);
return await _protocol.GetWorkspaceSymbolsAsync(_workspace.CurrentSolution, workspaceSymbolParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
[JsonRpcMethod(Methods.WorkspaceSymbolName, UseSingleObjectParameterDeserialization = true)]
public async Task<SymbolInformation[]> GetWorkspaceSymbolsAsync(WorkspaceSymbolParams workspaceSymbolParams, CancellationToken cancellationToken)
=> await _protocol.GetWorkspaceSymbolsAsync(_workspace.CurrentSolution, workspaceSymbolParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
#pragma warning disable VSTHRD100 // Avoid async void methods
private async void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
......
......@@ -14,7 +14,7 @@ public static class LspRequestExtensions
=> new LS.LspRequest<TIn, TOut>(lspRequest.Name);
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 @@
using Microsoft.CodeAnalysis.SignatureHelp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using Newtonsoft.Json.Linq;
using StreamJsonRpc;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare
{
[ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.TextDocumentCompletionName)]
internal class TypeScriptCompletionHandlerShim : CompletionHandler, ILspRequestHandler<object, object?, Solution>
internal class TypeScriptCompletionHandlerShim : CompletionHandler, ILspRequestHandler<CompletionParams, object?, Solution>
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -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>.
// However Live Share is unable to handle a SumType return when using ILspRequestHandler.
// So instead we just return the actual value from the SumType.
......@@ -246,7 +242,7 @@ public Task<WorkspaceEdit> HandleAsync(RenameParams param, RequestContext<Soluti
}
[ExportLspRequestHandler(LiveShareConstants.TypeScriptContractName, Methods.WorkspaceSymbolName)]
internal class TypeScriptWorkspaceSymbolsHandlerShim : WorkspaceSymbolsHandler, ILspRequestHandler<object, SymbolInformation[], Solution>
internal class TypeScriptWorkspaceSymbolsHandlerShim : WorkspaceSymbolsHandler, ILspRequestHandler<WorkspaceSymbolParams, SymbolInformation[], Solution>
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -254,13 +250,8 @@ public TypeScriptWorkspaceSymbolsHandlerShim()
{
}
public Task<SymbolInformation[]> HandleAsync(object input, 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<WorkspaceSymbolParams>(InProcLanguageServer.JsonSerializer);
return base.HandleRequestAsync(requestContext.Context, request, requestContext.GetClientCapabilities(), cancellationToken);
}
[JsonRpcMethod(UseSingleObjectParameterDeserialization = true)]
public Task<SymbolInformation[]> HandleAsync(WorkspaceSymbolParams request, RequestContext<Solution> requestContext, CancellationToken cancellationToken)
=> 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.
先完成此消息的编辑!
想要评论请 注册