static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, CharacterHit ch, bool allowWrapToNextLine) { int newVisualColumn = ch.FirstCharacterIndex + ch.TrailingLength; int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) newVisualColumn = targetLineStartCol + targetLine.Length - 1; int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset; SetCaretPosition(textArea, newVisualColumn, newOffset); }
/// <summary> /// Validates the visual column of the caret using the specified visual line. /// The visual line must contain the caret offset. /// </summary> void RevalidateVisualColumn(VisualLine visualLine) { if (visualLine == null) throw new ArgumentNullException("visualLine"); // mark column as validated visualColumnValid = true; int caretOffset = textView.Document.GetOffset(position.Location); int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset; position.VisualColumn = visualLine.ValidateVisualColumn(position, textArea.Selection.EnableVirtualSpace); // search possible caret positions int newVisualColumnForwards = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal, textArea.Selection.EnableVirtualSpace); // If position.VisualColumn was valid, we're done with validation. if (newVisualColumnForwards != position.VisualColumn) { // also search backwards so that we can pick the better match int newVisualColumnBackwards = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal, textArea.Selection.EnableVirtualSpace); if (newVisualColumnForwards < 0 && newVisualColumnBackwards < 0) throw ThrowUtil.NoValidCaretPosition(); // determine offsets for new visual column positions int newOffsetForwards; if (newVisualColumnForwards >= 0) newOffsetForwards = visualLine.GetRelativeOffset(newVisualColumnForwards) + firstDocumentLineOffset; else newOffsetForwards = -1; int newOffsetBackwards; if (newVisualColumnBackwards >= 0) newOffsetBackwards = visualLine.GetRelativeOffset(newVisualColumnBackwards) + firstDocumentLineOffset; else newOffsetBackwards = -1; int newVisualColumn, newOffset; // if there's only one valid position, use it if (newVisualColumnForwards < 0) { newVisualColumn = newVisualColumnBackwards; newOffset = newOffsetBackwards; } else if (newVisualColumnBackwards < 0) { newVisualColumn = newVisualColumnForwards; newOffset = newOffsetForwards; } else { // two valid positions: find the better match if (Math.Abs(newOffsetBackwards - caretOffset) < Math.Abs(newOffsetForwards - caretOffset)) { // backwards is better newVisualColumn = newVisualColumnBackwards; newOffset = newOffsetBackwards; } else { // forwards is better newVisualColumn = newVisualColumnForwards; newOffset = newOffsetForwards; } } this.Position = new TextViewPosition(textView.Document.GetLocation(newOffset), newVisualColumn); } }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine) { int newVC = visualLine.VisualLength; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset); }
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine) { int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart); if (newVC < 0) throw ThrowUtil.NoValidCaretPosition(); // when the caret is already at the start of the text, jump to start before whitespace if (newVC == textArea.Caret.VisualColumn) newVC = 0; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset); }
static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) { int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode); if (pos >= 0) { SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); } else { // move to start of next line DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine; if (nextDocumentLine != null) { VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine); pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode); if (pos < 0) throw ThrowUtil.NoValidCaretPosition(); SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset); } else { // at end of document Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength); SetCaretPosition(textArea, -1, textArea.Document.TextLength); } } }
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode) { int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode); if (pos >= 0) { SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset); } else { // move to end of previous line DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine; if (previousDocumentLine != null) { VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine); pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode); if (pos < 0) throw ThrowUtil.NoValidCaretPosition(); SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset); } else { // at start of document Debug.Assert(visualLine.FirstDocumentLine.Offset == 0); SetCaretPosition(textArea, 0, 0); } } }
private static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine, int newVisualColumn, bool allowWrapToNextLine) { int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine); if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) { if (newVisualColumn <= targetVisualLine.VisualLength) newVisualColumn = targetLineStartCol + targetLine.Length - 1; } int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset; SetCaretPosition(textArea, newVisualColumn, newOffset); }
/// <summary> /// Validates the visual column of the caret using the specified visual line. /// The visual line must contain the caret offset. /// </summary> void RevalidateVisualColumn(VisualLine visualLine) { if (visualLine == null) throw new ArgumentNullException("visualLine"); // mark column as validated visualColumnValid = true; int caretOffset = textView.Document.GetOffset(position); int firstDocumentLineOffset = visualLine.FirstDocumentLine.Offset; if (position.VisualColumn < 0) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { int offsetFromVisualColumn = visualLine.GetRelativeOffset(position.VisualColumn); offsetFromVisualColumn += firstDocumentLineOffset; if (offsetFromVisualColumn != caretOffset) { position.VisualColumn = visualLine.GetVisualColumn(caretOffset - firstDocumentLineOffset); } else { if (position.VisualColumn > visualLine.VisualLength) { position.VisualColumn = visualLine.VisualLength; } } } // search possible caret position (first try forwards) int newVisualColumn = visualLine.GetNextCaretPosition(position.VisualColumn - 1, LogicalDirection.Forward, CaretPositioningMode.Normal); if (newVisualColumn < 0) { // then try backwards newVisualColumn = visualLine.GetNextCaretPosition(position.VisualColumn + 1, LogicalDirection.Backward, CaretPositioningMode.Normal); } if (newVisualColumn < 0) throw ThrowUtil.NoValidCaretPosition(); if (newVisualColumn != position.VisualColumn) { int newOffset = visualLine.GetRelativeOffset(newVisualColumn) + firstDocumentLineOffset; this.Position = new TextViewPosition(textView.Document.GetLocation(newOffset), newVisualColumn); } }
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine, TextLine textLine) { int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength; int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC); SetCaretPosition(textArea, newVC, offset, isAtEndOfLine: true); }