public async Task <RazorProximityExpressionsResponse?> Handle(RazorProximityExpressionsParams request, CancellationToken cancellationToken) { var documentSnapshot = await TryGetDocumentSnapshotAndVersionAsync(request.Uri.GetAbsoluteOrUNCPath(), cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { return(null); } var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); var sourceText = await documentSnapshot.GetTextAsync(); var linePosition = new LinePosition(request.Position.Line, request.Position.Character); var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); if (codeDocument.IsUnsupported()) { return(null); } var projectedIndex = hostDocumentIndex; var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); // If we're in C#, then map to the right position in the generated document if (languageKind == RazorLanguageKind.CSharp && !_documentMappingService.TryMapToProjectedDocumentPosition(codeDocument, hostDocumentIndex, out _, out projectedIndex)) { return(null); } // Otherwise see if there is more C# on the line to map to else if (languageKind == RazorLanguageKind.Html && !_documentMappingService.TryMapToProjectedDocumentOrNextCSharpPosition(codeDocument, hostDocumentIndex, out _, out projectedIndex)) { return(null); } else if (languageKind == RazorLanguageKind.Razor) { return(null); } // Now ask Roslyn to adjust the breakpoint to a valid location in the code var csharpDocument = codeDocument.GetCSharpDocument(); var syntaxTree = CSharpSyntaxTree.ParseText(csharpDocument.GeneratedCode, cancellationToken: cancellationToken); var expressions = RazorCSharpProximityExpressionResolverService.GetProximityExpressions(syntaxTree, projectedIndex, cancellationToken)?.ToList(); if (expressions == null) { return(null); } _logger.LogTrace($"Proximity expressions request for ({request.Position.Line}, {request.Position.Character}) yielded {expressions.Count} results."); return(new RazorProximityExpressionsResponse { Expressions = expressions, }); }
public async Task <WrapWithTagResponse?> Handle(WrapWithTagParams request, CancellationToken cancellationToken) { var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return(documentSnapshot); }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { _logger.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } cancellationToken.ThrowIfCancellationRequested(); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); if (codeDocument.IsUnsupported()) { _logger.LogWarning($"Failed to retrieve generated output for document {request.TextDocument.Uri}."); return(null); } var sourceText = await documentSnapshot.GetTextAsync().ConfigureAwait(false); if (request.Range?.Start.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex) != true) { return(null); } var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); if (languageKind is not RazorLanguageKind.Html) { _logger.LogInformation($"Unsupported language {languageKind:G}."); return(null); } cancellationToken.ThrowIfCancellationRequested(); var parameter = request; var response = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorWrapWithTagEndpoint, parameter).ConfigureAwait(false); var htmlResponse = await response.Returning <WrapWithTagResponse>(cancellationToken).ConfigureAwait(false); return(htmlResponse); }
public async Task <RazorBreakpointSpanResponse?> Handle(RazorBreakpointSpanParams request, CancellationToken cancellationToken) { var documentSnapshot = await TryGetDocumentSnapshotAndVersionAsync(request.Uri.GetAbsoluteOrUNCPath(), cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { return(null); } var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); var sourceText = await documentSnapshot.GetTextAsync(); var linePosition = new LinePosition(request.Position.Line, request.Position.Character); var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); if (codeDocument.IsUnsupported()) { return(null); } var projectedIndex = hostDocumentIndex; var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); // If we're in C#, then map to the right position in the generated document if (languageKind == RazorLanguageKind.CSharp && !_documentMappingService.TryMapToProjectedDocumentPosition(codeDocument, hostDocumentIndex, out _, out projectedIndex)) { return(null); } // Otherwise see if there is more C# on the line to map to else if (languageKind == RazorLanguageKind.Html && !_documentMappingService.TryMapToProjectedDocumentOrNextCSharpPosition(codeDocument, hostDocumentIndex, out _, out projectedIndex)) { return(null); } else if (languageKind == RazorLanguageKind.Razor) { return(null); } // Now ask Roslyn to adjust the breakpoint to a valid location in the code var csharpDocument = codeDocument.GetCSharpDocument(); var syntaxTree = CSharpSyntaxTree.ParseText(csharpDocument.GeneratedCode, cancellationToken: cancellationToken); if (!RazorBreakpointSpans.TryGetBreakpointSpan(syntaxTree, projectedIndex, cancellationToken, out var csharpBreakpointSpan)) { return(null); } var csharpText = codeDocument.GetCSharpSourceText(); csharpText.GetLineAndOffset(csharpBreakpointSpan.Start, out var startLineIndex, out var startCharacterIndex); csharpText.GetLineAndOffset(csharpBreakpointSpan.End, out var endLineIndex, out var endCharacterIndex); var projectedRange = new Range() { Start = new Position(startLineIndex, startCharacterIndex), End = new Position(endLineIndex, endCharacterIndex), }; // Now map that new C# location back to the host document var mappingBehavior = GetMappingBehavior(documentSnapshot); if (!_documentMappingService.TryMapFromProjectedDocumentRange(codeDocument, projectedRange, mappingBehavior, out var hostDocumentRange)) { return(null); } cancellationToken.ThrowIfCancellationRequested(); _logger.LogTrace($"Breakpoint span request for ({request.Position.Line}, {request.Position.Character}) = ({hostDocumentRange.Start.Line}, {hostDocumentRange.Start.Character}"); return(new RazorBreakpointSpanResponse() { Range = hostDocumentRange }); }
public async Task <InlineCompletionList?> Handle(InlineCompletionRequest request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } _logger.LogInformation($"Starting request for {request.TextDocument.Uri} at {request.Position}."); var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return(documentSnapshot); }, cancellationToken).ConfigureAwait(false); if (document is null) { return(null); } var codeDocument = await document.GetGeneratedOutputAsync(); if (codeDocument.IsUnsupported()) { return(null); } var sourceText = await document.GetTextAsync(); var linePosition = new LinePosition(request.Position.Line, request.Position.Character); var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); // Map to the location in the C# document. if (languageKind != RazorLanguageKind.CSharp || !_documentMappingService.TryMapToProjectedDocumentPosition(codeDocument, hostDocumentIndex, out var projectedPosition, out _)) { _logger.LogInformation($"Unsupported location for {request.TextDocument.Uri}."); return(null); } var razorRequest = new RazorInlineCompletionRequest { TextDocument = request.TextDocument, Context = request.Context, Position = projectedPosition, Kind = languageKind, Options = request.Options, }; request.Position = projectedPosition; var response = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorInlineCompletionEndpoint, razorRequest).ConfigureAwait(false); var list = await response.Returning <InlineCompletionList>(cancellationToken).ConfigureAwait(false); if (list == null || !list.Items.Any()) { _logger.LogInformation($"Did not get any inline completions from delegation."); return(null); } var items = new List <InlineCompletionItem>(); var csharpDocOptions = codeDocument.GetCSharpDocument(); foreach (var item in list.Items) { var containsSnippet = item.TextFormat == InsertTextFormat.Snippet; var range = item.Range ?? new Range { Start = projectedPosition, End = projectedPosition }; if (!_documentMappingService.TryMapFromProjectedDocumentRange(codeDocument, range, out var rangeInRazorDoc)) { _logger.LogWarning($"Could not remap projected range {range} to razor document"); continue; } using var formattingContext = FormattingContext.Create(request.TextDocument.Uri, document, codeDocument, request.Options, _adhocWorkspaceFactory); if (!TryGetSnippetWithAdjustedIndentation(formattingContext, item.Text, hostDocumentIndex, out var newSnippetText)) { continue; } var remappedItem = new InlineCompletionItem { Command = item.Command, Range = rangeInRazorDoc, Text = newSnippetText.ToString(), TextFormat = item.TextFormat, }; items.Add(remappedItem); } if (items.Count == 0) { _logger.LogInformation($"Could not format / map the items from delegation."); return(null); } _logger.LogInformation($"Returning {items.Count} items."); return(new InlineCompletionList { Items = items.ToArray() }); }
public async Task <WorkspaceEdit?> Handle(TParams request, CancellationToken cancellationToken) { var documentAndVersion = await TryGetDocumentSnapshotAndVersionAsync( request.TextDocument.Uri.GetAbsoluteOrUNCPath(), cancellationToken).ConfigureAwait(false); if (documentAndVersion is null) { return(null); } var(documentSnapshot, version) = documentAndVersion; if (documentSnapshot is null) { return(null); } cancellationToken.ThrowIfCancellationRequested(); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); if (codeDocument.IsUnsupported()) { _logger.LogWarning($"Failed to retrieve generated output for document {request.TextDocument.Uri}."); return(null); } var sourceText = await documentSnapshot.GetTextAsync().ConfigureAwait(false); if (request.Range.Start.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex) != true) { return(null); } var languageKind = _razorDocumentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); // See if we can handle this directly in Razor. If not, we'll let things flow to the below delegated handling. var result = await TryGetRazorWorkspaceEditAsync(languageKind, request, cancellationToken).ConfigureAwait(false); if (result is not null) { return(result); } if (languageKind is not(RazorLanguageKind.CSharp or RazorLanguageKind.Html)) { _logger.LogInformation($"Unsupported language {languageKind:G}."); return(null); } var requestParams = CreateRazorRequestParameters(request); requestParams.HostDocumentVersion = version; requestParams.Kind = languageKind; // For CSharp we need to map the range to the generated document if (languageKind == RazorLanguageKind.CSharp) { if (!_razorDocumentMappingService.TryMapToProjectedDocumentRange(codeDocument, request.Range, out var projectedRange)) { return(null); } requestParams.Range = projectedRange; } var delegatedRequest = await _languageServer.SendRequestAsync(EndpointName, requestParams).ConfigureAwait(false); var response = await delegatedRequest.Returning <WorkspaceEdit?>(cancellationToken).ConfigureAwait(false); if (response is null) { return(null); } // The responses we get back will be for virtual documents, so we have to map them back to the real // document, and in the case of C#, map the returned ranges too var edit = MapWorkspaceEdit(response, mapRanges: languageKind == RazorLanguageKind.CSharp, codeDocument); return(edit); }