Пример #1
0
        // 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 <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;
            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;
            }
            var siblings            = currentStatement.Parent.Children;
            int currentStatementPos = siblings.IndexOf(currentStatement);
            int swapIndex           = currentStatementPos + (direction == MoveStatementDirection.Down ? 1 : -1);

            if (swapIndex < 0 || swapIndex >= siblings.Count)
            {
                return;
            }
            INode 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
            Location upperLocation = new Location[] { statementSelection.Start, swapSibling.StartLocation }.Min();

            if (direction == MoveStatementDirection.Up)
            {
                editor.Caret.Position = 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));
                editor.Caret.Offset = currentMovedOffset;
            }
        }
Пример #2
0
        BlockStatement GetInnerBlockOfControlNode(AstNode node, MoveStatementDirection direction)
        {
            if (node is IfElseStatement)
            {
                if (direction == MoveStatementDirection.Up)
                {
                    var ifStatement = (IfElseStatement)node;
                    if (ifStatement.FalseStatement.IsNull)
                    {
                        return(ifStatement.TrueStatement as BlockStatement);
                    }
                    return(ifStatement.FalseStatement as BlockStatement);
                }
                else
                {
                    return(((IfElseStatement)node).TrueStatement as BlockStatement);
                }
            }
            if (node is ForStatement)
            {
                return(((ForStatement)node).EmbeddedStatement as BlockStatement);
            }
            if (node is ForeachStatement)
            {
                return(((ForeachStatement)node).EmbeddedStatement as BlockStatement);
            }
            if (node is WhileStatement)
            {
                return(((WhileStatement)node).EmbeddedStatement as BlockStatement);
            }
            if (node is DoWhileStatement)
            {
                return(((DoWhileStatement)node).EmbeddedStatement as BlockStatement);
            }
            if (node is UsingStatement)
            {
                return(((UsingStatement)node).EmbeddedStatement as BlockStatement);
            }

            return(null);
        }
Пример #3
0
		// 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;
			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;
			var siblings = currentStatement.Parent.Children;
			int currentStatementPos = siblings.IndexOf(currentStatement);
			int swapIndex = currentStatementPos + (direction == MoveStatementDirection.Down ? 1 : -1);
			if (swapIndex < 0 || swapIndex >= siblings.Count)
				return;
			INode 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
			Location upperLocation = new Location[] {statementSelection.Start, swapSibling.StartLocation}.Min();
			if (direction == MoveStatementDirection.Up)
				editor.Caret.Position = upperLocation;
			else {
				// look where current statement ended because it is hard to calculate it correctly
				int currentMovedOffset = editor.Document.Text.IndexOf(currentNodeText, editor.Document.PositionToOffset(upperLocation));
				editor.Caret.Offset = currentMovedOffset;
			}
		}
