Пример #1
0
        private string GetWhitespaceString(LineColumn lineColumn, LineColumnDelta delta)
        {
            var sb = StringBuilderPool.Allocate();

            for (int i = 0; i < delta.Lines; i++)
            {
                sb.AppendLine();
            }

            if (delta.Spaces == 0)
            {
                return(StringBuilderPool.ReturnAndFree(sb));
            }

            var useTabs = this.OptionSet.GetOption(FormattingOptions.UseTabs, this.Language);
            var tabSize = this.OptionSet.GetOption(FormattingOptions.TabSize, this.Language);

            // space indicates indentation
            if (delta.Lines > 0 || lineColumn.Column == 0)
            {
                sb.Append(delta.Spaces.CreateIndentationString(useTabs, tabSize));
                return(StringBuilderPool.ReturnAndFree(sb));
            }

            var useTabOnlyForIndentation = this.OptionSet.GetOption(FormattingOptions.UseTabOnlyForIndentation, this.Language);

            // space indicates space between two noisy trivia or tokens
            sb.Append(GetSpacesOrTabs(lineColumn.Column, delta.Spaces, useTabs && !useTabOnlyForIndentation, tabSize));
            return(StringBuilderPool.ReturnAndFree(sb));
        }
Пример #2
0
        private string GetWhitespaceString(LineColumn lineColumn, LineColumnDelta delta)
        {
            var sb = StringBuilderPool.Allocate();

            var newLine = this.OptionSet.GetOption(FormattingOptions.NewLine, this.Language);

            for (int i = 0; i < delta.Lines; i++)
            {
                sb.Append(newLine);
            }

            if (delta.Spaces == 0)
            {
                return(StringBuilderPool.ReturnAndFree(sb));
            }

            var useTabs = this.OptionSet.GetOption(FormattingOptions.UseTabs, this.Language);
            var tabSize = this.OptionSet.GetOption(FormattingOptions.TabSize, this.Language);

            // space indicates indentation
            if (delta.Lines > 0 || lineColumn.Column == 0)
            {
                sb.AppendIndentationString(delta.Spaces, useTabs, tabSize);
                return(StringBuilderPool.ReturnAndFree(sb));
            }

            // space indicates space between two noisy trivia or tokens
            sb.Append(' ', repeatCount: delta.Spaces);
            return(StringBuilderPool.ReturnAndFree(sb));
        }
Пример #3
0
        private void AddWhitespaceTrivia(
            LineColumn lineColumn,
            LineColumnDelta delta,
            TextSpan notUsed,
            List <SyntaxTrivia> changes)
        {
            if (delta.Lines == 0 && delta.Spaces == 0)
            {
                // remove trivia
                return;
            }

            for (int i = 0; i < delta.Lines; i++)
            {
                changes.Add(CreateEndOfLine());
            }

            if (delta.Spaces == 0)
            {
                return;
            }

            var useTabs = this.OptionSet.GetOption(FormattingOptions.UseTabs, this.Language);
            var tabSize = this.OptionSet.GetOption(FormattingOptions.TabSize, this.Language);

            // space indicates indentation
            if (delta.Lines > 0 || lineColumn.Column == 0)
            {
                changes.Add(CreateWhitespace(delta.Spaces.CreateIndentationString(useTabs, tabSize)));
                return;
            }

            // space indicates space between two noisy trivia or tokens
            changes.Add(CreateWhitespace(GetSpaces(delta.Spaces)));
        }
Пример #4
0
 private void AddWhitespaceTrivia(
     LineColumn lineColumn,
     LineColumnDelta delta,
     List <SyntaxTrivia> changes)
 {
     AddWhitespaceTrivia(lineColumn, delta, default(TextSpan), changes);
 }
