示例#1
0
        public void FormatSpan(SnapshotSpan span)
        {
            // Formatting a snippet isn't cancellable.
            var cancellationToken = CancellationToken.None;

            // At this point, the $selection$ token has been replaced with the selected text and
            // declarations have been replaced with their default text. We need to format the
            // inserted snippet text while carefully handling $end$ position (where the caret goes
            // after Return is pressed). The IExpansionSession keeps a tracking point for this
            // position but we do the tracking ourselves to properly deal with virtual space. To
            // ensure the end location is correct, we take three extra steps:
            // 1. Insert an empty comment ("/**/" or "'") at the current $end$ position (prior
            //    to formatting), and keep a tracking span for the comment.
            // 2. After formatting the new snippet text, find and delete the empty multiline
            //    comment (via the tracking span) and notify the IExpansionSession of the new
            //    $end$ location. If the line then contains only whitespace (due to the formatter
            //    putting the empty comment on its own line), then delete the white space and
            //    remember the indentation depth for that line.
            // 3. When the snippet is finally completed (via Return), and PositionCaretForEditing()
            //    is called, check to see if the end location was on a line containing only white
            //    space in the previous step. If so, and if that line is still empty, then position
            //    the caret in virtual space.
            // This technique ensures that a snippet like "if($condition$) { $end$ }" will end up
            // as:
            //     if ($condition$)
            //     {
            //         $end$
            //     }
            if (!TryGetSubjectBufferSpan(span, out var snippetSpan))
            {
                return;
            }

            // Insert empty comment and track end position
            var snippetTrackingSpan = snippetSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive);

            var fullSnippetSpan = ExpansionSession.GetSnippetSpan();

            var isFullSnippetFormat     = fullSnippetSpan == span;
            var endPositionTrackingSpan = isFullSnippetFormat ? InsertEmptyCommentAndGetEndPositionTrackingSpan() : null;

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(SubjectBuffer.CurrentSnapshot, snippetTrackingSpan.GetSpan(SubjectBuffer.CurrentSnapshot));

            SubjectBuffer.CurrentSnapshot.FormatAndApplyToBuffer(formattingSpan, CancellationToken.None);

            if (isFullSnippetFormat)
            {
                CleanUpEndLocation(endPositionTrackingSpan);

                // Unfortunately, this is the only place we can safely add references and imports
                // specified in the snippet xml. In OnBeforeInsertion we have no guarantee that the
                // snippet xml will be available, and changing the buffer during OnAfterInsertion can
                // cause the underlying tracking spans to get out of sync.
                var currentStartPosition = snippetTrackingSpan.GetStartPoint(SubjectBuffer.CurrentSnapshot).Position;
                AddReferencesAndImports(
                    ExpansionSession, currentStartPosition, cancellationToken);

                SetNewEndPosition(endPositionTrackingSpan);
            }
        }
示例#2
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesOnPasteAsync(
            Document document,
            TextSpan textSpan,
            DocumentOptionSet?documentOptions,
            CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, textSpan);
            var service        = document.GetRequiredLanguageService <ISyntaxFormattingService>();

            var rules = new List <AbstractFormattingRule>()
            {
                new PasteFormattingRule()
            };

            rules.AddRange(service.GetDefaultFormattingRules());

            if (documentOptions == null)
            {
                var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService <IInferredIndentationService>();
                documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat : false, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language);
            var result            = service.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(formattingSpan), formattingOptions, rules, cancellationToken);

            return(result.GetTextChanges(cancellationToken).ToImmutableArray());
        }
        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());
        }
