public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (result.Kind != RazorLanguageKind.Razor)
            {
                // We don't care about changes to projected documents here.
                return(result);
            }

            var originalDiagnostics = context.CodeDocument.GetSyntaxTree().Diagnostics;

            var text           = context.SourceText;
            var edits          = result.Edits;
            var changes        = edits.Select(e => e.AsTextChange(text));
            var changedText    = text.WithChanges(changes);
            var changedContext = await context.WithTextAsync(changedText);

            var changedDiagnostics = changedContext.CodeDocument.GetSyntaxTree().Diagnostics;

            if (!originalDiagnostics.SequenceEqual(changedDiagnostics))
            {
                // Looks like we removed some non-whitespace content as part of formatting. Oops.
                // Discard this formatting result.

                if (DebugAssertsEnabled)
                {
                    Debug.Fail("A formatting result was rejected because the formatted text produced different diagnostics compared to the original text.");
                }

                return(new FormattingResult(Array.Empty <TextEdit>()));
            }

            return(result);
        }
Пример #2
0
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (context.IsFormatOnType || result.Kind != RazorLanguageKind.Razor)
            {
                // We don't want to handle OnTypeFormatting here.
                return(result);
            }

            // Apply previous edits if any.
            var originalText   = context.SourceText;
            var changedText    = originalText;
            var changedContext = context;

            if (result.Edits.Length > 0)
            {
                var changes = result.Edits.Select(e => e.AsTextChange(originalText)).ToArray();
                changedText    = changedText.WithChanges(changes);
                changedContext = await context.WithTextAsync(changedText);
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Apply original C# edits
            var csharpEdits = await FormatCSharpAsync(changedContext, cancellationToken);

            if (csharpEdits.Count > 0)
            {
                var csharpChanges = csharpEdits.Select(c => c.AsTextChange(changedText));
                changedText    = changedText.WithChanges(csharpChanges);
                changedContext = await changedContext.WithTextAsync(changedText);
            }

            cancellationToken.ThrowIfCancellationRequested();

            // We make an optimistic attempt at fixing corner cases.
            var cleanupChanges = CleanupDocument(changedContext);

            changedText    = changedText.WithChanges(cleanupChanges);
            changedContext = await changedContext.WithTextAsync(changedText);

            cancellationToken.ThrowIfCancellationRequested();

            var indentationChanges = await AdjustIndentationAsync(changedContext, cancellationToken);

            if (indentationChanges.Count > 0)
            {
                // Apply the edits that modify indentation.
                changedText = changedText.WithChanges(indentationChanges);
            }

            var finalChanges = SourceTextDiffer.GetMinimalTextChanges(originalText, changedText, lineDiffOnly: false);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            return(new FormattingResult(finalEdits));
        }
 public virtual Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
 {
     return(Task.FromResult(Execute(context, result)));
 }
 public virtual FormattingResult Execute(FormattingContext context, FormattingResult result)
 {
     return(result);
 }