Пример #5
0
        private LineColumnDelta GetLineColumnOfWhitespace(
            LineColumn lineColumn,
            SyntaxTrivia previousTrivia,
            SyntaxTrivia trivia1,
            LineColumnDelta whitespaceBetween,
            SyntaxTrivia trivia2)
        {
            Contract.Requires(IsWhitespaceOrEndOfLine(trivia2));

            // treat elastic as new line as long as its previous trivia is not elastic or
            // it has line break right before it
            if (trivia2.IsElastic())
            {
                // eat up consecutive elastic trivia or next line
                if (trivia1.IsElastic() || IsEndOfLine(trivia1))
                {
                    return(LineColumnDelta.Default);
                }

                // if there was alrady new lines, ignore elastic
                var lineColumnAfterPreviousTrivia = GetLineColumn(lineColumn, previousTrivia);

                var newLineFromPreviousOperation = (whitespaceBetween.Lines > 0) ||
                                                   (lineColumnAfterPreviousTrivia.Line > 0 && lineColumnAfterPreviousTrivia.Column == 0);
                if (newLineFromPreviousOperation && whitespaceBetween.WhitespaceOnly)
                {
                    return(LineColumnDelta.Default);
                }

                return(new LineColumnDelta(lines: 1, spaces: 0, whitespaceOnly: true, forceUpdate: true));
            }

            if (IsEndOfLine(trivia2))
            {
                return(new LineColumnDelta(lines: 1, spaces: 0, whitespaceOnly: true, forceUpdate: false));
            }

            var text = trivia2.ToFullString();

            return(new LineColumnDelta(
                       lines: 0,
                       spaces: text.ConvertTabToSpace(this.OptionSet.GetOption(FormattingOptions.TabSize, this.Language), lineColumn.With(whitespaceBetween).Column, text.Length),
                       whitespaceOnly: true,
                       forceUpdate: false));
        }
Пример #6
0
        public LineColumn With(LineColumnDelta delta)
        {
            if (delta.Lines <= 0)
            {
                return(new LineColumn
                {
                    Line = this.Line,
                    Column = this.Column + delta.Spaces,
                    WhitespaceOnly = this.WhitespaceOnly && delta.WhitespaceOnly
                });
            }

            return(new LineColumn
            {
                Line = this.Line + delta.Lines,
                Column = delta.Spaces,
                WhitespaceOnly = delta.WhitespaceOnly
            });
        }
Пример #7
0
        public LineColumn With(LineColumnDelta delta)
        {
            if (delta.Lines <= 0)
            {
                return new LineColumn
                {
                    Line = this.Line,
                    Column = this.Column + delta.Spaces,
                    WhitespaceOnly = this.WhitespaceOnly && delta.WhitespaceOnly
                };
            }

            return new LineColumn
            {
                Line = this.Line + delta.Lines,
                Column = delta.Spaces,
                WhitespaceOnly = delta.WhitespaceOnly
            };
        }
Пример #8
0
        internal LineColumnDelta With(LineColumnDelta delta)
        {
            if (delta.Lines <= 0)
            {
                return(new LineColumnDelta
                {
                    Lines = this.Lines,
                    Spaces = this.Spaces + delta.Spaces,
                    WhitespaceOnly = this.WhitespaceOnly && delta.WhitespaceOnly,
                    ForceUpdate = this.ForceUpdate || delta.ForceUpdate
                });
            }

            return(new LineColumnDelta
            {
                Lines = this.Lines + delta.Lines,
                Spaces = delta.Spaces,
                WhitespaceOnly = delta.WhitespaceOnly,
                ForceUpdate = this.ForceUpdate || delta.ForceUpdate || (this.Spaces > 0)
            });
        }
Пример #9
0
        internal LineColumnDelta With(LineColumnDelta delta)
        {
            if (delta.Lines <= 0)
            {
                return new LineColumnDelta
                {
                    Lines = this.Lines,
                    Spaces = this.Spaces + delta.Spaces,
                    WhitespaceOnly = this.WhitespaceOnly && delta.WhitespaceOnly,
                    ForceUpdate = this.ForceUpdate || delta.ForceUpdate
                };
            }

            return new LineColumnDelta
            {
                Lines = this.Lines + delta.Lines,
                Spaces = delta.Spaces,
                WhitespaceOnly = delta.WhitespaceOnly,
                ForceUpdate = this.ForceUpdate || delta.ForceUpdate || (this.Spaces > 0)
            };
        }