示例#4
0
        public int GetIndentationOfCurrentPosition(
            SyntaxNode root,
            IndentBlockOperation startingOperation,
            Func <SyntaxToken, int> tokenColumnGetter,
            CancellationToken cancellationToken)
        {
            var token = startingOperation.StartToken;

            // gather all indent operations
            var list = GetParentIndentBlockOperations(token);

            // remove one that is smaller than current one
            for (int i = list.Count - 1; i >= 0; i--)
            {
                if (CommonFormattingHelpers.IndentBlockOperationComparer(startingOperation, list[i]) < 0)
                {
                    list.RemoveAt(i);
                }
                else
                {
                    break;
                }
            }

            return(GetIndentationOfCurrentPosition(root, token, list, token.SpanStart, /* extraSpaces */ 0, tokenColumnGetter, cancellationToken));
        }
        public Task <Document> FormatAsync(Document document, ImmutableArray <TextSpan> changes, CancellationToken cancellationToken)
        {
            var root            = document.GetSyntaxRootSynchronously(cancellationToken);
            var formattingSpans = changes.Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken));
        }
示例#6
0
        public Document Format(Document document, IEnumerable <TextSpan> changes, CancellationToken cancellationToken)
        {
            var root            = document.GetSyntaxRootSynchronously(cancellationToken);
            var formattingSpans = changes.Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken));
        }
示例#7
0
        public override AdjustSpacesOperation GetAdjustSpacesOperation(SyntaxToken previousToken, SyntaxToken currentToken, OptionSet optionSet, NextOperation <AdjustSpacesOperation> nextOperation)
        {
            var operation = nextOperation.Invoke();

            if (operation == null)
            {
                return(null);
            }

            // if operation is already forced, return as it is.
            if (operation.Option == AdjustSpacesOption.ForceSpaces)
            {
                return(operation);
            }

            if (CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken))
            {
                // current implementation of engine gives higher priority on new line operations over space operations if
                // two are conflicting.
                // ex) new line operation says add 1 line between tokens, and
                //     space operation says give 1 space between two tokens (basically means remove new lines)
                //     then, engine will pick new line operation and ignore space operation

                // make every operation forced
                return(CreateAdjustSpacesOperation(Math.Max(0, operation.Space), AdjustSpacesOption.ForceSpaces));
            }

            return(operation);
        }
示例#8
0
        private void AdjustIndentationForSpan(
            Document document, ITextEdit edit, TextSpan visibleSpan, IFormattingRule baseIndentationRule, OptionSet options)
        {
            var root = document.GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);

            using (var rulePool = SharedPools.Default <List <IFormattingRule> >().GetPooledObject())
                using (var spanPool = SharedPools.Default <List <TextSpan> >().GetPooledObject())
                {
                    var venusFormattingRules = rulePool.Object;
                    var visibleSpans         = spanPool.Object;

                    venusFormattingRules.Add(baseIndentationRule);
                    venusFormattingRules.Add(ContainedDocumentPreserveFormattingRule.Instance);

                    var formattingRules = venusFormattingRules.Concat(Formatter.GetDefaultFormattingRules(document));

                    var workspace = document.Project.Solution.Workspace;
                    var changes   = Formatter.GetFormattedTextChanges(
                        root, new TextSpan[] { CommonFormattingHelpers.GetFormattingSpan(root, visibleSpan) },
                        workspace, options, formattingRules, CancellationToken.None);

                    visibleSpans.Add(visibleSpan);
                    var newChanges = FilterTextChanges(document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None), visibleSpans, changes.ToReadOnlyCollection()).Where(t => visibleSpan.Contains(t.Span));

                    foreach (var change in newChanges)
                    {
                        edit.Replace(change.Span.ToSpan(), change.NewText);
                    }
                }
        }
