public override 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 documentOptions = await ProtocolConversions.FormattingOptionsToDocumentOptionsAsync( request.Options, document, cancellationToken).ConfigureAwait(false); var options = DocumentationCommentOptions.From(documentOptions); // 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 documentationCommentResponse = await GetDocumentationCommentResponseAsync( request, document, service, options, 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 = IndentationOptions.From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); var braceCompletionAfterReturnResponse = await GetBraceCompletionAfterReturnResponseAsync( request, document, indentationOptions, cancellationToken).ConfigureAwait(false); if (braceCompletionAfterReturnResponse != null) { return(braceCompletionAfterReturnResponse); } } return(null); }
public async Task <ImmutableArray <TextChange> > GetFormattingChangesAsync( Document document, char typedChar, int caretPosition, DocumentOptionSet?documentOptions, CancellationToken cancellationToken) { // first, find the token user just typed. var token = await GetTokenBeforeTheCaretAsync(document, caretPosition, cancellationToken).ConfigureAwait(false); if (token.IsMissing || !ValidSingleOrMultiCharactersTokenKind(typedChar, token.Kind()) || token.IsKind(SyntaxKind.EndOfFileToken, SyntaxKind.None)) { return(ImmutableArray <TextChange> .Empty); } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var formattingRules = GetFormattingRules(document, caretPosition, token); var service = document.GetLanguageService <ISyntaxFactsService>(); if (service != null && service.IsInNonUserCode(token.SyntaxTree, caretPosition, cancellationToken)) { return(ImmutableArray <TextChange> .Empty); } var shouldNotFormat = await TokenShouldNotFormatOnTypeCharAsync(token, cancellationToken).ConfigureAwait(false); if (shouldNotFormat) { return(ImmutableArray <TextChange> .Empty); } var services = document.Project.Solution.Workspace.Services; if (documentOptions == null) { var inferredIndentationService = services.GetRequiredService <IInferredIndentationService>(); documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat : false, cancellationToken : cancellationToken).ConfigureAwait(false); } var options = IndentationOptions.From(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language); // Do not attempt to format on open/close brace if autoformat on close brace feature is // off, instead just smart indent. // // We want this behavior because it's totally reasonable for a user to want to not have // on automatic formatting because they feel it is too aggressive. However, by default, // if you have smart-indentation on and are just hitting enter, you'll common have the // caret placed one indent higher than your current construct. For example, if you have: // // if (true) // $ <-- smart indent will have placed the caret here here. // // This is acceptable given that the user may want to just write a simple statement there. // However, if they start writing `{`, then things should snap over to be: // // if (true) // { // // Importantly, this is just an indentation change, no actual 'formatting' is done. We do // the same with close brace. If you have: // // if (...) // { // bad . ly ( for (mmated+code) ) ; // $ <-- smart indent will have placed the care here. // // If the user hits `}` then we will properly smart indent the `}` to match the `{`. // However, we won't touch any of the other code in that block, unlike if we were // formatting. var onlySmartIndent = (token.IsKind(SyntaxKind.CloseBraceToken) && OnlySmartIndentCloseBrace(options.AutoFormattingOptions)) || (token.IsKind(SyntaxKind.OpenBraceToken) && OnlySmartIndentOpenBrace(options.AutoFormattingOptions)); if (onlySmartIndent) { // if we're only doing smart indent, then ignore all edits to this token that occur before // the span of the token. They're irrelevant and may screw up other code the user doesn't // want touched. var tokenEdits = await FormatTokenAsync(document, options, token, formattingRules, cancellationToken).ConfigureAwait(false); return(tokenEdits.Where(t => t.Span.Start >= token.FullSpan.Start).ToImmutableArray()); } // if formatting range fails, do format token one at least var changes = await FormatRangeAsync(document, options, token, formattingRules, cancellationToken).ConfigureAwait(false); if (changes.Length > 0) { return(changes); } return((await FormatTokenAsync(document, options, token, formattingRules, cancellationToken).ConfigureAwait(false)).ToImmutableArray()); }