protected void RunAutoInsertTest(string input, string expected, int tabSize = 4, bool insertSpaces = true, string fileKind = default, IReadOnlyList <TagHelperDescriptor> tagHelpers = default)
        {
            // Arrange
            TestFileMarkupParser.GetPosition(input, out input, out var location);

            var source = SourceText.From(input);

            source.GetLineAndOffset(location, out var line, out var column);
            var position = new Position(line, column);

            var path         = "file:///path/to/document.razor";
            var uri          = new Uri(path);
            var codeDocument = CreateCodeDocument(source, uri.AbsolutePath, tagHelpers, fileKind: fileKind);
            var options      = new FormattingOptions()
            {
                TabSize      = tabSize,
                InsertSpaces = insertSpaces,
            };

            var provider = CreateProvider();
            var context  = FormattingContext.Create(uri, Mock.Of <DocumentSnapshot>(MockBehavior.Strict), codeDocument, options, TestAdhocWorkspaceFactory.Instance);

            // Act
            if (!provider.TryResolveInsertion(position, context, out var edit, out _))
            {
                edit = null;
            }

            // Assert
            var edited = edit is null ? source : ApplyEdit(source, edit);
            var actual = edited.ToString();

            Assert.Equal(expected, actual);
        }
Ejemplo n.º 2
0
        protected void RunAutoInsertTest(string input, string expected, string character, int tabSize = 4, bool insertSpaces = true, string fileKind = default, IReadOnlyList <TagHelperDescriptor> tagHelpers = default)
        {
            // Arrange
            var location = input.IndexOf('|', StringComparison.Ordinal) + character.Length;

            input = input.Replace("|", character, StringComparison.Ordinal);

            var source = SourceText.From(input);

            source.GetLineAndOffset(location, out var line, out var column);
            var position = new Position(line, column);

            var path         = "file:///path/to/document.razor";
            var uri          = new Uri(path);
            var codeDocument = CreateCodeDocument(source, uri.AbsolutePath, tagHelpers, fileKind: fileKind);
            var options      = new FormattingOptions()
            {
                TabSize      = tabSize,
                InsertSpaces = insertSpaces,
            };

            var provider = CreateProvider();
            var context  = FormattingContext.Create(uri, Mock.Of <DocumentSnapshot>(), codeDocument, options, new Range(position, position));

            // Act
            if (!provider.TryResolveInsertion(position, context, out var edit, out var format))
            {
                edit = null;
            }

            // Assert
            var edited = edit == null ? source : ApplyEdit(source, edit);
            var actual = edited.ToString();

            Assert.Equal(expected, actual);
        }
        public async Task <OnAutoInsertResponse> Handle(OnAutoInsertParams request, CancellationToken cancellationToken)
        {
            var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
            {
                _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot);

                return(documentSnapshot);
            }, cancellationToken).ConfigureAwait(false);

            if (document is null || cancellationToken.IsCancellationRequested)
            {
                return(null);
            }

            var codeDocument = await document.GetGeneratedOutputAsync();

            if (codeDocument.IsUnsupported())
            {
                return(null);
            }

            cancellationToken.ThrowIfCancellationRequested();

            var character = request.Character;

            var applicableProviders = new List <RazorOnAutoInsertProvider>();

            for (var i = 0; i < _onAutoInsertProviders.Count; i++)
            {
                var formatOnTypeProvider = _onAutoInsertProviders[i];
                if (formatOnTypeProvider.TriggerCharacter == character)
                {
                    applicableProviders.Add(formatOnTypeProvider);
                }
            }

            if (applicableProviders.Count == 0)
            {
                // There's currently a bug in the LSP platform where other language clients OnAutoInsert trigger characters influence every language clients trigger characters.
                // To combat this we need to pre-emptively return so we don't try having our providers handle characters that they can't.
                return(null);
            }

            var uri      = request.TextDocument.Uri;
            var position = request.Position;

            using (var formattingContext = FormattingContext.Create(uri, document, codeDocument, request.Options, _workspaceFactory))
            {
                for (var i = 0; i < applicableProviders.Count; i++)
                {
                    if (applicableProviders[i].TryResolveInsertion(position, formattingContext, out var textEdit, out var format))
                    {
                        return(new OnAutoInsertResponse()
                        {
                            TextEdit = textEdit,
                            TextEditFormat = format,
                        });
                    }
                }
            }

            // No provider could handle the text edit.
            return(null);
        }
Ejemplo n.º 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()
        });
    }