Пример #10
0
        private LineColumn FormatFirstTriviaAndWhitespaceAfter <T>(
            LineColumn lineColumnBeforeTrivia1,
            SyntaxTrivia trivia1,
            LineColumnDelta existingWhitespaceBetween,
            SyntaxTrivia trivia2,
            Formatter <T> format,
            WhitespaceAppender <T> addWhitespaceTrivia,
            List <T> changes,
            CancellationToken cancellationToken)
        {
            var lineColumnAfterTrivia1 = trivia1.RawKind == 0 ?
                                         lineColumnBeforeTrivia1 : lineColumnBeforeTrivia1.With(format(lineColumnBeforeTrivia1, trivia1, changes, cancellationToken));

            var rule            = GetOverallLineColumnRuleBetween(trivia1, existingWhitespaceBetween, trivia2);
            var whitespaceDelta = Apply(lineColumnBeforeTrivia1, trivia1, lineColumnAfterTrivia1, existingWhitespaceBetween, trivia2, rule);

            var span = GetTextSpan(trivia1, trivia2);

            addWhitespaceTrivia(lineColumnAfterTrivia1, whitespaceDelta, span, changes);

            return(lineColumnAfterTrivia1.With(whitespaceDelta));
        }
Пример #11
0
        private LineColumnDelta Apply(
            LineColumn lineColumnBeforeTrivia1, SyntaxTrivia trivia1, LineColumn lineColumnAfterTrivia1, LineColumnDelta existingWhitespaceBetween, SyntaxTrivia trivia2, LineColumnRule rule)
        {
            // we do not touch spaces adjacent to missing token
            // [missing token] [whitespace] [trivia] or [trivia] [whitepsace] [missing token] case
            if ((this.Token1.IsMissing && trivia1.RawKind == 0) ||
                (trivia2.RawKind == 0 && this.Token2.IsMissing))
            {
                // leave things as it is
                return(existingWhitespaceBetween);
            }

            var lines = GetRuleLines(rule, lineColumnAfterTrivia1, existingWhitespaceBetween);
            var spaceOrIndentations = GetRuleSpacesOrIndentation(lineColumnBeforeTrivia1, trivia1, lineColumnAfterTrivia1, existingWhitespaceBetween, trivia2, rule);

            return(new LineColumnDelta(
                       lines,
                       spaceOrIndentations,
                       whitespaceOnly: true,
                       forceUpdate: existingWhitespaceBetween.ForceUpdate));
        }