示例#9
0
            public override string GetTextBetween(SyntaxToken token1, SyntaxToken token2)
            {
                var builder = StringBuilderPool.Allocate();

                CommonFormattingHelpers.AppendTextBetween(token1, token2, builder);

                return(StringBuilderPool.ReturnAndFree(builder));
            }
        public override AdjustNewLinesOperation GetAdjustNewLinesOperation(SyntaxToken previousToken, SyntaxToken currentToken, OptionSet optionSet, NextOperation <AdjustNewLinesOperation> nextOperation)
        {
            var operation = nextOperation.Invoke();

            if (operation == null)
            {
                // If there are more than one Type Parameter Constraint Clause then each go in separate line
                if (CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken) &&
                    currentToken.IsKind(SyntaxKind.WhereKeyword) &&
                    currentToken.Parent.IsKind(SyntaxKind.TypeParameterConstraintClause))
                {
                    // Check if there is another TypeParameterConstraintClause before
                    if (previousToken.Parent.Ancestors().OfType <TypeParameterConstraintClauseSyntax>().Any())
                    {
                        return(CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines));
                    }

                    // Check if there is another TypeParameterConstraintClause after
                    var firstTokenAfterTypeConstraint = currentToken.Parent.GetLastToken().GetNextToken();
                    var lastTokenForTypeConstraint    = currentToken.Parent.GetLastToken().GetNextToken();
                    if (CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(lastTokenForTypeConstraint, firstTokenAfterTypeConstraint) &&
                        firstTokenAfterTypeConstraint.IsKind(SyntaxKind.WhereKeyword) &&
                        firstTokenAfterTypeConstraint.Parent.IsKind(SyntaxKind.TypeParameterConstraintClause))
                    {
                        return(CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines));
                    }
                }

                return(null);
            }

            // if operation is already forced, return as it is.
            if (operation.Option == AdjustNewLinesOption.ForceLines)
            {
                return(operation);
            }

            if (!CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(previousToken, currentToken))
            {
                return(operation);
            }

            var betweenMemberOperation = GetAdjustNewLinesOperationBetweenMembers(previousToken, currentToken);

            if (betweenMemberOperation != null)
            {
                return(betweenMemberOperation);
            }

            var line = Math.Max(LineBreaksAfter(previousToken, currentToken), operation.Line);

            if (line == 0)
            {
                return(CreateAdjustNewLinesOperation(0, AdjustNewLinesOption.PreserveLines));
            }

            return(CreateAdjustNewLinesOperation(line, AdjustNewLinesOption.ForceLines));
        }
        public async Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan.HasValue ? textSpan.Value : new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            return(Formatter.GetFormattedTextChanges(root, new TextSpan[] { formattingSpan }, document.Project.Solution.Workspace, cancellationToken: cancellationToken));
        }
示例#12
0
        public Document Format(Document document, IEnumerable <TextSpan> changes, CancellationToken cancellationToken)
        {
            var snapshot = document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken).FindCorrespondingEditorTextSnapshot();

            var root            = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var formattingSpans = changes.Select(s => s.ToSnapshotSpan(snapshot))
                                  .Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s.Span.ToTextSpan()));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken));
        }
示例#13
0
        public static bool AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
        {
            var tree = token1.SyntaxTree;

            if (tree != null && tree.TryGetText(out var text))
            {
                return(text.AreOnSameLine(token1, token2));
            }

            return(CommonFormattingHelpers.GetTextBetween(token1, token2).ContainsLineBreak());
        }
示例#14
0
        public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document, TextSpan? textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var span = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);
            return Formatter.GetFormattedTextChanges(root,
                SpecializedCollections.SingletonEnumerable(formattingSpan),
                document.Project.Solution.Workspace, options, cancellationToken);
        }
        public async Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            var options = await document.GetDocumentOptionsWithInferredIndentationAsync(explicitFormat : true, indentationManagerService : _indentationManagerService, cancellationToken : cancellationToken).ConfigureAwait(false);

            return(Formatter.GetFormattedTextChanges(root,
                                                     SpecializedCollections.SingletonEnumerable(formattingSpan),
                                                     document.Project.Solution.Workspace, options, cancellationToken));
        }