Пример #5
0
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (!context.IsFormatOnType || result.Kind != RazorLanguageKind.CSharp)
            {
                // We don't want to handle regular formatting or non-C# on type formatting here.
                return(result);
            }

            // Normalize and re-map the C# edits.
            var codeDocument    = context.CodeDocument;
            var csharpText      = codeDocument.GetCSharpSourceText();
            var normalizedEdits = NormalizeTextEdits(csharpText, result.Edits);
            var mappedEdits     = RemapTextEdits(codeDocument, normalizedEdits, result.Kind);
            var filteredEdits   = FilterCSharpTextEdits(context, mappedEdits);

            if (filteredEdits.Length == 0)
            {
                // There are no CSharp edits for us to apply. No op.
                return(new FormattingResult(filteredEdits));
            }

            // Find the lines that were affected by these edits.
            var originalText = codeDocument.GetSourceText();
            var changes      = filteredEdits.Select(e => e.AsTextChange(originalText));

            // Apply the format on type edits sent over by the client.
            var formattedText  = ApplyChangesAndTrackChange(originalText, changes, out _, out var spanAfterFormatting);
            var changedContext = await context.WithTextAsync(formattedText);

            var rangeAfterFormatting = spanAfterFormatting.AsRange(formattedText);

            cancellationToken.ThrowIfCancellationRequested();

            // We make an optimistic attempt at fixing corner cases.
            var cleanupChanges = CleanupDocument(changedContext, rangeAfterFormatting);
            var cleanedText    = formattedText.WithChanges(cleanupChanges);

            changedContext = await changedContext.WithTextAsync(cleanedText);

            cancellationToken.ThrowIfCancellationRequested();

            // At this point we should have applied all edits that adds/removes newlines.
            // Let's now ensure the indentation of each of those lines is correct.

            // We only want to adjust the range that was affected.
            // We need to take into account the lines affected by formatting as well as cleanup.
            var lineDelta = LineDelta(formattedText, cleanupChanges, out var firstPosition, out var lastPosition);

            // Okay hear me out, I know this looks lazy, but it totally makes sense.
            // This method is called with edits that the C# formatter wants to make, and from those edits we work out which
            // other edits to apply etc. Fine, all good so far. BUT its totally possible that the user typed a closing brace
            // in the same position as the C# formatter thought it should be, on the line _after_ the code that the C# formatter
            // reformatted.
            //
            // For example, given:
            // if (true){
            //     }
            //
            // If the C# formatter is happy with the placement of that close brace then this method will get two edits:
            //  * On line 1 to indent the if by 4 spaces
            //  * On line 1 to add a newline and 4 spaces in front of the opening brace
            //
            // We'll happy format lines 1 and 2, and ignore the closing brace altogether. So, by looking one line further
            // we won't have that problem.
            if (rangeAfterFormatting.End.Line + lineDelta < cleanedText.Lines.Count)
            {
                lineDelta++;
            }

            // Now we know how many lines were affected by the cleanup and formatting, but we don't know where those lines are. For example, given:
            //
            // @if (true)
            // {
            //      }
            // else
            // {
            // $$}
            //
            // When typing that close brace, the changes would fix the previous close brace, but the line delta would be 0, so
            // we'd format line 6 and call it a day, even though the formatter made an edit on line 3. To fix this we use the
            // first and last position of edits made above, and make sure our range encompasses them as well. For convenience
            // we calculate these positions in the LineDelta method called above.
            // This is essentially: rangeToAdjust = new Range(Math.Min(firstFormattingEdit, userEdit), Math.Max(lastFormattingEdit, userEdit))
            var start = rangeAfterFormatting.Start;

            if (firstPosition is not null && firstPosition < start)
            {
                start = firstPosition;
            }

            var end = new Position(rangeAfterFormatting.End.Line + lineDelta, 0);

            if (lastPosition is not null && lastPosition < start)
            {
                end = lastPosition;
            }

            var rangeToAdjust = new Range(start, end);

            Debug.Assert(rangeToAdjust.End.IsValid(cleanedText), "Invalid range. This is unexpected.");

            var indentationChanges = await AdjustIndentationAsync(changedContext, cancellationToken, rangeToAdjust);

            if (indentationChanges.Count > 0)
            {
                // Apply the edits that modify indentation.
                cleanedText = cleanedText.WithChanges(indentationChanges);
            }

            // Now that we have made all the necessary changes to the document. Let's diff the original vs final version and return the diff.
            var finalChanges = cleanedText.GetTextChanges(originalText);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            return(new FormattingResult(finalEdits));
        }
 public abstract Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken);
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (context.IsFormatOnType || result.Kind != RazorLanguageKind.Razor)
            {
                // We don't want to handle OnTypeFormatting here.
                return(result);
            }

            // Apply previous edits if any.
            var originalText   = context.SourceText;
            var changedText    = originalText;
            var changedContext = context;

            if (result.Edits.Length > 0)
            {
                var changes = result.Edits.Select(e => e.AsTextChange(originalText)).ToArray();
                changedText    = changedText.WithChanges(changes);
                changedContext = await context.WithTextAsync(changedText);
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Apply original C# edits
            var csharpEdits = await FormatCSharpAsync(changedContext, cancellationToken);

            if (csharpEdits.Count > 0)
            {
                var csharpChanges = csharpEdits.Select(c => c.AsTextChange(changedText));
                changedText    = changedText.WithChanges(csharpChanges);
                changedContext = await changedContext.WithTextAsync(changedText);

                _logger.LogTestOnly($"After FormatCSharpAsync:\r\n{changedText}");
            }

            cancellationToken.ThrowIfCancellationRequested();

            var indentationChanges = await AdjustIndentationAsync(changedContext, cancellationToken);

            if (indentationChanges.Count > 0)
            {
                // Apply the edits that modify indentation.
                changedText = changedText.WithChanges(indentationChanges);

                _logger.LogTestOnly($"After AdjustIndentationAsync:\r\n{changedText}");
            }

            _logger.LogTestOnly($"Generated C#:\r\n{context.CSharpSourceText}");

            var finalChanges = changedText.GetTextChanges(originalText);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            return(new FormattingResult(finalEdits));
        }
