Skip to content

feat: support free-form custom input in Select via CreateCustomItem (#336) - #434

Open
mkarimdev wants to merge 1 commit into
shibayan:masterfrom
mkarimdev:feat/issue-336-select-or-free-type
Open

mkarimdev wants to merge 1 commit into
shibayan:masterfrom
mkarimdev:feat/issue-336-select-or-free-type

Conversation

@mkarimdev

Copy link
Copy Markdown

Summary

Adds opt-in free-form input to Prompt.Select<T>, so a pick list can also accept a value that is not in the list. Fixes #336.

var fruit = Prompt.Select(options =>
{
    options.Message = "Fruit";
    options.Items = ["apple", "banana"];

    // Only called when Enter cannot resolve a listed item.
    options.CreateCustomItem = text => text.Trim();
});

Behavior

Resolution order on Enter is unchanged except for the new fallback:

  1. An explicitly highlighted item (↑/↓) always wins.
  2. An exact, case-insensitive text match wins.
  3. Otherwise, with CreateCustomItem set and non-empty typed text, the callback produces the result.
  4. Otherwise the existing validation error is shown.

Details:

  • CreateCustomItem defaults to null; when it is not set, every existing outcome, error message, and single-item auto-selection is preserved.
  • A single filtered item is not auto-selected while a callback is configured and text is typed. This lets a user type app and create it even when apple is the only match; pressing ↓ still selects apple. The same policy drives rendering, so the highlighted row and the Enter result cannot disagree.
  • Empty Items is accepted only when the callback is set. Without a callback it still throws ArgumentException.
  • A callback exception is shown as a prompt error and the prompt continues. A null return is rejected with Validation_Invalid.
  • The callback receives the raw typed text (no trim/case folding); the answer is rendered through TextSelector like any other item.
  • No reflection or TypeConverter use, so the feature is Native AOT safe.

MultiSelect is unchanged: the public Paginator.TryGetSelectedItem signature is retained and the new overload is internal.

API

  • SelectOptions<T>.CreateCustomItem (Func<string, T>?)
  • SelectOptionsExtensions.WithCreateCustomItem(...)

Tests

18 new tests:

  • PaginatorTests: auto-select on/off, exact match, explicit highlight, empty list.
  • FormInteractionTests: creation, exact-match and highlight precedence, partial match without a false highlight, empty filter, empty Items with/without callback, factory exception, null return, no-callback regression, custom TextSelector.
  • FluentExtensionsTests: option assignment and null-argument validation.

Sharprompt.Tests (484) and Sharprompt.SourceGenerator.Tests (210) pass in Release; dotnet format reports no changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestion: Pick from list *or* free type

1 participant