Browse Source

Speeded up document script node formatting.

pull/32/merge
Mike Krüger 13 years ago
parent
commit
8639ca4d5b
  1. 7
      ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  2. 124
      ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
  3. 26
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SortUsingsAction.cs
  4. 10
      ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs
  5. 1
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs

7
ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -31,6 +31,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
@ -193,6 +194,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public DomRegion Region {
get {
return new DomRegion (StartLocation, EndLocation);
}
}
/// <summary> /// <summary>
/// Gets the region from StartLocation to EndLocation for this node. /// Gets the region from StartLocation to EndLocation for this node.
/// The file name of the region is set based on the parent SyntaxTree's file name. /// The file name of the region is set based on the parent SyntaxTree's file name.

124
ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs

@ -48,9 +48,9 @@ namespace ICSharpCode.NRefactory.CSharp
internal readonly string NewText; internal readonly string NewText;
internal TextReplaceAction DependsOn; internal TextReplaceAction DependsOn;
#if DEBUG #if DEBUG
internal readonly string StackTrace; internal readonly string StackTrace;
#endif #endif
public TextReplaceAction (int offset, int removalLength, string newText) public TextReplaceAction (int offset, int removalLength, string newText)
{ {
@ -98,9 +98,22 @@ namespace ICSharpCode.NRefactory.CSharp
set; set;
} }
public DomRegion FormattingRegion { List<DomRegion> formattingRegions = new List<DomRegion> ();
get; TextLocation lastFormattingLocation = new TextLocation(int.MaxValue, int.MaxValue);
set; public IEnumerable<DomRegion> FormattingRegions {
get {
return formattingRegions;
}
}
public void AddFormattingRegion (DomRegion region)
{
formattingRegions.Add(region);
if (formattingRegions.Count == 1) {
lastFormattingLocation = region.End;
} else {
lastFormattingLocation = lastFormattingLocation < region.End ? region.End : lastFormattingLocation;
}
} }
public AstFormattingVisitor(CSharpFormattingOptions policy, IDocument document, TextEditorOptions options = null) public AstFormattingVisitor(CSharpFormattingOptions policy, IDocument document, TextEditorOptions options = null)
@ -117,24 +130,33 @@ namespace ICSharpCode.NRefactory.CSharp
curIndent = new Indent(this.options); curIndent = new Indent(this.options);
} }
protected override void VisitChildren (AstNode node) void VisitChildrenToFormat (AstNode parent, Action<AstNode> callback)
{ {
AstNode next; AstNode next;
for (var child = node.FirstChild; child != null; child = next) { for (var child = parent.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue // Store next to allow the loop to continue
// if the visitor removes/replaces child. // if the visitor removes/replaces child.
next = child.NextSibling; next = child.NextSibling;
if (!FormattingRegion.IsEmpty) { if (formattingRegions.Count > 0) {
if (child.EndLocation < FormattingRegion.Begin) { if (formattingRegions.Any(r => r.IsInside(child.StartLocation) || r.IsInside(child.EndLocation))) {
continue; callback(child);
} else {
var childRegion = child.Region;
if (formattingRegions.Any(r => childRegion.IsInside(r.Begin) || childRegion.IsInside(r.End)))
callback(child);
} }
if (child.StartLocation > FormattingRegion.End) { if (child.StartLocation > lastFormattingLocation)
break; break;
} else {
callback(child);
} }
} }
child.AcceptVisitor (this);
} }
protected override void VisitChildren (AstNode node)
{
VisitChildrenToFormat (node, n => n.AcceptVisitor (this));
} }
/// <summary> /// <summary>
@ -166,6 +188,9 @@ namespace ICSharpCode.NRefactory.CSharp
public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null) public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null)
{ {
int endOffset = startOffset + length; int endOffset = startOffset + length;
// Console.WriteLine ("apply:"+ startOffset + "->" + endOffset);
// Console.WriteLine (document.Text.Substring (0, startOffset) + new string ('x',length) + document.Text.Substring (startOffset+ length));
TextReplaceAction previousChange = null; TextReplaceAction previousChange = null;
int delta = 0; int delta = 0;
var depChanges = new List<TextReplaceAction> (); var depChanges = new List<TextReplaceAction> ();
@ -187,11 +212,9 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
previousChange = change; previousChange = change;
bool skipChange = change.Offset + change.RemovalLength < startOffset || change.Offset > endOffset;
bool skipChange = change.Offset < startOffset || change.Offset > endOffset;
skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText); skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText);
skipChange &= !depChanges.Contains(change); skipChange &= !depChanges.Contains(change);
if (!skipChange) { if (!skipChange) {
documentReplace(change.Offset + delta, change.RemovalLength, change.NewText); documentReplace(change.Offset + delta, change.RemovalLength, change.NewText);
delta += change.NewText.Length - change.RemovalLength; delta += change.NewText.Length - change.RemovalLength;
@ -350,15 +373,11 @@ namespace ICSharpCode.NRefactory.CSharp
curIndent.Push(IndentType.Block); curIndent.Push(IndentType.Block);
} }
AstNode next; VisitChildrenToFormat (typeDeclaration, child => {
for (var child = typeDeclaration.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue
// if the visitor removes/replaces child.
next = child.NextSibling;
if (child is EntityDeclaration) if (child is EntityDeclaration)
FormatAttributedNode(child); FormatAttributedNode(child);
child.AcceptVisitor (this); child.AcceptVisitor (this);
} });
if (indentBody) { if (indentBody) {
curIndent.Pop (); curIndent.Pop ();
@ -439,18 +458,18 @@ namespace ICSharpCode.NRefactory.CSharp
if (lastNonWs >= 0) if (lastNonWs >= 0)
AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : ""); AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : "");
} }
// void ForceSpacesAfter (AstNode n, bool forceSpaces) // void ForceSpacesAfter (AstNode n, bool forceSpaces)
// { // {
// if (n == null) // if (n == null)
// return; // return;
// AstLocation location = n.EndLocation; // AstLocation location = n.EndLocation;
// int offset = data.LocationToOffset (location.Line, location.Column); // int offset = data.LocationToOffset (location.Line, location.Column);
// int i = offset; // int i = offset;
// while (i < data.Length && IsSpacing (data.GetCharAt (i))) { // while (i < data.Length && IsSpacing (data.GetCharAt (i))) {
// i++; // i++;
// } // }
// ForceSpace (offset - 1, i, forceSpaces); // ForceSpace (offset - 1, i, forceSpaces);
// } // }
void ForceSpacesAfter(AstNode n, bool forceSpaces) void ForceSpacesAfter(AstNode n, bool forceSpaces)
{ {
@ -469,21 +488,21 @@ namespace ICSharpCode.NRefactory.CSharp
ForceSpace(offset - 1, i, forceSpaces); ForceSpace(offset - 1, i, forceSpaces);
} }
// int ForceSpacesBefore (AstNode n, bool forceSpaces) // int ForceSpacesBefore (AstNode n, bool forceSpaces)
// { // {
// if (n == null || n.IsNull) // if (n == null || n.IsNull)
// return 0; // return 0;
// AstLocation location = n.StartLocation; // AstLocation location = n.StartLocation;
// //
// int offset = data.LocationToOffset (location.Line, location.Column); // int offset = data.LocationToOffset (location.Line, location.Column);
// int i = offset - 1; // int i = offset - 1;
// //
// while (i >= 0 && IsSpacing (data.GetCharAt (i))) { // while (i >= 0 && IsSpacing (data.GetCharAt (i))) {
// i--; // i--;
// } // }
// ForceSpace (i, offset, forceSpaces); // ForceSpace (i, offset, forceSpaces);
// return i; // return i;
// } // }
int ForceSpacesBefore(AstNode n, bool forceSpaces) int ForceSpacesBefore(AstNode n, bool forceSpaces)
{ {
@ -1045,10 +1064,12 @@ namespace ICSharpCode.NRefactory.CSharp
if (indent) { if (indent) {
curIndent.Push(IndentType.Block); curIndent.Push(IndentType.Block);
} }
foreach (var child in blockStatement.Children) {
VisitChildrenToFormat (blockStatement, child => {
if (child.Role == Roles.LBrace || child.Role == Roles.RBrace) { if (child.Role == Roles.LBrace || child.Role == Roles.RBrace) {
continue; return;
} }
if (child is Statement) { if (child is Statement) {
FixStatementIndentation(child.StartLocation); FixStatementIndentation(child.StartLocation);
child.AcceptVisitor(this); child.AcceptVisitor(this);
@ -1061,7 +1082,8 @@ namespace ICSharpCode.NRefactory.CSharp
if (child.StartLocation.Column > 1) if (child.StartLocation.Column > 1)
FixStatementIndentation(child.StartLocation); FixStatementIndentation(child.StartLocation);
} }
} });
if (indent) { if (indent) {
curIndent.Pop (); curIndent.Pop ();
} }

26
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SortUsingsAction.cs

@ -1,3 +1,29 @@
//
// SortUsingsAction.cs
//
// Author:
// Lopatkin Ilja
//
// Copyright (c) 2012 Lopatkin Ilja
//
// 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

10
ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs

@ -101,15 +101,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void FormatText(IEnumerable<AstNode> nodes) public override void FormatText(IEnumerable<AstNode> nodes)
{ {
var syntaxTree = SyntaxTree.Parse(currentDocument, "dummy.cs"); var syntaxTree = SyntaxTree.Parse(currentDocument, "dummy.cs");
var formatter = new AstFormattingVisitor(FormattingOptions, currentDocument, Options);
var segments = new List<ISegment>();
foreach (var node in nodes.OrderByDescending (n => n.StartLocation)) { foreach (var node in nodes.OrderByDescending (n => n.StartLocation)) {
var segment = GetSegment(node); var segment = GetSegment(node);
var formatter = new AstFormattingVisitor(FormattingOptions, currentDocument, Options);
formatter.FormattingRegion = new ICSharpCode.NRefactory.TypeSystem.DomRegion ( formatter.AddFormattingRegion (new ICSharpCode.NRefactory.TypeSystem.DomRegion (
currentDocument.GetLocation (segment.Offset), currentDocument.GetLocation (segment.Offset),
currentDocument.GetLocation (segment.EndOffset) currentDocument.GetLocation (segment.EndOffset)
); ));
segments.Add(segment);
}
syntaxTree.AcceptVisitor(formatter); syntaxTree.AcceptVisitor(formatter);
foreach (var segment in segments) {
formatter.ApplyChanges(segment.Offset, segment.Length); formatter.ApplyChanges(segment.Offset, segment.Length);
} }
} }

1
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs

@ -101,7 +101,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
" {" + Environment.NewLine + " {" + Environment.NewLine +
" int i;" + Environment.NewLine + " int i;" + Environment.NewLine +
" for (i = 1; i < 10; i++) {" + Environment.NewLine + " for (i = 1; i < 10; i++) {" + Environment.NewLine +
" " + Environment.NewLine +
" }" + Environment.NewLine + " }" + Environment.NewLine +
" }" + Environment.NewLine + " }" + Environment.NewLine +
"}", result); "}", result);

Loading…
Cancel
Save