|
|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|