Beispiel #1
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));
        }
Beispiel #2
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));
        }
Beispiel #3
0
 private void AddWhitespaceTrivia(
     LineColumn lineColumn,
     LineColumnDelta delta,
     List <SyntaxTrivia> changes)
 {
     AddWhitespaceTrivia(lineColumn, delta, default(TextSpan), changes);
 }
Beispiel #4
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)));
        }
Beispiel #5
0
        public AbstractTriviaFormatter(
            FormattingContext context,
            ChainedFormattingRules formattingRules,
            SyntaxToken token1,
            SyntaxToken token2,
            string originalString,
            int lineBreaks,
            int spaces)
        {
            Contract.ThrowIfNull(context);
            Contract.ThrowIfNull(formattingRules);
            Contract.ThrowIfNull(originalString);

            Contract.ThrowIfFalse(lineBreaks >= 0);
            Contract.ThrowIfFalse(spaces >= 0);

            Contract.ThrowIfTrue(token1 == default(SyntaxToken) && token2 == default(SyntaxToken));

            this.Context         = context;
            this.FormattingRules = formattingRules;
            this.OriginalString  = originalString;

            this.Token1 = token1;
            this.Token2 = token2;

            if (token1 == default(SyntaxToken))
            {
                this.language = token2.Language;
            }
            else
            {
                this.language = token1.Language;
            }

            this.LineBreaks = lineBreaks;
            this.Spaces     = spaces;

            this.InitialLineColumn = GetInitialLineColumn();

            // "Spaces" holds either space counts between two tokens if two are on same line or indentation of token2 if
            // two are on different line. but actual "Indentation" of the line could be different than "Spaces" if there is
            // noisy trivia before token2 on the same line.
            // this.indentation indicates that trivia's indentation
            //
            // ex) [indentation]/** */ token2
            //     [spaces            ]
            this.indentation = (this.LineBreaks > 0) ? GetIndentation() : -1;

            // check whether first line between two tokens contains only whitespace
            // depends on this we decide where to insert blank lines at the end
            this.firstLineBlank = FirstLineBlank();
        }
Beispiel #6
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));
        }
Beispiel #7
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;
            }
        }
Beispiel #8
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));
        }
        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));
        }
Beispiel #10
0
 /// <summary>
 /// return 0 or 1 based on line column of the trivia1's end point
 /// this is based on our structured trivia's implementation detail that some structured trivia can have
 /// one new line at the end of the trivia
 /// </summary>
 private int GetTrailingLinesAtEndOfTrivia1(LineColumn lineColumnAfterTrivia1)
 {
     return((lineColumnAfterTrivia1.Column == 0 && lineColumnAfterTrivia1.Line > 0) ? 1 : 0);
 }
Beispiel #11
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);
        }
 public bool Equals(LineColumn other)
 {
     return this.Line.Equals(other.Line) &&
            this.Column.Equals(other.Column);
 }