Пример #4
0
        void MoveStatement(ITextEditor editor, MoveStatementDirection direction)
        {
            IList <AstNode> commentsBlankLines;
            var             parsedCU = ParseDocument(editor, out commentsBlankLines);

            if (parsedCU == null)
            {
                return;
            }

            var selectionStart = editor.Document.GetLocation(editor.SelectionStart);
            var selectionEnd   = editor.Document.GetLocation(editor.SelectionStart + editor.SelectionLength);

            AstNode currentStatement = parsedCU.GetNodeContaining(selectionStart, selectionEnd);

            if (currentStatement == null)
            {
                return;
            }
            var interestingNodeTypes = new[] {
                typeof(Statement), typeof(EntityDeclaration), typeof(UsingDeclaration),
                typeof(NewLineNode), typeof(Comment), typeof(PreProcessorDirective)
            };

            if (!IsNodeTypeInteresting(currentStatement, interestingNodeTypes))
            {
                // Ignore non-interesting nodes in the AST
                currentStatement = GetInterestingParent(currentStatement, interestingNodeTypes);
            }
            if (currentStatement == null)
            {
                return;
            }

            List <AstNode> currentStatementSiblings = null;

            if ((currentStatement is BlockStatement) &&
                ((currentStatement.Parent is Statement) || (currentStatement.Parent is EntityDeclaration)) &&
                !(currentStatement.Parent is BlockStatement))
            {
                // Extend current statement to owner of this block statement
                currentStatement = currentStatement.Parent;
            }

            if ((currentStatement is Comment) && ((Comment)currentStatement).IsDocumentation &&
                (currentStatement.Parent is EntityDeclaration))
            {
                // Documentation comments belong to their method declaration
                currentStatement = currentStatement.Parent;
            }

            currentStatementSiblings = currentStatement.Parent.Children.Where(
                c => IsNodeTypeInteresting(c, interestingNodeTypes) && !(c is NewLineNode)
                ).ToList();

            // Collect all statements intersecting with selection lines
            Func <AstNode, bool> selectionExpansionPredicate = node =>
                                                               ((node.EndLocation.Line >= selectionStart.Line) && (node.StartLocation.Line <= selectionEnd.Line));
            var selectedStatements = currentStatementSiblings.Where(selectionExpansionPredicate);

            if (!selectedStatements.Any())
            {
                return;
            }

            // Find out which nodes we have to swap selected statements with
            AstNode swapSibling = null;

            if (direction == MoveStatementDirection.Up)
            {
                int indexOfFirstSelectedSibling = currentStatementSiblings.IndexOf(selectedStatements.First());
                swapSibling = (indexOfFirstSelectedSibling > 0) ? currentStatementSiblings[indexOfFirstSelectedSibling - 1] : null;
            }
            else
            {
                int indexOfLastSelectedSibling = currentStatementSiblings.IndexOf(selectedStatements.Last());
                swapSibling = (indexOfLastSelectedSibling < currentStatementSiblings.Count - 1) ? currentStatementSiblings[indexOfLastSelectedSibling + 1] : null;
            }

            IEnumerable <AstNode> swapSiblings = null;

            if (swapSibling != null)
            {
                Func <AstNode, bool> swapExpansionPredicate = node =>
                                                              ((node.EndLocation.Line >= swapSibling.StartLocation.Line) && (node.StartLocation.Line <= swapSibling.EndLocation.Line));
                swapSiblings = currentStatementSiblings.Where(swapExpansionPredicate);
            }

            if (!selectedStatements.Any(node => node is PreProcessorDirective))
            {
                // Handling moving into neighbour block statements or moving the line out of them
                if (direction == MoveStatementDirection.Up)
                {
                    if (swapSibling != null)
                    {
                        var lastSwapSibling     = swapSiblings.Last();
                        var innerBlockStatement = GetInnerBlockOfControlNode(lastSwapSibling, direction);
                        if (innerBlockStatement != null)
                        {
                            // Swap with end brace
                            swapSiblings = new[] {
                                (AstNode)innerBlockStatement.RBraceToken, lastSwapSibling.Children.Last()
                            };
                        }
                    }
                    else
                    {
                        // Check if we are inside of a block statement where we can move the lines out from
                        var firstSelectedStatement = selectedStatements.First();
                        if ((firstSelectedStatement.Parent is BlockStatement) &&
                            NodeSupportsBlockMovement(firstSelectedStatement.Parent.Parent))
                        {
                            // Our swap sibling is the starting brace of block statement and head of parent statement
                            swapSiblings = new[] {
                                firstSelectedStatement.Parent.Parent.Children.First(),
                                ((BlockStatement)firstSelectedStatement.Parent).LBraceToken
                            };
                        }
                    }
                }
                else
                {
                    if (swapSibling != null)
                    {
                        var firstSwapSibling    = swapSiblings.First();
                        var innerBlockStatement = GetInnerBlockOfControlNode(firstSwapSibling, direction);
                        if (innerBlockStatement != null)
                        {
                            // Swap with start brace of block statement
                            swapSiblings = new[] { firstSwapSibling.Children.First(), innerBlockStatement.LBraceToken };
                        }
                    }
                    else
                    {
                        // Check if we are inside of a block statement where we can move the lines out from
                        var lastSelectedStatement = selectedStatements.Last();
                        if ((lastSelectedStatement.Parent is BlockStatement) &&
                            NodeSupportsBlockMovement(lastSelectedStatement.Parent.Parent))
                        {
                            // Our swap sibling is the ending brace of block statement (and foot statement, like with do...while loops)
                            swapSiblings = new[] {
                                ((BlockStatement)lastSelectedStatement.Parent).RBraceToken,
                                lastSelectedStatement.Parent.Parent.Children.Last()
                            };
                        }
                    }
                }
            }

            if (swapSiblings == null)
            {
                return;
            }

            // Swap lines of current and neighbour statements
            TextLocation movedTextStart   = selectedStatements.First().StartLocation;
            TextLocation movedTextEnd     = selectedStatements.Last().EndLocation;
            TextLocation swappedTextStart = swapSiblings.First().StartLocation;
            TextLocation swappedTextEnd   = swapSiblings.Last().EndLocation;

            string currentNodeText = editor.Document.GetText(movedTextStart, movedTextEnd);
            string swappedNodeText = editor.Document.GetText(swappedTextStart, swappedTextEnd);

            SwapText(editor.Document, movedTextStart, movedTextEnd, swappedTextStart, swappedTextEnd);

            // Select moved text
//			editor.Select(editor.Document.GetOffset(swappedTextStart.Line, swappedTextStart.Column), 5);//currentNodeText.Length);
//			SelectText(new Selection {
//			            Start = new TextLocation(swappedTextStart.Line, 0),
//			            End = new TextLocation(swappedTextStart.Line + (movedTextEnd.Line - movedTextStart.Line), 200) },
//			           editor);

//			currentStatement = parsedCU.GetNodeContaining(selectionStart, selectionEnd);

            // Move caret to the start of moved statement
            TextLocation upperLocation = new TextLocation[] { movedTextStart, swappedTextStart }.Min();
            int          currentMovedOffset = editor.Document.Text.IndexOf(currentNodeText, editor.Document.GetOffset(upperLocation));
            int          swappedMovedOffset = editor.Document.Text.IndexOf(swappedNodeText, editor.Document.GetOffset(upperLocation));

            if (direction == MoveStatementDirection.Up)
            {
                editor.Caret.Location = upperLocation;
            }
            else
            {
                // look where current statement ended up because it is hard to calculate it correctly
                editor.Caret.Offset = currentMovedOffset;
            }

            // Correct indentation
            editor.Language.FormattingStrategy.IndentLines(
                editor,
                editor.Document.GetLineForOffset(currentMovedOffset).LineNumber,
                editor.Document.GetLineForOffset(currentMovedOffset + currentNodeText.Length).LineNumber);
            editor.Language.FormattingStrategy.IndentLines(
                editor,
                editor.Document.GetLineForOffset(swappedMovedOffset).LineNumber,
                editor.Document.GetLineForOffset(swappedMovedOffset + swappedNodeText.Length).LineNumber);
        }
