From 1681740ef479e0fc8455516c71c1fbb608bb809c Mon Sep 17 00:00:00 2001 From: mkonicek Date: Fri, 10 Dec 2010 00:26:36 +0100 Subject: [PATCH] Move statement up/down - basic version with comments. --- .../AvalonEdit.AddIn/Src/CodeManipulation.cs | 127 +++++++++++------- 1 file changed, 81 insertions(+), 46 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs index eca0dc0442..a6bed52ca0 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeManipulation.cs @@ -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 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 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 } } - static void SwapText(IDocument document, Location start1, Location end1, Location start2, Location end2) + static Selection TryExtendSelectionToComments(IDocument document, Selection selection, IList 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 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 commentsBlankLines, out INode selectedResultNode, Type[] interestingNodeTypes) { - IList 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 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 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 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 commentsBlankLines) + { + if (selection == null) + throw new ArgumentNullException("selection"); + return ExtendSelectionToComments(document, selection.Start, selection.End, commentsBlankLines); } /// @@ -251,5 +248,43 @@ namespace ICSharpCode.AvalonEdit.AddIn parsedSpecials = parser.Lexer.SpecialTracker.CurrentSpecials; return parsedCU; } + + /// + /// Swaps 2 ranges of text in a document. + /// + 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); + } } }