Beispiel #13
0
 private TextChange GetWhitespaceTextChange(LineColumn lineColumn, LineColumnDelta delta, TextSpan span)
 {
     return(new TextChange(span, GetWhitespaceString(lineColumn, delta)));
 }
        private LineColumnDelta FormatStructuredTrivia(
            LineColumn lineColumn, SyntaxTrivia trivia, List<TextChange> changes, CancellationToken cancellationToken)
        {
            if (trivia.Kind() == SyntaxKind.SkippedTokensTrivia)
            {
                // don't touch anything if it contains skipped tokens
                _succeeded = false;
                return GetLineColumnDelta(lineColumn, trivia);
            }

            // TODO : make document comment to be formatted by structured trivia formatter as well.
            if (!trivia.IsDocComment())
            {
                var result = CSharpStructuredTriviaFormatEngine.Format(
                    trivia, this.InitialLineColumn.Column, this.OptionSet, this.FormattingRules, cancellationToken);
                if (result.GetTextChanges(cancellationToken).Count == 0)
                {
                    return GetLineColumnDelta(lineColumn, trivia);
                }

                changes.AddRange(result.GetTextChanges(cancellationToken));

                var formattedTrivia = SyntaxFactory.Trivia((StructuredTriviaSyntax)result.GetFormattedRoot(cancellationToken));
                return GetLineColumnDelta(lineColumn, formattedTrivia);
            }

            var docComment = FormatDocumentComment(lineColumn, trivia);
            if (docComment != trivia)
            {
                changes.Add(new TextChange(trivia.FullSpan, docComment.ToFullString()));
            }

            return GetLineColumnDelta(lineColumn, docComment);
        }
        private SyntaxTrivia FormatDocumentComment(LineColumn lineColumn, SyntaxTrivia trivia)
        {
            var indentation = lineColumn.Column;

            if (trivia.IsSingleLineDocComment())
            {
                var text = trivia.ToFullString();

                // When the doc comment is parsed from source, even if it is only one
                // line long, the end-of-line will get included into the trivia text.
                // If the doc comment was parsed from a text fragment, there may not be
                // an end-of-line at all. We need to trim the end before we check the
                // number of line breaks in the text.
                var textWithoutFinalNewLine = text.TrimEnd(null);
                if (!textWithoutFinalNewLine.ContainsLineBreak())
                {
                    return trivia;
                }

                var singleLineDocumentationCommentExteriorCommentRewriter = new DocumentationCommentExteriorCommentRewriter(
                    true /* forceIndentation */,
                    indentation,
                    0 /* indentationDelta */,
                    this.OptionSet);
                var newTrivia = singleLineDocumentationCommentExteriorCommentRewriter.VisitTrivia(trivia);

                return newTrivia;
            }

            var indentationDelta = indentation - GetExistingIndentation(trivia);
            if (indentationDelta == 0)
            {
                return trivia;
            }

            var multiLineDocumentationCommentExteriorCommentRewriter = new DocumentationCommentExteriorCommentRewriter(
                    false /* forceIndentation */,
                    indentation,
                    indentationDelta,
                    this.OptionSet);
            var newMultiLineTrivia = multiLineDocumentationCommentExteriorCommentRewriter.VisitTrivia(trivia);

            return newMultiLineTrivia;
        }
        protected override LineColumnDelta Format(
            LineColumn lineColumn, SyntaxTrivia trivia, List<TextChange> changes, CancellationToken cancellationToken)
        {
            if (trivia.HasStructure)
            {
                return FormatStructuredTrivia(lineColumn, trivia, changes, cancellationToken);
            }

            if (TryFormatMultiLineCommentTrivia(lineColumn, trivia, out var newComment))
            {
                changes.Add(new TextChange(trivia.FullSpan, newComment.ToFullString()));
                return GetLineColumnDelta(lineColumn, newComment);
            }

            return GetLineColumnDelta(lineColumn, trivia);
        }
        private bool TryFormatMultiLineCommentTrivia(LineColumn lineColumn, SyntaxTrivia trivia, out SyntaxTrivia result)
        {
            result = default(SyntaxTrivia);

            if (trivia.Kind() != SyntaxKind.MultiLineCommentTrivia)
            {
                return false;
            }

            var indentation = lineColumn.Column;
            var indentationDelta = indentation - GetExistingIndentation(trivia);
            if (indentationDelta != 0)
            {
                var multiLineComment = trivia.ToFullString().ReindentStartOfXmlDocumentationComment(
                    false /* forceIndentation */,
                    indentation,
                    indentationDelta,
                    this.OptionSet.GetOption(FormattingOptions.UseTabs, LanguageNames.CSharp),
                    this.OptionSet.GetOption(FormattingOptions.TabSize, LanguageNames.CSharp),
                    this.OptionSet.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp));

                var multilineCommentTrivia = SyntaxFactory.ParseLeadingTrivia(multiLineComment);
                Contract.ThrowIfFalse(multilineCommentTrivia.Count == 1);

                result = multilineCommentTrivia.ElementAt(0);
                return true;
            }

            return false;
        }
Beispiel #18
0
 /// <summary>
 /// format the given trivia at the line column position and put result to the changes list
 /// </summary>
 protected abstract LineColumnDelta Format(LineColumn lineColumn, SyntaxTrivia trivia, ArrayBuilder <SyntaxTrivia> changes, CancellationToken cancellationToken);
 public Range(LineColumn start, LineColumn end)
 {
     Start = start;
     End = end;
 }
Beispiel #20
0
        private void AddWhitespaceTextChange(LineColumn lineColumn, LineColumnDelta delta, TextSpan span, List <TextChange> changes)
        {
            var newText = GetWhitespaceString(lineColumn, delta);

            changes.Add(new TextChange(span, newText));
        }
Beispiel #21
0
 /// <summary>
 /// format the given trivia at the line column position and put text change result to the changes list
 /// </summary>
 protected abstract LineColumnDelta Format(LineColumn lineColumn, SyntaxTrivia trivia, List <TextChange> changes, CancellationToken cancellationToken);
Beispiel #22
0
        protected LineColumnDelta GetLineColumnDelta(LineColumn lineColumn, SyntaxTrivia trivia)
        {
            var text = trivia.ToFullString();

            return(GetLineColumnDelta(lineColumn.Column, text));
        }
        protected override LineColumnDelta Format(
            LineColumn lineColumn, SyntaxTrivia trivia, List<SyntaxTrivia> changes,
            CancellationToken cancellationToken)
        {
            if (trivia.HasStructure)
            {
                return FormatStructuredTrivia(lineColumn, trivia, changes, cancellationToken);
            }

            var newComment = default(SyntaxTrivia);
            if (TryFormatMultiLineCommentTrivia(lineColumn, trivia, out newComment))
            {
                changes.Add(newComment);
                return GetLineColumnDelta(lineColumn, newComment);
            }

            changes.Add(trivia);
            return GetLineColumnDelta(lineColumn, trivia);
        }