using System.Drawing; using System.Text; using Pastel; namespace Yuanshen.Common.Console; public static class ConsolePrompt { private const string ClearLine = "\u001b[2K"; private const int PromptWidth = 60; private static readonly object SyncRoot = new(); private static readonly StringBuilder Buffer = new(); private static string _label = ">"; private static bool _active; private static Func? _handler; public static void Start(string label, Func handler) { ConsoleTheme.Enable(); _label = label; _handler = handler; _active = true; lock (SyncRoot) Draw(); Thread thread = new(ReadLoop) { IsBackground = true, Name = "console-prompt" }; thread.Start(); } public static void Write(string line) { lock (SyncRoot) { if (_active) System.Console.Write("\r" + ClearLine); foreach (string part in line.Split('\n')) System.Console.WriteLine(ConsoleTheme.Center(part.TrimEnd('\r'))); if (_active) Draw(); } } public static void Reply(string line) => Write(line.Pastel(ConsoleTheme.Text)); public static void Warn(string line) => Write(line.Pastel(Color.FromArgb(0xFF, 0xB3, 0x4D))); private static void Draw() { int pad = Math.Max((ConsoleTheme.Width - PromptWidth) / 2, 0); System.Console.Write("\r" + ClearLine); System.Console.Write(new string(' ', pad)); System.Console.Write(_label.Pastel(ConsoleTheme.Accent)); System.Console.Write(' '); System.Console.Write(Buffer.ToString().Pastel(ConsoleTheme.Text)); } private static void ReadLoop() { while (_active) { ConsoleKeyInfo key; try { key = System.Console.ReadKey(intercept: true); } catch (InvalidOperationException) { _active = false; return; } if (key.Key == ConsoleKey.Enter) { string command; lock (SyncRoot) { command = Buffer.ToString().Trim(); Buffer.Clear(); System.Console.Write("\r" + ClearLine); if (command.Length != 0) System.Console.WriteLine(ConsoleTheme.Center($"{_label} {command}".Pastel(ConsoleTheme.Muted))); Draw(); } if (command.Length != 0 && _handler is not null) Dispatch(command); continue; } lock (SyncRoot) { if (key.Key == ConsoleKey.Backspace) { if (Buffer.Length != 0) Buffer.Length--; } else if (!char.IsControl(key.KeyChar)) { Buffer.Append(key.KeyChar); } Draw(); } } } private static void Dispatch(string command) { _ = Task.Run(async () => { try { await _handler!(command); } catch (Exception exception) { Write($" console command failed: {exception.Message}".Pastel(Color.IndianRed)); } }); } }