using TinyTUI.Input;
using TinyTUI.Text;
namespace TinyTUI.Components;
///
/// 支持多行文本编辑的基础编辑器组件
///
public sealed partial class Editor(ITextMeasurer? textMeasurer = null) : IInputComponent
{
private readonly ITextMeasurer _textMeasurer = textMeasurer ?? new TerminalTextMeasurer();
private readonly List _lines = [string.Empty];
private readonly Stack _undoStack = [];
private readonly Stack _redoStack = [];
private readonly List _history = [];
private int _cursorRow;
private int _cursorColumn;
private int _historyIndex = -1;
private string _historyDraft = string.Empty;
private int _lastRenderWidth = 80;
private int _scrollOffset;
private int? _preferredVisualColumn;
///
/// 获取或设置编辑器高度
///
public int Height { get; set; } = 5;
///
/// 获取或设置是否按可用宽度软换行
///
public bool SoftWrap { get; set; } = true;
///
/// 获取或设置空编辑器的输入提示
///
public string Placeholder { get; set; } = string.Empty;
///
/// 获取当前编辑器文本
///
public string Value
{
get => string.Join('\n', _lines);
set => SetValue(value);
}
///
/// 在文本变化时触发
///
public Action? OnChanged { get; set; }
///
/// 在用户取消编辑时触发
///
public Action? OnCanceled { get; set; }
///
/// 在用户提交编辑内容时触发
///
public Action? OnSubmitted { get; set; }
///
public void HandleInput(TuiInputEvent input)
{
switch (input)
{
case { Kind: TuiInputEventKind.Text }:
Edit(() => InsertText(input.Value));
break;
case { Kind: TuiInputEventKind.Paste }:
Edit(() => InsertText(input.Value.Replace("\r\n", "\n")));
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl("z"):
Undo();
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl("y"):
Redo();
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl("c"):
Edit(ClearText);
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl(KeyNames.Left):
MoveWordLeft();
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl(KeyNames.Right):
MoveWordRight();
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl(KeyNames.Backspace):
Edit(DeleteWordBackward);
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl(KeyNames.Delete):
Edit(DeleteWordForward);
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Enter }:
Edit(SplitLine);
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl(KeyNames.Enter):
Submit();
break;
case { Kind: TuiInputEventKind.Key, Value: var key } when key == KeyNames.Ctrl("s"):
Submit();
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Backspace }:
Edit(Backspace);
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Delete }:
Edit(Delete);
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Left }:
MoveLeft();
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Right }:
MoveRight();
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Up }:
if (!TryNavigateHistory(-1)) MoveVertical(-1);
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Down }:
if (!TryNavigateHistory(1)) MoveVertical(1);
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Home }:
MoveToLineStart();
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.End }:
MoveToLineEnd();
break;
case { Kind: TuiInputEventKind.Key, Value: KeyNames.Escape }:
Cancel();
break;
}
}
///
/// 提交当前编辑内容
///
public void Submit() => OnSubmitted?.Invoke(Value);
///
/// 取消当前编辑
///
public void Cancel() => OnCanceled?.Invoke();
///
/// 清空编辑器内容
///
public void Clear() => SetValue(string.Empty);
}