public override async Task <RazorDiagnosticsResponse?> TranslateAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Diagnostic[] diagnostics, CancellationToken cancellationToken) { if (!_documentManager.TryGetDocument(razorDocumentUri, out var documentSnapshot)) { return(new RazorDiagnosticsResponse() { Diagnostics = Array.Empty <Diagnostic>(), }); } var diagnosticsParams = new RazorDiagnosticsParams() { Kind = languageKind, RazorDocumentUri = razorDocumentUri, Diagnostics = diagnostics }; var response = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorDiagnosticsParams, RazorDiagnosticsResponse>( documentSnapshot.Snapshot.TextBuffer, LanguageServerConstants.RazorTranslateDiagnosticsEndpoint, RazorLSPConstants.RazorLanguageServerName, diagnosticsParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, RazorLSPConstants.RazorLanguageServerName, out var result)) { return(null); } return(result); }
public async Task <CompletionItem?> HandleRequestAsync(CompletionItem request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request.Data is null) { _logger.LogInformation("Received no completion resolve data."); return(request); } _logger.LogInformation("Starting request to resolve completion."); var resolveData = request.Data is CompletionResolveData data ? data : ((JToken)request.Data).ToObject <CompletionResolveData>(); if (resolveData is null) { _logger.LogInformation("CompletionResolveData failed to serialize."); return(request); } // Set the original resolve data back so the language server deserializes it correctly. request.Data = resolveData.OriginalData; if (!_completionRequestContextCache.TryGet(resolveData.ResultId, out var requestContext)) { _logger.LogInformation("Could not find the associated request context."); return(request); } if (!_documentManager.TryGetDocument(requestContext.HostDocumentUri, out var documentSnapshot)) { _logger.LogError("Could not find the associated host document for completion resolve: {0}.", requestContext.HostDocumentUri); return(request); } var serverKind = requestContext.LanguageServerKind; var languageServerName = serverKind.ToLanguageServerName(); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <CompletionItem, CompletionItem>( textBuffer, Methods.TextDocumentCompletionResolveName, languageServerName, request, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, RazorLSPConstants.RazorCSharpLanguageServerName, out var result)) { return(request); } _logger.LogInformation("Received result, post-processing."); var postProcessedResult = await PostProcessCompletionItemAsync(request, result, requestContext, documentSnapshot, cancellationToken).ConfigureAwait(false); _logger.LogInformation("Returning resolved completion."); return(postProcessedResult); }
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); }
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 is 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 serverKind = projectionResult.LanguageKind.ToLanguageServerKind(); var languageServerName = serverKind.ToLanguageServerName(); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>( textBuffer, Methods.TextDocumentSignatureHelpName, languageServerName, textDocumentPositionParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var signatureHelp)) { return(null); } _logger.LogInformation("Returning result."); return(signatureHelp); }
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 <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 is 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 languageServerName = serverKind.ToLanguageServerName(); var textBuffer = serverKind.GetTextBuffer(documentSnapshot); var response = await _requestInvoker.ReinvokeRequestOnServerAsync <DocumentHighlightParams, DocumentHighlight[]>( textBuffer, Methods.TextDocumentDocumentHighlightName, languageServerName, documentHighlightParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, languageServerName, out var highlights)) { return(null); } if (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?.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 <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 <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>()); }