public async Task <SignatureHelp> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri }, }; _logger.LogInformation($"Requesting signature help for {projectionResult.Uri}."); var signatureHelp = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>( Methods.TextDocumentSignatureHelpName, projectionResult.LanguageKind.ToContainedLanguageContentType(), textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (signatureHelp is null) { _logger.LogInformation("Returning no result."); } else { _logger.LogInformation("Returning result."); } return(signatureHelp); }
public async Task <DocumentOnTypeRenameResponseItem> HandleRequestAsync(DocumentOnTypeRenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } cancellationToken.ThrowIfCancellationRequested(); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult is null || projectionResult.LanguageKind != RazorLanguageKind.Html) { return(null); } var onTypeRenameParams = new DocumentOnTypeRenameParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var contentType = projectionResult.LanguageKind.ToContainedLanguageContentType(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnTypeRenameParams, DocumentOnTypeRenameResponseItem>( MSLSPMethods.OnTypeRenameName, contentType, onTypeRenameParams, cancellationToken).ConfigureAwait(false); if (response is null) { return(null); } var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, response.Ranges, cancellationToken).ConfigureAwait(false); if (mappingResult is null || (_documentManager.TryGetDocument(request.TextDocument.Uri, out var mappedDocumentSnapshot) && mappingResult.HostDocumentVersion != mappedDocumentSnapshot.Version)) { // Couldn't remap the range or the document changed in the meantime. Discard this result. return(null); } response.Ranges = mappingResult.Ranges; return(response); }
public async Task <DocumentOnAutoInsertResponseItem> HandleRequestAsync(DocumentOnAutoInsertParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (!AllowedTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { // We haven't built support for this character yet. return(null); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null || projectionResult.LanguageKind != RazorLanguageKind.Html) { return(null); } var formattingParams = new DocumentOnAutoInsertParams() { Character = request.Character, Options = request.Options, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var contentType = projectionResult.LanguageKind.ToContainedLanguageContentType(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnAutoInsertParams, DocumentOnAutoInsertResponseItem>( MSLSPMethods.OnAutoInsertName, contentType, formattingParams, cancellationToken).ConfigureAwait(false); if (response == null) { return(null); } var remappedEdit = await _documentMappingProvider.RemapTextEditsAsync(projectionResult.Uri, new[] { response.TextEdit }, cancellationToken).ConfigureAwait(false); if (!remappedEdit.Any()) { return(null); } var remappedResponse = new DocumentOnAutoInsertResponseItem() { TextEdit = remappedEdit.Single(), TextEditFormat = response.TextEditFormat, }; return(remappedResponse); }
public async Task <WorkspaceEdit> HandleRequestAsync(RenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { // We only support C# renames for now. return(null); } cancellationToken.ThrowIfCancellationRequested(); var renameParams = new RenameParams() { Position = projectionResult.Position, NewName = request.NewName, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var result = await _requestInvoker.ReinvokeRequestOnServerAsync <RenameParams, WorkspaceEdit>( Methods.TextDocumentRenameName, projectionResult.LanguageKind.ToContainedLanguageContentType(), renameParams, cancellationToken).ConfigureAwait(false); if (result == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var remappedResult = await _documentMappingProvider.RemapWorkspaceEditAsync(result, cancellationToken).ConfigureAwait(false); return(remappedResult); }
public async Task <Location[]> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null || projectionResult.LanguageKind != RazorLanguageKind.CSharp) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var serverKind = LanguageServerKind.CSharp; var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var result = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Location[]>( Methods.TextDocumentImplementationName, serverKind, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (result == null || result.Length == 0) { return(result); } cancellationToken.ThrowIfCancellationRequested(); var remappedLocations = await _documentMappingProvider.RemapLocationsAsync(result, cancellationToken).ConfigureAwait(false); return(remappedLocations); }
public async Task <SignatureHelp> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null || projectionResult.LanguageKind != RazorLanguageKind.CSharp) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri }, }; var signatureHelp = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>( Methods.TextDocumentSignatureHelpName, RazorLSPConstants.CSharpContentTypeName, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); return(signatureHelp); }
public async Task <DocumentOnTypeRenameResponseItem> HandleRequestAsync(DocumentOnTypeRenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } cancellationToken.ThrowIfCancellationRequested(); _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult is null) { return(null); } else if (projectionResult.LanguageKind != RazorLanguageKind.Html) { _logger.LogInformation($"Unsupported language kind {projectionResult.LanguageKind:G}."); return(null); } var onTypeRenameParams = new DocumentOnTypeRenameParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; _logger.LogInformation($"Requesting OnTypeRename for {projectionResult.Uri}."); var contentType = projectionResult.LanguageKind.ToContainedLanguageContentType(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnTypeRenameParams, DocumentOnTypeRenameResponseItem>( MSLSPMethods.OnTypeRenameName, contentType, onTypeRenameParams, cancellationToken).ConfigureAwait(false); if (response is null) { _logger.LogInformation("Received no results."); return(null); } _logger.LogInformation($"Received response, remapping."); var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, response.Ranges, cancellationToken).ConfigureAwait(false); if (mappingResult is null || (_documentManager.TryGetDocument(request.TextDocument.Uri, out var mappedDocumentSnapshot) && mappingResult.HostDocumentVersion != mappedDocumentSnapshot.Version)) { // Couldn't remap the range or the document changed in the meantime. Discard this result. _logger.LogInformation($"Mapping failed. Versions: {documentSnapshot.Version} -> {mappingResult?.HostDocumentVersion}."); return(null); } response.Ranges = mappingResult.Ranges; _logger.LogInformation("Returned remapped result."); return(response); }
public async Task <Hover> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } // Switch to a background thread. await TaskScheduler.Default; var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; Hover result; try { result = await _requestInvoker.RequestServerAsync <TextDocumentPositionParams, Hover>( Methods.TextDocumentHoverName, serverKind, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); } catch { // Ensure we fail silently (Temporary till roslyn update is live) return(null); } if (result?.Range == null || result?.Contents == null) { return(null); } var mappingResult = await _documentMappingProvider.MapToDocumentRangeAsync(projectionResult.LanguageKind, request.TextDocument.Uri, result.Range, cancellationToken).ConfigureAwait(false); if (mappingResult == null) { // Couldn't remap the edits properly. Returning hover at initial request position. return(new Hover { Contents = result.Contents, Range = new Range() { Start = request.Position, End = request.Position } }); } else if (mappingResult.HostDocumentVersion != documentSnapshot.Version) { // Discard hover if document has changed. return(null); } return(new Hover { Contents = result.Contents, Range = mappingResult.Range }); }
public async Task <SumType <CompletionItem[], CompletionList>?> HandleRequestAsync(CompletionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; var(succeeded, result) = await TryGetProvisionalCompletionsAsync(request, documentSnapshot, projectionResult, cancellationToken).ConfigureAwait(false); if (succeeded) { // This means the user has just typed a dot after some identifier such as (cursor is pipe): "DateTime.| " // In this case Razor interprets after the dot as Html and before it as C#. // We use this criteria to provide a better completion experience for what we call provisional changes. } else if (!TriggerAppliesToProjection(request.Context, projectionResult.LanguageKind)) { return(null); } else { var completionContext = RewriteContext(request.Context, projectionResult.LanguageKind); // This is a valid non-provisional completion request. var completionParams = new CompletionParams() { Context = completionContext, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; result = await _requestInvoker.ReinvokeRequestOnServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>( Methods.TextDocumentCompletionName, serverKind.ToContentType(), completionParams, cancellationToken).ConfigureAwait(false); } if (TryConvertToCompletionList(result, out var completionList)) { var wordExtent = documentSnapshot.Snapshot.GetWordExtent(request.Position.Line, request.Position.Character, _textStructureNavigator); if (serverKind == LanguageServerKind.CSharp) { completionList = PostProcessCSharpCompletionList(request, documentSnapshot, wordExtent, completionList); } completionList = TranslateTextEdits(request.Position, projectionResult.Position, wordExtent, completionList); var requestContext = new CompletionRequestContext(documentSnapshot.Uri, projectionResult.Uri, serverKind); var resultId = _completionRequestContextCache.Set(requestContext); SetResolveData(resultId, completionList); } return(completionList);
public async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (!AllTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { // Unexpected trigger character. return(null); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var triggerCharacterKind = await GetTriggerCharacterLanguageKindAsync(documentSnapshot, request.Position, request.Character, cancellationToken).ConfigureAwait(false); if (triggerCharacterKind == null || triggerCharacterKind != RazorLanguageKind.CSharp) { return(null); } if (!IsApplicableTriggerCharacter(request.Character, triggerCharacterKind.Value)) { // We were triggered but the trigger character doesn't make sense for the current cursor position. Bail. return(null); } cancellationToken.ThrowIfCancellationRequested(); var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var formattingParams = new DocumentOnTypeFormattingParams() { Character = request.Character, Options = request.Options, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; cancellationToken.ThrowIfCancellationRequested(); var contentType = triggerCharacterKind.Value.ToContainedLanguageContentType(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnTypeFormattingParams, TextEdit[]>( Methods.TextDocumentOnTypeFormattingName, contentType, formattingParams, cancellationToken).ConfigureAwait(false); if (response == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var remappedEdits = await _documentMappingProvider.RemapFormattedTextEditsAsync(projectionResult.Uri, response, request.Options, cancellationToken).ConfigureAwait(false); return(remappedEdits); }
public async Task <WorkspaceEdit?> HandleRequestAsync(RenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult is null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var renameParams = new RenameParams() { Position = projectionResult.Position, NewName = request.NewName, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; _logger.LogInformation($"Requesting rename for {projectionResult.Uri}."); var serverKind = projectionResult.LanguageKind.ToLanguageServerKind(); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var languageServerName = serverKind.ToLanguageServerName(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <RenameParams, WorkspaceEdit>( textBuffer, Methods.TextDocumentRenameName, languageServerName, renameParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var result)) { return(null); } _logger.LogInformation("Received result, remapping."); var remappedResult = await _documentMappingProvider.RemapWorkspaceEditAsync(result, cancellationToken).ConfigureAwait(false); _logger.LogInformation("Returned rename result."); return(remappedResult); }
// Internal for testing internal async override Task <VSInternalReferenceItem[]> HandleRequestAsync(ReferenceParams request, ClientCapabilities clientCapabilities, string token, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var referenceParams = new SerializableReferenceParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri }, Context = request.Context, PartialResultToken = token // request.PartialResultToken }; _logger.LogInformation("Attaching to progress listener."); if (!_lspProgressListener.TryListenForProgress( token, onProgressNotifyAsync: (value, ct) => ProcessReferenceItemsAsync(value, request.PartialResultToken, ct), DelayAfterLastNotifyAsync, cancellationToken, out var onCompleted)) { _logger.LogWarning("Failed to attach to progress listener."); return(null); } _logger.LogInformation($"Requesting references for {projectionResult.Uri}."); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <SerializableReferenceParams, VSInternalReferenceItem[]>( Methods.TextDocumentReferencesName, projectionResult.LanguageKind.ToContainedLanguageServerName(), referenceParams, cancellationToken).ConfigureAwait(false); var result = response.Result; if (result is null) { _logger.LogInformation("Received no results from initial request."); return(null); } cancellationToken.ThrowIfCancellationRequested(); _logger.LogInformation("Waiting on progress notifications."); // We must not return till we have received the progress notifications // and reported the results via the PartialResultToken await onCompleted.ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); _logger.LogInformation("Finished waiting, remapping results."); // Results returned through Progress notification var remappedResults = await RemapReferenceItemsAsync(result, cancellationToken).ConfigureAwait(false); _logger.LogInformation($"Returning {remappedResults.Length} results."); return(remappedResults); // Local functions async Task DelayAfterLastNotifyAsync(CancellationToken cancellationToken) { using var combined = ImmediateNotificationTimeout.CombineWith(cancellationToken); try { await Task.Delay(WaitForProgressNotificationTimeout, combined.Token).ConfigureAwait(false); } catch (TaskCanceledException) when(ImmediateNotificationTimeout.IsCancellationRequested) { // The delay was requested to complete immediately } } }
public async Task <SumType <Location[]?, VSInternalReferenceItem[]?> > HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(new()); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult is null) { return(new()); } cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var serverKind = projectionResult.LanguageKind.ToLanguageServerKind(); var languageServerName = serverKind.ToLanguageServerName(); _logger.LogInformation($"Requesting {languageServerName} implementation for {projectionResult.Uri}."); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SumType <Location[]?, VSInternalReferenceItem[]?> >( textBuffer, Methods.TextDocumentImplementationName, languageServerName, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var result)) { return(new()); } cancellationToken.ThrowIfCancellationRequested(); // From some language servers we get VSInternalReferenceItem results, and from some we get Location results. // We check for the _vs_id property, which is required in VSInternalReferenceItem, to know which is which. if (result.Value is VSInternalReferenceItem[] referenceItems) { var remappedLocations = await FindAllReferencesHandler.RemapReferenceItemsAsync(referenceItems, _documentMappingProvider, _documentManager, cancellationToken).ConfigureAwait(false); _logger.LogInformation($"Returning {remappedLocations?.Length} internal reference items."); return(remappedLocations); } else if (result.Value is Location[] locations) { var remappedLocations = await _documentMappingProvider.RemapLocationsAsync(locations, cancellationToken).ConfigureAwait(false); _logger.LogInformation($"Returning {remappedLocations?.Length} locations."); return(remappedLocations); } _logger.LogInformation("Received no results."); return(Array.Empty <VSInternalReferenceItem>()); }
public async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (!AllowedTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { // We haven't built support for this character yet. return(EmptyEdits); } await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(EmptyEdits); } await SwitchToBackgroundThread().ConfigureAwait(false); var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null || projectionResult.LanguageKind != RazorLanguageKind.Html) { return(EmptyEdits); } if (request.Options.OtherOptions == null) { request.Options.OtherOptions = new Dictionary <string, object>(); } request.Options.OtherOptions[LanguageServerConstants.ExpectsCursorPlaceholderKey] = true; var formattingParams = new DocumentOnTypeFormattingParams() { Character = request.Character, Options = request.Options, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; var edits = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnTypeFormattingParams, TextEdit[]>( Methods.TextDocumentOnTypeFormattingName, serverKind, formattingParams, cancellationToken).ConfigureAwait(false); if (edits == null) { return(EmptyEdits); } var mappedEdits = new List <TextEdit>(); foreach (var edit in edits) { if (edit.Range == null || edit.NewText == null) { // Sometimes the HTML language server returns invalid edits like these. We should just ignore those. continue; } var mappingResult = await _documentMappingProvider.MapToDocumentRangeAsync(projectionResult.LanguageKind, request.TextDocument.Uri, edit.Range, cancellationToken).ConfigureAwait(false); if (mappingResult == null || mappingResult.HostDocumentVersion != documentSnapshot.Version) { // Couldn't remap the edits properly. Discard this request. return(EmptyEdits); } var mappedEdit = new TextEdit() { NewText = edit.NewText, Range = mappingResult.Range }; mappedEdits.Add(mappedEdit); } if (mappedEdits.Count == 0) { return(EmptyEdits); } await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var newDocumentSnapshot) || newDocumentSnapshot.Version != documentSnapshot.Version) { // The document changed while were working on the background. Discard this request. return(EmptyEdits); } await _editorService.ApplyTextEditsAsync(documentSnapshot.Uri, documentSnapshot.Snapshot, mappedEdits).ConfigureAwait(false); // We would have already applied the edits and moved the cursor. Return empty. return(EmptyEdits); }
public async Task <Hover> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var contentType = projectionResult.LanguageKind.ToContainedLanguageContentType(); cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var result = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Hover>( Methods.TextDocumentHoverName, contentType, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (result?.Range == null || result?.Contents == null) { return(null); } var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync(projectionResult.LanguageKind, request.TextDocument.Uri, new[] { result.Range }, cancellationToken).ConfigureAwait(false); if (mappingResult == null || mappingResult.Ranges[0].IsUndefined()) { // Couldn't remap the edits properly. Returning hover at initial request position. return(CreateHover(result, new Range { Start = request.Position, End = request.Position })); } else if (mappingResult.HostDocumentVersion != documentSnapshot.Version) { // Discard hover if document has changed. return(null); } return(CreateHover(result, mappingResult.Ranges[0])); }
public async Task <TextEdit[]> HandleRequestAsync(DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (!AllTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { // Unexpected trigger character. return(null); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var triggerCharacterKind = await GetTriggerCharacterLanguageKindAsync(documentSnapshot, request.Position, request.Character, cancellationToken).ConfigureAwait(false); if (triggerCharacterKind == null) { _logger.LogInformation($"Failed to identify trigger character language context."); return(null); } else if (triggerCharacterKind != RazorLanguageKind.CSharp) { _logger.LogInformation($"Unsupported trigger character language {triggerCharacterKind:G}."); return(null); } if (!IsApplicableTriggerCharacter(request.Character, triggerCharacterKind.Value)) { // We were triggered but the trigger character doesn't make sense for the current cursor position. Bail. _logger.LogInformation("Unsupported trigger character location."); return(null); } cancellationToken.ThrowIfCancellationRequested(); var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var formattingParams = new DocumentOnTypeFormattingParams() { Character = request.Character, Options = request.Options, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; cancellationToken.ThrowIfCancellationRequested(); _logger.LogInformation($"Requesting formatting for {projectionResult.Uri}."); var contentType = triggerCharacterKind.Value.ToContainedLanguageContentType(); var textEdits = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnTypeFormattingParams, TextEdit[]>( Methods.TextDocumentOnTypeFormattingName, contentType, formattingParams, cancellationToken).ConfigureAwait(false); if (textEdits == null) { _logger.LogInformation("Received no results."); return(null); } _logger.LogInformation($"Received {textEdits.Length} results, remapping."); cancellationToken.ThrowIfCancellationRequested(); var remappedTextEdits = await _documentMappingProvider.RemapFormattedTextEditsAsync(projectionResult.Uri, textEdits, request.Options, containsSnippet : false, cancellationToken).ConfigureAwait(false); _logger.LogInformation($"Returning {remappedTextEdits?.Length} text edits."); return(remappedTextEdits); }
public async Task <Hover?> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult is null) { return(null); } var languageServerName = projectionResult.LanguageKind.ToContainedLanguageServerName(); cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; _logger.LogInformation($"Requesting hovers for {projectionResult.Uri}."); var serverKind = projectionResult.LanguageKind.ToLanguageServerKind(); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Hover>( textBuffer, Methods.TextDocumentHoverName, languageServerName, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var result)) { return(null); } if (result.Range is null) { _logger.LogInformation("Received no results."); return(null); } _logger.LogInformation("Received result, remapping."); var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, new[] { result.Range }, cancellationToken).ConfigureAwait(false); if (mappingResult is null || mappingResult.Ranges[0].IsUndefined()) { // Couldn't remap the edits properly. Returning hover at initial request position. _logger.LogInformation("Mapping failed"); return(CreateHover(result, new Range { Start = request.Position, End = request.Position })); }
public async Task <SumType <CompletionItem[], CompletionList>?> HandleRequestAsync(CompletionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } // Switch to a background thread. await TaskScheduler.Default; var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; var(succeeded, result) = await TryGetProvisionalCompletionsAsync(request, documentSnapshot, projectionResult, cancellationToken).ConfigureAwait(false); if (succeeded) { // This means the user has just typed a dot after some identifier such as (cursor is pipe): "DateTime.| " // In this case Razor interprets after the dot as Html and before it as C#. // We use this criteria to provide a better completion experience for what we call provisional changes. } else if (!TriggerAppliesToProjection(request.Context, projectionResult.LanguageKind)) { return(null); } else { // This is a valid non-provisional completion request. var completionParams = new CompletionParams() { Context = request.Context, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; result = await _requestInvoker.RequestServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>( Methods.TextDocumentCompletionName, serverKind, completionParams, cancellationToken).ConfigureAwait(false); } if (result.HasValue) { // Set some context on the CompletionItem so the CompletionResolveHandler can handle it accordingly. result = SetResolveData(result.Value, serverKind); } return(result); }
public async Task <DocumentHighlight[]> HandleRequestAsync(DocumentHighlightParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null || projectionResult.LanguageKind != RazorLanguageKind.CSharp) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var serverKind = LanguageServerKind.CSharp; var documentHighlightParams = new DocumentHighlightParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var highlights = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentHighlightParams, DocumentHighlight[]>( Methods.TextDocumentDocumentHighlightName, serverKind, documentHighlightParams, cancellationToken).ConfigureAwait(false); if (highlights == null || highlights.Length == 0) { return(highlights); } var remappedHighlights = new List <DocumentHighlight>(); var rangesToMap = highlights.Select(r => r.Range).ToArray(); var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, rangesToMap, cancellationToken).ConfigureAwait(false); if (mappingResult == null || mappingResult.HostDocumentVersion != documentSnapshot.Version) { // Couldn't remap the range or the document changed in the meantime. Discard this highlight. return(Array.Empty <DocumentHighlight>()); } for (var i = 0; i < highlights.Length; i++) { var highlight = highlights[i]; var range = mappingResult.Ranges[i]; if (range.IsUndefined()) { // Couldn't remap the range correctly. Discard this range. continue; } var remappedHighlight = new DocumentHighlight() { Range = range, Kind = highlight.Kind }; remappedHighlights.Add(remappedHighlight); } return(remappedHighlights.ToArray()); }
public async Task <SumType <CompletionItem[], CompletionList>?> HandleRequestAsync(CompletionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } if (!TryGetWordExtent(request, documentSnapshot, out var wordExtent)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { if (IsRazorCompilerBugWithCSharpKeywords(request, wordExtent)) { var csharpPolyfilledCompletionList = new CompletionList() { Items = Array.Empty <CompletionItem>(), IsIncomplete = true, }; csharpPolyfilledCompletionList = IncludeCSharpKeywords(csharpPolyfilledCompletionList); return(csharpPolyfilledCompletionList); } return(null); } var projectedPosition = projectionResult.Position; var projectedDocumentUri = projectionResult.Uri; var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; var languageServerName = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? RazorLSPConstants.RazorCSharpLanguageServerName : RazorLSPConstants.HtmlLanguageServerName; var(succeeded, result) = await TryGetProvisionalCompletionsAsync(request, documentSnapshot, projectionResult, cancellationToken).ConfigureAwait(false); if (succeeded) { // This means the user has just typed a dot after some identifier such as (cursor is pipe): "DateTime.| " // In this case Razor interprets after the dot as Html and before it as C#. // We use this criteria to provide a better completion experience for what we call provisional changes. serverKind = LanguageServerKind.CSharp; if (documentSnapshot.TryGetVirtualDocument <CSharpVirtualDocumentSnapshot>(out var csharpVirtualDocumentSnapshot)) { projectedDocumentUri = csharpVirtualDocumentSnapshot.Uri; } else { _logger.LogError("Could not acquire C# virtual document snapshot after provisional completion."); } } else if (!TriggerAppliesToProjection(request.Context, projectionResult.LanguageKind)) { _logger.LogInformation("Trigger does not apply to projection."); return(null); } else { // This is a valid non-provisional completion request. _logger.LogInformation("Searching for non-provisional completions, rewriting context."); var completionContext = RewriteContext(request.Context, projectionResult.LanguageKind); var completionParams = new CompletionParams() { Context = completionContext, Position = projectedPosition, TextDocument = new TextDocumentIdentifier() { Uri = projectedDocumentUri } }; _logger.LogInformation($"Requesting non-provisional completions for {projectedDocumentUri}."); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>( textBuffer, Methods.TextDocumentCompletionName, languageServerName, completionParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out result)) { return(null); } _logger.LogInformation("Found non-provisional completion"); } if (TryConvertToCompletionList(result, out var completionList)) { if (serverKind == LanguageServerKind.CSharp) { completionList = PostProcessCSharpCompletionList(request, documentSnapshot, wordExtent, completionList); } completionList = TranslateTextEdits(request.Position, projectedPosition, wordExtent, completionList); var requestContext = new CompletionRequestContext(documentSnapshot.Uri, projectedDocumentUri, serverKind); var resultId = _completionRequestContextCache.Set(requestContext); SetResolveData(resultId, completionList); } if (completionList != null) { completionList = completionList is VSInternalCompletionList vsCompletionList ? new OptimizedVSCompletionList(vsCompletionList) : new OptimizedVSCompletionList(completionList); } _logger.LogInformation("Returning completion list."); return(completionList);
public async Task <DocumentHighlight[]> HandleRequestAsync(DocumentHighlightParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } var serverKind = projectionResult.LanguageKind == RazorLanguageKind.CSharp ? LanguageServerKind.CSharp : LanguageServerKind.Html; cancellationToken.ThrowIfCancellationRequested(); var documentHighlightParams = new DocumentHighlightParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; _logger.LogInformation($"Requesting highlights for {projectionResult.Uri} at ({projectionResult.Position?.Line}, {projectionResult.Position?.Character})."); var highlights = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentHighlightParams, DocumentHighlight[]>( Methods.TextDocumentDocumentHighlightName, serverKind.ToContentType(), documentHighlightParams, cancellationToken).ConfigureAwait(false); if (highlights == null || highlights.Length == 0) { _logger.LogInformation("Received no results."); return(highlights); } _logger.LogInformation($"Received {highlights.Length} results, remapping."); var remappedHighlights = new List <DocumentHighlight>(); var rangesToMap = highlights.Select(r => r.Range).ToArray(); var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, rangesToMap, cancellationToken).ConfigureAwait(false); if (mappingResult == null || mappingResult.HostDocumentVersion != documentSnapshot.Version) { // Couldn't remap the range or the document changed in the meantime. Discard this highlight. _logger.LogInformation($"Mapping failed. Versions: {documentSnapshot.Version} -> {mappingResult?.HostDocumentVersion}."); return(Array.Empty <DocumentHighlight>()); } for (var i = 0; i < highlights.Length; i++) { var highlight = highlights[i]; var range = mappingResult.Ranges[i]; if (range.IsUndefined()) { // Couldn't remap the range correctly. Discard this range. continue; } var remappedHighlight = new DocumentHighlight() { Range = range, Kind = highlight.Kind }; remappedHighlights.Add(remappedHighlight); } _logger.LogInformation($"Returning {remappedHighlights.Count} highlights."); return(remappedHighlights.ToArray()); }
public async Task <DocumentOnAutoInsertResponseItem> HandleRequestAsync(DocumentOnAutoInsertParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (!AllAllowedTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { // We haven't built support for this character yet. return(null); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}, with trigger character {request.Character}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } else if (projectionResult.LanguageKind == RazorLanguageKind.Razor) { _logger.LogInformation("OnAutoInsert not supported in Razor context."); return(null); } else if (projectionResult.LanguageKind == RazorLanguageKind.Html && !HTMLAllowedTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { _logger.LogInformation("Inapplicable HTML trigger char."); return(null); } else if (projectionResult.LanguageKind == RazorLanguageKind.CSharp && !CSharpAllowedTriggerCharacters.Contains(request.Character, StringComparer.Ordinal)) { _logger.LogInformation("Inapplicable C# trigger char."); return(null); } var formattingParams = new DocumentOnAutoInsertParams() { Character = request.Character, Options = request.Options, Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; _logger.LogInformation($"Requesting auto-insert for {projectionResult.Uri}."); var contentType = projectionResult.LanguageKind.ToContainedLanguageContentType(); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentOnAutoInsertParams, DocumentOnAutoInsertResponseItem>( MSLSPMethods.OnAutoInsertName, contentType, formattingParams, cancellationToken).ConfigureAwait(false); if (response == null) { _logger.LogInformation("Received no results."); return(null); } _logger.LogInformation("Received result, remapping."); var containsSnippet = response.TextEditFormat == InsertTextFormat.Snippet; var remappedEdits = await _documentMappingProvider.RemapFormattedTextEditsAsync( projectionResult.Uri, new[] { response.TextEdit }, request.Options, containsSnippet, cancellationToken).ConfigureAwait(false); if (!remappedEdits.Any()) { _logger.LogInformation("No edits remain after remapping."); return(null); } var remappedEdit = remappedEdits.Single(); var remappedResponse = new DocumentOnAutoInsertResponseItem() { TextEdit = remappedEdit, TextEditFormat = response.TextEditFormat, }; _logger.LogInformation($"Returning edit."); return(remappedResponse); }
public async Task <Location[]> HandleRequestAsync(TextDocumentPositionParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri}."); if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync( documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var textDocumentPositionParams = new TextDocumentPositionParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; var serverKind = projectionResult.LanguageKind.ToLanguageServerKind(); var languageServerName = serverKind.ToLanguageServerName(); _logger.LogInformation($"Requesting {languageServerName} implementation for {projectionResult.Uri}."); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Location[]>( textBuffer, Methods.TextDocumentImplementationName, languageServerName, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var locations)) { return(null); } if (locations.Length == 0) { _logger.LogInformation("Received no results."); return(locations); } _logger.LogInformation($"Received {locations.Length} results, remapping."); cancellationToken.ThrowIfCancellationRequested(); var remappedLocations = await _documentMappingProvider.RemapLocationsAsync(locations, cancellationToken).ConfigureAwait(false); _logger.LogInformation($"Returning {remappedLocations?.Length} locations."); return(remappedLocations); }
// Internal for testing internal async override Task <VSReferenceItem[]> HandleRequestAsync(ReferenceParams request, ClientCapabilities clientCapabilities, string token, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } if (clientCapabilities is null) { throw new ArgumentNullException(nameof(clientCapabilities)); } if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot)) { return(null); } var projectionResult = await _projectionProvider.GetProjectionAsync(documentSnapshot, request.Position, cancellationToken).ConfigureAwait(false); if (projectionResult == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var referenceParams = new SerializableReferenceParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri }, Context = request.Context, PartialResultToken = token // request.PartialResultToken }; if (!_lspProgressListener.TryListenForProgress( token, onProgressNotifyAsync: (value, ct) => ProcessReferenceItemsAsync(value, request.PartialResultToken, ct), WaitForProgressNotificationTimeout, cancellationToken, out var onCompleted)) { return(null); } var result = await _requestInvoker.ReinvokeRequestOnServerAsync <SerializableReferenceParams, VSReferenceItem[]>( Methods.TextDocumentReferencesName, projectionResult.LanguageKind.ToContainedLanguageContentType(), referenceParams, cancellationToken).ConfigureAwait(false); if (result == null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); // We must not return till we have received the progress notifications // and reported the results via the PartialResultToken await onCompleted.ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Results returned through Progress notification var remappedResults = await RemapReferenceItemsAsync(result, cancellationToken).ConfigureAwait(false); return(remappedResults); }