Пример #8
0
        private bool FormatsOutsidePureCSharpDirectiveBlocks(FormattingContext context, FormattingResult result)
        {
            var text          = context.SourceText;
            var changes       = result.Edits.Select(e => e.AsTextChange(text));
            var changedText   = text.WithChanges(changes);
            var affectedSpan  = changedText.GetEncompassingTextChangeRange(text).Span;
            var affectedRange = affectedSpan.AsRange(text);

            var syntaxTree = context.CodeDocument.GetSyntaxTree();
            var nodes      = syntaxTree.GetCodeBlockDirectives();

            var affectedCodeDirective = nodes.FirstOrDefault(n =>
            {
                var range = n.GetRange(context.CodeDocument.Source);
                return(range.Contains(affectedRange));
            });

            if (affectedCodeDirective == null)
            {
                // This edit lies outside any C# directive blocks.
                return(true);
            }

            if (!(affectedCodeDirective.Body is RazorDirectiveBodySyntax directiveBody))
            {
                // This can't happen realistically. Just being defensive.
                return(false);
            }

            // Get the inner code block node that contains the actual code.
            var innerCodeBlockNode = directiveBody.CSharpCode.DescendantNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax);

            if (innerCodeBlockNode == null)
            {
                // Nothing to check.
                return(false);
            }

            if (ContainsNonCSharpContent(innerCodeBlockNode))
            {
                // We currently don't support formatting code block directives with Markup or other Razor constructs.

                _logger.LogDebug("A formatting result was rejected because it was going to format code directive with mixed content.");

                return(true);
            }

            return(false);
        }
