You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
662 lines
21 KiB
662 lines
21 KiB
// |
|
// FormattingVisitor.cs |
|
// |
|
// Author: |
|
// Mike Krüger <mkrueger@xamarin.com> |
|
// |
|
// Copyright (c) 2010 Novell, Inc (http://www.novell.com) |
|
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy |
|
// of this software and associated documentation files (the "Software"), to deal |
|
// in the Software without restriction, including without limitation the rights |
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
// copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in |
|
// all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
// THE SOFTWARE. |
|
using System; |
|
using System.Text; |
|
using System.Linq; |
|
using ICSharpCode.NRefactory.Editor; |
|
using ICSharpCode.NRefactory.TypeSystem; |
|
using System.Threading; |
|
|
|
namespace ICSharpCode.NRefactory.CSharp |
|
{ |
|
[Obsolete("This class was replaced by CSharpFormatter.")] |
|
public class AstFormattingVisitor {} |
|
|
|
partial class FormattingVisitor : DepthFirstAstVisitor |
|
{ |
|
readonly CSharpFormatter formatter; |
|
readonly FormattingChanges changes; |
|
readonly IDocument document; |
|
readonly CancellationToken token; |
|
|
|
Indent curIndent; |
|
|
|
public bool HadErrors { |
|
get; |
|
set; |
|
} |
|
|
|
|
|
CSharpFormattingOptions policy { |
|
get { |
|
return formatter.Policy; |
|
} |
|
} |
|
|
|
TextEditorOptions options { |
|
get { |
|
return formatter.TextEditorOptions; |
|
} |
|
} |
|
|
|
FormattingChanges.TextReplaceAction AddChange(int offset, int removedChars, string insertedText) |
|
{ |
|
return changes.AddChange(offset, removedChars, insertedText); |
|
} |
|
|
|
public FormattingVisitor(CSharpFormatter formatter, IDocument document, FormattingChanges changes, CancellationToken token) |
|
{ |
|
if (formatter == null) |
|
throw new ArgumentNullException("formatter"); |
|
if (document == null) |
|
throw new ArgumentNullException("document"); |
|
if (changes == null) |
|
throw new ArgumentNullException("changes"); |
|
|
|
this.formatter = formatter; |
|
this.changes = changes; |
|
this.document = document; |
|
this.token = token; |
|
|
|
curIndent = new Indent(formatter.TextEditorOptions); |
|
} |
|
|
|
void VisitChildrenToFormat (AstNode parent, Action<AstNode> callback) |
|
{ |
|
AstNode next; |
|
for (var child = parent.FirstChild; child != null; child = next) { |
|
token.ThrowIfCancellationRequested(); |
|
// Store next to allow the loop to continue |
|
// if the visitor removes/replaces child. |
|
next = child.GetNextSibling(NoWhitespacePredicate); |
|
|
|
if (formatter.FormattingRegions.Count > 0) { |
|
if (formatter.FormattingRegions.Any(r => r.IsInside(child.StartLocation) || r.IsInside(child.EndLocation))) { |
|
callback(child); |
|
} else { |
|
var childRegion = child.Region; |
|
if (formatter.FormattingRegions.Any(r => childRegion.IsInside(r.Begin) || childRegion.IsInside(r.End))) |
|
callback(child); |
|
} |
|
if (child.StartLocation > formatter.lastFormattingLocation) |
|
break; |
|
} else { |
|
callback(child); |
|
} |
|
} |
|
} |
|
|
|
protected override void VisitChildren (AstNode node) |
|
{ |
|
VisitChildrenToFormat (node, n => n.AcceptVisitor (this)); |
|
} |
|
|
|
public void EnsureNewLinesAfter(AstNode node, int blankLines) |
|
{ |
|
if (formatter.FormattingMode != FormattingMode.Intrusive) |
|
blankLines = 1; |
|
int foundBlankLines = 0; |
|
var nextNode = node.GetNextNode (); |
|
AstNode lastNewLine = null; |
|
while (nextNode != null) { |
|
if (!(nextNode is NewLineNode)) |
|
break; |
|
lastNewLine = nextNode; |
|
foundBlankLines++; |
|
nextNode = nextNode.GetNextNode (); |
|
} |
|
if (nextNode == null) |
|
return; |
|
var start = document.GetOffset(node.EndLocation); |
|
var end = document.GetOffset((lastNewLine ?? nextNode).StartLocation); |
|
var sb = new StringBuilder(options.EolMarker.Length * blankLines); |
|
for (int i = 0; i < blankLines + (lastNewLine != null ? -1 : 0); i++) { |
|
sb.Append(options.EolMarker); |
|
} |
|
AddChange(start, end - start, sb.ToString()); |
|
} |
|
|
|
public void EnsureBlankLinesBefore(AstNode node, int blankLines) |
|
{ |
|
if (formatter.FormattingMode != FormattingMode.Intrusive) |
|
return; |
|
var loc = node.StartLocation; |
|
int line = loc.Line; |
|
do { |
|
line--; |
|
} while (line > 0 && IsSpacing(document.GetLineByNumber(line))); |
|
int end = document.GetOffset(loc.Line, 1); |
|
int start = document.GetOffset(line + 1, 1); |
|
var sb = new StringBuilder (); |
|
for (int i = 0; i < blankLines; i++) { |
|
sb.Append(options.EolMarker); |
|
} |
|
if (end - start == 0 && sb.Length == 0) |
|
return; |
|
AddChange(start, end - start, sb.ToString()); |
|
} |
|
|
|
bool IsSimpleAccessor(Accessor accessor) |
|
{ |
|
if (accessor.IsNull || accessor.Body.IsNull || accessor.Body.FirstChild == null) { |
|
return true; |
|
} |
|
if (accessor.Body.Statements.Count() != 1) { |
|
return false; |
|
} |
|
return !(accessor.Body.Statements.FirstOrDefault() is BlockStatement); |
|
|
|
} |
|
|
|
bool IsSpacing(char ch) |
|
{ |
|
return ch == ' ' || ch == '\t'; |
|
} |
|
|
|
bool IsSpacing(ISegment segment) |
|
{ |
|
int endOffset = segment.EndOffset; |
|
for (int i = segment.Offset; i < endOffset; i++) { |
|
if (!IsSpacing(document.GetCharAt(i))) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
int SearchLastNonWsChar(int startOffset, int endOffset) |
|
{ |
|
startOffset = Math.Max(0, startOffset); |
|
endOffset = Math.Max(startOffset, endOffset); |
|
if (startOffset >= endOffset) { |
|
return startOffset; |
|
} |
|
int result = -1; |
|
bool inComment = false; |
|
|
|
for (int i = startOffset; i < endOffset && i < document.TextLength; i++) { |
|
char ch = document.GetCharAt(i); |
|
if (IsSpacing(ch)) { |
|
continue; |
|
} |
|
if (ch == '/' && i + 1 < document.TextLength && document.GetCharAt(i + 1) == '/') { |
|
return result; |
|
} |
|
if (ch == '/' && i + 1 < document.TextLength && document.GetCharAt(i + 1) == '*') { |
|
inComment = true; |
|
i++; |
|
continue; |
|
} |
|
if (inComment && ch == '*' && i + 1 < document.TextLength && document.GetCharAt(i + 1) == '/') { |
|
inComment = false; |
|
i++; |
|
continue; |
|
} |
|
if (!inComment) { |
|
result = i; |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
void ForceSpace(int startOffset, int endOffset, bool forceSpace) |
|
{ |
|
int lastNonWs = SearchLastNonWsChar(startOffset, endOffset); |
|
if (lastNonWs >= 0) |
|
AddChange(lastNonWs + 1, Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : ""); |
|
} |
|
|
|
void ForceSpacesAfter(AstNode n, bool forceSpaces) |
|
{ |
|
if (n == null) { |
|
return; |
|
} |
|
TextLocation location = n.EndLocation; |
|
int offset = document.GetOffset(location); |
|
if (location.Column > document.GetLineByNumber(location.Line).Length) { |
|
return; |
|
} |
|
int i = offset; |
|
while (i < document.TextLength && IsSpacing (document.GetCharAt (i))) { |
|
i++; |
|
} |
|
ForceSpace(offset - 1, i, forceSpaces); |
|
} |
|
|
|
int ForceSpacesBefore(AstNode n, bool forceSpaces) |
|
{ |
|
if (n == null || n.IsNull) { |
|
return 0; |
|
} |
|
TextLocation location = n.StartLocation; |
|
// respect manual line breaks. |
|
if (location.Column <= 1 || GetIndentation(location.Line).Length == location.Column - 1) { |
|
return 0; |
|
} |
|
|
|
int offset = document.GetOffset(location); |
|
int i = offset - 1; |
|
while (i >= 0 && IsSpacing (document.GetCharAt (i))) { |
|
i--; |
|
} |
|
ForceSpace(i, offset, forceSpaces); |
|
return i; |
|
} |
|
|
|
int ForceSpacesBeforeRemoveNewLines(AstNode n, bool forceSpace = true) |
|
{ |
|
if (n == null || n.IsNull) { |
|
return 0; |
|
} |
|
int offset = document.GetOffset(n.StartLocation); |
|
int i = offset - 1; |
|
while (i >= 0) { |
|
char ch = document.GetCharAt(i); |
|
if (!IsSpacing(ch) && ch != '\r' && ch != '\n') |
|
break; |
|
i--; |
|
} |
|
var length = Math.Max(0, (offset - 1) - i); |
|
AddChange(i + 1, length, forceSpace ? " " : ""); |
|
return i; |
|
} |
|
|
|
static bool NoWhitespacePredicate(AstNode arg) |
|
{ |
|
return !(arg is NewLineNode || arg is WhitespaceNode); |
|
} |
|
|
|
static bool IsMember(AstNode nextSibling) |
|
{ |
|
return nextSibling != null && nextSibling.NodeType == NodeType.Member; |
|
} |
|
|
|
void FormatParameters(AstNode node) |
|
{ |
|
Wrapping methodCallArgumentWrapping; |
|
bool newLineAferMethodCallOpenParentheses; |
|
bool methodClosingParenthesesOnNewLine; |
|
bool spaceWithinMethodCallParentheses; |
|
bool spaceAfterMethodCallParameterComma; |
|
bool spaceBeforeMethodCallParameterComma; |
|
|
|
CSharpTokenNode rParToken; |
|
AstNodeCollection<ParameterDeclaration> parameters; |
|
|
|
var constructorDeclaration = node as ConstructorDeclaration; |
|
if (constructorDeclaration != null) { |
|
methodCallArgumentWrapping = policy.MethodDeclarationParameterWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferMethodDeclarationOpenParentheses; |
|
methodClosingParenthesesOnNewLine = policy.MethodDeclarationClosingParenthesesOnNewLine; |
|
|
|
spaceWithinMethodCallParentheses = policy.SpaceWithinConstructorDeclarationParentheses; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterConstructorDeclarationParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeConstructorDeclarationParameterComma; |
|
rParToken = constructorDeclaration.RParToken; |
|
parameters = constructorDeclaration.Parameters; |
|
} else if (node is IndexerDeclaration) { |
|
var indexer = (IndexerDeclaration)node; |
|
methodCallArgumentWrapping = policy.IndexerDeclarationParameterWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferIndexerDeclarationOpenBracket; |
|
methodClosingParenthesesOnNewLine = policy.IndexerDeclarationClosingBracketOnNewLine; |
|
|
|
spaceWithinMethodCallParentheses = policy.SpaceWithinIndexerDeclarationBracket; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterIndexerDeclarationParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeIndexerDeclarationParameterComma; |
|
rParToken = indexer.RBracketToken; |
|
parameters = indexer.Parameters; |
|
} else if (node is OperatorDeclaration) { |
|
var op = (OperatorDeclaration)node; |
|
methodCallArgumentWrapping = policy.MethodDeclarationParameterWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferMethodDeclarationOpenParentheses; |
|
methodClosingParenthesesOnNewLine = policy.MethodDeclarationClosingParenthesesOnNewLine; |
|
spaceWithinMethodCallParentheses = policy.SpaceWithinMethodDeclarationParentheses; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterMethodDeclarationParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeMethodDeclarationParameterComma; |
|
rParToken = op.RParToken; |
|
parameters = op.Parameters; |
|
} else { |
|
var methodDeclaration = node as MethodDeclaration; |
|
methodCallArgumentWrapping = policy.MethodDeclarationParameterWrapping; |
|
newLineAferMethodCallOpenParentheses = policy.NewLineAferMethodDeclarationOpenParentheses; |
|
methodClosingParenthesesOnNewLine = policy.MethodDeclarationClosingParenthesesOnNewLine; |
|
spaceWithinMethodCallParentheses = policy.SpaceWithinMethodDeclarationParentheses; |
|
spaceAfterMethodCallParameterComma = policy.SpaceAfterMethodDeclarationParameterComma; |
|
spaceBeforeMethodCallParameterComma = policy.SpaceBeforeMethodDeclarationParameterComma; |
|
rParToken = methodDeclaration.RParToken; |
|
parameters = methodDeclaration.Parameters; |
|
} |
|
if (formatter.FormattingMode == FormattingMode.OnTheFly) |
|
methodCallArgumentWrapping = Wrapping.DoNotChange; |
|
|
|
bool wrapMethodCall = DoWrap(methodCallArgumentWrapping, rParToken, parameters.Count); |
|
if (wrapMethodCall && parameters.Any()) { |
|
if (newLineAferMethodCallOpenParentheses) { |
|
curIndent.Push(IndentType.Continuation); |
|
foreach (var arg in parameters) { |
|
FixStatementIndentation(arg.StartLocation); |
|
} |
|
curIndent.Pop(); |
|
} else { |
|
int extraSpaces = parameters.First().StartLocation.Column - 1 - curIndent.IndentString.Length; |
|
curIndent.ExtraSpaces += extraSpaces; |
|
foreach (var arg in parameters.Skip(1)) { |
|
FixStatementIndentation(arg.StartLocation); |
|
} |
|
curIndent.ExtraSpaces -= extraSpaces; |
|
} |
|
if (!rParToken.IsNull) { |
|
if (methodClosingParenthesesOnNewLine) { |
|
FixStatementIndentation(rParToken.StartLocation); |
|
} else { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); |
|
} |
|
} |
|
} else { |
|
foreach (var arg in parameters.Skip (1)) { |
|
if (arg.GetPrevSibling(NoWhitespacePredicate) != null) { |
|
if (methodCallArgumentWrapping == Wrapping.DoNotWrap) { |
|
ForceSpacesBeforeRemoveNewLines(arg, spaceAfterMethodCallParameterComma && arg.GetPrevSibling(NoWhitespacePredicate).Role == Roles.Comma); |
|
} else { |
|
ForceSpacesBefore(arg, spaceAfterMethodCallParameterComma && arg.GetPrevSibling(NoWhitespacePredicate).Role == Roles.Comma); |
|
} |
|
} |
|
arg.AcceptVisitor(this); |
|
} |
|
if (!rParToken.IsNull) { |
|
if (methodCallArgumentWrapping == Wrapping.DoNotWrap) { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); |
|
} else { |
|
bool sameLine = rParToken.GetPrevNode().StartLocation.Line == rParToken.StartLocation.Line; |
|
if (sameLine) { |
|
ForceSpacesBeforeRemoveNewLines(rParToken, spaceWithinMethodCallParentheses); |
|
} else { |
|
FixStatementIndentation(rParToken.StartLocation); |
|
} |
|
} |
|
} |
|
} |
|
if (!rParToken.IsNull) { |
|
foreach (var comma in rParToken.Parent.Children.Where(n => n.Role == Roles.Comma)) { |
|
ForceSpacesBefore(comma, spaceBeforeMethodCallParameterComma); |
|
} |
|
} |
|
} |
|
|
|
void ForceSpaceBefore(AstNode node, bool forceSpace) |
|
{ |
|
_ForceSpaceBefore(document.GetOffset(node.StartLocation), forceSpace); |
|
} |
|
|
|
void _ForceSpaceBefore(int offset, bool forceSpace) |
|
{ |
|
bool insertedSpace = false; |
|
do { |
|
char ch = document.GetCharAt(offset); |
|
//Console.WriteLine (ch); |
|
if (!IsSpacing(ch) && (insertedSpace || !forceSpace)) { |
|
break; |
|
} |
|
if (ch == ' ' && forceSpace) { |
|
if (insertedSpace) { |
|
AddChange(offset, 1, null); |
|
} else { |
|
insertedSpace = true; |
|
} |
|
} else if (forceSpace) { |
|
if (!insertedSpace) { |
|
AddChange(offset, IsSpacing(ch) ? 1 : 0, " "); |
|
insertedSpace = true; |
|
} else if (IsSpacing(ch)) { |
|
AddChange(offset, 1, null); |
|
} |
|
} |
|
|
|
offset--; |
|
} while (offset >= 0); |
|
} |
|
|
|
public void FixSemicolon(CSharpTokenNode semicolon) |
|
{ |
|
if (semicolon.IsNull) { |
|
return; |
|
} |
|
int endOffset = document.GetOffset(semicolon.StartLocation); |
|
int offset = endOffset; |
|
while (offset - 1 > 0 && char.IsWhiteSpace (document.GetCharAt (offset - 1))) { |
|
offset--; |
|
} |
|
if (offset < endOffset) { |
|
AddChange(offset, endOffset - offset, null); |
|
} |
|
} |
|
|
|
void PlaceOnNewLine(NewLinePlacement newLine, AstNode keywordNode) |
|
{ |
|
if (keywordNode == null || newLine == NewLinePlacement.DoNotCare) { |
|
return; |
|
} |
|
|
|
var prev = keywordNode.GetPrevNode (); |
|
if (prev is Comment || prev is PreProcessorDirective) |
|
return; |
|
|
|
int offset = document.GetOffset(keywordNode.StartLocation); |
|
|
|
int whitespaceStart = SearchWhitespaceStart(offset); |
|
string indentString = newLine == NewLinePlacement.NewLine ? options.EolMarker + curIndent.IndentString : " "; |
|
AddChange(whitespaceStart, offset - whitespaceStart, indentString); |
|
} |
|
|
|
string nextStatementIndent; |
|
|
|
void FixStatementIndentation(TextLocation location) |
|
{ |
|
if (location.Line < 1 || location.Column < 1) { |
|
Console.WriteLine("invalid location!"); |
|
return; |
|
} |
|
int offset = document.GetOffset(location); |
|
if (offset <= 0) { |
|
Console.WriteLine("possible wrong offset"); |
|
Console.WriteLine(Environment.StackTrace); |
|
return; |
|
} |
|
bool isEmpty = IsLineIsEmptyUpToEol(offset); |
|
int lineStart = SearchWhitespaceLineStart(offset); |
|
string indentString = nextStatementIndent ?? (isEmpty ? "" : options.EolMarker) + curIndent.IndentString; |
|
nextStatementIndent = null; |
|
AddChange(lineStart, offset - lineStart, indentString); |
|
} |
|
|
|
void FixIndentation (AstNode node) |
|
{ |
|
FixIndentation(node.StartLocation, 0); |
|
} |
|
|
|
void FixIndentation(TextLocation location, int relOffset) |
|
{ |
|
if (location.Line < 1 || location.Line > document.LineCount) { |
|
Console.WriteLine("Invalid location " + location); |
|
Console.WriteLine(Environment.StackTrace); |
|
return; |
|
} |
|
|
|
string lineIndent = GetIndentation(location.Line); |
|
string indentString = curIndent.IndentString; |
|
if (indentString != lineIndent && location.Column - 1 + relOffset == lineIndent.Length) { |
|
AddChange(document.GetOffset(location.Line, 1), lineIndent.Length, indentString); |
|
} |
|
} |
|
|
|
void FixIndentationForceNewLine(AstNode node) |
|
{ |
|
if (node.GetPrevNode () is NewLineNode) { |
|
FixIndentation(node); |
|
} else { |
|
int offset = document.GetOffset(node.StartLocation); |
|
AddChange(offset, 0, curIndent.IndentString); |
|
} |
|
} |
|
|
|
string GetIndentation(int lineNumber) |
|
{ |
|
var line = document.GetLineByNumber(lineNumber); |
|
var b = new StringBuilder (); |
|
int endOffset = line.EndOffset; |
|
for (int i = line.Offset; i < endOffset; i++) { |
|
char c = document.GetCharAt(i); |
|
if (!IsSpacing(c)) { |
|
break; |
|
} |
|
b.Append(c); |
|
} |
|
return b.ToString(); |
|
} |
|
|
|
|
|
void FixOpenBrace(BraceStyle braceStyle, AstNode lbrace) |
|
{ |
|
if (lbrace.IsNull) |
|
return; |
|
switch (braceStyle) { |
|
case BraceStyle.DoNotChange: |
|
return; |
|
|
|
case BraceStyle.BannerStyle: |
|
case BraceStyle.EndOfLine: |
|
var prev = lbrace.GetPrevNode(); |
|
while (prev is NewLineNode) |
|
prev = prev.GetPrevNode(); |
|
if (prev is PreProcessorDirective) |
|
return; |
|
int prevOffset = document.GetOffset(prev.EndLocation); |
|
|
|
if (prev is Comment || prev is PreProcessorDirective) { |
|
int next = document.GetOffset(lbrace.GetNextNode ().StartLocation); |
|
AddChange(prevOffset, next - prevOffset, ""); |
|
while (prev is Comment || prev is PreProcessorDirective) |
|
prev = prev.GetPrevNode(); |
|
prevOffset = document.GetOffset(prev.EndLocation); |
|
AddChange(prevOffset, 0, " {"); |
|
} else { |
|
int braceOffset2 = document.GetOffset(lbrace.StartLocation); |
|
AddChange(prevOffset, braceOffset2 - prevOffset, " "); |
|
} |
|
break; |
|
case BraceStyle.EndOfLineWithoutSpace: |
|
prev = lbrace.GetPrevNode(); |
|
while (prev is NewLineNode) |
|
prev = prev.GetPrevNode(); |
|
if (prev is PreProcessorDirective) |
|
return; |
|
prevOffset = document.GetOffset(prev.EndLocation); |
|
int braceOffset = document.GetOffset(lbrace.StartLocation); |
|
AddChange(prevOffset, braceOffset - prevOffset, ""); |
|
break; |
|
|
|
case BraceStyle.NextLine: |
|
prev = lbrace.GetPrevNode(); |
|
while (prev is NewLineNode) |
|
prev = prev.GetPrevNode(); |
|
if (prev is PreProcessorDirective) |
|
return; |
|
prevOffset = document.GetOffset(prev.EndLocation); |
|
braceOffset = document.GetOffset(lbrace.StartLocation); |
|
AddChange(prevOffset, braceOffset - prevOffset, options.EolMarker + curIndent.IndentString); |
|
break; |
|
case BraceStyle.NextLineShifted: |
|
prev = lbrace.GetPrevNode(); |
|
while (prev is NewLineNode) |
|
prev = prev.GetPrevNode(); |
|
if (prev is PreProcessorDirective) |
|
return; |
|
prevOffset = document.GetOffset(prev.EndLocation); |
|
braceOffset = document.GetOffset(lbrace.StartLocation); |
|
curIndent.Push(IndentType.Block); |
|
AddChange(prevOffset, braceOffset - prevOffset, options.EolMarker + curIndent.IndentString); |
|
curIndent.Pop(); |
|
break; |
|
case BraceStyle.NextLineShifted2: |
|
prev = lbrace.GetPrevNode(); |
|
while (prev is NewLineNode) |
|
prev = prev.GetPrevNode(); |
|
if (prev is PreProcessorDirective) |
|
return; |
|
prevOffset = document.GetOffset(prev.EndLocation); |
|
braceOffset = document.GetOffset(lbrace.StartLocation); |
|
curIndent.Push(IndentType.Block); |
|
AddChange(prevOffset, braceOffset - prevOffset, options.EolMarker + curIndent.IndentString); |
|
curIndent.Pop(); |
|
break; |
|
} |
|
} |
|
|
|
void CorrectClosingBrace (AstNode rbrace) |
|
{ |
|
int braceOffset = document.GetOffset(rbrace.StartLocation); |
|
var prevNode = rbrace.GetPrevNode(); |
|
int prevNodeOffset = prevNode != null ? document.GetOffset(prevNode.EndLocation) : 0; |
|
if (prevNode is NewLineNode) { |
|
AddChange(prevNodeOffset, braceOffset - prevNodeOffset, curIndent.IndentString); |
|
} else { |
|
AddChange(prevNodeOffset, braceOffset - prevNodeOffset, options.EolMarker + curIndent.IndentString); |
|
} |
|
} |
|
|
|
void FixClosingBrace(BraceStyle braceStyle, AstNode rbrace) |
|
{ |
|
if (rbrace.IsNull) |
|
return; |
|
switch (braceStyle) { |
|
case BraceStyle.DoNotChange: |
|
return; |
|
|
|
case BraceStyle.NextLineShifted: |
|
case BraceStyle.BannerStyle: |
|
curIndent.Push(IndentType.Block); |
|
CorrectClosingBrace (rbrace); |
|
curIndent.Pop (); |
|
break; |
|
case BraceStyle.EndOfLineWithoutSpace: |
|
case BraceStyle.EndOfLine: |
|
case BraceStyle.NextLine: |
|
CorrectClosingBrace (rbrace); |
|
break; |
|
|
|
case BraceStyle.NextLineShifted2: |
|
curIndent.Push(IndentType.Block); |
|
CorrectClosingBrace (rbrace); |
|
curIndent.Pop (); |
|
break; |
|
} |
|
|
|
} |
|
|
|
} |
|
} |
|
|
|
|