Пример #12
0
        protected override LineColumnRule GetLineColumnRuleBetween(SyntaxTrivia trivia1, LineColumnDelta existingWhitespaceBetween, bool implicitLineBreak, SyntaxTrivia trivia2)
        {
            if (IsStartOrEndOfFile(trivia1, trivia2))
            {
                return LineColumnRule.PreserveLinesWithAbsoluteIndentation(lines: 0, indentation: 0);
            }

            // [trivia] [whitespace] [token] case
            if (trivia2.IsKind(SyntaxKind.None))
            {
                var insertNewLine = this.FormattingRules.GetAdjustNewLinesOperation(this.Token1, this.Token2) != null;

                if (IsMultilineComment(trivia1))
                {
                    return LineColumnRule.PreserveLinesWithGivenIndentation(lines: insertNewLine ? 1 : 0);
                }

                if (insertNewLine)
                {
                    return LineColumnRule.PreserveLinesWithDefaultIndentation(lines: 0);
                }

                if (existingWhitespaceBetween.Lines > 0 && existingWhitespaceBetween.Spaces != this.Spaces)
                {
                    return LineColumnRule.PreserveWithGivenSpaces(spaces: this.Spaces);
                }

                return LineColumnRule.Preserve();
            }

            // preprocessor case
            if (SyntaxFacts.IsPreprocessorDirective(trivia2.Kind()))
            {
                // Check for immovable preprocessor directives, which are bad directive trivia 
                // without a preceding line break
                if (trivia2.IsKind(SyntaxKind.BadDirectiveTrivia) && existingWhitespaceBetween.Lines == 0 && !implicitLineBreak)
                {
                    _succeeded = false;
                    return LineColumnRule.Preserve();
                }

                // if current line is the first line of the file, don't put extra line 1
                var lines = (trivia1.IsKind(SyntaxKind.None) && this.Token1.IsKind(SyntaxKind.None)) ? 0 : 1;

                if (trivia2.IsKind(SyntaxKind.RegionDirectiveTrivia) || trivia2.IsKind(SyntaxKind.EndRegionDirectiveTrivia))
                {
                    return LineColumnRule.PreserveLinesWithDefaultIndentation(lines);
                }

                return LineColumnRule.PreserveLinesWithAbsoluteIndentation(lines, indentation: 0);
            }

            // comments case
            if (trivia2.IsRegularOrDocComment())
            {
                // start of new comments group
                if (!trivia1.IsRegularComment() || existingWhitespaceBetween.Lines > 1)
                {
                    if (this.FormattingRules.GetAdjustNewLinesOperation(this.Token1, this.Token2) != null)
                    {
                        return LineColumnRule.PreserveLinesWithDefaultIndentation(lines: 0);
                    }

                    return LineColumnRule.PreserveLinesWithGivenIndentation(lines: 0);
                }

                // comments after existing comment
                if (existingWhitespaceBetween.Lines == 0)
                {
                    return LineColumnRule.PreserveLinesWithGivenIndentation(lines: 0);
                }

                return LineColumnRule.PreserveLinesWithFollowingPrecedingIndentation();
            }

            if (trivia2.IsKind(SyntaxKind.SkippedTokensTrivia))
            {
                // if there is any skipped tokens, it is not possible to format this trivia range.
                _succeeded = false;
            }

            return LineColumnRule.Preserve();
        }
Пример #13
0
        private void AddWhitespaceTextChange(LineColumn lineColumn, LineColumnDelta delta, TextSpan span, List <TextChange> changes)
        {
            var newText = GetWhitespaceString(lineColumn, delta);

            changes.Add(new TextChange(span, newText));
        }
Пример #14
0
 private TextChange GetWhitespaceTextChange(LineColumn lineColumn, LineColumnDelta delta, TextSpan span)
 {
     return(new TextChange(span, GetWhitespaceString(lineColumn, delta)));
 }
Пример #15
0
 /// <summary>
 /// return line column rule for the given two trivia
 /// </summary>
 protected abstract LineColumnRule GetLineColumnRuleBetween(SyntaxTrivia trivia1, LineColumnDelta existingWhitespaceBetween, bool implicitLineBreak, SyntaxTrivia trivia2);
