public override async Task <VSInternalInlineCompletionList?> HandleRequestAsync(VSInternalInlineCompletionRequest request, RequestContext context, CancellationToken cancellationToken) { Contract.ThrowIfNull(context.Document); // First get available snippets if any. var snippetInfoService = context.Document.Project.GetRequiredLanguageService <ISnippetInfoService>(); var snippetInfo = snippetInfoService.GetSnippetsIfAvailable(); if (!snippetInfo.Any()) { return(null); } // Then attempt to get the word at the requested position. var sourceText = await context.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); var syntaxFactsService = context.Document.Project.GetRequiredLanguageService <ISyntaxFactsService>(); var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); var position = sourceText.Lines.GetPosition(linePosition); if (!SnippetUtilities.TryGetWordOnLeft(position, sourceText, syntaxFactsService, out var wordOnLeft)) { return(null); } // Find the snippet with shortcut text that matches the typed word. var wordText = sourceText.GetSubText(wordOnLeft.Value).ToString(); if (!BuiltInSnippets.Contains(wordText, StringComparer.OrdinalIgnoreCase)) { return(null); } var matchingSnippetInfo = snippetInfo.First(s => wordText.Equals(s.Shortcut, StringComparison.OrdinalIgnoreCase)); var parsedSnippet = _xmlSnippetParser.GetParsedXmlSnippet(matchingSnippetInfo, context); if (parsedSnippet == null) { return(null); } // Use the formatting options specified by the client to format the snippet. var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, context.Document, cancellationToken).ConfigureAwait(false); var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, formattingOptions, cancellationToken).ConfigureAwait(false); return(new VSInternalInlineCompletionList { Items = new VSInternalInlineCompletionItem[] { new VSInternalInlineCompletionItem { Range = ProtocolConversions.TextSpanToRange(wordOnLeft.Value, sourceText), Text = formattedLspSnippet, TextFormat = InsertTextFormat.Snippet, } } }); }
protected static async Task <LSP.TextEdit[]?> GetTextEditsAsync( RequestContext context, LSP.FormattingOptions options, IGlobalOptionService globalOptions, CancellationToken cancellationToken, LSP.Range?range = null) { var document = context.Document; if (document == null) { return(null); } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var rangeSpan = (range != null) ? ProtocolConversions.RangeToTextSpan(range, text) : new TextSpan(0, root.FullSpan.Length); var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, rangeSpan); // We should use the options passed in by LSP instead of the document's options. var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(options, document, globalOptions, cancellationToken).ConfigureAwait(false); var services = document.Project.Solution.Services; var textChanges = Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, rules: null, cancellationToken); var edits = new ArrayBuilder <LSP.TextEdit>(); edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); return(edits.ToArrayAndFree()); }
public async Task <LSP.VSInternalDocumentOnAutoInsertResponseItem?> HandleRequestAsync( LSP.VSInternalDocumentOnAutoInsertParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; if (document == null) { return(null); } var service = document.GetRequiredLanguageService <IDocumentationCommentSnippetService>(); // We should use the options passed in by LSP instead of the document's options. var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, _globalOptions, cancellationToken).ConfigureAwait(false); // The editor calls this handler for C# and VB comment characters, but we only need to process the one for the language that matches the document if (request.Character == "\n" || request.Character == service.DocumentationCommentCharacter) { var docCommentOptions = _globalOptions.GetDocumentationCommentOptions(formattingOptions, document.Project.Language); var documentationCommentResponse = await GetDocumentationCommentResponseAsync( request, document, service, docCommentOptions, cancellationToken).ConfigureAwait(false); if (documentationCommentResponse != null) { return(documentationCommentResponse); } } // Only support this for razor as LSP doesn't support overtype yet. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1165179/ // Once LSP supports overtype we can move all of brace completion to LSP. if (request.Character == "\n" && context.ServerKind == WellKnownLspServerKinds.RazorLspServer) { var indentationOptions = new IndentationOptions(formattingOptions) { AutoFormattingOptions = _globalOptions.GetAutoFormattingOptions(document.Project.Language) }; var braceCompletionAfterReturnResponse = await GetBraceCompletionAfterReturnResponseAsync( request, document, indentationOptions, cancellationToken).ConfigureAwait(false); if (braceCompletionAfterReturnResponse != null) { return(braceCompletionAfterReturnResponse); } } return(null); }
public async Task <TextEdit[]?> HandleRequestAsync( DocumentOnTypeFormattingParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; if (document == null) { return(null); } var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(request.Character) || SyntaxFacts.IsNewLine(request.Character[0])) { return(Array.Empty <TextEdit>()); } var formattingService = document.Project.LanguageServices.GetRequiredService <ISyntaxFormattingService>(); var documentSyntax = await ParsedDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); if (!formattingService.ShouldFormatOnTypedCharacter(documentSyntax, request.Character[0], position, cancellationToken)) { return(Array.Empty <TextEdit>()); } // We should use the options passed in by LSP instead of the document's options. var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(request.Options, document, _globalOptions, cancellationToken).ConfigureAwait(false); var indentationOptions = new IndentationOptions(formattingOptions) { AutoFormattingOptions = _globalOptions.GetAutoFormattingOptions(document.Project.Language) }; var textChanges = formattingService.GetFormattingChangesOnTypedCharacter(documentSyntax, position, indentationOptions, cancellationToken); if (textChanges.IsEmpty) { return(Array.Empty <TextEdit>()); } var edits = new ArrayBuilder <TextEdit>(); edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, documentSyntax.Text))); return(edits.ToArrayAndFree()); }