From 95109a4af2c6aa0a50fdb8ebe5d0727c7e76cf23 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Thu, 6 Jun 2013 01:00:24 +0200 Subject: [PATCH] CodeManipulation (Alt+Arrow code moving, Ctrl+W selection extension) now works again. --- .../Project/CSharpBinding.csproj | 2 +- .../Project/Src/CodeManipulation.cs | 124 ++++++++---------- 2 files changed, 55 insertions(+), 71 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index cd4338d5e3..64906ad045 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -67,6 +67,7 @@ + @@ -104,7 +105,6 @@ Code - diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CodeManipulation.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CodeManipulation.cs index 40ed4fcd26..64912fa231 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CodeManipulation.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CodeManipulation.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -/* + using System.Windows.Input; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Editing; @@ -13,11 +13,8 @@ using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.PatternMatching; -//using ICSharpCode.NRefactory.Ast; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Editor; -using ICSharpCode.SharpDevelop.Refactoring; -//using Ast = ICSharpCode.NRefactory.Ast; namespace CSharpBinding { @@ -139,46 +136,43 @@ namespace CSharpBinding // move selection - find outermost node in selection, swap selection with closest child of its parent to the selection void MoveStatement(ITextEditor editor, MoveStatementDirection direction) { - IList commentsBlankLines; + 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; + AstNode currentStatement; Selection statementSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out currentStatement, new Type[] { typeof(Statement), - typeof(MemberNode), - typeof(FieldDeclaration), - typeof(ConstructorDeclaration), - typeof(DestructorDeclaration) }); + typeof(EntityDeclaration) }); if (currentStatement == null) return; statementSelection = TryExtendSelectionToComments(editor.Document, statementSelection, commentsBlankLines); // Take its sibling if (currentStatement.Parent == null) return; - var siblings = currentStatement.Parent.Children; + var siblings = currentStatement.Parent.Children.Where(c => (c.Role.GetType() == currentStatement.Role.GetType())).ToList(); int currentStatementPos = siblings.IndexOf(currentStatement); int swapIndex = currentStatementPos + (direction == MoveStatementDirection.Down ? 1 : -1); if (swapIndex < 0 || swapIndex >= siblings.Count) return; - INode swapSibling = siblings[swapIndex]; + AstNode swapSibling = siblings[swapIndex]; // Swap them 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 TextLocation upperLocation = new TextLocation[] {statementSelection.Start, swapSibling.StartLocation}.Min(); if (direction == MoveStatementDirection.Up) - editor.Caret.Position = upperLocation; + editor.Caret.Location = upperLocation; else { // look where current statement ended up because it is hard to calculate it correctly - int currentMovedOffset = editor.Document.Text.IndexOf(currentNodeText, editor.Document.PositionToOffset(upperLocation)); + int currentMovedOffset = editor.Document.Text.IndexOf(currentNodeText, editor.Document.GetOffset(upperLocation)); editor.Caret.Offset = currentMovedOffset; } } - Selection TryExtendSelectionToComments(IDocument document, Selection selection, IList commentsBlankLines) + Selection TryExtendSelectionToComments(IDocument document, Selection selection, IList commentsBlankLines) { var extendedToComments = ExtendSelectionToComments(document, selection, commentsBlankLines); if (extendedToComments != null) @@ -188,13 +182,13 @@ namespace CSharpBinding public void ExtendSelection() { - INode selectedNode = null; - IList commentsBlankLines; + AstNode selectedNode = null; + IList commentsBlankLines; var parsedCU = ParseDocument(editor, out commentsBlankLines); if (parsedCU == null) return; ISegment oldSelection = new TextSegment { StartOffset = editor.SelectionStart, Length = editor.SelectionLength }; - Selection extendedSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out selectedNode, new Type[] { typeof(INode) }); // any node type + Selection extendedSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out selectedNode, new Type[] { typeof(AstNode) }); // any node type SelectText(extendedSelection, editor); @@ -203,7 +197,7 @@ namespace CSharpBinding LoggingService.Debug("pushed: " + oldSelection); } else { LoggingService.Debug("not accepted: " + oldSelection); - } + } } public void ShrinkSelection() @@ -216,14 +210,14 @@ namespace CSharpBinding } // could work to extend selection to set of adjacent statements separated by blank lines - Selection ExtendSelection(ITextEditor editor, SyntaxTree parsedCU, IList commentsBlankLines, out INode selectedResultNode, Type[] interestingNodeTypes) + Selection ExtendSelection(ITextEditor editor, SyntaxTree parsedCU, IList commentsBlankLines, out AstNode selectedResultNode, Type[] interestingNodeTypes) { selectedResultNode = null; - var selectionStart = editor.Document.OffsetToPosition(editor.SelectionStart); - var selectionEnd = editor.Document.OffsetToPosition(editor.SelectionStart + editor.SelectionLength); + var selectionStart = editor.Document.GetLocation(editor.SelectionStart); + var selectionEnd = editor.Document.GetLocation(editor.SelectionStart + editor.SelectionLength); - Ast.INode currentNode = parsedCU.Children.Select(n => EditorContext.FindInnermostNodeContainingSelection(n, selectionStart, selectionEnd)).FirstOrDefault(n => n != null); + AstNode currentNode = parsedCU.GetNodeContaining(selectionStart, selectionEnd); if (currentNode == null) return null; if (!IsNodeTypeInteresting(currentNode, interestingNodeTypes)) { // ignore uninteresting nodes in the AST @@ -263,7 +257,7 @@ namespace CSharpBinding // if the extended selection would contain blank lines, extend the selection only to the blank lines/comments on both sides (use siblings) // if the selection contains blank lines or comments on both sides, dont do this - var blankLines = commentsBlankLines.Where(s => s is BlankLine).Cast().ToList(); + // var blankLines = commentsBlankLines.Where(s => s is BlankLine).Cast().ToList(); //if (SelectionContainsBlankLines(extendedSelectionStart, extendedLocationEnd, blankLines)) { if (false) { // blank line separators - implement later @@ -281,7 +275,7 @@ namespace CSharpBinding return new Selection { Start = selectionStart, End = selectionEnd }; } - Selection ExtendSelectionToComments(IDocument document, Selection selection, IList commentsBlankLines) + Selection ExtendSelectionToComments(IDocument document, Selection selection, IList commentsBlankLines) { if (selection == null) throw new ArgumentNullException("selection"); @@ -291,7 +285,7 @@ namespace CSharpBinding /// /// If there is a comment block immediately before selection, or behind selection on the same line, add it to selection. /// - Selection ExtendSelectionToComments(IDocument document, Location selectionStart, Location selectionEnd, IList commentsBlankLines) + Selection ExtendSelectionToComments(IDocument document, TextLocation selectionStart, TextLocation selectionEnd, IList commentsBlankLines) { var comments = commentsBlankLines.Where(s => s is Comment).Cast(); // add "var i = 5; // comments" comments @@ -307,38 +301,37 @@ namespace CSharpBinding /// /// If there is a comment block behind selection on the same line ("var i = 5; // comment"), add it to selection. /// - Selection ExtendSelectionToEndOfLineComments(IDocument document, Location selectionStart, Location selectionEnd, IEnumerable commentsBlankLines) + Selection ExtendSelectionToEndOfLineComments(IDocument document, TextLocation selectionStart, TextLocation selectionEnd, IEnumerable commentsBlankLines) { - var lineComment = commentsBlankLines.FirstOrDefault(c => c.StartPosition.Line == selectionEnd.Line && c.StartPosition >= selectionEnd); + var lineComment = commentsBlankLines.FirstOrDefault(c => c.StartLocation.Line == selectionEnd.Line && c.StartLocation >= selectionEnd); if (lineComment == null) { return null; } - bool isWholeLineSelected = IsWhitespaceBetween(document, new Location(1, selectionStart.Line), selectionStart); + bool isWholeLineSelected = IsWhitespaceBetween(document, new TextLocation(selectionStart.Line, 1), selectionStart); if (!isWholeLineSelected) { // whole line must be selected before we add the comment return null; } - // fix the end of comment set to next line incorrectly by the parser - int fixEndPos = document.PositionToOffset(lineComment.EndPosition) - 1; - return new Selection { Start = selectionStart, End = document.OffsetToPosition(fixEndPos) }; + int endPos = document.GetOffset(lineComment.EndLocation); + return new Selection { Start = selectionStart, End = document.GetLocation(endPos) }; } /// /// If there is a comment block immediately before selection, add it to selection. /// - Selection ExtendSelectionToSeparateComments(IDocument document, Location selectionStart, Location selectionEnd, IEnumerable commentsBlankLines) + Selection ExtendSelectionToSeparateComments(IDocument document, TextLocation selectionStart, TextLocation selectionEnd, IEnumerable commentsBlankLines) { - var comments = commentsBlankLines.Where(c => c.CommentStartsLine).ToList(); - int commentIndex = comments.FindIndex(c => c.EndPosition <= selectionStart && IsWhitespaceBetween(document, c.EndPosition, selectionStart)); + var comments = commentsBlankLines.Where(c => (c is Comment) && ((Comment) c).StartsLine).ToList(); + int commentIndex = comments.FindIndex(c => c.EndLocation <= selectionStart && IsWhitespaceBetween(document, c.EndLocation, selectionStart)); if (commentIndex < 0) { return null; } var extendedSelection = new Selection { Start = selectionStart, End = selectionEnd }; // start at the selection and keep adding comments upwards as long as they are separated only by whitespace - while (commentIndex >= 0 && IsWhitespaceBetween(document, comments[commentIndex].EndPosition, extendedSelection.Start)) { + while (commentIndex >= 0 && IsWhitespaceBetween(document, comments[commentIndex].EndLocation, extendedSelection.Start)) { var comment = comments[commentIndex]; // Include the "//, /*, ///" since they are not included by the parser - extendedSelection.Start = ExtendLeft(comment.StartPosition, document, "///", "/*", "//") ; + extendedSelection.Start = ExtendLeft(comment.StartLocation, document, "///", "/*", "//") ; commentIndex--; } return extendedSelection; @@ -347,7 +340,7 @@ namespace CSharpBinding /// /// Searches for parent of interesting type. Skips uninteresting parents. /// - INode GetInterestingParent(INode node, Type[] interestingNodeTypes) + AstNode GetInterestingParent(AstNode node, Type[] interestingNodeTypes) { var parent = node.Parent; while(parent != null) { @@ -364,15 +357,15 @@ namespace CSharpBinding return interestingNodeTypes.Any(interestingType => interestingType.IsAssignableFrom(nodeType) || (nodeType == interestingType)); } - bool SelectionContainsBlankLines(Location selectionStart, Location selectionEnd, List blankLines) + bool SelectionContainsBlankLines(TextLocation selectionStart, TextLocation selectionEnd, List blankLines) { - return blankLines.Exists(b => b.StartPosition >= selectionStart && b.EndPosition <= selectionEnd); + return blankLines.Exists(b => b.StartLocation >= selectionStart && b.EndLocation <= selectionEnd); } - bool IsWhitespaceBetween(IDocument document, Location startPos, Location endPos) + bool IsWhitespaceBetween(IDocument document, TextLocation startPos, TextLocation endPos) { - int startOffset = document.PositionToOffset(startPos); - int endOffset = document.PositionToOffset(endPos); + int startOffset = document.GetOffset(startPos); + int endOffset = document.GetOffset(endPos); if (startOffset > endOffset) { throw new ArgumentException("Invalid range for (startPos, endPos)"); } @@ -383,14 +376,14 @@ namespace CSharpBinding /// If the text at startPos is preceded by any of the prefixes, moves the start backwards to include one prefix /// (the rightmost one). /// - Location ExtendLeft(Location startPos, IDocument document, params String[] prefixes) + TextLocation ExtendLeft(TextLocation startPos, IDocument document, params String[] prefixes) { - int startOffset = document.PositionToOffset(startPos); + int startOffset = document.GetOffset(startPos); foreach (string prefix in prefixes) { if (startOffset < prefix.Length) continue; string realPrefix = document.GetText(startOffset - prefix.Length, prefix.Length); if (realPrefix == prefix) { - return document.OffsetToPosition(startOffset - prefix.Length); + return document.GetLocation(startOffset - prefix.Length); } } // no prefixes -> do not extend @@ -398,42 +391,34 @@ namespace CSharpBinding } // could depend just on IDocument - SyntaxTree ParseDocument(ITextEditor editor, out IList parsedSpecials) + SyntaxTree ParseDocument(ITextEditor editor, out IList parsedSpecials) { parsedSpecials = null; - var editorLang = EditorContext.GetEditorLanguage(editor); - if (editorLang == null) return null; - var parser = ParserFactory.CreateParser(editorLang.Value, editor.Document.CreateReader()); + CompilerSettings compilerSettings = new CompilerSettings(); + var parser = new CSharpParser(); if (parser == null) return null; - parser.ParseMethodBodies = true; - parser.Lexer.SkipAllComments = false; - parser.Parse(); - var parsedCU = parser.SyntaxTree; - if (parsedCU == null) return null; - foreach (var node in parsedCU.Children) { - // fix StartLocation / EndLocation - node.AcceptVisitor(new ICSharpCode.NRefactory.Visitors.SetRegionInclusionVisitor(), null); - } - parsedSpecials = parser.Lexer.SpecialTracker.CurrentSpecials; - return parsedCU; + var syntaxTree = parser.Parse(editor.Document.CreateReader()); + if (syntaxTree == null) return null; + parsedSpecials = new List(syntaxTree.Descendants.OfType()); + return syntaxTree; } /// /// Swaps 2 ranges of text in a document. /// - void SwapText(IDocument document, Location start1, Location end1, Location start2, Location end2) + void SwapText(IDocument document, TextLocation start1, TextLocation end1, TextLocation start2, TextLocation end2) { if (start1 > start2) { - Location sw; + TextLocation 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; + int offset1 = document.GetOffset(start1); + int len1 = document.GetOffset(end1) - offset1; + int offset2 = document.GetOffset(start2); + int len2 = document.GetOffset(end2) - offset2; string text1 = document.GetText(offset1, len1); string text2 = document.GetText(offset2, len2); @@ -450,8 +435,8 @@ namespace CSharpBinding return; int startOffset, endOffset; try { - startOffset = editor.Document.PositionToOffset(selection.Start); - endOffset = editor.Document.PositionToOffset(selection.End); + startOffset = editor.Document.GetOffset(selection.Start); + endOffset = editor.Document.GetOffset(selection.End); } catch (ArgumentOutOfRangeException) { return; } @@ -459,4 +444,3 @@ namespace CSharpBinding } } } -*/ \ No newline at end of file