示例#16
0
        private void AddChangeSignatureIndentOperation(List <IndentBlockOperation> list, SyntaxNode node)
        {
            if (node.Parent != null)
            {
                var baseToken  = node.Parent.GetFirstToken();
                var startToken = node.GetFirstToken();
                var endToken   = node.GetLastToken();
                var span       = CommonFormattingHelpers.GetSpanIncludingTrailingAndLeadingTriviaOfAdjacentTokens(startToken, endToken);
                span = TextSpan.FromBounds(Math.Max(baseToken.Span.End, span.Start), span.End);

                list.Add(FormattingOperations.CreateRelativeIndentBlockOperation(baseToken, startToken, endToken, span, indentationDelta: 1, option: IndentBlockOption.RelativeToFirstTokenOnBaseTokenLine));
            }
        }
        public Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            ITextBuffer textBuffer,
            TextSpan?textSpan,
            CancellationToken cancellationToken)
        {
            var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken);
            var options        = textBuffer.GetSyntaxFormattingOptions(_editorOptionsService, parsedDocument.LanguageServices, explicitFormat: true);

            var span           = textSpan ?? new TextSpan(0, parsedDocument.Root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(parsedDocument.Root, span);

            return(Task.FromResult(Formatter.GetFormattedTextChanges(parsedDocument.Root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Services, options, cancellationToken).ToImmutableArray()));
        }
        private static bool AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
        {
            var tree = token1.SyntaxTree;
            var text = default(SourceText);

            if (tree != null && tree.TryGetText(out text))
            {
                var line1 = text.Lines.IndexOf(token1.Span.End);
                var line2 = text.Lines.IndexOf(token2.SpanStart);

                return(line1 == line2);
            }

            return(CommonFormattingHelpers.GetTextBetween(token1, token2).GetNumberOfLineBreaks() == 0);
        }
示例#19
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            TextSpan?textSpan,
            CancellationToken cancellationToken)
        {
            var options = await _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat : true, cancellationToken).ConfigureAwait(false);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            var services = document.Project.Solution.Workspace.Services;

            return(Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, options, cancellationToken).ToImmutableArray());
        }
            public AbstractComplexTrivia(OptionSet optionSet, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2)
                : base(optionSet, token1.Language)
            {
                Contract.ThrowIfNull(treeInfo);

                _token1 = token1;
                _token2 = token2;

                _treatAsElastic = CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(token1, token2);

                this.TreeInfo       = treeInfo;
                this.OriginalString = this.TreeInfo.GetTextBetween(token1, token2);
                ExtractLineAndSpace(this.OriginalString, out var lineBreaks, out var spaces);

                this.LineBreaks = lineBreaks;
                this.Spaces     = spaces;
            }