Пример #9
0
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (context.IsFormatOnType)
            {
                // We don't want to handle OnTypeFormatting here.
                return(result);
            }

            var originalText = context.SourceText;

            var htmlEdits = await HtmlFormatter.FormatAsync(context, context.Range, cancellationToken);

            var normalizedEdits = NormalizeTextEdits(originalText, htmlEdits);
            var mappedEdits     = RemapTextEdits(context.CodeDocument, normalizedEdits, RazorLanguageKind.Html);
            var changes         = mappedEdits.Select(e => e.AsTextChange(originalText));

            var changedText    = originalText;
            var changedContext = context;

            if (changes.Any())
            {
                changedText = originalText.WithChanges(changes);
                // Create a new formatting context for the changed razor document.
                changedContext = await context.WithTextAsync(changedText);
            }

            var indentationChanges = AdjustRazorIndentation(changedContext);

            if (indentationChanges.Count > 0)
            {
                // Apply the edits that adjust indentation.
                changedText = changedText.WithChanges(indentationChanges);
            }

            var finalChanges = SourceTextDiffer.GetMinimalTextChanges(originalText, changedText, lineDiffOnly: false);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            return(new FormattingResult(finalEdits));
        }
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result)
        {
            if (context.IsFormatOnType)
            {
                // We don't want to handle OnTypeFormatting here.
                return(result);
            }

            Debug.Assert(result.Edits.Length == 0, "CodeBlockDirectiveFormatter should be invoked first.");

            var edits = RemapTextEdits(context.CodeDocument, result.Edits, result.Kind);

            // A code block directive is any extensible directive that can contain C# code. Here is how we represent it,
            // E.g,
            //
            //     @code {  public class Foo { }  }
            // ^                                  ^ ----> Full code block directive range (Includes preceding whitespace)
            //     ^                              ^ ----> Directive range
            //      ^                             ^ ----> DirectiveBody range
            //            ^                      ^  ----> inner codeblock range
            //
            // In this method, we are going to do the following for each code block directive,
            // 1. Format the inner codeblock using the C# formatter
            // 2. Adjust the absolute indentation of the lines formatted by the C# formatter while maintaining the relative indentation
            // 3. Indent the start of the code block (@code {) correctly and move any succeeding code to a separate line
            // 4. Indent the end of the code block (}) correctly and move it to a separate line if necessary
            // 5. Once all the edits are applied, compute the diff for this particular code block and add it to the global list of edits
            //
            var source     = context.CodeDocument.Source;
            var syntaxTree = context.CodeDocument.GetSyntaxTree();
            var nodes      = syntaxTree.GetCodeBlockDirectives();

            var allEdits = new List <TextEdit>();

            // Iterate in reverse so that the newline changes don't affect the next code block directive.
            for (var i = nodes.Count - 1; i >= 0; i--)
            {
                var directive = nodes[i];
                if (!(directive.Body is RazorDirectiveBodySyntax directiveBody))
                {
                    // This can't happen realistically. Just being defensive.
                    continue;
                }

                var directiveRange = directive.GetRange(source);
                if (!directiveRange.OverlapsWith(context.Range))
                {
                    // This block isn't in the selected range.
                    continue;
                }

                // Get the inner code block node that contains the actual code.
                var innerCodeBlockNode = directiveBody.CSharpCode.DescendantNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax);
                if (innerCodeBlockNode == null)
                {
                    // Nothing to indent.
                    continue;
                }

                if (innerCodeBlockNode.DescendantNodes().Any(n =>
                                                             n is MarkupBlockSyntax ||
                                                             n is CSharpTransitionSyntax ||
                                                             n is RazorCommentBlockSyntax))
                {
                    // We currently don't support formatting code block directives with Markup or other Razor constructs.
                    continue;
                }

                var originalText        = context.SourceText;
                var changedText         = originalText;
                var innerCodeBlockRange = innerCodeBlockNode.GetRange(source);

                // Compute the range inside the code block that overlaps with the provided input range.
                var csharprangeToFormat = innerCodeBlockRange.Overlap(context.Range);
                if (csharprangeToFormat != null)
                {
                    var codeEdits = await CSharpFormatter.FormatAsync(context.CodeDocument, csharprangeToFormat, context.Uri, context.Options);

                    changedText = ApplyCSharpEdits(context, innerCodeBlockRange, codeEdits, minCSharpIndentLevel: 2);
                }

                var newEdits = new List <TextEdit>();
                FormatCodeBlockStart(context, changedText, directiveBody, innerCodeBlockNode, newEdits);
                FormatCodeBlockEnd(context, changedText, directiveBody, innerCodeBlockNode, newEdits);
                changedText = ApplyChanges(changedText, newEdits.Select(e => e.AsTextChange(changedText)));

                // We've now applied all the edits we wanted to do. We now need to identify everything that changed in the given code block.
                // We need to include the preceding newline in our input range because we could have unindented the code block to achieve the correct indentation.
                // Without including the preceding newline, that edit would be lost.
                var fullCodeBlockDirectiveSpan = GetSpanIncludingPrecedingWhitespaceInLine(originalText, directive.Position, directive.EndPosition);
                var changes = Diff(originalText, changedText, fullCodeBlockDirectiveSpan);

                var transformedEdits = changes.Select(c => c.AsTextEdit(originalText));
                allEdits.AddRange(transformedEdits);
            }

            var normalizedEdits = NormalizeTextEdits(context.SourceText, allEdits.ToArray());

            return(new FormattingResult(normalizedEdits));
        }
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (context.IsFormatOnType)
            {
                // We don't want to handle OnTypeFormatting here.
                return(result);
            }

            // Apply previous edits if any.
            var originalText   = context.SourceText;
            var changedText    = originalText;
            var changedContext = context;

            if (result.Edits.Length > 0)
            {
                var changes = result.Edits.Select(e => e.AsTextChange(originalText)).ToArray();
                changedText    = changedText.WithChanges(changes);
                changedContext = await context.WithTextAsync(changedText);

                cancellationToken.ThrowIfCancellationRequested();
            }

            // Format the razor bits of the file
            var syntaxTree = changedContext.CodeDocument.GetSyntaxTree();
            var edits      = FormatRazor(changedContext, syntaxTree);

            // Compute the final combined set of edits
            var formattingChanges = edits.Select(e => e.AsTextChange(changedText));

            changedText = changedText.WithChanges(formattingChanges);

            var finalChanges = changedText.GetTextChanges(originalText);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            return(new FormattingResult(finalEdits));
        }
        public async override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (!context.IsFormatOnType || result.Kind != RazorLanguageKind.CSharp)
            {
                // We don't want to handle regular formatting or non-C# on type formatting here.
                return(result);
            }

            // Normalize and re-map the C# edits.
            var codeDocument = context.CodeDocument;
            var csharpText   = codeDocument.GetCSharpSourceText();

            var textEdits = result.Edits;

            if (textEdits.Length == 0)
            {
                if (!DocumentMappingService.TryMapToProjectedDocumentPosition(codeDocument, context.HostDocumentIndex, out _, out var projectedIndex))
                {
                    _logger.LogWarning($"Failed to map to projected position for document {context.Uri}.");
                    return(result);
                }

                // Ask C# for formatting changes.
                var indentationOptions = new RazorIndentationOptions(
                    UseTabs: !context.Options.InsertSpaces,
                    TabSize: context.Options.TabSize,
                    IndentationSize: context.Options.TabSize);
                var autoFormattingOptions = new RazorAutoFormattingOptions(
                    formatOnReturn: true, formatOnTyping: true, formatOnSemicolon: true, formatOnCloseBrace: true);

                var formattingChanges = await RazorCSharpFormattingInteractionService.GetFormattingChangesAsync(
                    context.CSharpWorkspaceDocument,
                    typedChar : context.TriggerCharacter,
                    projectedIndex,
                    indentationOptions,
                    autoFormattingOptions,
                    indentStyle : CodeAnalysis.Formatting.FormattingOptions.IndentStyle.Smart,
                    cancellationToken).ConfigureAwait(false);

                if (formattingChanges.IsEmpty)
                {
                    _logger.LogInformation("Received no results.");
                    return(result);
                }

                textEdits = formattingChanges.Select(change => change.AsTextEdit(csharpText)).ToArray();
                _logger.LogInformation($"Received {textEdits.Length} results from C#.");
            }

            var normalizedEdits = NormalizeTextEdits(csharpText, textEdits, out var originalTextWithChanges);
            var mappedEdits     = RemapTextEdits(codeDocument, normalizedEdits, result.Kind);
            var filteredEdits   = FilterCSharpTextEdits(context, mappedEdits);

            if (filteredEdits.Length == 0)
            {
                // There are no CSharp edits for us to apply. No op.
                return(new FormattingResult(filteredEdits));
            }

            // Find the lines that were affected by these edits.
            var originalText = codeDocument.GetSourceText();
            var changes      = filteredEdits.Select(e => e.AsTextChange(originalText));

            // Apply the format on type edits sent over by the client.
            var formattedText  = ApplyChangesAndTrackChange(originalText, changes, out _, out var spanAfterFormatting);
            var changedContext = await context.WithTextAsync(formattedText);

            var rangeAfterFormatting = spanAfterFormatting.AsRange(formattedText);

            cancellationToken.ThrowIfCancellationRequested();

            // We make an optimistic attempt at fixing corner cases.
            var cleanupChanges = CleanupDocument(changedContext, rangeAfterFormatting);
            var cleanedText    = formattedText.WithChanges(cleanupChanges);

            changedContext = await changedContext.WithTextAsync(cleanedText);

            cancellationToken.ThrowIfCancellationRequested();

            // At this point we should have applied all edits that adds/removes newlines.
            // Let's now ensure the indentation of each of those lines is correct.

            // We only want to adjust the range that was affected.
            // We need to take into account the lines affected by formatting as well as cleanup.
            var lineDelta = LineDelta(formattedText, cleanupChanges, out var firstPosition, out var lastPosition);

            // Okay hear me out, I know this looks lazy, but it totally makes sense.
            // This method is called with edits that the C# formatter wants to make, and from those edits we work out which
            // other edits to apply etc. Fine, all good so far. BUT its totally possible that the user typed a closing brace
            // in the same position as the C# formatter thought it should be, on the line _after_ the code that the C# formatter
            // reformatted.
            //
            // For example, given:
            // if (true){
            //     }
            //
            // If the C# formatter is happy with the placement of that close brace then this method will get two edits:
            //  * On line 1 to indent the if by 4 spaces
            //  * On line 1 to add a newline and 4 spaces in front of the opening brace
            //
            // We'll happy format lines 1 and 2, and ignore the closing brace altogether. So, by looking one line further
            // we won't have that problem.
            if (rangeAfterFormatting.End.Line + lineDelta < cleanedText.Lines.Count)
            {
                lineDelta++;
            }

            // Now we know how many lines were affected by the cleanup and formatting, but we don't know where those lines are. For example, given:
            //
            // @if (true)
            // {
            //      }
            // else
            // {
            // $$}
            //
            // When typing that close brace, the changes would fix the previous close brace, but the line delta would be 0, so
            // we'd format line 6 and call it a day, even though the formatter made an edit on line 3. To fix this we use the
            // first and last position of edits made above, and make sure our range encompasses them as well. For convenience
            // we calculate these positions in the LineDelta method called above.
            // This is essentially: rangeToAdjust = new Range(Math.Min(firstFormattingEdit, userEdit), Math.Max(lastFormattingEdit, userEdit))
            var start = rangeAfterFormatting.Start;

            if (firstPosition is not null && firstPosition < start)
            {
                start = firstPosition;
            }

            var end = new Position(rangeAfterFormatting.End.Line + lineDelta, 0);

            if (lastPosition is not null && lastPosition < start)
            {
                end = lastPosition;
            }

            var rangeToAdjust = new Range(start, end);

            Debug.Assert(rangeToAdjust.End.IsValid(cleanedText), "Invalid range. This is unexpected.");

            var indentationChanges = await AdjustIndentationAsync(changedContext, cancellationToken, rangeToAdjust);

            if (indentationChanges.Count > 0)
            {
                // Apply the edits that modify indentation.
                cleanedText = cleanedText.WithChanges(indentationChanges);
            }

            // Now that we have made all the necessary changes to the document. Let's diff the original vs final version and return the diff.
            var finalChanges = cleanedText.GetTextChanges(originalText);
            var finalEdits   = finalChanges.Select(f => f.AsTextEdit(originalText)).ToArray();

            if (context.AutomaticallyAddUsings)
            {
                // Because we need to parse the C# code twice for this operation, lets do a quick check to see if its even necessary
                if (textEdits.Any(e => e.NewText.IndexOf("using") != -1))
                {
                    finalEdits = await AddUsingStatementEditsAsync(codeDocument, finalEdits, csharpText, originalTextWithChanges, cancellationToken);
                }
            }

            return(new FormattingResult(finalEdits));
        }
        public override Task <FormattingResult> ExecuteAsync(FormattingContext context, FormattingResult result, CancellationToken cancellationToken)
        {
            if (result.Kind != RazorLanguageKind.Razor)
            {
                // We don't care about changes to projected documents here.
                return(Task.FromResult(result));
            }

            var text        = context.SourceText;
            var edits       = result.Edits;
            var changes     = edits.Select(e => e.AsTextChange(text));
            var changedText = text.WithChanges(changes);

            if (!text.NonWhitespaceContentEquals(changedText))
            {
                // Looks like we removed some non-whitespace content as part of formatting. Oops.
                // Discard this formatting result.

                if (DebugAssertsEnabled)
                {
                    Debug.Fail("A formatting result was rejected because it was going to change non-whitespace content in the document.");
                }

                return(Task.FromResult(new FormattingResult(Array.Empty <TextEdit>())));
            }

            return(Task.FromResult(result));
        }