void ReplaceText(TextLocation start, TextLocation end, TextData replacement, bool moveCaretToEnd)
        {
            TextPencil pencil;

            if (!this.IsReadOnly && this.Buffer.TryGetPencil(out pencil))
            {
                var meta = new SelectionUndoMetadata { OldSelection = GetSelection() };

                this.inputBasedEdit = true;
                using (pencil)
                {
                    pencil.UndoUnit.Metadata = meta;
                    pencil.Write(start, end, replacement);
                }
                this.inputBasedEdit = false;

                if (moveCaretToEnd)
                {
                    TextLocation caretLoc;

                    if (replacement.Lines.Count > 1)
                    {
                        caretLoc = new TextLocation(start.Line + replacement.Lines.Count - 1, replacement.Lines[replacement.Lines.Count - 1].Length);
                    }
                    else
                    {
                        caretLoc = new TextLocation(start.Line, start.Index + replacement.Lines[0].Length);
                    }

                    var lineVisual = GetLineVisual(caretLoc.Line);
                    MoveCaret(lineVisual.MapToCoordinate(caretLoc), false);
                }

                meta.NewSelection = GetSelection();
            }
        }
        void InsertText(string text, bool moveCaretToEnd)
        {
            if (this.IsReadOnly)
            {
                return;
            }

            TextPencil pencil;

            if (!string.IsNullOrEmpty(text) && this.Buffer.TryGetPencil(out pencil))
            {
                var selection = GetSelection();
                var meta = new SelectionUndoMetadata { OldSelection = selection };

                if (selection.TopVirtualSpaces > 0)
                {
                    text = new string(' ', selection.TopVirtualSpaces) + text;
                }

                var data = TextData.FromString(text);

                this.inputBasedEdit = true;
                using (pencil)
                {
                    pencil.UndoUnit.Metadata = meta;
                    pencil.Write(selection.Range.Start, selection.Range.End, data);
                }
                this.inputBasedEdit = false;

                if (moveCaretToEnd)
                {
                    TextLocation caretLoc;

                    if (data.Lines.Count > 1)
                    {
                        caretLoc = new TextLocation(selection.Range.Start.Line + data.Lines.Count - 1, data.Lines[data.Lines.Count - 1].Length);
                    }
                    else
                    {
                        caretLoc = new TextLocation(selection.Range.Start.Line, selection.Range.Start.Index + data.Lines[0].Length);
                    }

                    var lineVisual = GetLineVisual(caretLoc.Line);
                    MoveCaret(lineVisual.MapToCoordinate(caretLoc), false);
                }

                meta.NewSelection = GetSelection();
            }
        }