Add Spectre.Console integration for rich terminal output#9
Merged
carldebilly merged 9 commits intomainfrom Mar 17, 2026
Merged
Conversation
Introduces a new extension package that provides: - SpectreInteractionHandler: rich prompts (SelectionPrompt, MultiSelectionPrompt, ConfirmationPrompt, TextPrompt, Secret) replacing the built-in arrow-key menus - IAnsiConsole DI injection for commands to use Spectre renderables (tables, trees, panels, markup) - SpectreHumanOutputTransformer: "spectre" output format rendering collections as bordered Spectre tables Usage: services.AddSpectreConsole() + app.UseSpectreConsole()
Comprehensive sample with 14 commands: tour (guided walkthrough), list (auto-rendered table), detail (Panel+Grid), chart (BarChart+ BreakdownChart), tree, json (JsonText), path (TextPath+Columns), calendar, figlet (FigletText), status (spinner), progress (bars), add/configure/login (Spectre-powered prompts via IReplInteractionChannel). Also fix banner rendering for custom output formats: both TryRenderBannerAsync and ShouldRenderBanner hardcoded "human" as the only banner-eligible format, so banners never appeared with Spectre. Added OutputOptions.BannerFormats (ISet<string>) so custom formats like "spectre" can opt in, and UseSpectreConsole() registers itself. The sample banner now uses IAnsiConsole to render a FigletText header.
Introduce SpectreConsoleOptions with a configurable Unicode property so terminals that lack Unicode support can opt out: .UseSpectreConsole(o => o.Unicode = false) Force Console.OutputEncoding to UTF-8 when Unicode is enabled, fixing progress bars, spinners and box-drawing characters that rendered as '?' on Windows due to the default code page. Both SessionAnsiConsole factory methods now apply options through a single ApplyOptions helper, ready for future capability settings.
- samples/07-spectre/README.md: full guide with command reference, features coverage table, integration paths, and configuration - src/Repl.Spectre/README.md: updated with SpectreConsoleOptions, banner IAnsiConsole injection, prompt mapping table, setup guide - README.md: add Repl.Spectre to packages table, sample 07 to learning path, interaction doc to documentation index - docs/architecture.md: add Repl.Spectre to project boundaries - docs/interaction.md: add Spectre.Console integration section
… catches - Fix MapBackToOriginalIndex returning 0 instead of -1 on no-match, which silently included the first choice in multi-selection results - Add using declaration on StringWriter in RenderToString - Replace generic catch clauses with specific exception types (IOException, PlatformNotSupportedException, InvalidOperationException) - Use explicit .Where() filter instead of if-in-foreach - Add Repl.SpectreTests project with unit tests for the bug and helpers - Add BannerFormats unit tests in Repl.Tests
Move the swap of the default item to index 0 before building the SelectionPrompt and calling AddChoices, since Spectre copies items at call time and ignores subsequent list mutations.
When AskSecretOptions is null, the Spectre handler was calling Secret(mask: null) which hides all keystroke feedback. The core framework defaults Mask to '*', so the Spectre handler should match that behavior.
Add remarks explaining the process-wide shared state and the refactoring path if per-app isolation is needed in the future.
Distinguish between no options (default to '*') and explicit Mask = null (invisible input with no echo), matching the contract defined by AskSecretOptions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Repl.Spectrepackage providing Spectre.Console integration for REPL applications that want rich terminal renderingSpectreHumanOutputTransformer: renders objects as bordered tables, grids with label-value pairs, and color-codedIReplResultmessages (green for success, red for error, yellow for validation/not found, etc.)SpectreInteractionHandler: handles interactive prompts (single/multi selection, confirmation, text input, secret input, clear screen) using Spectre.Console widgets, with automatic fallback toUnhandledfor hosted sessions or redirected inputSessionAnsiConsole: per-sessionIAnsiConsoleisolation routing output throughReplSessionIO, supporting both live terminal and string-capture rendering modesSpectreConsoleOptions: configurable Unicode support for Spectre renderingSpectreReplExtensions.UseSpectreConsole(): single extension method to register the transformer, interaction handler, and banner format in one callBannerFormatsonOutputOptions: extensible set of output format names eligible for banner rendering, replacing the previous hardcoded"human"check — allows custom formats like"spectre"to display banners_Abort→Abort) for Spectre display and maps selections back to original indices07-spectredemonstrating 21 Spectre.Console features including tables, panels, trees, bar charts, calendars, Figlet text, and interactive promptsMapBackToOriginalIndexreturning 0 instead of -1 on no-match, which silently included the wrong choice in multi-selection resultsusingon disposableStringWriter