namespace Terminal.Gui.Views; public partial class TextView { /// /// Inserts the given text at the current cursor position exactly as if the user had just /// typed it /// /// Text to add public void InsertText (string toAdd) { foreach (char ch in toAdd) { Key key; try { key = new (ch); } catch (Exception) { throw new ArgumentException ( $"Cannot insert character '{ch}' because it does not map to a Key" ); } InsertText (key); if (NeedsDraw) { Adjust (); } else { PositionCursor (); } } } private void Insert (Cell cell) { List line = GetCurrentLine (); if (Used) { line.Insert (Math.Min (CurrentColumn, line.Count), cell); } else { if (CurrentColumn < line.Count) { line.RemoveAt (CurrentColumn); } line.Insert (Math.Min (CurrentColumn, line.Count), cell); } int prow = CurrentRow - _topRow; if (!_wrapNeeded) { // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method. //SetNeedsDraw (new (0, prow, Math.Max (Viewport.Width, 0), Math.Max (prow + 1, 0))); SetNeedsDraw (); } } private void InsertAllText (string text, bool fromClipboard = false) { if (string.IsNullOrEmpty (text)) { return; } List> lines; if (fromClipboard && text == _copiedText) { lines = _copiedCellsList; } else { // Get selected attribute Attribute? attribute = GetSelectedAttribute (CurrentRow, CurrentColumn); lines = Cell.StringToLinesOfCells (text, attribute); } if (lines.Count == 0) { return; } SetWrapModel (); List line = GetCurrentLine (); _historyText.Add ([new (line)], CursorPosition); // Optimize single line if (lines.Count == 1) { line.InsertRange (CurrentColumn, lines [0]); CurrentColumn += lines [0].Count; _historyText.Add ( [new (line)], CursorPosition, TextEditingLineStatus.Replaced ); if (!_wordWrap && CurrentColumn - _leftColumn > Viewport.Width) { _leftColumn = Math.Max (CurrentColumn - Viewport.Width + 1, 0); } if (_wordWrap) { SetNeedsDraw (); } else { // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method. //SetNeedsDraw (new (0, currentRow - topRow, Viewport.Width, Math.Max (currentRow - topRow + 1, 0))); SetNeedsDraw (); } UpdateWrapModel (); OnContentsChanged (); return; } List? rest = null; var lastPosition = 0; if (_model.Count > 0 && line.Count > 0 && !_copyWithoutSelection) { // Keep a copy of the rest of the line int restCount = line.Count - CurrentColumn; rest = line.GetRange (CurrentColumn, restCount); line.RemoveRange (CurrentColumn, restCount); } // First line is inserted at the current location, the rest is appended line.InsertRange (CurrentColumn, lines [0]); //model.AddLine (currentRow, lines [0]); List> addedLines = [new (line)]; for (var i = 1; i < lines.Count; i++) { _model.AddLine (CurrentRow + i, lines [i]); addedLines.Add ([.. lines [i]]); } if (rest is { }) { List last = _model.GetLine (CurrentRow + lines.Count - 1); lastPosition = last.Count; last.InsertRange (last.Count, rest); addedLines.Last ().InsertRange (addedLines.Last ().Count, rest); } _historyText.Add (addedLines, CursorPosition, TextEditingLineStatus.Added); // Now adjust column and row positions CurrentRow += lines.Count - 1; CurrentColumn = rest is { } ? lastPosition : lines [^1].Count; Adjust (); _historyText.Add ( [new (line)], CursorPosition, TextEditingLineStatus.Replaced ); UpdateWrapModel (); OnContentsChanged (); } private bool InsertText (Key a, Attribute? attribute = null) { //So that special keys like tab can be processed if (_isReadOnly) { return true; } SetWrapModel (); _historyText.Add ([new (GetCurrentLine ())], CursorPosition); if (IsSelecting) { ClearSelectedRegion (); } if ((uint)a.KeyCode == '\n') { _model.AddLine (CurrentRow + 1, []); CurrentRow++; CurrentColumn = 0; } else if ((uint)a.KeyCode == '\r') { CurrentColumn = 0; } else { if (Used) { Insert (new () { Grapheme = a.AsRune.ToString (), Attribute = attribute }); CurrentColumn++; if (CurrentColumn >= _leftColumn + Viewport.Width) { _leftColumn++; SetNeedsDraw (); } } else { Insert (new () { Grapheme = a.AsRune.ToString (), Attribute = attribute }); CurrentColumn++; } } _historyText.Add ( [new (GetCurrentLine ())], CursorPosition, TextEditingLineStatus.Replaced ); UpdateWrapModel (); OnContentsChanged (); return true; } #region History Event Handlers private void HistoryText_ChangeText (object sender, HistoryTextItemEventArgs obj) { SetWrapModel (); if (obj is { }) { int startLine = obj.CursorPosition.Y; if (obj.RemovedOnAdded is { }) { int offset; if (obj.IsUndoing) { offset = Math.Max (obj.RemovedOnAdded.Lines.Count - obj.Lines.Count, 1); } else { offset = obj.RemovedOnAdded.Lines.Count - 1; } for (var i = 0; i < offset; i++) { if (Lines > obj.RemovedOnAdded.CursorPosition.Y) { _model.RemoveLine (obj.RemovedOnAdded.CursorPosition.Y); } else { break; } } } for (var i = 0; i < obj.Lines.Count; i++) { if (i == 0 || obj.LineStatus == TextEditingLineStatus.Original || obj.LineStatus == TextEditingLineStatus.Attribute) { _model.ReplaceLine (startLine, obj.Lines [i]); } else if (obj is { IsUndoing: true, LineStatus: TextEditingLineStatus.Removed } or { IsUndoing: false, LineStatus: TextEditingLineStatus.Added }) { _model.AddLine (startLine, obj.Lines [i]); } else if (Lines > obj.CursorPosition.Y + 1) { _model.RemoveLine (obj.CursorPosition.Y + 1); } startLine++; } CursorPosition = obj.FinalCursorPosition; } UpdateWrapModel (); Adjust (); OnContentsChanged (); } #endregion }