Пример #5
0
		// 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<AstNode> commentsBlankLines;
			var parsedCU = ParseDocument(editor, out commentsBlankLines);
			if (parsedCU == null)	return;
			
			// Find the Statement or Definition containing caret -> Extend selection to Statement or Definition
			
			AstNode currentStatement;
			Selection statementSelection = ExtendSelection(editor, parsedCU, commentsBlankLines, out currentStatement, new Type[] {
			                                               	typeof(Statement),
			                                               	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.Where(c => (c.Role.GetType() == currentStatement.Role.GetType())).ToList();
			int currentStatementStartPos = siblings.IndexOf(currentStatement);
			int currentStatementEndPos = currentStatementStartPos;
			
			AstNode swapStartSibling = null;
			AstNode swapEndSibling = null;
			
			// Expand selection to full line, if there is more than one statement in it
			AstNode currentSelectionStartNode = currentStatement;
			while ((currentSelectionStartNode.PrevSibling != null)
			       && !(currentSelectionStartNode.PrevSibling is NewLineNode)
			       && (currentSelectionStartNode.Parent == currentSelectionStartNode.PrevSibling.Parent)) {
				currentSelectionStartNode = currentSelectionStartNode.PrevSibling;
				if (currentSelectionStartNode.EndLocation.Line >= statementSelection.Start.Line) {
					statementSelection.Start = currentSelectionStartNode.StartLocation;
					if (!(currentSelectionStartNode is Comment))
						currentStatementStartPos--;
				} else {
					// This node won't belong to current selection, so go back to next element
					currentSelectionStartNode = currentSelectionStartNode.NextSibling;
					break;
				}
			}
			AstNode currentSelectionEndNode = currentStatement;
			while ((currentSelectionEndNode.NextSibling != null)
			       && !(currentSelectionEndNode.NextSibling is NewLineNode)
			       && (currentSelectionEndNode.Parent == currentSelectionEndNode.NextSibling.Parent)) {
				currentSelectionEndNode = currentSelectionEndNode.NextSibling;
				if (currentSelectionEndNode.StartLocation.Line <= statementSelection.End.Line) {
					statementSelection.End = currentSelectionEndNode.EndLocation;
					if (!(currentSelectionEndNode is Comment))
						currentStatementEndPos++;
				} else {
					// This node won't belong to current selection, so go back to next element
					currentSelectionEndNode = currentSelectionEndNode.NextSibling;
					break;
				}
			}
			
			int swapIndex = 0;
			if (direction == MoveStatementDirection.Down) {
				swapIndex = currentStatementEndPos + 1;
			} else {
				swapIndex = currentStatementStartPos - 1;
			}
			Func<AstNode, bool> isAllowedGrandParentNode =
				(n => (n is IfElseStatement) || (n is ForStatement) || (n is ForeachStatement) || (n is WhileStatement) || (n is DoWhileStatement));
			if (swapIndex < 0) {
				// This is the 1st statement in block, so swap it with beginning of the block to get it outside of it
				var parentNode = currentStatement.Parent as BlockStatement;
				if (parentNode != null) {
					var grandParentNode = parentNode.Parent;
					if ((grandParentNode != null) && isAllowedGrandParentNode(grandParentNode)) {
						// Swap with head of grandparent statement
						swapStartSibling = grandParentNode;
						swapEndSibling = ((BlockStatement) parentNode).LBraceToken;
					}
				}
			} else if (swapIndex >= siblings.Count) {
				// This is the last statement in block, so swap it with block end to get the statement outside of it
				var parentNode = currentStatement.Parent as BlockStatement;
				if (parentNode != null) {
					var grandParentNode = parentNode.Parent;
					if ((grandParentNode != null) && isAllowedGrandParentNode(grandParentNode)) {
						// Swap with rest of grandparent control statement
						swapStartSibling = ((BlockStatement) parentNode).RBraceToken;
						swapEndSibling = grandParentNode;
					}
				}
			} else {
				// In the middle of current block
				swapStartSibling = siblings[swapIndex];
				swapEndSibling = swapStartSibling;
				
				// Special handling for swap nodes containing blocks: Move current statement into it
				if (swapStartSibling is IfElseStatement) {
					var ifElseStatement = swapStartSibling as IfElseStatement;
					if (direction == MoveStatementDirection.Up) {
						BlockStatement swappedIfElseBlock = ifElseStatement.FalseStatement as BlockStatement;
						if (swappedIfElseBlock == null)
							swappedIfElseBlock = ifElseStatement.TrueStatement as BlockStatement;
						if (swappedIfElseBlock != null) {
							swapStartSibling = swappedIfElseBlock.RBraceToken;
						}
					} else {
						BlockStatement swappedIfElseBlock = ifElseStatement.TrueStatement as BlockStatement;
						if (swappedIfElseBlock == null)
							swappedIfElseBlock = ifElseStatement.TrueStatement as BlockStatement;
						if (swappedIfElseBlock != null) {
							swapEndSibling = swappedIfElseBlock.LBraceToken;
						}
					}
				} else {
					BlockStatement innerBlockStatement = GetInnerBlockOfControlNode(swapStartSibling);
					if (innerBlockStatement != null) {
						if (direction == MoveStatementDirection.Up) {
							swapStartSibling = innerBlockStatement.RBraceToken;
						} else {
							swapEndSibling = innerBlockStatement.LBraceToken;
						}
					}
				}
			}

			if ((swapStartSibling == null) || (swapEndSibling == null))
				return;
			
			Selection swapSiblingSelection = ExtendSelectionToComments(editor.Document, swapStartSibling.StartLocation, swapEndSibling.EndLocation, commentsBlankLines);
			if (swapSiblingSelection == null)
				swapSiblingSelection = new Selection() { Start = swapStartSibling.StartLocation, End = swapEndSibling.EndLocation };
			
			// Expand swapSiblingSelection, too, if there are > 1 statements in line
			if (direction == MoveStatementDirection.Up) {
				AstNode tempNode = swapStartSibling;
				while ((tempNode.PrevSibling != null) && !(tempNode.PrevSibling is NewLineNode)) {
					tempNode = tempNode.PrevSibling;
					if (tempNode.EndLocation.Line >= swapSiblingSelection.Start.Line) {
						swapSiblingSelection.Start = tempNode.StartLocation;
					} else {
						break;
					}
				}
			} else {
				AstNode tempNode = swapEndSibling;
				while ((tempNode.NextSibling != null) && !(tempNode.NextSibling is NewLineNode)) {
					tempNode = tempNode.NextSibling;
					if (tempNode.StartLocation.Line <= swapSiblingSelection.End.Line) {
						swapSiblingSelection.End = tempNode.EndLocation;
					} else {
						break;
					}
				}
			}
			
			// Preserve the indentation of moved statement
			if (statementSelection.Start.Column > swapSiblingSelection.Start.Column) {
				statementSelection = new Selection {
					Start = new TextLocation(statementSelection.Start.Line, swapSiblingSelection.Start.Column),
					End = statementSelection.End
				};
			} else if (statementSelection.Start.Column < swapSiblingSelection.Start.Column) {
				swapSiblingSelection = new Selection {
					Start = new TextLocation(swapSiblingSelection.Start.Line, statementSelection.Start.Column),
					End = swapSiblingSelection.End
				};
			}
			
			// Swap them
			string currentNodeText = editor.Document.GetText(statementSelection.Start, statementSelection.End);
			SwapText(editor.Document, statementSelection.Start, statementSelection.End, swapSiblingSelection.Start, swapSiblingSelection.End);
			// Move caret to the start of moved statement
			TextLocation upperLocation = new TextLocation[] {statementSelection.Start, swapSiblingSelection.Start}.Min();
			if (direction == MoveStatementDirection.Up)
				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.GetOffset(upperLocation));
				editor.Caret.Offset = currentMovedOffset;
			}
		}
