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