using TinyTUI.Input;
using TinyTUI.Text;
namespace TinyTUI.Components;
///
/// 支持多行文本编辑的基础编辑器组件
///
public sealed partial class Editor(ITextMeasurer? textMeasurer = null, KeybindingRegistry? keybindings = null) : IInputComponent, IFocusableComponent
{
private readonly ITextMeasurer _textMeasurer = textMeasurer ?? new TerminalTextMeasurer();
private readonly KeybindingRegistry _keybindings = keybindings ?? KeybindingRegistry.CreateDefault();
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 bool Focused { get; set; }
///
/// 获取当前编辑器文本
///
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 }:
HandleKey(input);
break;
}
}
///
/// 提交当前编辑内容
///
public void Submit() => OnSubmitted?.Invoke(Value);
///
/// 取消当前编辑
///
public void Cancel() => OnCanceled?.Invoke();
///
/// 清空编辑器内容
///
public void Clear() => SetValue(string.Empty);
///
/// 根据动作映射处理多行编辑器快捷键
///
private void HandleKey(TuiInputEvent input)
{
if (_keybindings.Matches(input, TuiKeybindings.EditorUndo))
{
Undo();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorRedo))
{
Redo();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorClear))
{
Edit(ClearText);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorWordLeft))
{
MoveWordLeft();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorWordRight))
{
MoveWordRight();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorDeleteWordBackward))
{
Edit(DeleteWordBackward);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorDeleteWordForward))
{
Edit(DeleteWordForward);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorSubmit))
{
Submit();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorNewLine))
{
Edit(SplitLine);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorDeleteCharBackward))
{
Edit(Backspace);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorDeleteCharForward))
{
Edit(Delete);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorLeft))
{
MoveLeft();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorRight))
{
MoveRight();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorUp))
{
if (!TryNavigateHistory(-1)) MoveVertical(-1);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorDown))
{
if (!TryNavigateHistory(1)) MoveVertical(1);
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorLineStart))
{
MoveToLineStart();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.EditorCursorLineEnd))
{
MoveToLineEnd();
return;
}
if (_keybindings.Matches(input, TuiKeybindings.InputCancel))
Cancel();
}
}