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
            });
        }
示例#4
0
    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()
        });
    }
示例#5
0
        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);
        }