Browse Source

Move statement up/down - basic version with comments.

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

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

@ -42,8 +42,14 @@ namespace ICSharpCode.AvalonEdit.AddIn
// move selection - find outermost node in selection, swap selection with closest child of its parent to the selection // 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) 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 // Find the Statement or Definition containing caret -> Extend selection to Statement or Definition
INode currentStatement = ExtendSelection(editor, new Type[] {
INode currentStatement;
Selection statementSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out currentStatement, new Type[] {
typeof(Statement), typeof(Statement),
typeof(MemberNode), typeof(MemberNode),
typeof(FieldDeclaration), typeof(FieldDeclaration),
@ -51,6 +57,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
typeof(DestructorDeclaration) }); typeof(DestructorDeclaration) });
if (currentStatement == null) if (currentStatement == null)
return; return;
statementSelection = TryExtendSelectionToComments(editor.Document, statementSelection, commentsBlankLines);
// Take its sibling // Take its sibling
if (currentStatement.Parent == null) if (currentStatement.Parent == null)
return; return;
@ -61,10 +68,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
return; return;
INode swapSibling = siblings[swapIndex]; INode swapSibling = siblings[swapIndex];
// Swap them // Swap them
string currentNodeText = editor.Document.GetText(currentStatement.StartLocation, currentStatement.EndLocation); string currentNodeText = editor.Document.GetText(statementSelection.Start, statementSelection.End);
SwapText(editor.Document, currentStatement.StartLocation, currentStatement.EndLocation, swapSibling.StartLocation, swapSibling.EndLocation); SwapText(editor.Document, statementSelection.Start, statementSelection.End, swapSibling.StartLocation, swapSibling.EndLocation);
// Move caret to the start of moved statement // 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) if (direction == MoveStatementDirection.Up)
editor.Caret.Position = upperLocation; editor.Caret.Position = upperLocation;
else { else {
@ -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) { var extendedToComments = ExtendSelectionToComments(document, selection, commentsBlankLines);
Location sw; if (extendedToComments != null)
sw = start1; start1 = start2; start2 = sw; return extendedToComments;
sw = end1; end1 = end2; end2 = sw; return selection;
}
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);
}
} }
public static void ExtendSelection(ITextEditor editor) 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 // 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; selectedResultNode = null;
var parsedCU = ParseDocument(editor, out commentsBlankLines);
if (parsedCU == null) return null;
var selectionStart = editor.Document.OffsetToPosition(editor.SelectionStart); var selectionStart = editor.Document.OffsetToPosition(editor.SelectionStart);
var selectionEnd = editor.Document.OffsetToPosition(editor.SelectionStart + editor.SelectionLength); var selectionEnd = editor.Document.OffsetToPosition(editor.SelectionStart + editor.SelectionLength);
@ -120,7 +117,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
currentNode = GetInterestingParent(currentNode, interestingNodeTypes); currentNode = GetInterestingParent(currentNode, interestingNodeTypes);
} }
if (currentNode == null) return null; if (currentNode == null) return null;
var selectedResultNode = currentNode; selectedResultNode = currentNode;
// whole node already selected -> expand selection // whole node already selected -> expand selection
if (currentNode.StartLocation == selectionStart && currentNode.EndLocation == selectionEnd) { if (currentNode.StartLocation == selectionStart && currentNode.EndLocation == selectionEnd) {
@ -139,8 +136,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
while (parent != null && parent.StartLocation == selectionStart && parent.EndLocation == selectionEnd) { while (parent != null && parent.StartLocation == selectionStart && parent.EndLocation == selectionEnd) {
parent = GetInterestingParent(parent, interestingNodeTypes); parent = GetInterestingParent(parent, interestingNodeTypes);
} }
if (parent == null) if (parent == null) {
return currentNode; return new Selection { Start = selectionStart, End = selectionEnd };
}
// Select the parent // Select the parent
var extendedSelectionStart = parent.StartLocation; var extendedSelectionStart = parent.StartLocation;
var extendedLocationEnd = parent.EndLocation; var extendedLocationEnd = parent.EndLocation;
@ -163,15 +161,14 @@ namespace ICSharpCode.AvalonEdit.AddIn
selectionEnd = currentNode.EndLocation; selectionEnd = currentNode.EndLocation;
selectedResultNode = currentNode; selectedResultNode = currentNode;
} }
int startOffset, endOffset; return new Selection { Start = selectionStart, End = selectionEnd };
try {
startOffset = editor.Document.PositionToOffset(selectionStart);
endOffset = editor.Document.PositionToOffset(selectionEnd);
} catch(ArgumentOutOfRangeException) {
return null;
} }
editor.Select(startOffset, endOffset - startOffset);
return selectedResultNode; 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> /// <summary>
@ -251,5 +248,43 @@ namespace ICSharpCode.AvalonEdit.AddIn
parsedSpecials = parser.Lexer.SpecialTracker.CurrentSpecials; parsedSpecials = parser.Lexer.SpecialTracker.CurrentSpecials;
return parsedCU; 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