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 <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); }