Browse Source

Move statement up/down - basic version with comments.

pull/15/head
mkonicek 15 years ago
parent
commit
1681740ef4
  1. 127
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs

127
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs

@ -42,15 +42,22 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -42,15 +42,22 @@ namespace ICSharpCode.AvalonEdit.AddIn
// move selection - find outermost node in selection, swap selection with closest child of its parent to the selection
static void MoveStatement(ITextEditor editor, MoveStatementDirection direction)
{
IList<ISpecial> commentsBlankLines;
var parsedCU = ParseDocument(editor, out commentsBlankLines);
if (parsedCU == null) return;
// Find the Statement or Definition containing caret -> Extend selection to Statement or Definition
INode currentStatement = ExtendSelection(editor, new Type[] {
typeof(Statement),
typeof(MemberNode),
typeof(FieldDeclaration),
typeof(ConstructorDeclaration),
typeof(DestructorDeclaration) });
INode currentStatement;
Selection statementSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out currentStatement, new Type[] {
typeof(Statement),
typeof(MemberNode),
typeof(FieldDeclaration),
typeof(ConstructorDeclaration),
typeof(DestructorDeclaration) });
if (currentStatement == null)
return;
statementSelection = TryExtendSelectionToComments(editor.Document, statementSelection, commentsBlankLines);
// Take its sibling
if (currentStatement.Parent == null)
return;
@ -61,10 +68,10 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -61,10 +68,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
return;
INode swapSibling = siblings[swapIndex];
// Swap them
string currentNodeText = editor.Document.GetText(currentStatement.StartLocation, currentStatement.EndLocation);
SwapText(editor.Document, currentStatement.StartLocation, currentStatement.EndLocation, swapSibling.StartLocation, swapSibling.EndLocation);
string currentNodeText = editor.Document.GetText(statementSelection.Start, statementSelection.End);
SwapText(editor.Document, statementSelection.Start, statementSelection.End, swapSibling.StartLocation, swapSibling.EndLocation);
// Move caret to the start of moved statement
Location upperLocation = new Location[] {currentStatement.StartLocation, swapSibling.StartLocation}.Min();
Location upperLocation = new Location[] {statementSelection.Start, swapSibling.StartLocation}.Min();
if (direction == MoveStatementDirection.Up)
editor.Caret.Position = upperLocation;
else {
@ -74,40 +81,30 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -74,40 +81,30 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
}
static void SwapText(IDocument document, Location start1, Location end1, Location start2, Location end2)
static Selection TryExtendSelectionToComments(IDocument document, Selection selection, IList<ISpecial> commentsBlankLines)
{
if (start1 > start2) {
Location sw;
sw = start1; start1 = start2; start2 = sw;
sw = end1; end1 = end2; end2 = sw;
}
if (end1 >= start2)
throw new InvalidOperationException("Cannot swap overlaping segments");
int offset1 = document.PositionToOffset(start1);
int len1 = document.PositionToOffset(end1) - offset1;
int offset2 = document.PositionToOffset(start2);
int len2 = document.PositionToOffset(end2) - offset2;
string text1 = document.GetText(offset1, len1);
string text2 = document.GetText(offset2, len2);
using (var undoGroup = document.OpenUndoGroup()) {
document.Replace(offset2, len2, text1);
document.Replace(offset1, len1, text2);
}
var extendedToComments = ExtendSelectionToComments(document, selection, commentsBlankLines);
if (extendedToComments != null)
return extendedToComments;
return selection;
}
public static void ExtendSelection(ITextEditor editor)
{
ExtendSelection(editor, new Type[] { typeof(INode) }); // any node type
INode selectedNode = null;
IList<ISpecial> commentsBlankLines;
var parsedCU = ParseDocument(editor, out commentsBlankLines);
if (parsedCU == null) return;
Selection extendedSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out selectedNode, new Type[] { typeof(INode) }); // any node type
SelectText(extendedSelection, editor);
}
// could work to extend selection to set of adjacent statements - e.g. select 3 lines
static INode ExtendSelection(ITextEditor editor, Type[] interestingNodeTypes)
static Selection ExtendSelection(ITextEditor editor, CompilationUnit parsedCU, IList<ISpecial> commentsBlankLines, out INode selectedResultNode, Type[] interestingNodeTypes)
{
IList<ISpecial> commentsBlankLines;
var parsedCU = ParseDocument(editor, out commentsBlankLines);
if (parsedCU == null) return null;
selectedResultNode = null;
var selectionStart = editor.Document.OffsetToPosition(editor.SelectionStart);
var selectionEnd = editor.Document.OffsetToPosition(editor.SelectionStart + editor.SelectionLength);
@ -120,7 +117,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -120,7 +117,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
currentNode = GetInterestingParent(currentNode, interestingNodeTypes);
}
if (currentNode == null) return null;
var selectedResultNode = currentNode;
selectedResultNode = currentNode;
// whole node already selected -> expand selection
if (currentNode.StartLocation == selectionStart && currentNode.EndLocation == selectionEnd) {
@ -139,8 +136,9 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -139,8 +136,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
while (parent != null && parent.StartLocation == selectionStart && parent.EndLocation == selectionEnd) {
parent = GetInterestingParent(parent, interestingNodeTypes);
}
if (parent == null)
return currentNode;
if (parent == null) {
return new Selection { Start = selectionStart, End = selectionEnd };
}
// Select the parent
var extendedSelectionStart = parent.StartLocation;
var extendedLocationEnd = parent.EndLocation;
@ -163,15 +161,14 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -163,15 +161,14 @@ namespace ICSharpCode.AvalonEdit.AddIn
selectionEnd = currentNode.EndLocation;
selectedResultNode = currentNode;
}
int startOffset, endOffset;
try {
startOffset = editor.Document.PositionToOffset(selectionStart);
endOffset = editor.Document.PositionToOffset(selectionEnd);
} catch(ArgumentOutOfRangeException) {
return null;
}
editor.Select(startOffset, endOffset - startOffset);
return selectedResultNode;
return new Selection { Start = selectionStart, End = selectionEnd };
}
static Selection ExtendSelectionToComments(IDocument document, Selection selection, IList<ISpecial> commentsBlankLines)
{
if (selection == null)
throw new ArgumentNullException("selection");
return ExtendSelectionToComments(document, selection.Start, selection.End, commentsBlankLines);
}
/// <summary>
@ -251,5 +248,43 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -251,5 +248,43 @@ namespace ICSharpCode.AvalonEdit.AddIn
parsedSpecials = parser.Lexer.SpecialTracker.CurrentSpecials;
return parsedCU;
}
/// <summary>
/// Swaps 2 ranges of text in a document.
/// </summary>
static void SwapText(IDocument document, Location start1, Location end1, Location start2, Location end2)
{
if (start1 > start2) {
Location sw;
sw = start1; start1 = start2; start2 = sw;
sw = end1; end1 = end2; end2 = sw;
}
if (end1 >= start2)
throw new InvalidOperationException("Cannot swap overlaping segments");
int offset1 = document.PositionToOffset(start1);
int len1 = document.PositionToOffset(end1) - offset1;
int offset2 = document.PositionToOffset(start2);
int len2 = document.PositionToOffset(end2) - offset2;
string text1 = document.GetText(offset1, len1);
string text2 = document.GetText(offset2, len2);
using (var undoGroup = document.OpenUndoGroup()) {
document.Replace(offset2, len2, text1);
document.Replace(offset1, len1, text2);
}
}
static void SelectText(Selection selection, ITextEditor editor)
{
int startOffset, endOffset;
try {
startOffset = editor.Document.PositionToOffset(selection.Start);
endOffset = editor.Document.PositionToOffset(selection.End);
} catch (ArgumentOutOfRangeException) {
return;
}
editor.Select(startOffset, endOffset - startOffset);
}
}
}

Loading…
Cancel
Save