/// <summary> /// If there is a comment block immediately before selection, add it to selection. /// </summary> Selection ExtendSelectionToSeparateComments(IDocument document, Location selectionStart, Location selectionEnd, IEnumerable<Comment> commentsBlankLines) { var comments = commentsBlankLines.Where(c => c.CommentStartsLine).ToList(); int commentIndex = comments.FindIndex(c => c.EndPosition <= selectionStart && IsWhitespaceBetween(document, c.EndPosition, 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)) { var comment = comments[commentIndex]; // Include the "//, /*, ///" since they are not included by the parser extendedSelection.Start = ExtendLeft(comment.StartPosition, document, "///", "/*", "//") ; commentIndex--; } return extendedSelection; }
void SelectText(Selection selection, ITextEditor editor) { if (selection == null) return; int startOffset, endOffset; try { startOffset = editor.Document.PositionToOffset(selection.Start); endOffset = editor.Document.PositionToOffset(selection.End); } catch (ArgumentOutOfRangeException) { return; } editor.Select(startOffset, endOffset - startOffset); }
Selection TryExtendSelectionToComments(IDocument document, Selection selection, IList<ISpecial> commentsBlankLines) { var extendedToComments = ExtendSelectionToComments(document, selection, commentsBlankLines); if (extendedToComments != null) return extendedToComments; return selection; }
Selection ExtendSelectionToComments(IDocument document, Selection selection, IList<ISpecial> commentsBlankLines) { if (selection == null) throw new ArgumentNullException("selection"); return ExtendSelectionToComments(document, selection.Start, selection.End, commentsBlankLines); }
public void JumpTo(int line, int column) { locationJumpedTo = new TextLocation(column, line); selection = Selection.Create(textArea, -1, -1); }
public MockTextEditor() { textArea = new TextArea(); textArea.Document = textDocument; selection = Selection.Create(textArea, -1, -1); }
// 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; } }
public void Select(int selectionStart, int selectionLength) { selection = Selection.Create(textArea, selectionStart, selectionLength + selectionStart); }
/// <summary> /// Clears the current selection. /// </summary> public void ClearSelection() { Selection = emptySelection; }
void textArea_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mode = SelectionMode.None; if (!e.Handled && e.ChangedButton == MouseButton.Left) { ModifierKeys modifiers = Keyboard.Modifiers; bool shift = (modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; if (enableTextDragDrop && e.ClickCount == 1 && !shift) { int visualColumn; bool isAtEndOfLine; int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine); if (textArea.Selection.Contains(offset)) { if (textArea.CaptureMouse()) { mode = SelectionMode.PossibleDragStart; possibleDragStartMousePos = e.GetPosition(textArea); } e.Handled = true; return; } } var oldPosition = textArea.Caret.Position; SetCaretOffsetToMousePosition(e); if (!shift) { textArea.ClearSelection(); } if (textArea.CaptureMouse()) { if ((modifiers & ModifierKeys.Alt) == ModifierKeys.Alt && textArea.Options.EnableRectangularSelection) { mode = SelectionMode.Rectangular; if (shift && textArea.Selection is RectangleSelection) { textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); } } else if (e.ClickCount == 1 && ((modifiers & ModifierKeys.Control) == 0)) { mode = SelectionMode.Normal; if (shift && !(textArea.Selection is RectangleSelection)) { textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position); } } else { SimpleSegment startWord; if (e.ClickCount == 3) { mode = SelectionMode.WholeLine; startWord = GetLineAtMousePosition(e); } else { mode = SelectionMode.WholeWord; startWord = GetWordAtMousePosition(e); } if (startWord == SimpleSegment.Invalid) { mode = SelectionMode.None; textArea.ReleaseMouseCapture(); return; } if (shift && !textArea.Selection.IsEmpty) { if (startWord.Offset < textArea.Selection.SurroundingSegment.Offset) { textArea.Selection = textArea.Selection.SetEndpoint(new TextViewPosition(textArea.Document.GetLocation(startWord.Offset))); } else if (startWord.EndOffset > textArea.Selection.SurroundingSegment.EndOffset) { textArea.Selection = textArea.Selection.SetEndpoint(new TextViewPosition(textArea.Document.GetLocation(startWord.EndOffset))); } this.startWord = new AnchorSegment(textArea.Document, textArea.Selection.SurroundingSegment); } else { textArea.Selection = Selection.Create(textArea, startWord.Offset, startWord.EndOffset); this.startWord = new AnchorSegment(textArea.Document, startWord.Offset, startWord.Length); } } } } e.Handled = true; }
void textArea_Drop(object sender, DragEventArgs e) { try { DragDropEffects effect = GetEffect(e); e.Effects = effect; if (effect != DragDropEffects.None) { string text = e.Data.GetData(DataFormats.UnicodeText, true) as string; if (text != null) { int start = textArea.Caret.Offset; if (mode == SelectionMode.Drag && textArea.Selection.Contains(start)) { Debug.WriteLine("Drop: did not drop: drop target is inside selection"); e.Effects = DragDropEffects.None; } else { Debug.WriteLine("Drop: insert at " + start); bool rectangular = e.Data.GetDataPresent(RectangleSelection.RectangularSelectionDataType); string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); text = TextUtilities.NormalizeNewLines(text, newLine); string pasteFormat; // fill the suggested DataFormat used for the paste action: if (rectangular) { pasteFormat = RectangleSelection.RectangularSelectionDataType; } else { pasteFormat = DataFormats.UnicodeText; } var pastingEventArgs = new DataObjectPastingEventArgs(e.Data, true, pasteFormat); textArea.RaiseEvent(pastingEventArgs); if (pastingEventArgs.CommandCancelled) { return; } // DataObject.PastingEvent handlers might have changed the format to apply. rectangular = pastingEventArgs.FormatToApply == RectangleSelection.RectangularSelectionDataType; // Mark the undo group with the currentDragDescriptor, if the drag // is originating from the same control. This allows combining // the undo groups when text is moved. textArea.Document.UndoStack.StartUndoGroup(this.currentDragDescriptor); try { if (rectangular && RectangleSelection.PerformRectangularPaste(textArea, textArea.Caret.Position, text, true)) { } else { textArea.Document.Insert(start, text); textArea.Selection = Selection.Create(textArea, start, start + text.Length); } } finally { textArea.Document.UndoStack.EndUndoGroup(); } } e.Handled = true; } } } catch (Exception ex) { OnDragException(ex); } }
void AssertSelectionsAreEqual(Selection expectedSelection, IScriptingConsoleTextEditor consoleTextEditor) { int selectionEnd = consoleTextEditor.SelectionStart + consoleTextEditor.SelectionLength; Selection actualSelection = Selection.Create(avalonEditTextEditor.TextArea, consoleTextEditor.SelectionStart, selectionEnd); Assert.AreEqual(expectedSelection, actualSelection); }
/// <summary> /// Clears the current selection. /// </summary> public void ClearSelection() { this.Selection = emptySelection; }