/// <summary> Inserts the given content into this instance. </summary> /// <param name="caret"> The caret which represents the point at which the content should be /// inserted. </param> /// <param name="text"> The text that should be inserted into the text fragment </param> public TextCaret Insert(TextCaret caret, string text) { if (caret.Content != this) { throw new ArgumentException("Caret does not refer to this Content instance", nameof(caret)); } if (text == null) { throw new ArgumentNullException(nameof(text)); } // easy, it's empty if (text == "") { return(caret); } var originalNumGraphemes = _buffer.GraphemeLength; _buffer.InsertText(caret.Offset.CharOffset, text); var nowNumGraphemes = _buffer.GraphemeLength; NotifyChanged(); return(TextCaret.FromOffset(this, caret.Offset.GraphemeOffset + nowNumGraphemes - originalNumGraphemes)); }
/// <summary> Retrieves a cursor that points at the given character. </summary> /// <exception cref="Exception"> Thrown when an exception error condition occurs. </exception> /// <param name="graphemeIndex"> The index of the grapheme to point at. </param> /// <returns> A TextBlockValueCursor that is pointing at the given grapheme. </returns> public TextCaret CursorFromGraphemeIndex(int graphemeIndex) { if (graphemeIndex < 0 || graphemeIndex > _buffer.GraphemeLength) { throw new ArgumentException($"Invalid index for cursor; index={graphemeIndex}; maximum={_buffer.GraphemeLength}", nameof(graphemeIndex)); } return(TextCaret.FromOffset(this, graphemeIndex)); }
/// <summary> Inserts the given content into this instance. </summary> /// <param name="caret"> The caret which represents the point at which the content should be /// inserted. </param> /// <param name="newContent"> The content to insert. </param> /// <param name="autoMerge"> (Optional) True to automatically merge similar fragments together. </param> public TextCaret Insert(TextCaret caret, TextBlockContent newContent, bool autoMerge = true) { if (newContent == this) { throw new ArgumentException("Content cannot be inserted into itself", nameof(newContent)); } return(Insert(caret, newContent.GetText())); }
/// <summary> Makes sure that <paramref name="caretStart"/> comes before <paramref name="caretEnd"/>. </summary> private void NormalizePositioning(ref TextCaret caretStart, ref TextCaret caretEnd) { if (caretStart.Offset.GraphemeOffset > caretEnd.Offset.GraphemeOffset) { var temp = caretStart; caretStart = caretEnd; caretEnd = temp; } }
private void VerifyExtractParameters(TextCaret caretStart, TextCaret caretEnd) { if (!caretStart.IsValid || caretStart.Content != this) { throw new ArgumentException("Start cursor is not pointing at this content", nameof(caretStart)); } if (!caretEnd.IsValid || caretStart.Content != this) { throw new ArgumentException("End cursor is not pointing at this content", nameof(caretEnd)); } }
public TextBlockContent ExtractOrCloneContent(TextCaret caretStart, TextCaret caretEnd, bool shouldRemoveContent) { VerifyExtractParameters(caretStart, caretEnd); NormalizePositioning(ref caretStart, ref caretEnd); // zero-width; this check is needed, as the normalization process might shift the end to be // before the start when both are pointing at the end of a fragment (the start is normalized to // point at the beginning of the next fragment instead). if (caretStart == caretEnd) { return(new TextBlockContent()); } var start = caretStart.Offset; var end = caretEnd.Offset; if (start == end) { return(new TextBlockContent()); } else if (caretStart.IsAtBlockStart && caretEnd.IsAtBlockEnd) { var newContent = new TextBlockContent(this); if (shouldRemoveContent) { RemoveAll(); } return(newContent); } else { var clone = new TextBlockContent(_buffer.GetText(start, end)); if (shouldRemoveContent) { _buffer.DeleteText(start, end); NotifyChanged(); } return(clone); } }
/// <summary> Deletes text at the given position. </summary> public static TextCaret DeleteText(this TextCaret caret, int numberOfGraphemes) { var endCaret = caret; while (numberOfGraphemes > 0) { var next = endCaret.GetNextPosition(); if (!next.IsValid) { break; } endCaret = next; numberOfGraphemes--; } // TODO special case when we're deleting the entire fragment caret.Content.DeleteText(caret.Offset, endCaret.Offset); return(TextCaret.FromOffset(caret.Content, caret.Offset.GraphemeOffset)); }
public SerializedData(TextCaret caret) { _graphemeOffset = caret.Offset.GraphemeOffset; _pathToBlock = caret.Block.GetBlockPath(); }
/// <summary> Gets a cursor that is looking at the end of this content. </summary> public TextCaret GetCaretAtEnd() => TextCaret.FromEnd(this);
/// <summary> Gets a cursor that is looking at the beginning of this content. </summary> public TextCaret GetCaretAtStart() => TextCaret.FromBeginning(this);
public TextBlockContent Clone() => CloneContent(TextCaret.FromBeginning(this), TextCaret.FromEnd(this));
public TextBlockContent CloneContent(TextCaret start, TextCaret end) => ExtractOrCloneContent(start, end, shouldRemoveContent: false);
/// <summary> Inserts text at the given location. </summary> public static TextCaret InsertText(this TextCaret original, string text) { return(original.Content.Insert(original, text)); }