From 16603a1e73b1cf96093bbdcc625cf621e110004b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:31:26 +0000 Subject: [PATCH 1/5] Initial plan From f6274467caa4350bcd2d2c0821d45eb3137494f2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:37:53 +0000 Subject: [PATCH 2/5] Initial plan Co-authored-by: shibayan <1356444+shibayan@users.noreply.github.com> --- global.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 global.json diff --git a/global.json b/global.json new file mode 100644 index 0000000..14c6e50 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.418", + "rollForward": "latestPatch" + } +} From 111653b6d9dcee977a89f48accace5a50e026fbf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:42:49 +0000 Subject: [PATCH 3/5] Refactor overall architecture: ConsoleKeyBinding, simplified handlers, ESC key, fixed lifecycle Co-authored-by: shibayan <1356444+shibayan@users.noreply.github.com> --- Sharprompt.Tests/ConsoleKeyBindingTests.cs | 109 +++++++++++++++++++++ Sharprompt/Forms/FormBase.cs | 24 ++++- Sharprompt/Forms/ListForm.cs | 6 +- Sharprompt/Forms/MultiSelectForm.cs | 44 ++++----- Sharprompt/Forms/PasswordForm.cs | 6 +- Sharprompt/Forms/SelectForm.cs | 22 ++--- Sharprompt/Forms/TextFormBase.cs | 100 ++++++++++++------- Sharprompt/Internal/ConsoleKeyBinding.cs | 20 ++++ Sharprompt/Internal/OffscreenBuffer.cs | 2 +- 9 files changed, 248 insertions(+), 85 deletions(-) create mode 100644 Sharprompt.Tests/ConsoleKeyBindingTests.cs create mode 100644 Sharprompt/Internal/ConsoleKeyBinding.cs diff --git a/Sharprompt.Tests/ConsoleKeyBindingTests.cs b/Sharprompt.Tests/ConsoleKeyBindingTests.cs new file mode 100644 index 0000000..0de2cf2 --- /dev/null +++ b/Sharprompt.Tests/ConsoleKeyBindingTests.cs @@ -0,0 +1,109 @@ +using System; + +using Sharprompt.Internal; + +using Xunit; + +namespace Sharprompt.Tests; + +public class ConsoleKeyBindingTests +{ + [Fact] + public void Constructor_DefaultModifiers_IsNone() + { + var binding = new ConsoleKeyBinding(ConsoleKey.Enter); + + Assert.Equal(ConsoleKey.Enter, binding.Key); + Assert.Equal(default(ConsoleModifiers), binding.Modifiers); + } + + [Fact] + public void Constructor_WithModifiers_StoresModifiers() + { + var binding = new ConsoleKeyBinding(ConsoleKey.LeftArrow, ConsoleModifiers.Control); + + Assert.Equal(ConsoleKey.LeftArrow, binding.Key); + Assert.Equal(ConsoleModifiers.Control, binding.Modifiers); + } + + [Fact] + public void Equals_SameKeyAndModifiers_ReturnsTrue() + { + var a = new ConsoleKeyBinding(ConsoleKey.A, ConsoleModifiers.Control); + var b = new ConsoleKeyBinding(ConsoleKey.A, ConsoleModifiers.Control); + + Assert.Equal(a, b); + Assert.True(a == b); + Assert.False(a != b); + } + + [Fact] + public void Equals_DifferentKey_ReturnsFalse() + { + var a = new ConsoleKeyBinding(ConsoleKey.A); + var b = new ConsoleKeyBinding(ConsoleKey.B); + + Assert.NotEqual(a, b); + Assert.False(a == b); + Assert.True(a != b); + } + + [Fact] + public void Equals_SameKeyDifferentModifiers_ReturnsFalse() + { + var plain = new ConsoleKeyBinding(ConsoleKey.LeftArrow); + var ctrl = new ConsoleKeyBinding(ConsoleKey.LeftArrow, ConsoleModifiers.Control); + + Assert.NotEqual(plain, ctrl); + Assert.False(plain == ctrl); + Assert.True(plain != ctrl); + } + + [Fact] + public void GetHashCode_SameKeyAndModifiers_SameHash() + { + var a = new ConsoleKeyBinding(ConsoleKey.Delete, ConsoleModifiers.Control); + var b = new ConsoleKeyBinding(ConsoleKey.Delete, ConsoleModifiers.Control); + + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public void GetHashCode_DifferentBindings_DifferentHash() + { + var a = new ConsoleKeyBinding(ConsoleKey.Delete); + var b = new ConsoleKeyBinding(ConsoleKey.Delete, ConsoleModifiers.Control); + + Assert.NotEqual(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public void CanBeUsedAsDictionaryKey() + { + var dict = new System.Collections.Generic.Dictionary + { + [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = "plain left", + [new ConsoleKeyBinding(ConsoleKey.LeftArrow, ConsoleModifiers.Control)] = "ctrl left" + }; + + Assert.Equal("plain left", dict[new ConsoleKeyBinding(ConsoleKey.LeftArrow)]); + Assert.Equal("ctrl left", dict[new ConsoleKeyBinding(ConsoleKey.LeftArrow, ConsoleModifiers.Control)]); + } + + [Fact] + public void Equals_WithObject_ReturnsTrueForSameBinding() + { + var a = new ConsoleKeyBinding(ConsoleKey.Enter); + object b = new ConsoleKeyBinding(ConsoleKey.Enter); + + Assert.True(a.Equals(b)); + } + + [Fact] + public void Equals_WithDifferentType_ReturnsFalse() + { + var a = new ConsoleKeyBinding(ConsoleKey.Enter); + + Assert.False(a.Equals("Enter")); + } +} diff --git a/Sharprompt/Forms/FormBase.cs b/Sharprompt/Forms/FormBase.cs index b47f263..71f3cd4 100644 --- a/Sharprompt/Forms/FormBase.cs +++ b/Sharprompt/Forms/FormBase.cs @@ -18,6 +18,11 @@ protected FormBase() _consoleDriver.CancellationCallback = CancellationHandler; _formRenderer = new FormRenderer(_consoleDriver); + + KeyHandlerMaps = new() + { + [new ConsoleKeyBinding(ConsoleKey.Escape)] = HandleEscape + }; } private readonly IConsoleDriver _consoleDriver; @@ -25,13 +30,17 @@ protected FormBase() protected TextInputBuffer InputBuffer { get; } = new(); - protected Dictionary> KeyHandlerMaps { get; set; } = new(); + protected Dictionary> KeyHandlerMaps { get; set; } protected int Width => _consoleDriver.WindowWidth; protected int Height => _consoleDriver.WindowHeight; - public void Dispose() => _formRenderer.Dispose(); + public void Dispose() + { + _formRenderer.Dispose(); + _consoleDriver.Dispose(); + } public T Start() { @@ -99,7 +108,9 @@ private bool TryGetResult([NotNullWhen(true)] out T? result) return HandleEnter(out result); } - if (KeyHandlerMaps.TryGetValue(keyInfo.Key, out var keyHandler) && keyHandler(keyInfo)) + var binding = new ConsoleKeyBinding(keyInfo.Key, keyInfo.Modifiers); + + if (KeyHandlerMaps.TryGetValue(binding, out var keyHandler) && keyHandler()) { continue; } @@ -131,4 +142,11 @@ private void CancellationHandler() Environment.Exit(1); } + + private bool HandleEscape() + { + CancellationHandler(); + + return true; + } } diff --git a/Sharprompt/Forms/ListForm.cs b/Sharprompt/Forms/ListForm.cs index aa0b507..5ed0b0e 100644 --- a/Sharprompt/Forms/ListForm.cs +++ b/Sharprompt/Forms/ListForm.cs @@ -89,15 +89,15 @@ protected override bool HandleEnter([NotNullWhen(true)] out IEnumerable? resu return false; } - protected override bool HandleDelete(ConsoleKeyInfo keyInfo) + protected override bool HandleCtrlDelete() { - if (keyInfo.Modifiers == ConsoleModifiers.Control && _inputItems.Count > 0) + if (_inputItems.Count > 0) { _inputItems.RemoveAt(_inputItems.Count - 1); return true; } - return base.HandleDelete(keyInfo); + return base.HandleCtrlDelete(); } } diff --git a/Sharprompt/Forms/MultiSelectForm.cs b/Sharprompt/Forms/MultiSelectForm.cs index 39bfa4a..819e88c 100644 --- a/Sharprompt/Forms/MultiSelectForm.cs +++ b/Sharprompt/Forms/MultiSelectForm.cs @@ -25,16 +25,16 @@ public MultiSelectForm(MultiSelectOptions options) _selectedItems.Add(defaultValue); } - KeyHandlerMaps = new() + KeyHandlerMaps = new(KeyHandlerMaps) { - [ConsoleKey.Spacebar] = HandleSpacebar, - [ConsoleKey.UpArrow] = HandleUpArrow, - [ConsoleKey.DownArrow] = HandleDownArrow, - [ConsoleKey.LeftArrow] = HandleLeftArrow, - [ConsoleKey.RightArrow] = HandleRightArrow, - [ConsoleKey.Backspace] = HandleBackspace, - [ConsoleKey.A] = HandleAWithControl, - [ConsoleKey.I] = HandleIWithControl, + [new ConsoleKeyBinding(ConsoleKey.Spacebar)] = HandleSpacebar, + [new ConsoleKeyBinding(ConsoleKey.UpArrow)] = HandleUpArrow, + [new ConsoleKeyBinding(ConsoleKey.DownArrow)] = HandleDownArrow, + [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow, + [new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow, + [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace, + [new ConsoleKeyBinding(ConsoleKey.A, ConsoleModifiers.Control)] = HandleCtrlA, + [new ConsoleKeyBinding(ConsoleKey.I, ConsoleModifiers.Control)] = HandleCtrlI, }; } @@ -124,7 +124,7 @@ protected override bool HandleTextInput(ConsoleKeyInfo keyInfo) return true; } - private bool HandleSpacebar(ConsoleKeyInfo keyInfo) + private bool HandleSpacebar() { if (!_paginator.TryGetSelectedItem(out var currentItem)) { @@ -146,35 +146,35 @@ private bool HandleSpacebar(ConsoleKeyInfo keyInfo) return true; } - private bool HandleUpArrow(ConsoleKeyInfo keyInfo) + private bool HandleUpArrow() { _paginator.PreviousItem(); return true; } - private bool HandleDownArrow(ConsoleKeyInfo keyInfo) + private bool HandleDownArrow() { _paginator.NextItem(); return true; } - private bool HandleLeftArrow(ConsoleKeyInfo keyInfo) + private bool HandleLeftArrow() { _paginator.PreviousPage(); return true; } - private bool HandleRightArrow(ConsoleKeyInfo keyInfo) + private bool HandleRightArrow() { _paginator.NextPage(); return true; } - private bool HandleBackspace(ConsoleKeyInfo keyInfo) + private bool HandleBackspace() { if (InputBuffer.IsStart) { @@ -187,13 +187,8 @@ private bool HandleBackspace(ConsoleKeyInfo keyInfo) return true; } - private bool HandleAWithControl(ConsoleKeyInfo keyInfo) + private bool HandleCtrlA() { - if (keyInfo.Modifiers != ConsoleModifiers.Control) - { - return false; - } - if (_selectedItems.Count == _paginator.TotalCount) { _selectedItems.Clear(); @@ -209,13 +204,8 @@ private bool HandleAWithControl(ConsoleKeyInfo keyInfo) return true; } - private bool HandleIWithControl(ConsoleKeyInfo keyInfo) + private bool HandleCtrlI() { - if (keyInfo.Modifiers != ConsoleModifiers.Control) - { - return false; - } - var invertedItems = _paginator.Except(_selectedItems).ToArray(); _selectedItems.Clear(); diff --git a/Sharprompt/Forms/PasswordForm.cs b/Sharprompt/Forms/PasswordForm.cs index d063d48..b633c51 100644 --- a/Sharprompt/Forms/PasswordForm.cs +++ b/Sharprompt/Forms/PasswordForm.cs @@ -14,9 +14,9 @@ public PasswordForm(PasswordOptions options) _options = options; - KeyHandlerMaps = new() + KeyHandlerMaps = new(KeyHandlerMaps) { - [ConsoleKey.Backspace] = HandleBackspace + [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace }; } @@ -63,7 +63,7 @@ protected override bool HandleEnter([NotNullWhen(true)] out string? result) return true; } - private bool HandleBackspace(ConsoleKeyInfo keyInfo) + private bool HandleBackspace() { if (InputBuffer.IsStart) { diff --git a/Sharprompt/Forms/SelectForm.cs b/Sharprompt/Forms/SelectForm.cs index 78e2bd9..6800ac4 100644 --- a/Sharprompt/Forms/SelectForm.cs +++ b/Sharprompt/Forms/SelectForm.cs @@ -19,13 +19,13 @@ public SelectForm(SelectOptions options) LoopingSelection = options.LoopingSelection }; - KeyHandlerMaps = new() + KeyHandlerMaps = new(KeyHandlerMaps) { - [ConsoleKey.UpArrow] = HandleUpArrow, - [ConsoleKey.DownArrow] = HandleDownArrow, - [ConsoleKey.LeftArrow] = HandleLeftArrow, - [ConsoleKey.RightArrow] = HandleRightArrow, - [ConsoleKey.Backspace] = HandleBackspace + [new ConsoleKeyBinding(ConsoleKey.UpArrow)] = HandleUpArrow, + [new ConsoleKeyBinding(ConsoleKey.DownArrow)] = HandleDownArrow, + [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow, + [new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow, + [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace }; } @@ -94,35 +94,35 @@ protected override bool HandleTextInput(ConsoleKeyInfo keyInfo) return true; } - private bool HandleUpArrow(ConsoleKeyInfo keyInfo) + private bool HandleUpArrow() { _paginator.PreviousItem(); return true; } - private bool HandleDownArrow(ConsoleKeyInfo keyInfo) + private bool HandleDownArrow() { _paginator.NextItem(); return true; } - private bool HandleLeftArrow(ConsoleKeyInfo keyInfo) + private bool HandleLeftArrow() { _paginator.PreviousPage(); return true; } - private bool HandleRightArrow(ConsoleKeyInfo keyInfo) + private bool HandleRightArrow() { _paginator.NextPage(); return true; } - private bool HandleBackspace(ConsoleKeyInfo keyInfo) + private bool HandleBackspace() { if (InputBuffer.IsStart) { diff --git a/Sharprompt/Forms/TextFormBase.cs b/Sharprompt/Forms/TextFormBase.cs index bd12429..9ebfca7 100644 --- a/Sharprompt/Forms/TextFormBase.cs +++ b/Sharprompt/Forms/TextFormBase.cs @@ -1,61 +1,77 @@ using System; +using Sharprompt.Internal; + namespace Sharprompt.Forms; internal abstract class TextFormBase : FormBase { protected TextFormBase() { - KeyHandlerMaps = new() + KeyHandlerMaps = new(KeyHandlerMaps) { - [ConsoleKey.LeftArrow] = HandleLeftArrow, - [ConsoleKey.RightArrow] = HandleRightArrow, - [ConsoleKey.Home] = HandleHome, - [ConsoleKey.End] = HandleEnd, - [ConsoleKey.Backspace] = HandleBackspace, - [ConsoleKey.Delete] = HandleDelete + [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow, + [new ConsoleKeyBinding(ConsoleKey.LeftArrow, ConsoleModifiers.Control)] = HandleCtrlLeftArrow, + [new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow, + [new ConsoleKeyBinding(ConsoleKey.RightArrow, ConsoleModifiers.Control)] = HandleCtrlRightArrow, + [new ConsoleKeyBinding(ConsoleKey.Home)] = HandleHome, + [new ConsoleKeyBinding(ConsoleKey.End)] = HandleEnd, + [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace, + [new ConsoleKeyBinding(ConsoleKey.Backspace, ConsoleModifiers.Control)] = HandleCtrlBackspace, + [new ConsoleKeyBinding(ConsoleKey.Delete)] = HandleDelete, + [new ConsoleKeyBinding(ConsoleKey.Delete, ConsoleModifiers.Control)] = HandleCtrlDelete }; } - protected virtual bool HandleLeftArrow(ConsoleKeyInfo keyInfo) + protected virtual bool HandleLeftArrow() { if (InputBuffer.IsStart) { return false; } - if (keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control)) - { - InputBuffer.MoveToPreviousWord(); - } - else + InputBuffer.MoveBackward(); + + return true; + } + + protected virtual bool HandleCtrlLeftArrow() + { + if (InputBuffer.IsStart) { - InputBuffer.MoveBackward(); + return false; } + InputBuffer.MoveToPreviousWord(); + return true; } - protected virtual bool HandleRightArrow(ConsoleKeyInfo keyInfo) + protected virtual bool HandleRightArrow() { if (InputBuffer.IsEnd) { return false; } - if (keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control)) - { - InputBuffer.MoveToNextWord(); - } - else + InputBuffer.MoveForward(); + + return true; + } + + protected virtual bool HandleCtrlRightArrow() + { + if (InputBuffer.IsEnd) { - InputBuffer.MoveForward(); + return false; } + InputBuffer.MoveToNextWord(); + return true; } - protected virtual bool HandleHome(ConsoleKeyInfo keyInfo) + protected virtual bool HandleHome() { if (InputBuffer.IsStart) { @@ -67,7 +83,7 @@ protected virtual bool HandleHome(ConsoleKeyInfo keyInfo) return true; } - protected virtual bool HandleEnd(ConsoleKeyInfo keyInfo) + protected virtual bool HandleEnd() { if (InputBuffer.IsEnd) { @@ -79,41 +95,51 @@ protected virtual bool HandleEnd(ConsoleKeyInfo keyInfo) return true; } - protected virtual bool HandleBackspace(ConsoleKeyInfo keyInfo) + protected virtual bool HandleBackspace() { if (InputBuffer.IsStart) { return false; } - if (keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control)) - { - InputBuffer.BackspaceWord(); - } - else + InputBuffer.Backspace(); + + return true; + } + + protected virtual bool HandleCtrlBackspace() + { + if (InputBuffer.IsStart) { - InputBuffer.Backspace(); + return false; } + InputBuffer.BackspaceWord(); + return true; } - protected virtual bool HandleDelete(ConsoleKeyInfo keyInfo) + protected virtual bool HandleDelete() { if (InputBuffer.IsEnd) { return false; } - if (keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control)) - { - InputBuffer.DeleteWord(); - } - else + InputBuffer.Delete(); + + return true; + } + + protected virtual bool HandleCtrlDelete() + { + if (InputBuffer.IsEnd) { - InputBuffer.Delete(); + return false; } + InputBuffer.DeleteWord(); + return true; } } diff --git a/Sharprompt/Internal/ConsoleKeyBinding.cs b/Sharprompt/Internal/ConsoleKeyBinding.cs new file mode 100644 index 0000000..0f1141c --- /dev/null +++ b/Sharprompt/Internal/ConsoleKeyBinding.cs @@ -0,0 +1,20 @@ +using System; + +namespace Sharprompt.Internal; + +internal readonly struct ConsoleKeyBinding(ConsoleKey key, ConsoleModifiers modifiers = default) : IEquatable +{ + public ConsoleKey Key { get; } = key; + + public ConsoleModifiers Modifiers { get; } = modifiers; + + public bool Equals(ConsoleKeyBinding other) => Key == other.Key && Modifiers == other.Modifiers; + + public override bool Equals(object? obj) => obj is ConsoleKeyBinding other && Equals(other); + + public override int GetHashCode() => HashCode.Combine(Key, Modifiers); + + public static bool operator ==(ConsoleKeyBinding left, ConsoleKeyBinding right) => left.Equals(right); + + public static bool operator !=(ConsoleKeyBinding left, ConsoleKeyBinding right) => !left.Equals(right); +} diff --git a/Sharprompt/Internal/OffscreenBuffer.cs b/Sharprompt/Internal/OffscreenBuffer.cs index d6a080f..96bc6b4 100644 --- a/Sharprompt/Internal/OffscreenBuffer.cs +++ b/Sharprompt/Internal/OffscreenBuffer.cs @@ -56,7 +56,7 @@ private int WrittenLineCount } } - public void Dispose() => _consoleDriver.Dispose(); + public void Dispose() { } public void Write(string text) => Write(text, Console.ForegroundColor); From 2b00ec99bdda376d814860bd90842f7b643d627d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 06:27:37 +0000 Subject: [PATCH 4/5] Resolve conflicts with master: integrate PromptConfiguration refactor (#332) with ConsoleKeyBinding architecture Co-authored-by: shibayan <1356444+shibayan@users.noreply.github.com> --- Sharprompt/ConfirmOptions.cs | 13 +-- Sharprompt/Forms/ConfirmForm.cs | 2 +- Sharprompt/Forms/FormBase.cs | 18 +-- Sharprompt/Forms/FormRenderer.cs | 6 +- Sharprompt/Forms/InputForm.cs | 2 +- Sharprompt/Forms/ListForm.cs | 2 +- Sharprompt/Forms/MultiSelectForm.cs | 105 ++++-------------- Sharprompt/Forms/PasswordForm.cs | 7 +- Sharprompt/Forms/SelectForm.cs | 86 ++------------ Sharprompt/Forms/SelectFormBase.cs | 89 +++++++++++++++ Sharprompt/Forms/TextFormBase.cs | 2 +- Sharprompt/InputOptions.cs | 9 +- Sharprompt/Internal/OffscreenBuffer.cs | 10 +- .../Internal/OffscreenBufferExtensions.cs | 12 +- Sharprompt/ListOptions.cs | 8 +- Sharprompt/MultiSelectOptions.cs | 9 +- Sharprompt/PasswordOptions.cs | 9 +- Sharprompt/Prompt.Basic.cs | 12 +- Sharprompt/Prompt.Configuration.cs | 39 ++----- Sharprompt/PromptConfiguration.cs | 47 ++++++++ Sharprompt/PromptOptions.cs | 13 +++ Sharprompt/SelectOptions.cs | 9 +- 22 files changed, 244 insertions(+), 265 deletions(-) create mode 100644 Sharprompt/Forms/SelectFormBase.cs create mode 100644 Sharprompt/PromptConfiguration.cs create mode 100644 Sharprompt/PromptOptions.cs diff --git a/Sharprompt/ConfirmOptions.cs b/Sharprompt/ConfirmOptions.cs index f084e8d..da32230 100644 --- a/Sharprompt/ConfirmOptions.cs +++ b/Sharprompt/ConfirmOptions.cs @@ -1,15 +1,6 @@ -using System; +namespace Sharprompt; -namespace Sharprompt; - -public class ConfirmOptions +public class ConfirmOptions : PromptOptions { - public string Message { get; set; } = null!; - public bool? DefaultValue { get; set; } - - internal void EnsureOptions() - { - ArgumentNullException.ThrowIfNull(Message); - } } diff --git a/Sharprompt/Forms/ConfirmForm.cs b/Sharprompt/Forms/ConfirmForm.cs index 499fe7e..8b25173 100644 --- a/Sharprompt/Forms/ConfirmForm.cs +++ b/Sharprompt/Forms/ConfirmForm.cs @@ -7,7 +7,7 @@ namespace Sharprompt.Forms; internal class ConfirmForm : TextFormBase { - public ConfirmForm(ConfirmOptions options) + public ConfirmForm(ConfirmOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); diff --git a/Sharprompt/Forms/FormBase.cs b/Sharprompt/Forms/FormBase.cs index 71f3cd4..f47892c 100644 --- a/Sharprompt/Forms/FormBase.cs +++ b/Sharprompt/Forms/FormBase.cs @@ -11,13 +11,14 @@ namespace Sharprompt.Forms; internal abstract class FormBase : IDisposable { - protected FormBase() + protected FormBase(PromptConfiguration configuration) { - _consoleDriver = Prompt.ConsoleDriverFactory() ?? throw new InvalidOperationException("ConsoleDriverFactory must return a non-null IConsoleDriver instance."); + _configuration = configuration; + _consoleDriver = configuration.ConsoleDriverFactory() ?? throw new InvalidOperationException("ConsoleDriverFactory must return a non-null IConsoleDriver instance."); _consoleDriver.CancellationCallback = CancellationHandler; - _formRenderer = new FormRenderer(_consoleDriver); + _formRenderer = new FormRenderer(_consoleDriver, configuration); KeyHandlerMaps = new() { @@ -27,6 +28,9 @@ [new ConsoleKeyBinding(ConsoleKey.Escape)] = HandleEscape private readonly IConsoleDriver _consoleDriver; private readonly FormRenderer _formRenderer; + private readonly PromptConfiguration _configuration; + + protected PromptConfiguration Configuration => _configuration; protected TextInputBuffer InputBuffer { get; } = new(); @@ -36,11 +40,7 @@ [new ConsoleKeyBinding(ConsoleKey.Escape)] = HandleEscape protected int Height => _consoleDriver.WindowHeight; - public void Dispose() - { - _formRenderer.Dispose(); - _consoleDriver.Dispose(); - } + public void Dispose() => _consoleDriver.Dispose(); public T Start() { @@ -135,7 +135,7 @@ private void CancellationHandler() { _formRenderer.Cancel(); - if (Prompt.ThrowExceptionOnCancel) + if (_configuration.ThrowExceptionOnCancel) { throw new PromptCanceledException(Resource.Message_PromptCanceled, GetType().Name); } diff --git a/Sharprompt/Forms/FormRenderer.cs b/Sharprompt/Forms/FormRenderer.cs index afe2d8e..ed19175 100644 --- a/Sharprompt/Forms/FormRenderer.cs +++ b/Sharprompt/Forms/FormRenderer.cs @@ -5,14 +5,12 @@ namespace Sharprompt.Forms; -internal class FormRenderer(IConsoleDriver consoleDriver) : IDisposable +internal class FormRenderer(IConsoleDriver consoleDriver, PromptConfiguration configuration) { - private readonly OffscreenBuffer _offscreenBuffer = new(consoleDriver); + private readonly OffscreenBuffer _offscreenBuffer = new(consoleDriver, configuration); public string? ErrorMessage { get; set; } - public void Dispose() => _offscreenBuffer.Dispose(); - public void Cancel() => _offscreenBuffer.Cancel(); public void Render(Action template) diff --git a/Sharprompt/Forms/InputForm.cs b/Sharprompt/Forms/InputForm.cs index 7798362..3b68395 100644 --- a/Sharprompt/Forms/InputForm.cs +++ b/Sharprompt/Forms/InputForm.cs @@ -8,7 +8,7 @@ namespace Sharprompt.Forms; internal class InputForm : TextFormBase { - public InputForm(InputOptions options) + public InputForm(InputOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); diff --git a/Sharprompt/Forms/ListForm.cs b/Sharprompt/Forms/ListForm.cs index 5ed0b0e..d588566 100644 --- a/Sharprompt/Forms/ListForm.cs +++ b/Sharprompt/Forms/ListForm.cs @@ -9,7 +9,7 @@ namespace Sharprompt.Forms; internal class ListForm : TextFormBase> where T : notnull { - public ListForm(ListOptions options) + public ListForm(ListOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); diff --git a/Sharprompt/Forms/MultiSelectForm.cs b/Sharprompt/Forms/MultiSelectForm.cs index 819e88c..ab6d816 100644 --- a/Sharprompt/Forms/MultiSelectForm.cs +++ b/Sharprompt/Forms/MultiSelectForm.cs @@ -8,59 +8,48 @@ namespace Sharprompt.Forms; -internal class MultiSelectForm : FormBase> where T : notnull +internal class MultiSelectForm : SelectFormBase> where T : notnull { - public MultiSelectForm(MultiSelectOptions options) + public MultiSelectForm(MultiSelectOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); _options = options; - _paginator = new Paginator(options.Items, Math.Min(options.PageSize, Height - 2), Optional.Empty, options.TextSelector) - { - LoopingSelection = options.LoopingSelection - }; + + InitializePaginator(options.Items, options.PageSize, Optional.Empty, options.TextSelector, options.LoopingSelection); foreach (var defaultValue in options.DefaultValues) { _selectedItems.Add(defaultValue); } - KeyHandlerMaps = new(KeyHandlerMaps) - { - [new ConsoleKeyBinding(ConsoleKey.Spacebar)] = HandleSpacebar, - [new ConsoleKeyBinding(ConsoleKey.UpArrow)] = HandleUpArrow, - [new ConsoleKeyBinding(ConsoleKey.DownArrow)] = HandleDownArrow, - [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow, - [new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow, - [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace, - [new ConsoleKeyBinding(ConsoleKey.A, ConsoleModifiers.Control)] = HandleCtrlA, - [new ConsoleKeyBinding(ConsoleKey.I, ConsoleModifiers.Control)] = HandleCtrlI, - }; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.Spacebar)] = HandleSpacebar; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.A, ConsoleModifiers.Control)] = HandleCtrlA; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.I, ConsoleModifiers.Control)] = HandleCtrlI; } private readonly MultiSelectOptions _options; - private readonly Paginator _paginator; private readonly HashSet _selectedItems = []; protected override void InputTemplate(OffscreenBuffer offscreenBuffer) { - _paginator.UpdatePageSize(Math.Min(_options.PageSize, Height - 2)); + Paginator.UpdatePageSize(Math.Min(_options.PageSize, Height - 2)); offscreenBuffer.WritePrompt(_options.Message); - offscreenBuffer.Write(_paginator.FilterKeyword); + offscreenBuffer.Write(Paginator.FilterKeyword); offscreenBuffer.PushCursor(); - if (string.IsNullOrEmpty(_paginator.FilterKeyword)) + if (string.IsNullOrEmpty(Paginator.FilterKeyword)) { offscreenBuffer.WriteHint(Resource.MultiSelectForm_Message_Hint); } - var hasSelected = _paginator.TryGetSelectedItem(out var selectedItem); + var hasSelected = Paginator.TryGetSelectedItem(out var selectedItem); var comparer = EqualityComparer.Default; - foreach (var item in _paginator.CurrentItems) + foreach (var item in Paginator.CurrentItems) { var value = _options.TextSelector(item); var isChecked = _selectedItems.Contains(item); @@ -69,26 +58,22 @@ protected override void InputTemplate(OffscreenBuffer offscreenBuffer) if (hasSelected && comparer.Equals(item, selectedItem)) { - offscreenBuffer.WriteSelect($"{Prompt.Symbols.Selector} {(isChecked ? Prompt.Symbols.Selected : Prompt.Symbols.NotSelect)} {value}"); + offscreenBuffer.WriteSelect($"{Configuration.Symbols.Selector} {(isChecked ? Configuration.Symbols.Selected : Configuration.Symbols.NotSelect)} {value}"); } else { if (isChecked) { - offscreenBuffer.WriteSelect($" {Prompt.Symbols.Selected} {value}"); + offscreenBuffer.WriteSelect($" {Configuration.Symbols.Selected} {value}"); } else { - offscreenBuffer.Write($" {Prompt.Symbols.NotSelect} {value}"); + offscreenBuffer.Write($" {Configuration.Symbols.NotSelect} {value}"); } } } - if (_paginator.PageCount > 1) - { - offscreenBuffer.WriteLine(); - offscreenBuffer.WriteHint(_options.Pagination(_paginator.TotalCount, _paginator.CurrentPage + 1, _paginator.PageCount)); - } + RenderPagination(offscreenBuffer, _options.Pagination); } protected override void FinishTemplate(OffscreenBuffer offscreenBuffer, IEnumerable result) @@ -115,18 +100,9 @@ protected override bool HandleEnter([NotNullWhen(true)] out IEnumerable? resu return false; } - protected override bool HandleTextInput(ConsoleKeyInfo keyInfo) - { - base.HandleTextInput(keyInfo); - - _paginator.UpdateFilter(InputBuffer.ToString()); - - return true; - } - private bool HandleSpacebar() { - if (!_paginator.TryGetSelectedItem(out var currentItem)) + if (!Paginator.TryGetSelectedItem(out var currentItem)) { return false; } @@ -146,56 +122,15 @@ private bool HandleSpacebar() return true; } - private bool HandleUpArrow() - { - _paginator.PreviousItem(); - - return true; - } - - private bool HandleDownArrow() - { - _paginator.NextItem(); - - return true; - } - - private bool HandleLeftArrow() - { - _paginator.PreviousPage(); - - return true; - } - - private bool HandleRightArrow() - { - _paginator.NextPage(); - - return true; - } - - private bool HandleBackspace() - { - if (InputBuffer.IsStart) - { - return false; - } - - InputBuffer.Backspace(); - _paginator.UpdateFilter(InputBuffer.ToString()); - - return true; - } - private bool HandleCtrlA() { - if (_selectedItems.Count == _paginator.TotalCount) + if (_selectedItems.Count == Paginator.TotalCount) { _selectedItems.Clear(); } else { - foreach (var item in _paginator) + foreach (var item in Paginator) { _selectedItems.Add(item); } @@ -206,7 +141,7 @@ private bool HandleCtrlA() private bool HandleCtrlI() { - var invertedItems = _paginator.Except(_selectedItems).ToArray(); + var invertedItems = Paginator.Except(_selectedItems).ToArray(); _selectedItems.Clear(); diff --git a/Sharprompt/Forms/PasswordForm.cs b/Sharprompt/Forms/PasswordForm.cs index b633c51..a5692a0 100644 --- a/Sharprompt/Forms/PasswordForm.cs +++ b/Sharprompt/Forms/PasswordForm.cs @@ -8,16 +8,13 @@ namespace Sharprompt.Forms; internal class PasswordForm : FormBase { - public PasswordForm(PasswordOptions options) + public PasswordForm(PasswordOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); _options = options; - KeyHandlerMaps = new(KeyHandlerMaps) - { - [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace - }; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace; } private readonly PasswordOptions _options; diff --git a/Sharprompt/Forms/SelectForm.cs b/Sharprompt/Forms/SelectForm.cs index 6800ac4..0b862b7 100644 --- a/Sharprompt/Forms/SelectForm.cs +++ b/Sharprompt/Forms/SelectForm.cs @@ -7,44 +7,32 @@ namespace Sharprompt.Forms; -internal class SelectForm : FormBase where T : notnull +internal class SelectForm : SelectFormBase where T : notnull { - public SelectForm(SelectOptions options) + public SelectForm(SelectOptions options, PromptConfiguration configuration) : base(configuration) { options.EnsureOptions(); _options = options; - _paginator = new Paginator(options.Items, Math.Min(options.PageSize, Height - 2), Optional.Create(options.DefaultValue), options.TextSelector) - { - LoopingSelection = options.LoopingSelection - }; - KeyHandlerMaps = new(KeyHandlerMaps) - { - [new ConsoleKeyBinding(ConsoleKey.UpArrow)] = HandleUpArrow, - [new ConsoleKeyBinding(ConsoleKey.DownArrow)] = HandleDownArrow, - [new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow, - [new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow, - [new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace - }; + InitializePaginator(options.Items, options.PageSize, Optional.Create(options.DefaultValue), options.TextSelector, options.LoopingSelection); } private readonly SelectOptions _options; - private readonly Paginator _paginator; protected override void InputTemplate(OffscreenBuffer offscreenBuffer) { - _paginator.UpdatePageSize(Math.Min(_options.PageSize, Height - 2)); + Paginator.UpdatePageSize(Math.Min(_options.PageSize, Height - 2)); offscreenBuffer.WritePrompt(_options.Message); - offscreenBuffer.Write(_paginator.FilterKeyword); + offscreenBuffer.Write(Paginator.FilterKeyword); offscreenBuffer.PushCursor(); - var hasSelected = _paginator.TryGetSelectedItem(out var selectedItem); + var hasSelected = Paginator.TryGetSelectedItem(out var selectedItem); var comparer = EqualityComparer.Default; - foreach (var item in _paginator.CurrentItems) + foreach (var item in Paginator.CurrentItems) { var value = _options.TextSelector(item); @@ -52,7 +40,7 @@ protected override void InputTemplate(OffscreenBuffer offscreenBuffer) if (hasSelected && comparer.Equals(item, selectedItem)) { - offscreenBuffer.WriteSelect($"{Prompt.Symbols.Selector} {value}"); + offscreenBuffer.WriteSelect($"{Configuration.Symbols.Selector} {value}"); } else { @@ -60,11 +48,7 @@ protected override void InputTemplate(OffscreenBuffer offscreenBuffer) } } - if (_paginator.PageCount > 1) - { - offscreenBuffer.WriteLine(); - offscreenBuffer.WriteHint(_options.Pagination(_paginator.TotalCount, _paginator.CurrentPage + 1, _paginator.PageCount)); - } + RenderPagination(offscreenBuffer, _options.Pagination); } protected override void FinishTemplate(OffscreenBuffer offscreenBuffer, T result) @@ -75,7 +59,7 @@ protected override void FinishTemplate(OffscreenBuffer offscreenBuffer, T result protected override bool HandleEnter([NotNullWhen(true)] out T? result) { - if (_paginator.TryGetSelectedItem(out result)) + if (Paginator.TryGetSelectedItem(out result)) { return true; } @@ -84,54 +68,4 @@ protected override bool HandleEnter([NotNullWhen(true)] out T? result) return false; } - - protected override bool HandleTextInput(ConsoleKeyInfo keyInfo) - { - base.HandleTextInput(keyInfo); - - _paginator.UpdateFilter(InputBuffer.ToString()); - - return true; - } - - private bool HandleUpArrow() - { - _paginator.PreviousItem(); - - return true; - } - - private bool HandleDownArrow() - { - _paginator.NextItem(); - - return true; - } - - private bool HandleLeftArrow() - { - _paginator.PreviousPage(); - - return true; - } - - private bool HandleRightArrow() - { - _paginator.NextPage(); - - return true; - } - - private bool HandleBackspace() - { - if (InputBuffer.IsStart) - { - return false; - } - - InputBuffer.Backspace(); - _paginator.UpdateFilter(InputBuffer.ToString()); - - return true; - } } diff --git a/Sharprompt/Forms/SelectFormBase.cs b/Sharprompt/Forms/SelectFormBase.cs new file mode 100644 index 0000000..88c4350 --- /dev/null +++ b/Sharprompt/Forms/SelectFormBase.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; + +using Sharprompt.Internal; + +namespace Sharprompt.Forms; + +internal abstract class SelectFormBase : FormBase where TItem : notnull +{ + protected SelectFormBase(PromptConfiguration configuration) : base(configuration) + { + } + + protected Paginator Paginator { get; private set; } = null!; + + protected void InitializePaginator(IEnumerable items, int pageSize, Optional defaultValue, Func textSelector, bool loopingSelection) + { + Paginator = new Paginator(items, Math.Min(pageSize, Height - 2), defaultValue, textSelector) + { + LoopingSelection = loopingSelection + }; + + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.UpArrow)] = HandleUpArrow; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.DownArrow)] = HandleDownArrow; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.LeftArrow)] = HandleLeftArrow; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.RightArrow)] = HandleRightArrow; + KeyHandlerMaps[new ConsoleKeyBinding(ConsoleKey.Backspace)] = HandleBackspace; + } + + protected override bool HandleTextInput(ConsoleKeyInfo keyInfo) + { + InputBuffer.Insert(keyInfo.KeyChar); + + Paginator.UpdateFilter(InputBuffer.ToString()); + + return true; + } + + protected void RenderPagination(OffscreenBuffer offscreenBuffer, Func pagination) + { + if (Paginator.PageCount > 1) + { + offscreenBuffer.WriteLine(); + offscreenBuffer.WriteHint(pagination(Paginator.TotalCount, Paginator.CurrentPage + 1, Paginator.PageCount)); + } + } + + private bool HandleUpArrow() + { + Paginator.PreviousItem(); + + return true; + } + + private bool HandleDownArrow() + { + Paginator.NextItem(); + + return true; + } + + private bool HandleLeftArrow() + { + Paginator.PreviousPage(); + + return true; + } + + private bool HandleRightArrow() + { + Paginator.NextPage(); + + return true; + } + + private bool HandleBackspace() + { + if (InputBuffer.IsStart) + { + return false; + } + + InputBuffer.Backspace(); + + Paginator.UpdateFilter(InputBuffer.ToString()); + + return true; + } +} diff --git a/Sharprompt/Forms/TextFormBase.cs b/Sharprompt/Forms/TextFormBase.cs index 9ebfca7..33b784f 100644 --- a/Sharprompt/Forms/TextFormBase.cs +++ b/Sharprompt/Forms/TextFormBase.cs @@ -6,7 +6,7 @@ namespace Sharprompt.Forms; internal abstract class TextFormBase : FormBase { - protected TextFormBase() + protected TextFormBase(PromptConfiguration configuration) : base(configuration) { KeyHandlerMaps = new(KeyHandlerMaps) { diff --git a/Sharprompt/InputOptions.cs b/Sharprompt/InputOptions.cs index ba70cbb..6e967a3 100644 --- a/Sharprompt/InputOptions.cs +++ b/Sharprompt/InputOptions.cs @@ -4,18 +4,11 @@ namespace Sharprompt; -public class InputOptions +public class InputOptions : PromptOptions { - public string Message { get; set; } = null!; - public string? Placeholder { get; set; } public object? DefaultValue { get; set; } public IList> Validators { get; } = []; - - internal void EnsureOptions() - { - ArgumentNullException.ThrowIfNull(Message); - } } diff --git a/Sharprompt/Internal/OffscreenBuffer.cs b/Sharprompt/Internal/OffscreenBuffer.cs index 96bc6b4..17ee9ea 100644 --- a/Sharprompt/Internal/OffscreenBuffer.cs +++ b/Sharprompt/Internal/OffscreenBuffer.cs @@ -5,16 +5,18 @@ namespace Sharprompt.Internal; -internal class OffscreenBuffer : IDisposable +internal class OffscreenBuffer { - public OffscreenBuffer(IConsoleDriver consoleDriver) + public OffscreenBuffer(IConsoleDriver consoleDriver, PromptConfiguration configuration) { _consoleDriver = consoleDriver; + _configuration = configuration; _cursorBottom = _consoleDriver.CursorTop; } private readonly IConsoleDriver _consoleDriver; + private readonly PromptConfiguration _configuration; private readonly List> _outputBuffer = [[]]; private int _cursorBottom; @@ -23,6 +25,8 @@ public OffscreenBuffer(IConsoleDriver consoleDriver) private int _cachedWrittenLineCount; private int _cachedBufferWidth; + internal PromptConfiguration Configuration => _configuration; + private int WrittenLineCount { get @@ -56,8 +60,6 @@ private int WrittenLineCount } } - public void Dispose() { } - public void Write(string text) => Write(text, Console.ForegroundColor); public void Write(string text, ConsoleColor color) diff --git a/Sharprompt/Internal/OffscreenBufferExtensions.cs b/Sharprompt/Internal/OffscreenBufferExtensions.cs index 297d9c2..a4cee8b 100644 --- a/Sharprompt/Internal/OffscreenBufferExtensions.cs +++ b/Sharprompt/Internal/OffscreenBufferExtensions.cs @@ -4,23 +4,23 @@ internal static class OffscreenBufferExtensions { public static void WritePrompt(this OffscreenBuffer offscreenBuffer, string message) { - offscreenBuffer.Write(Prompt.Symbols.Prompt, Prompt.ColorSchema.PromptSymbol); + offscreenBuffer.Write(offscreenBuffer.Configuration.Symbols.Prompt, offscreenBuffer.Configuration.ColorSchema.PromptSymbol); offscreenBuffer.Write($" {message}: "); } public static void WriteDone(this OffscreenBuffer offscreenBuffer, string message) { - offscreenBuffer.Write(Prompt.Symbols.Done, Prompt.ColorSchema.DoneSymbol); + offscreenBuffer.Write(offscreenBuffer.Configuration.Symbols.Done, offscreenBuffer.Configuration.ColorSchema.DoneSymbol); offscreenBuffer.Write($" {message}: "); } - public static void WriteError(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write($"{Prompt.Symbols.Error} {message}", Prompt.ColorSchema.Error); + public static void WriteError(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write($"{offscreenBuffer.Configuration.Symbols.Error} {message}", offscreenBuffer.Configuration.ColorSchema.Error); - public static void WriteAnswer(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, Prompt.ColorSchema.Answer); + public static void WriteAnswer(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, offscreenBuffer.Configuration.ColorSchema.Answer); - public static void WriteSelect(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, Prompt.ColorSchema.Select); + public static void WriteSelect(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, offscreenBuffer.Configuration.ColorSchema.Select); - public static void WriteHint(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, Prompt.ColorSchema.Hint); + public static void WriteHint(this OffscreenBuffer offscreenBuffer, string message) => offscreenBuffer.Write(message, offscreenBuffer.Configuration.ColorSchema.Hint); public static void WriteInput(this OffscreenBuffer offscreenBuffer, TextInputBuffer textInputBuffer) { diff --git a/Sharprompt/ListOptions.cs b/Sharprompt/ListOptions.cs index b4e5110..bebf64a 100644 --- a/Sharprompt/ListOptions.cs +++ b/Sharprompt/ListOptions.cs @@ -6,10 +6,8 @@ namespace Sharprompt; -public class ListOptions where T : notnull +public class ListOptions : PromptOptions where T : notnull { - public string Message { get; set; } = null!; - public IEnumerable DefaultValues { get; set; } = []; public int Minimum { get; set; } = 1; @@ -18,9 +16,9 @@ public class ListOptions where T : notnull public IList> Validators { get; } = []; - internal void EnsureOptions() + internal override void EnsureOptions() { - ArgumentNullException.ThrowIfNull(Message); + base.EnsureOptions(); if (Minimum < 0) { diff --git a/Sharprompt/MultiSelectOptions.cs b/Sharprompt/MultiSelectOptions.cs index 92bd64a..5aa3afb 100644 --- a/Sharprompt/MultiSelectOptions.cs +++ b/Sharprompt/MultiSelectOptions.cs @@ -5,7 +5,7 @@ namespace Sharprompt; -public class MultiSelectOptions where T : notnull +public class MultiSelectOptions : PromptOptions where T : notnull { public MultiSelectOptions() { @@ -16,8 +16,6 @@ public MultiSelectOptions() } } - public string Message { get; set; } = null!; - public IEnumerable Items { get; set; } = null!; public IEnumerable DefaultValues { get; set; } = []; @@ -34,9 +32,10 @@ public MultiSelectOptions() public bool LoopingSelection { get; set; } = true; - internal void EnsureOptions() + internal override void EnsureOptions() { - ArgumentNullException.ThrowIfNull(Message); + base.EnsureOptions(); + ArgumentNullException.ThrowIfNull(Items); ArgumentNullException.ThrowIfNull(DefaultValues); ArgumentNullException.ThrowIfNull(TextSelector); diff --git a/Sharprompt/PasswordOptions.cs b/Sharprompt/PasswordOptions.cs index c97d4ef..54365ce 100644 --- a/Sharprompt/PasswordOptions.cs +++ b/Sharprompt/PasswordOptions.cs @@ -4,19 +4,18 @@ namespace Sharprompt; -public class PasswordOptions +public class PasswordOptions : PromptOptions { - public string Message { get; set; } = null!; - public string? Placeholder { get; set; } public string PasswordChar { get; set; } = "*"; public IList> Validators { get; } = []; - internal void EnsureOptions() + internal override void EnsureOptions() { - ArgumentNullException.ThrowIfNull(Message); + base.EnsureOptions(); + ArgumentNullException.ThrowIfNull(PasswordChar); } } diff --git a/Sharprompt/Prompt.Basic.cs b/Sharprompt/Prompt.Basic.cs index 2a12620..05d2d5f 100644 --- a/Sharprompt/Prompt.Basic.cs +++ b/Sharprompt/Prompt.Basic.cs @@ -11,7 +11,7 @@ public static partial class Prompt { public static T Input(InputOptions options) { - using var form = new InputForm(options); + using var form = new InputForm(options, s_configuration); return form.Start(); } @@ -39,7 +39,7 @@ public static T Input(string message, object? defaultValue = default, string? public static string Password(PasswordOptions options) { - using var form = new PasswordForm(options); + using var form = new PasswordForm(options, s_configuration); return form.Start(); } @@ -67,7 +67,7 @@ public static string Password(string message, string passwordChar = "*", string? public static bool Confirm(ConfirmOptions options) { - using var form = new ConfirmForm(options); + using var form = new ConfirmForm(options, s_configuration); return form.Start(); } @@ -92,7 +92,7 @@ public static bool Confirm(string message, bool? defaultValue = default) public static T Select(SelectOptions options) where T : notnull { - using var form = new SelectForm(options); + using var form = new SelectForm(options, s_configuration); return form.Start(); } @@ -129,7 +129,7 @@ public static T Select(string message, IEnumerable? items = default, int p public static IEnumerable MultiSelect(MultiSelectOptions options) where T : notnull { - using var form = new MultiSelectForm(options); + using var form = new MultiSelectForm(options, s_configuration); return form.Start(); } @@ -172,7 +172,7 @@ public static IEnumerable MultiSelect(string message, IEnumerable? item public static IEnumerable List(ListOptions options) where T : notnull { - using var form = new ListForm(options); + using var form = new ListForm(options, s_configuration); return form.Start(); } diff --git a/Sharprompt/Prompt.Configuration.cs b/Sharprompt/Prompt.Configuration.cs index d873494..34314de 100644 --- a/Sharprompt/Prompt.Configuration.cs +++ b/Sharprompt/Prompt.Configuration.cs @@ -8,18 +8,20 @@ namespace Sharprompt; public static partial class Prompt { - public static bool ThrowExceptionOnCancel { get; set; } = false; + internal static readonly PromptConfiguration s_configuration = new(); - private static Func s_consoleDriverFactory = () => new DefaultConsoleDriver(); + public static PromptConfiguration Configuration => s_configuration; + + public static bool ThrowExceptionOnCancel + { + get => s_configuration.ThrowExceptionOnCancel; + set => s_configuration.ThrowExceptionOnCancel = value; + } public static Func ConsoleDriverFactory { - get => s_consoleDriverFactory; - set - { - ArgumentNullException.ThrowIfNull(value); - s_consoleDriverFactory = value; - } + get => s_configuration.ConsoleDriverFactory; + set => s_configuration.ConsoleDriverFactory = value; } public static CultureInfo Culture @@ -28,24 +30,7 @@ public static CultureInfo Culture set => Resource.Culture = value; } - public static class ColorSchema - { - public static ConsoleColor DoneSymbol { get; set; } = ConsoleColor.Green; - public static ConsoleColor PromptSymbol { get; set; } = ConsoleColor.Green; - public static ConsoleColor Answer { get; set; } = ConsoleColor.Cyan; - public static ConsoleColor Select { get; set; } = ConsoleColor.Green; - public static ConsoleColor Error { get; set; } = ConsoleColor.Red; - public static ConsoleColor Hint { get; set; } = ConsoleColor.DarkGray; - public static ConsoleColor DisabledOption { get; set; } = ConsoleColor.DarkCyan; - } + public static PromptColorSchema ColorSchema => s_configuration.ColorSchema; - public static class Symbols - { - public static Symbol Prompt { get; set; } = new("?", "?"); - public static Symbol Done { get; set; } = new("✔", "V"); - public static Symbol Error { get; set; } = new("»", ">>"); - public static Symbol Selector { get; set; } = new("›", ">"); - public static Symbol Selected { get; set; } = new("◉", "(*)"); - public static Symbol NotSelect { get; set; } = new("◯", "( )"); - } + public static PromptSymbols Symbols => s_configuration.Symbols; } diff --git a/Sharprompt/PromptConfiguration.cs b/Sharprompt/PromptConfiguration.cs new file mode 100644 index 0000000..aef59ca --- /dev/null +++ b/Sharprompt/PromptConfiguration.cs @@ -0,0 +1,47 @@ +using System; + +using Sharprompt.Drivers; + +namespace Sharprompt; + +public class PromptConfiguration +{ + public bool ThrowExceptionOnCancel { get; set; } + + private Func _consoleDriverFactory = () => new DefaultConsoleDriver(); + + public Func ConsoleDriverFactory + { + get => _consoleDriverFactory; + set + { + ArgumentNullException.ThrowIfNull(value); + _consoleDriverFactory = value; + } + } + + public PromptColorSchema ColorSchema { get; } = new(); + + public PromptSymbols Symbols { get; } = new(); +} + +public class PromptColorSchema +{ + public ConsoleColor DoneSymbol { get; set; } = ConsoleColor.Green; + public ConsoleColor PromptSymbol { get; set; } = ConsoleColor.Green; + public ConsoleColor Answer { get; set; } = ConsoleColor.Cyan; + public ConsoleColor Select { get; set; } = ConsoleColor.Green; + public ConsoleColor Error { get; set; } = ConsoleColor.Red; + public ConsoleColor Hint { get; set; } = ConsoleColor.DarkGray; + public ConsoleColor DisabledOption { get; set; } = ConsoleColor.DarkCyan; +} + +public class PromptSymbols +{ + public Symbol Prompt { get; set; } = new("?", "?"); + public Symbol Done { get; set; } = new("✔", "V"); + public Symbol Error { get; set; } = new("»", ">>"); + public Symbol Selector { get; set; } = new("›", ">"); + public Symbol Selected { get; set; } = new("◉", "(*)"); + public Symbol NotSelect { get; set; } = new("◯", "( )"); +} diff --git a/Sharprompt/PromptOptions.cs b/Sharprompt/PromptOptions.cs new file mode 100644 index 0000000..fee305e --- /dev/null +++ b/Sharprompt/PromptOptions.cs @@ -0,0 +1,13 @@ +using System; + +namespace Sharprompt; + +public abstract class PromptOptions +{ + public string Message { get; set; } = null!; + + internal virtual void EnsureOptions() + { + ArgumentNullException.ThrowIfNull(Message); + } +} diff --git a/Sharprompt/SelectOptions.cs b/Sharprompt/SelectOptions.cs index 14c8c30..b5452bc 100644 --- a/Sharprompt/SelectOptions.cs +++ b/Sharprompt/SelectOptions.cs @@ -5,7 +5,7 @@ namespace Sharprompt; -public class SelectOptions where T : notnull +public class SelectOptions : PromptOptions where T : notnull { public SelectOptions() { @@ -16,8 +16,6 @@ public SelectOptions() } } - public string Message { get; set; } = null!; - public IEnumerable Items { get; set; } = null!; public object? DefaultValue { get; set; } @@ -30,9 +28,10 @@ public SelectOptions() public bool LoopingSelection { get; set; } = true; - internal void EnsureOptions() + internal override void EnsureOptions() { - ArgumentNullException.ThrowIfNull(Message); + base.EnsureOptions(); + ArgumentNullException.ThrowIfNull(Items); ArgumentNullException.ThrowIfNull(TextSelector); ArgumentNullException.ThrowIfNull(Pagination); From 850bbf99153cd4dda225df09771be5b2ba5357ed Mon Sep 17 00:00:00 2001 From: Tatsuro Shibamura Date: Thu, 5 Mar 2026 16:10:44 +0900 Subject: [PATCH 5/5] Delete global.json --- global.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 global.json diff --git a/global.json b/global.json deleted file mode 100644 index 14c6e50..0000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sdk": { - "version": "8.0.418", - "rollForward": "latestPatch" - } -}