示例#21
0
        public async Task<IList<TextChange>> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, textSpan);
            var service = document.GetLanguageService<ISyntaxFormattingService>();
            if (service == null)
            {
                return SpecializedCollections.EmptyList<TextChange>();
            }

            var rules = new List<IFormattingRule>() { new PasteFormattingRule() };
            rules.AddRange(service.GetDefaultFormattingRules());

            return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Workspace, options, rules, cancellationToken);
        }
        private void ApplyEdits(Document document, ITextView textView, ITextBuffer subjectBuffer, string title, CommentSelectionResult edits, CancellationToken cancellationToken)
        {
            var originalSnapshot = subjectBuffer.CurrentSnapshot;

            // Apply the text changes.
            using (var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                subjectBuffer.ApplyChanges(edits.TextChanges);
                transaction.Complete();
            }

            if (edits.TrackingSpans.Any())
            {
                // Create tracking spans to track the text changes.
                var trackingSpans = edits.TrackingSpans
                                    .SelectAsArray(textSpan => (originalSpan: textSpan, trackingSpan: CreateTrackingSpan(edits.ResultOperation, originalSnapshot, textSpan.TrackingTextSpan)));

                // Convert the tracking spans into snapshot spans for formatting and selection.
                var trackingSnapshotSpans = trackingSpans.Select(s => CreateSnapshotSpan(subjectBuffer.CurrentSnapshot, s.trackingSpan, s.originalSpan));

                if (edits.ResultOperation == Operation.Uncomment && document.SupportsSyntaxTree)
                {
                    // Format the document only during uncomment operations.  Use second transaction so it can be undone.
                    using var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService);

                    var newText       = subjectBuffer.CurrentSnapshot.AsText();
                    var oldSyntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken);
                    var newRoot       = oldSyntaxTree.WithChangedText(newText).GetRoot(cancellationToken);

                    var formattingOptions = subjectBuffer.GetSyntaxFormattingOptions(_editorOptionsService, document.Project.LanguageServices, explicitFormat: false);
                    var formattingSpans   = trackingSnapshotSpans.Select(change => CommonFormattingHelpers.GetFormattingSpan(newRoot, change.Span.ToTextSpan()));
                    var formattedChanges  = Formatter.GetFormattedTextChanges(newRoot, formattingSpans, document.Project.Solution.Services, formattingOptions, rules: null, cancellationToken);

                    subjectBuffer.ApplyChanges(formattedChanges);

                    transaction.Complete();
                }

                // Set the multi selection after edits have been applied.
                textView.SetMultiSelection(trackingSnapshotSpans);
            }
        }
        private void AddSwitchIndentationOperation(List <IndentBlockOperation> list, SyntaxNode node, OptionSet optionSet)
        {
            var section = node as SwitchSectionSyntax;

            if (section == null || !optionSet.GetOption(CSharpFormattingOptions.IndentSwitchCaseSection))
            {
                return;
            }

            // can this ever happen?
            if (section.Labels.Count == 0 &&
                section.Statements.Count == 0)
            {
                return;
            }

            // see whether we are the last statement
            var switchStatement = node.Parent as SwitchStatementSyntax;
            var lastSection     = switchStatement.Sections.Last() == node;

            if (section.Statements.Count == 0)
            {
                // even if there is no statement under section, we still want indent operation
                var lastTokenOfLabel = section.Labels.Last().GetLastToken(includeZeroWidth: true);
                var nextToken        = lastTokenOfLabel.GetNextToken(includeZeroWidth: true);

                AddIndentBlockOperation(list, lastTokenOfLabel, lastTokenOfLabel,
                                        lastSection ?
                                        TextSpan.FromBounds(lastTokenOfLabel.FullSpan.End, nextToken.SpanStart) : TextSpan.FromBounds(lastTokenOfLabel.FullSpan.End, lastTokenOfLabel.FullSpan.End));
                return;
            }

            var startToken = section.Statements.First().GetFirstToken(includeZeroWidth: true);
            var endToken   = section.Statements.Last().GetLastToken(includeZeroWidth: true);

            // see whether we are the last statement
            var span = CommonFormattingHelpers.GetSpanIncludingTrailingAndLeadingTriviaOfAdjacentTokens(startToken, endToken);

            span = lastSection ? span : TextSpan.FromBounds(span.Start, endToken.FullSpan.End);

            AddIndentBlockOperation(list, startToken, endToken, span);
        }
示例#24
0
        protected void RemoveIndentBlockOperation(
            List <IndentBlockOperation> list,
            SyntaxToken startToken,
            SyntaxToken endToken)
        {
            if (startToken.CSharpKind() == SyntaxKind.None || endToken.CSharpKind() == SyntaxKind.None)
            {
                return;
            }

            var span = CommonFormattingHelpers.GetSpanIncludingTrailingAndLeadingTriviaOfAdjacentTokens(startToken, endToken);

            for (int i = 0; i < list.Count; i++)
            {
                if (list[i] != null && list[i].TextSpan == span)
                {
                    list[i] = null;
                    return;
                }
            }
        }
示例#25
0
        protected static void AddUnindentBlockOperation(
            List <IndentBlockOperation> list,
            SyntaxToken startToken,
            SyntaxToken endToken,
            bool includeTriviaAtEnd  = false,
            IndentBlockOption option = IndentBlockOption.RelativePosition
            )
        {
            if (startToken.Kind() == SyntaxKind.None || endToken.Kind() == SyntaxKind.None)
            {
                return;
            }

            if (includeTriviaAtEnd)
            {
                list.Add(
                    FormattingOperations.CreateIndentBlockOperation(
                        startToken,
                        endToken,
                        indentationDelta: -1,
                        option: option
                        )
                    );
            }
            else
            {
                var startPosition = CommonFormattingHelpers.GetStartPositionOfSpan(startToken);
                var endPosition   = endToken.Span.End;

                list.Add(
                    FormattingOperations.CreateIndentBlockOperation(
                        startToken,
                        endToken,
                        TextSpan.FromBounds(startPosition, endPosition),
                        indentationDelta: -1,
                        option: option
                        )
                    );
            }
        }