Пример #6
0
		BlockStatement GetInnerBlockOfControlNode(AstNode node, MoveStatementDirection direction)
		{
			if (node is IfElseStatement) {
				if (direction == MoveStatementDirection.Up) {
					var ifStatement = (IfElseStatement) node;
					if (ifStatement.FalseStatement.IsNull)
						return ifStatement.TrueStatement as BlockStatement;
					return ifStatement.FalseStatement as BlockStatement;
				} else {
					return ((IfElseStatement) node).TrueStatement as BlockStatement;
				}
			}
			if (node is ForStatement) {
				return ((ForStatement) node).EmbeddedStatement as BlockStatement;
			}
			if (node is ForeachStatement) {
				return ((ForeachStatement) node).EmbeddedStatement as BlockStatement;
			}
			if (node is WhileStatement) {
				return ((WhileStatement) node).EmbeddedStatement as BlockStatement;
			}
			if (node is DoWhileStatement) {
				return ((DoWhileStatement) node).EmbeddedStatement as BlockStatement;
			}
			if (node is UsingStatement) {
				return ((UsingStatement) node).EmbeddedStatement as BlockStatement;
			}
			
			return null;
		}
Пример #7
0
		void MoveStatement(ITextEditor editor, MoveStatementDirection direction)
		{
			IList<AstNode> commentsBlankLines;
			var parsedCU = ParseDocument(editor, out commentsBlankLines);
			if (parsedCU == null) return;
			
			var selectionStart = editor.Document.GetLocation(editor.SelectionStart);
			var selectionEnd = editor.Document.GetLocation(editor.SelectionStart + editor.SelectionLength);
			
			AstNode currentStatement = parsedCU.GetNodeContaining(selectionStart, selectionEnd);
			if (currentStatement == null)
				return;
			var interestingNodeTypes = new[] {
				typeof(Statement), typeof(EntityDeclaration), typeof(UsingDeclaration),
				typeof(NewLineNode), typeof(Comment), typeof(PreProcessorDirective)
			};
			if (!IsNodeTypeInteresting(currentStatement, interestingNodeTypes)) {
				// Ignore non-interesting nodes in the AST
				currentStatement = GetInterestingParent(currentStatement, interestingNodeTypes);
			}
			if (currentStatement == null)
				return;
			
			List<AstNode> currentStatementSiblings = null;
			if ((currentStatement is BlockStatement) &&
			    ((currentStatement.Parent is Statement) || (currentStatement.Parent is EntityDeclaration)) &&
			    !(currentStatement.Parent is BlockStatement)) {
				// Extend current statement to owner of this block statement
				currentStatement = currentStatement.Parent;
			}
			
			if ((currentStatement is Comment) && ((Comment) currentStatement).IsDocumentation &&
			    (currentStatement.Parent is EntityDeclaration)) {
				// Documentation comments belong to their method declaration
				currentStatement = currentStatement.Parent;
			}
			
			currentStatementSiblings = currentStatement.Parent.Children.Where(
				c => IsNodeTypeInteresting(c, interestingNodeTypes) && !(c is NewLineNode)
			).ToList();
			
			// Collect all statements intersecting with selection lines
			Func<AstNode, bool> selectionExpansionPredicate = node =>
				((node.EndLocation.Line >= selectionStart.Line) && (node.StartLocation.Line <= selectionEnd.Line));
			var selectedStatements = currentStatementSiblings.Where(selectionExpansionPredicate);
			if (!selectedStatements.Any())
				return;
			
			// Find out which nodes we have to swap selected statements with
			AstNode swapSibling = null;
			if (direction == MoveStatementDirection.Up) {
				int indexOfFirstSelectedSibling = currentStatementSiblings.IndexOf(selectedStatements.First());
				swapSibling = (indexOfFirstSelectedSibling > 0) ? currentStatementSiblings[indexOfFirstSelectedSibling - 1] : null;
			} else {
				int indexOfLastSelectedSibling = currentStatementSiblings.IndexOf(selectedStatements.Last());
				swapSibling = (indexOfLastSelectedSibling < currentStatementSiblings.Count - 1) ? currentStatementSiblings[indexOfLastSelectedSibling + 1] : null;
			}
			
			IEnumerable<AstNode> swapSiblings = null;
			if (swapSibling != null) {
				Func<AstNode, bool> swapExpansionPredicate = node =>
					((node.EndLocation.Line >= swapSibling.StartLocation.Line) && (node.StartLocation.Line <= swapSibling.EndLocation.Line));
				swapSiblings = currentStatementSiblings.Where(swapExpansionPredicate);
			}
			
			if (!selectedStatements.Any(node => node is PreProcessorDirective)) {
				// Handling moving into neighbour block statements or moving the line out of them
				if (direction == MoveStatementDirection.Up) {
					if (swapSibling != null) {
						var lastSwapSibling = swapSiblings.Last();
						var innerBlockStatement = GetInnerBlockOfControlNode(lastSwapSibling, direction);
						if (innerBlockStatement != null) {
							// Swap with end brace
							swapSiblings = new[] {
								(AstNode) innerBlockStatement.RBraceToken, lastSwapSibling.Children.Last()
							};
						}
					} else {
						// Check if we are inside of a block statement where we can move the lines out from
						var firstSelectedStatement = selectedStatements.First();
						if ((firstSelectedStatement.Parent is BlockStatement) &&
						    NodeSupportsBlockMovement(firstSelectedStatement.Parent.Parent)) {
							// Our swap sibling is the starting brace of block statement and head of parent statement
							swapSiblings = new[] {
								firstSelectedStatement.Parent.Parent.Children.First(),
								((BlockStatement) firstSelectedStatement.Parent).LBraceToken
							};
						}
					}
				} else {
					if (swapSibling != null) {
						var firstSwapSibling = swapSiblings.First();
						var innerBlockStatement = GetInnerBlockOfControlNode(firstSwapSibling, direction);
						if (innerBlockStatement != null) {
							// Swap with start brace of block statement
							swapSiblings = new[] { firstSwapSibling.Children.First(), innerBlockStatement.LBraceToken };
						}
					} else {
						// Check if we are inside of a block statement where we can move the lines out from
						var lastSelectedStatement = selectedStatements.Last();
						if ((lastSelectedStatement.Parent is BlockStatement) &&
						    NodeSupportsBlockMovement(lastSelectedStatement.Parent.Parent)) {
							// Our swap sibling is the ending brace of block statement (and foot statement, like with do...while loops)
							swapSiblings = new[] {
								((BlockStatement) lastSelectedStatement.Parent).RBraceToken,
								lastSelectedStatement.Parent.Parent.Children.Last()
							};
						}
					}
				}
			}
			
			if (swapSiblings == null)
				return;
			
			// Swap lines of current and neighbour statements
			TextLocation movedTextStart = selectedStatements.First().StartLocation;
			TextLocation movedTextEnd = selectedStatements.Last().EndLocation;
			TextLocation swappedTextStart = swapSiblings.First().StartLocation;
			TextLocation swappedTextEnd = swapSiblings.Last().EndLocation;
			
			string currentNodeText = editor.Document.GetText(movedTextStart, movedTextEnd);
			string swappedNodeText = editor.Document.GetText(swappedTextStart, swappedTextEnd);
			SwapText(editor.Document, movedTextStart, movedTextEnd, swappedTextStart, swappedTextEnd);
			
			// Select moved text
//			editor.Select(editor.Document.GetOffset(swappedTextStart.Line, swappedTextStart.Column), 5);//currentNodeText.Length);
//			SelectText(new Selection {
//			           	Start = new TextLocation(swappedTextStart.Line, 0),
//			           	End = new TextLocation(swappedTextStart.Line + (movedTextEnd.Line - movedTextStart.Line), 200) },
//			           editor);
			
//			currentStatement = parsedCU.GetNodeContaining(selectionStart, selectionEnd);
			
			// Move caret to the start of moved statement
			TextLocation upperLocation = new TextLocation[] { movedTextStart, swappedTextStart }.Min();
			int currentMovedOffset = editor.Document.Text.IndexOf(currentNodeText, editor.Document.GetOffset(upperLocation));
			int swappedMovedOffset = editor.Document.Text.IndexOf(swappedNodeText, editor.Document.GetOffset(upperLocation));
			if (direction == MoveStatementDirection.Up) {
				editor.Caret.Location = upperLocation;
			} else {
				// look where current statement ended up because it is hard to calculate it correctly
				editor.Caret.Offset = currentMovedOffset;
			}
			
			// Correct indentation
			editor.Language.FormattingStrategy.IndentLines(
				editor,
				editor.Document.GetLineForOffset(currentMovedOffset).LineNumber,
				editor.Document.GetLineForOffset(currentMovedOffset + currentNodeText.Length).LineNumber);
			editor.Language.FormattingStrategy.IndentLines(
				editor,
				editor.Document.GetLineForOffset(swappedMovedOffset).LineNumber,
				editor.Document.GetLineForOffset(swappedMovedOffset + swappedNodeText.Length).LineNumber);
		}