Пример #16
0
        /// <summary>
        /// get line column rule between two trivia
        /// </summary>
        private LineColumnRule GetOverallLineColumnRuleBetween(SyntaxTrivia trivia1, LineColumnDelta existingWhitespaceBetween, bool implicitLineBreak, SyntaxTrivia trivia2)
        {
            var defaultRule = GetLineColumnRuleBetween(trivia1, existingWhitespaceBetween, implicitLineBreak, trivia2);

            SyntaxToken token1;
            SyntaxToken token2;

            GetTokensAtEdgeOfStructureTrivia(trivia1, trivia2, out token1, out token2);

            // if there are tokens, try formatting rules to see whether there is a user supplied one
            if (token1.RawKind == 0 || token2.RawKind == 0)
            {
                return(defaultRule);
            }

            // use line defined by the token formatting rules
            var lineOperation = this.FormattingRules.GetAdjustNewLinesOperation(token1, token2);

            // there is existing lines, but no line operation
            if (existingWhitespaceBetween.Lines != 0 && lineOperation == null)
            {
                return(defaultRule);
            }

            if (lineOperation != null)
            {
                switch (lineOperation.Option)
                {
                case AdjustNewLinesOption.PreserveLines:
                    if (existingWhitespaceBetween.Lines != 0)
                    {
                        return(defaultRule.With(lines: lineOperation.Line, lineOperation: LineColumnRule.LineOperations.Preserve));
                    }

                    break;

                case AdjustNewLinesOption.ForceLines:
                    return(defaultRule.With(lines: lineOperation.Line, lineOperation: LineColumnRule.LineOperations.Force));

                case AdjustNewLinesOption.ForceLinesIfOnSingleLine:
                    if (this.Context.TokenStream.TwoTokensOnSameLine(token1, token2))
                    {
                        return(defaultRule.With(lines: lineOperation.Line, lineOperation: LineColumnRule.LineOperations.Force));
                    }

                    break;

                default:
                    throw Contract.Unreachable;
                }
            }

            // use space defined by the regular formatting rules
            var spaceOperation = this.FormattingRules.GetAdjustSpacesOperation(token1, token2);

            if (spaceOperation == null)
            {
                return(defaultRule);
            }

            if (spaceOperation != null &&
                spaceOperation.Option == AdjustSpacesOption.DefaultSpacesIfOnSingleLine &&
                spaceOperation.Space == 1)
            {
                return(defaultRule);
            }

            return(defaultRule.With(spaces: spaceOperation.Space));
        }
Пример #17
0
        private int GetRuleLines(LineColumnRule rule, LineColumn lineColumnAfterTrivia1, LineColumnDelta existingWhitespaceBetween)
        {
            var adjustedRuleLines = Math.Max(0, rule.Lines - GetTrailingLinesAtEndOfTrivia1(lineColumnAfterTrivia1));

            return((rule.LineOperation == LineColumnRule.LineOperations.Preserve) ? Math.Max(adjustedRuleLines, existingWhitespaceBetween.Lines) : adjustedRuleLines);
        }
Пример #18
0
        private int GetRuleSpacesOrIndentation(
            LineColumn lineColumnBeforeTrivia1, SyntaxTrivia trivia1, LineColumn lineColumnAfterTrivia1, LineColumnDelta existingWhitespaceBetween, SyntaxTrivia trivia2, LineColumnRule rule)
        {
            var lineColumnAfterExistingWhitespace = lineColumnAfterTrivia1.With(existingWhitespaceBetween);

            // next trivia is moved to next line or already on a new line, use indentation
            if (rule.Lines > 0 || lineColumnAfterExistingWhitespace.WhitespaceOnly)
            {
                switch (rule.IndentationOperation)
                {
                case LineColumnRule.IndentationOperations.Absolute:
                    return(Math.Max(0, rule.Indentation));

                case LineColumnRule.IndentationOperations.Default:
                    return(this.Context.GetBaseIndentation(trivia2.RawKind == 0 ? this.EndPosition : trivia2.SpanStart));

                case LineColumnRule.IndentationOperations.Given:
                    return((trivia2.RawKind == 0) ? this.Spaces : Math.Max(0, this.indentation));

                case LineColumnRule.IndentationOperations.Follow:
                    return(Math.Max(0, lineColumnBeforeTrivia1.Column));

                case LineColumnRule.IndentationOperations.Preserve:
                    return(existingWhitespaceBetween.Spaces);

                default:
                    throw Contract.Unreachable;
                }
            }

            // okay, we are not on a its own line, use space information
            switch (rule.SpaceOperation)
            {
            case LineColumnRule.SpaceOperations.Preserve:
                return(Math.Max(rule.Spaces, existingWhitespaceBetween.Spaces));

            case LineColumnRule.SpaceOperations.Force:
                return(Math.Max(rule.Spaces, 0));

            default:
                throw Contract.Unreachable;
            }
        }