示例#26
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            TextSpan?textSpan,
            DocumentOptionSet?documentOptions,
            CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            if (documentOptions == null)
            {
                var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService <IInferredIndentationService>();
                documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat : true, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            var services          = document.Project.Solution.Workspace.Services;
            var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, services, document.Project.Language);

            return(Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, cancellationToken).ToImmutableArray());
        }
示例#27
0
        private void AddSwitchIndentationOperation(List <IndentBlockOperation> list, SyntaxNode node, OptionSet optionSet)
        {
            var section = node as SwitchSectionSyntax;

            if (section == null)
            {
                return;
            }

            // can this ever happen?
            if (section.Labels.Count == 0 &&
                section.Statements.Count == 0)
            {
                return;
            }

            var indentSwitchCase          = optionSet.GetOption(CSharpFormattingOptions.IndentSwitchCaseSection);
            var indentSwitchCaseWhenBlock = optionSet.GetOption(CSharpFormattingOptions.IndentSwitchCaseSectionWhenBlock);

            if (!indentSwitchCase && !indentSwitchCaseWhenBlock)
            {
                // Never indent
                return;
            }

            var alwaysIndent = indentSwitchCase && indentSwitchCaseWhenBlock;

            if (!alwaysIndent)
            {
                // Only one of these values can be true at this point.
                Debug.Assert(indentSwitchCase != indentSwitchCaseWhenBlock);

                var firstStatementIsBlock =
                    section.Statements.Count > 0 &&
                    section.Statements[0].IsKind(SyntaxKind.Block);

                if (indentSwitchCaseWhenBlock != firstStatementIsBlock)
                {
                    return;
                }
            }

            // see whether we are the last statement
            var switchStatement = node.Parent as SwitchStatementSyntax;
            var lastSection     = switchStatement.Sections.Last() == node;

            if (section.Statements.Count == 0)
            {
                // even if there is no statement under section, we still want indent operation
                var lastTokenOfLabel = section.Labels.Last().GetLastToken(includeZeroWidth: true);
                var nextToken        = lastTokenOfLabel.GetNextToken(includeZeroWidth: true);

                AddIndentBlockOperation(list, lastTokenOfLabel, lastTokenOfLabel,
                                        lastSection ?
                                        TextSpan.FromBounds(lastTokenOfLabel.FullSpan.End, nextToken.SpanStart) : TextSpan.FromBounds(lastTokenOfLabel.FullSpan.End, lastTokenOfLabel.FullSpan.End));
                return;
            }

            var startToken = section.Statements.First().GetFirstToken(includeZeroWidth: true);
            var endToken   = section.Statements.Last().GetLastToken(includeZeroWidth: true);

            // see whether we are the last statement
            var span = CommonFormattingHelpers.GetSpanIncludingTrailingAndLeadingTriviaOfAdjacentTokens(startToken, endToken);

            span = lastSection ? span : TextSpan.FromBounds(span.Start, endToken.FullSpan.End);

            AddIndentBlockOperation(list, startToken, endToken, span);
        }
示例#28
0
        /// <summary>
        /// create indent block region around the start and end token with the given indentation delta added to the column of the base token
        /// </summary>
        public static IndentBlockOperation CreateRelativeIndentBlockOperation(SyntaxToken baseToken, SyntaxToken startToken, SyntaxToken endToken, int indentationDelta, IndentBlockOption option)
        {
            var span = CommonFormattingHelpers.GetSpanIncludingTrailingAndLeadingTriviaOfAdjacentTokens(startToken, endToken);

            return(CreateRelativeIndentBlockOperation(baseToken, startToken, endToken, span, indentationDelta, option));
        }