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)); }
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)); }
private void AddWhitespaceTrivia( LineColumn lineColumn, LineColumnDelta delta, List <SyntaxTrivia> changes) { AddWhitespaceTrivia(lineColumn, delta, default(TextSpan), changes); }
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))); }
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(); }
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)); }
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; } }
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)); }
/// <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); }
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); }
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; }
/// <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; }
private void AddWhitespaceTextChange(LineColumn lineColumn, LineColumnDelta delta, TextSpan span, List <TextChange> changes) { var newText = GetWhitespaceString(lineColumn, delta); changes.Add(new TextChange(span, newText)); }
/// <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);
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); }