diff --git a/.agents/skills/pretty-console-expert/SKILL.md b/.agents/skills/pretty-console-expert/SKILL.md old mode 100644 new mode 100755 index a96f758..138a3b6 --- a/.agents/skills/pretty-console-expert/SKILL.md +++ b/.agents/skills/pretty-console-expert/SKILL.md @@ -7,18 +7,13 @@ description: Expert workflow for using PrettyConsole correctly and efficiently i ## Core Workflow -1. Verify the installed PrettyConsole version before coding. -- Read `Directory.Packages.props`, `*.csproj`, and/or run `dotnet list package`. -- Keep implementation compatible with the installed version; do not "fix" compilation by downgrading unless the user explicitly requests downgrading. - -2. Bring extension APIs into scope: +1. Bring extension APIs into scope: ```csharp using PrettyConsole; -using static System.Console; // optional ``` -3. Choose APIs by intent. +2. Choose APIs by intent. - Styled output: `Console.WriteInterpolated`, `Console.WriteLineInterpolated`. - Inputs/prompts: `Console.TryReadLine`, `Console.ReadLine`, `Console.Confirm`, `Console.RequestAnyInput`. - Dynamic rendering and line control: `Console.Overwrite`, `Console.ClearNextLines`, `Console.SkipLines`, `Console.NewLine`. @@ -27,7 +22,7 @@ using static System.Console; // optional - Menus/tables: `Console.Selection`, `Console.MultiSelection`, `Console.TreeMenu`, `Console.Table`. - Low-level override only: use `Console.Write(...)` / `Console.WriteLine(...)` span+`ISpanFormattable` overloads only when you intentionally bypass the handler for a custom formatting pipeline. -4. Route output deliberately. +3. Route output deliberately. - Keep normal prompts, menus, tables, durable user-facing output, and machine-readable non-error output on `OutputPipe.Out` unless there is a specific reason not to. - Use `OutputPipe.Error` for transient live UI and for actual errors/diagnostics/warnings so stdout stays pipe-friendly and error output remains distinguishable. - `LiveConsoleRegion` should usually live on `OutputPipe.Error` in interactive CLIs. Keep the durable lines that must coordinate with it flowing through the region instance instead of writing directly to the same pipe elsewhere. @@ -51,7 +46,7 @@ using static System.Console; // optional - Prefer `Color`, `Markup`, and guarded `AnsiToken` in styled output. Use `Color.*` for token-based color APIs such as `ProgressBar`, `Spinner`, `TypeWrite`, and `LiveConsoleRegion.RenderProgress`. Keep `ConsoleColor` for APIs that explicitly require it, such as low-level span writes or `Console.SetColors`. - Route transient UI (spinner/progress/overwrite loops) to `OutputPipe.Error` to keep stdout pipe-friendly, and use `OutputPipe.Error` for genuine errors/diagnostics. Keep ordinary non-error interaction flow on `OutputPipe.Out`. - Spinner/progress/overwrite output is caller-owned after rendering completes. Explicitly remove it with `Console.ClearNextLines(totalLines, pipe)` or intentionally keep the region with `Console.SkipLines(totalLines)`. -- `LiveConsoleRegion` is the right primitive when durable line output and transient status must interleave over time. It is line-oriented: use `WriteLine`, not inline writes, for cooperating durable output above the retained region. +- `LiveConsoleRegion` is the right primitive when durable line output and transient status must interleave over time. It is line-oriented: use `WriteLine`, not inline writes, for cooperating durable output above the retained region. Disposing the region clears the retained snapshot automatically; call `Clear()` only when the region should disappear before the object itself is disposed and you still want to reuse that same instance later. - Only use the bounded `Channel` snapshot pattern when multiple producers must update the same live region at high frequency. For single-producer or modest-rate updates, keep the rendering loop simple. ## Practical Patterns @@ -114,12 +109,12 @@ live.Render($"Resolving graph"); live.WriteLine($"Updated package-a"); live.RenderProgress(65, (builder, out handler) => handler = builder.Build(OutputPipe.Error, $"Compiling")); -live.Clear(); +live.Render($"Linking"); ``` ## Reference File -Read [references/v5-api-map.md](references/v5-api-map.md) when you need exact usage snippets, migration mapping from old APIs, or a compile-fix checklist. +Read [references/v6-api-map.md](references/v6-api-map.md) when you need exact usage snippets, migration mapping from old APIs, or a compile-fix checklist. Read [references/testing-with-consolecontext.md](references/testing-with-consolecontext.md) when the task involves testing a PrettyConsole-based CLI or command handler. If public API usage changes in the edited project, ask whether to update `README.md` and changelog/release-notes files. diff --git a/.agents/skills/pretty-console-expert/references/v5-api-map.md b/.agents/skills/pretty-console-expert/references/v6-api-map.md similarity index 63% rename from .agents/skills/pretty-console-expert/references/v5-api-map.md rename to .agents/skills/pretty-console-expert/references/v6-api-map.md index dc71729..a6082c7 100644 --- a/.agents/skills/pretty-console-expert/references/v5-api-map.md +++ b/.agents/skills/pretty-console-expert/references/v6-api-map.md @@ -1,30 +1,16 @@ -# PrettyConsole v5 API Map +# PrettyConsole v6 API Map -Use this file when implementing or reviewing PrettyConsole usage so code compiles against modern APIs and keeps allocation-conscious patterns. +Use this file when implementing or reviewing PrettyConsole usage so code compiles against the current surface and keeps the library's allocation-conscious patterns. -## 1. Version First - -Read installed version before coding: - -```bash -dotnet list package -rg -n "PrettyConsole" --glob "*.csproj" . -# optionally also check central package management if present: -# rg -n "PrettyConsole" Directory.Packages.props -``` - -If version and request conflict, keep the installed version and adapt code accordingly. - -## 2. Namespace and Setup +## 1. Namespace and Setup ```csharp using PrettyConsole; -using static System.Console; // optional ``` PrettyConsole methods are extension members on `System.Console`. -## 3. Correct Modern APIs +## 2. Correct v6 APIs - Styled writes: - `Console.WriteInterpolated(...)` @@ -39,6 +25,11 @@ PrettyConsole methods are extension members on `System.Console`. - `Console.ClearNextLines(...)` - `Console.SkipLines(...)` - `Console.NewLine(...)` +- Live retained UI: + - `LiveConsoleRegion.WriteLine(...)` + - `LiveConsoleRegion.Render(...)` + - `LiveConsoleRegion.RenderProgress(...)` + - `LiveConsoleRegion.Clear()` - Progress: - `ProgressBar.Update(...)` - `ProgressBar.Render(...)` @@ -52,9 +43,25 @@ PrettyConsole methods are extension members on `System.Console`. ### Output routing - Keep prompts, menus, tables, final user-facing output, and machine-readable non-error output on `OutputPipe.Out` unless you intentionally need a different split. -- Use `OutputPipe.Error` for transient live UI and for actual errors/diagnostics/warnings so stdout remains pipe-friendly and error output stays distinct. +- Use `OutputPipe.Error` for transient live UI and for actual errors, diagnostics, and warnings so stdout remains pipe-friendly and error output stays distinct. +- `LiveConsoleRegion` should usually live on `OutputPipe.Error` in interactive CLIs. Keep durable lines that must coordinate with it flowing through the region instance instead of writing directly to the same pipe elsewhere. +- Disposing a `LiveConsoleRegion` clears the retained snapshot and then permanently closes the region. Call `Clear()` only when you want to remove the current snapshot but keep the region instance reusable for later renders. - Avoid mixing a single interactive exchange across `Out` and `Error` unless the split is intentional. +### Interpolated-handler styling model + +- Prefer `Color`, `Markup`, and guarded `AnsiToken` inside interpolation holes: + + ```csharp + Console.WriteLineInterpolated($"{Color.Green}ready{Color.Default}"); + Console.WriteLineInterpolated($"{Markup.Bold}build{Markup.ResetBold} complete"); + ``` + +- `ConsoleColor` interpolation still works for compatibility, but `Color.*` is the primary v6 surface for styled output. +- For APIs that explicitly take `AnsiToken`, use `Color.*` or `new AnsiToken("...")`. +- Do not embed raw escape sequences directly in string literals. Keep ANSI inside interpolation holes so PrettyConsole can isolate the token safely. +- If you must branch on ANSI capability outside the guarded token model, use `ConsoleContext.IsAnsiSupported`. + ### Interpolated-handler special formats - `TimeSpan` with `:duration`: @@ -84,31 +91,32 @@ Use these only when intentionally bypassing the interpolated handler for a custo ### New lines and blank lines - Use `Console.NewLine(pipe)` when the intent is only to end the current line or emit a blank line. -- Do not use `Console.WriteLineInterpolated($"")` or payloads like `$"{ConsoleColor.Default}"` just to force a newline. +- Do not use `Console.WriteLineInterpolated($"")` or reset-only payloads such as `$"{Color.Default}"` just to force a newline. - Use `WriteLineInterpolated(...)` when you are actually writing content and also want the trailing newline. -## 4. Old -> New Migration Table +## 3. Old -> New Migration Table - `IndeterminateProgressBar` -> `Spinner` - `AnimationSequence` -> `Pattern` - `ProgressBar.WriteProgressBar` -> `ProgressBar.Render` - `PrettyConsoleExtensions` -> `ConsoleContext` -- Legacy `ColoredOutput`/`Color` types -> `ConsoleColor` helpers and tuples +- Legacy `ColoredOutput`/`Color` types -> `Color`, `Markup`, `AnsiToken`, and `ConsoleColor` compatibility where the API explicitly asks for it +- `Markup` and `AnsiColors` raw string expectations -> guarded `AnsiToken` values -## 5. Compile-Safe Patterns +## 4. Compile-Safe Patterns ### Styled output ```csharp -Console.WriteInterpolated($"[{ConsoleColor.Cyan}info{ConsoleColor.Default}] {message}"); -Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Red}error{ConsoleColor.Default}: {message}"); +Console.WriteInterpolated($"[{Color.Cyan}info{Color.Default}] {message}"); +Console.WriteLineInterpolated(OutputPipe.Error, $"{Color.Red}error{Color.Default}: {message}"); Console.NewLine(); ``` ### Typed input ```csharp -if (!Console.TryReadLine(out int port, $"Port ({ConsoleColor.Green}5000{ConsoleColor.Default}): ")) +if (!Console.TryReadLine(out int port, $"Port ({Color.Green}5000{Color.Default}): ")) port = 5000; ``` @@ -126,9 +134,9 @@ static string PromptSelection(string title, string[] options) { while (selection.Length == 0) { Console.Overwrite(() => { - selection = Console.Selection(options, $"{ConsoleColor.Cyan}{title}{ConsoleColor.DefaultForeground}:"); + selection = Console.Selection(options, $"{Color.Cyan}{title}{Color.DefaultForeground}:"); if (selection.Length == 0) - Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Red}Invalid choice."); + Console.WriteLineInterpolated(OutputPipe.Error, $"{Color.Red}Invalid choice.{Color.Default}"); }, lines: options.Length + 3, pipe: OutputPipe.Out); } @@ -152,7 +160,7 @@ var workTask = Task.Run(async () => { var spinner = new Spinner(); await spinner.RunAsync(workTask, (builder, out handler) => { var current = Math.Min(Volatile.Read(ref step), steps.Length - 1); - handler = builder.Build(OutputPipe.Error, $"Current step: {ConsoleColor.Green}{steps[current]}"); + handler = builder.Build(OutputPipe.Error, $"Current step: {Color.Green}{steps[current]}"); }); ``` @@ -162,20 +170,34 @@ Use this when the spinner header should reflect concurrently changing state with ```csharp Console.Overwrite(percent, static current => { - ProgressBar.Render(OutputPipe.Error, current, ConsoleColor.Cyan, maxLineWidth: 40); + ProgressBar.Render(OutputPipe.Error, current, Color.Cyan, maxLineWidth: 40); Console.NewLine(OutputPipe.Error); - Console.WriteInterpolated(OutputPipe.Error, $"Downloading assets... {ConsoleColor.Cyan}{current}"); + Console.WriteInterpolated(OutputPipe.Error, $"Downloading assets... {Color.Cyan}{current}{Color.Default}"); }, lines: 2, pipe: OutputPipe.Error); ``` Prefer this shape for live `status + progress` regions. It keeps the state explicit, avoids closure allocations, and makes the rendered height obvious. +### Retained live region + +```csharp +using var live = new LiveConsoleRegion(OutputPipe.Error); + +live.Render($"Resolving graph"); +live.WriteLine($"Fetched package-a"); +live.RenderProgress(65, (builder, out handler) => + handler = builder.Build(OutputPipe.Error, $"Compiling {Color.Cyan}core{Color.Default}")); +live.Render($"Linking {Color.Cyan}core{Color.Default}"); +``` + +Prefer `LiveConsoleRegion` when durable lines must keep flowing above a pinned transient line on the same pipe over time. + ### Overwrite loop cleanup ```csharp Console.Overwrite(() => { Console.WriteLineInterpolated(OutputPipe.Error, $"Running..."); - ProgressBar.Render(OutputPipe.Error, percent, ConsoleColor.Cyan); + ProgressBar.Render(OutputPipe.Error, percent, Color.Cyan); }, lines: 2, pipe: OutputPipe.Error); Console.ClearNextLines(2, OutputPipe.Error); @@ -221,12 +243,13 @@ Why this works: For single-producer or modest-rate updates, prefer a simpler render loop without the channel. -## 6. Performance Checklist +## 5. Performance Checklist - Prefer interpolated handlers over string concatenation. -- Treat span/formattable `Write`/`WriteLine` overloads as advanced escape hatches, not default app-level APIs. -- Use `Console.NewLine(pipe)` for bare line breaks instead of empty/reset-only `WriteLineInterpolated(...)` calls. -- Keep ANSI/decorations in interpolation holes, not raw literal spans. -- Use `OutputPipe.Error` for transient rendering and genuine errors/diagnostics, but keep ordinary non-error interaction flow on `OutputPipe.Out`. +- Treat span/formattable `Write` and `WriteLine` overloads as advanced escape hatches, not default app-level APIs. +- Use `Console.NewLine(pipe)` for bare line breaks instead of empty or reset-only `WriteLineInterpolated(...)` calls. +- Keep ANSI and decorations in interpolation holes, not raw literal spans. +- Use `Color.*` for token-based color APIs such as `ProgressBar`, `Spinner`, `TypeWrite`, and `LiveConsoleRegion.RenderProgress`. +- Use `OutputPipe.Error` for transient rendering and genuine errors or diagnostics, but keep ordinary non-error interaction flow on `OutputPipe.Out`. - Clean up live UI explicitly after the last frame with `ClearNextLines(...)` or keep it intentionally with `SkipLines(...)`. - Avoid introducing wrapper abstractions when direct PrettyConsole APIs already solve the task. diff --git a/AGENTS.md b/AGENTS.md index 04cdab0..b8f0c3a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,7 +10,7 @@ Summary - PrettyConsole.Tests/ — interactive/demo runner (manually selects visual feature demos) - PrettyConsole.UnitTests/ — TUnit-based automated tests run with `dotnet run` - Examples/ — standalone `.cs` sample apps plus `assets/` previews; documented in `Examples/README.md` and excluded from automated builds/tests -- v6.0.0 (current) follows released `v5.4.2` directly. It adds `LiveConsoleRegion`, introduces `Color`/`Markup`/`AnsiToken` as the preferred styled-output model, extends that model to `ProgressBar`, `Spinner`, `TypeWrite`, and `LiveConsoleRegion.RenderProgress`, and adds `ConsoleContext.IsAnsiSupported` for ANSI capability checks. `Markup` and `AnsiColors` now expose `AnsiToken` values instead of raw strings. v5.4.0 renamed `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. +- v6.0.1 (current) follows released `v6.0.0` directly and keeps the same public API surface while fixing shipped docs/skill guidance. v6.0.0 added `LiveConsoleRegion`, introduced `Color`/`Markup`/`AnsiToken` as the preferred styled-output model, extended that model to `ProgressBar`, `Spinner`, `TypeWrite`, and `LiveConsoleRegion.RenderProgress`, and added `ConsoleContext.IsAnsiSupported` for ANSI capability checks. `Markup` and `AnsiColors` now expose `AnsiToken` values instead of raw strings. v5.4.0 renamed `IndeterminateProgressBar` to `Spinner` (and `AnimationSequence` to `Pattern`), triggers the line reset at the start of each spinner frame, gives all `RunAsync` overloads default cancellation tokens, and renames `ProgressBar.WriteProgressBar` to `Render` while adding handler-factory overloads and switching header parameters to `string`. It still passes handlers by `ref`, adds `AppendInline`, and introduces the ctor that takes only `OutputPipe` + optional `IFormatProvider`; `SkipLines` advances the cursor while keeping overwritten UIs; `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` has the boolean last; spinner header factories use `PrettyConsoleInterpolatedStringHandlerFactory` with the singleton builder; `AnsiColors` is public. v5.2.0 rewrote the handler to buffer before writing and added `WhiteSpace`; v5.1.0 renamed `PrettyConsoleExtensions` to `ConsoleContext`, added `Console.WriteWhiteSpaces(length, pipe)`, and made `Out`/`Error`/`In` settable; v5.0.0 removed the legacy `ColoredOutput`/`Color` types in favor of `ConsoleColor` helpers and tuples. Commands you’ll use often @@ -69,15 +69,15 @@ High-level architecture and key concepts - Inputs - `ReadLine`/`TryReadLine` support `IParsable` types, optional defaults, enum parsing with `ignoreCase`, and interpolated prompts. `Confirm` exposes `DefaultConfirmValues`, overloads for custom truthy tokens, and interpolated prompts; `RequestAnyInput` blocks on `ReadKey` with colored prompts if desired. - Rendering controls - - `ClearNextLines`, `GoToLine`, `GetCurrentLine`, and `SkipLines` coordinate bounded screen regions; `Clear` wipes the buffer when safe. `SkipLines` lets you advance the cursor to preserve overwritten UIs (progress bars, spinners) after completion. These helpers underpin progress rendering and overwrite scenarios. + - `ClearNextLines`, `GoToLine`, `GetCurrentLine`, and `SkipLines` coordinate bounded screen regions. `SkipLines` lets you advance the cursor to preserve overwritten UIs (progress bars, spinners) after completion. These helpers underpin progress rendering and overwrite scenarios. - Advanced outputs - - `OverwriteCurrentLine`, `Overwrite`, and `Overwrite` run user actions while clearing a configurable number of lines. Set the `lines` argument to however many rows you emit during the action (e.g., the multi-progress sample uses `lines: 2`) and call `Console.ClearNextLines` once after the last overwrite to remove residual UI. `TypeWrite`/`TypeWriteLine` animate character-by-character output with adjustable delays. + - `Overwrite` and `Overwrite` run user actions while clearing a configurable number of lines. Set the `lines` argument to however many rows you emit during the action (e.g., the multi-progress sample uses `lines: 2`) and call `Console.ClearNextLines` once after the last overwrite to remove residual UI. `TypeWrite`/`TypeWriteLine` animate character-by-character output with adjustable delays. - Live regions - `LiveConsoleRegion` owns one retained live region on a single `OutputPipe` and coordinates it with durable line output on that same pipe. Use `WriteLine` for durable lines that should stream above the retained region, `Render` for arbitrary transient snapshots, `RenderProgress` as the built-in progress convenience, and `Clear`/`Dispose` to remove the region. Treat it as a cooperating-writers abstraction: output that must coordinate with the live region should flow through the region instance rather than writing directly to the same pipe behind its back. - Menus and tables - `Selection` returns a single choice or empty string on invalid input; `MultiSelection` parses space-separated indices into string arrays; `TreeMenu` renders two-level hierarchies and validates input (throwing `ArgumentException` when selections are invalid); `Table` renders headers + columns with width calculations. - Progress bars - - `Spinner` (formerly `IndeterminateProgressBar`) binds to running `Task` instances, optionally starts tasks, supports cancellable `RunAsync` overloads with default tokens, exposes `Pattern` (formerly `AnimationSequence`), `Patterns`, `ForegroundColor`, `DisplayElapsedTime`, and `UpdateRate`. Frames render on the error pipe and auto-clear. Header factories use `PrettyConsoleInterpolatedStringHandlerFactory`; call `(builder, out handler) => handler = builder.Build(OutputPipe.Error, $"status")` with the singleton `PrettyConsoleInterpolatedStringHandlerBuilder`. + - `Spinner` (formerly `IndeterminateProgressBar`) binds to running `Task` instances, optionally starts tasks, supports cancellable `RunAsync` overloads with default tokens, exposes `Pattern` (formerly `AnimationSequence`), `Patterns`, `ForegroundColor`, `DisplayElapsedTime`, and `UpdateRate`. Frames render on the error pipe, clear at the start of each repaint, and leave the final row visible until the caller clears or keeps it. Header factories use `PrettyConsoleInterpolatedStringHandlerFactory`; call `(builder, out handler) => handler = builder.Build(OutputPipe.Error, $"status")` with the singleton `PrettyConsoleInterpolatedStringHandlerBuilder`. - `ProgressBar` maintains a single-line bar on the error pipe. `Update` accepts `int`/`double` percentages plus optional status spans, and exposes `ProgressChar`, `ForegroundColor`, and `ProgressColor` for customization. The static `ProgressBar.Render` helper (renamed from `WriteProgressBar`) renders one-off segments without moving the cursor, so you can stack multiple bars within an `Overwrite` block. It now also has overloads that accept `PrettyConsoleInterpolatedStringHandlerFactory` for low-allocation headers. - Packaging and targets - `PrettyConsole.csproj` targets net10.0, enables trimming/AOT (`IsTrimmable`, `IsAotCompatible`), embeds SourceLink, and grants `InternalsVisibleTo` the unit-test project. diff --git a/Examples/README.md b/Examples/README.md index 2f24121..008cfc9 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -2,7 +2,7 @@ These are simple examples of UIs that can be achieved by properly using the APIs that `PrettyConsole` provides. The examples are written using .NET 10 file-based apps, and can be run with `dotnet run example.cs` (change to the specific "app" name that you want). -- Please keep in mind that colors in the recordings might not appear exactly like their name in code (i.e `ConsoleColor.Green` may be a different color in the recordings), this is not an issue with the package, it is the because themes are used in the environment of the recordings, and they override how colors are rendered. +- Please keep in mind that colors in the recordings might not appear exactly like their name in code (for example `Color.Green` may look different in the recording). This is not an issue with the package; terminal themes in the recording environment can override how colors are rendered. ## [Interactive menu](interactive-menu.cs) diff --git a/Examples/brew-style-downloads.cs b/Examples/brew-style-downloads.cs index 188283c..43104a7 100644 --- a/Examples/brew-style-downloads.cs +++ b/Examples/brew-style-downloads.cs @@ -1,4 +1,4 @@ -#:package PrettyConsole@5.4.0 +#:package PrettyConsole@6.0.0 using PrettyConsole; @@ -23,10 +23,10 @@ foreach (var download in downloads) { int written = 0; if (download.IsComplete) { - written += Console.WriteInterpolated(OutputPipe.Error, $"{ConsoleColor.Green}✔︎{ConsoleColor.DefaultForeground} {download.Name}") - 1; + written += Console.WriteInterpolated(OutputPipe.Error, $"{Color.Green}✔︎{Color.Default} {download.Name}") - 1; // I remove 1 from written here because "✔︎" is 2 characters long but renders a single block in the terminal } else { - written += Console.WriteInterpolated(OutputPipe.Error, $"{ConsoleColor.Green}{spinner[spinnerIndex]}{ConsoleColor.DefaultForeground} {download.Name}"); + written += Console.WriteInterpolated(OutputPipe.Error, $"{Color.Green}{spinner[spinnerIndex]}{Color.Default} {download.Name}"); } var current = (double)download.BytesDownloaded; @@ -51,7 +51,7 @@ Console.ClearNextLines(count, OutputPipe.Error); } -Console.WriteLineInterpolated($"{ConsoleColor.Green}Done!{ConsoleColor.DefaultForeground}"); +Console.WriteLineInterpolated($"{Color.Green}Done!"); /// /// Represents a single download in a "brew" style feed with progress tracking. diff --git a/Examples/compilation-spinner.cs b/Examples/compilation-spinner.cs index b4ae9ed..af4e1c7 100644 --- a/Examples/compilation-spinner.cs +++ b/Examples/compilation-spinner.cs @@ -1,4 +1,4 @@ -#:package PrettyConsole@5.4.0 +#:package PrettyConsole@6.0.0 using System.Diagnostics; using PrettyConsole; @@ -22,15 +22,15 @@ var spinner = new Spinner { Pattern = Spinner.Patterns.Braille, - ForegroundColor = ConsoleColor.Green, + ForegroundColor = Color.Green, DisplayElapsedTime = true, UpdateRate = 100, }; await spinner.RunAsync(build, (builder, out handler) => { var current = Volatile.Read(ref step); - handler = builder.Build(OutputPipe.Error, $"Current step: {ConsoleColor.Green}{steps[current]}"); + handler = builder.Build(OutputPipe.Error, $"Current step: {Color.Green}{steps[current]}"); }, CancellationToken.None); var elapsed = Stopwatch.GetElapsedTime(start); -Console.WriteLineInterpolated($"Build complete in {ConsoleColor.Green}{elapsed:duration}"); +Console.WriteLineInterpolated($"Build complete in {Color.Green}{elapsed:duration}"); diff --git a/Examples/interactive-menu.cs b/Examples/interactive-menu.cs index fc2e364..cd390b6 100644 --- a/Examples/interactive-menu.cs +++ b/Examples/interactive-menu.cs @@ -1,4 +1,4 @@ -#:package PrettyConsole@5.4.0 +#:package PrettyConsole@6.0.0 using PrettyConsole; @@ -14,7 +14,7 @@ title: "Pick region", options: ["us-east", "us-west", "eu-central"]); -Console.WriteLineInterpolated($"{ConsoleColor.Green}Ready to deploy!"); +Console.WriteLineInterpolated($"{Color.Green}Ready to deploy!"); Console.WriteLineInterpolated($"Environment: {Markup.Underline}{environment}{Markup.ResetUnderline}"); Console.WriteLineInterpolated($"Features: {Markup.Underline}{string.Join(", ", features)}{Markup.ResetUnderline}"); Console.WriteLineInterpolated($"Region: {Markup.Underline}{region}{Markup.ResetUnderline}"); @@ -27,9 +27,9 @@ static string PromptSelection(string title, string[] options) { while (selection.Length == 0) { Console.Overwrite(() => { - selection = Console.Selection(options, $"{ConsoleColor.Cyan}{title}{ConsoleColor.DefaultForeground}:"); + selection = Console.Selection(options, $"{Color.Cyan}{title}{Color.Default}:"); if (selection.Length == 0) { - Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Red}Invalid choice. Try again."); + Console.WriteLineInterpolated(OutputPipe.Error, $"{Color.Red}Invalid choice. Try again."); } }, lines: options.Length + 3, pipe: OutputPipe.Out); } @@ -42,9 +42,9 @@ static string[] PromptMultiSelection(string title, string[] options) { while (selection.Length == 0) { Console.Overwrite(() => { - selection = Console.MultiSelection(options, $"{ConsoleColor.Cyan}{title}{ConsoleColor.DefaultForeground}:"); + selection = Console.MultiSelection(options, $"{Color.Cyan}{title}{Color.Default}:"); if (selection.Length == 0) { - Console.WriteLineInterpolated(OutputPipe.Error, $"{ConsoleColor.Red}Please pick at least one option."); + Console.WriteLineInterpolated(OutputPipe.Error, $"{Color.Red}Please pick at least one option."); } }, lines: options.Length + 3, pipe: OutputPipe.Out); } diff --git a/Examples/progress-with-status.cs b/Examples/progress-with-status.cs index e89b8c4..a592da3 100644 --- a/Examples/progress-with-status.cs +++ b/Examples/progress-with-status.cs @@ -1,13 +1,13 @@ -#:package PrettyConsole@5.4.0 +#:package PrettyConsole@6.0.0 using PrettyConsole; Console.CursorVisible = false; for (int i = 0; i <= 100; i += 4) { Console.Overwrite(i, static ii => { - ProgressBar.Render(OutputPipe.Error, ii, ConsoleColor.Cyan, maxLineWidth: 40); + ProgressBar.Render(OutputPipe.Error, ii, Color.Cyan, maxLineWidth: 40); Console.NewLine(OutputPipe.Error); - Console.WriteInterpolated(OutputPipe.Error, $"Downloading assets... {ConsoleColor.Cyan}{ii}"); + Console.WriteInterpolated(OutputPipe.Error, $"Downloading assets... {Color.Cyan}{ii}"); }, lines: 2, pipe: OutputPipe.Error); await Task.Delay(70); @@ -15,4 +15,4 @@ Console.CursorVisible = true; Console.ClearNextLines(2, OutputPipe.Error); -Console.WriteLineInterpolated($"{ConsoleColor.Green}Download complete!"); +Console.WriteLineInterpolated($"{Color.Green}Download complete!"); diff --git a/PrettyConsole/LiveConsoleRegion.cs b/PrettyConsole/LiveConsoleRegion.cs index 85a73bf..d157068 100644 --- a/PrettyConsole/LiveConsoleRegion.cs +++ b/PrettyConsole/LiveConsoleRegion.cs @@ -4,6 +4,7 @@ namespace PrettyConsole; /// /// Manages a retained transient console region on a single output pipe while coordinating durable writes above it. +/// Disposing the region clears the retained snapshot and permanently closes the instance. /// public sealed class LiveConsoleRegion : IDisposable { private const int InitialSnapshotCapacity = 256; @@ -132,7 +133,8 @@ public void RenderProgress( } /// - /// Clears the retained region from the console and discards the current snapshot. + /// Clears the retained region from the console and discards the current snapshot without disposing the region. + /// Call this when the pinned region should disappear before the region instance itself goes out of scope and you still intend to reuse it later. /// public void Clear() { lock (_lock) { @@ -149,21 +151,13 @@ public void Clear() { } } - /// + /// + /// Clears any retained snapshot and permanently closes the region. + /// After disposal, the region can no longer be rendered to or written through. + /// public void Dispose() { - lock (_lock) { - if (_disposed) { - return; - } - - if (_isVisible) { - ClearVisibleOnly(); - } - - _snapshot.Clear(); - OccupiedLines = 0; - _disposed = true; - } + Clear(); + _disposed = true; } private void ClearVisibleOnly() { diff --git a/PrettyConsole/PrettyConsole.csproj b/PrettyConsole/PrettyConsole.csproj index 578602b..8f1f88b 100755 --- a/PrettyConsole/PrettyConsole.csproj +++ b/PrettyConsole/PrettyConsole.csproj @@ -25,7 +25,7 @@ https://github.com/dusrdev/PrettyConsole/ https://github.com/dusrdev/PrettyConsole/ git - 6.0.0 + 6.0.1 enable true MIT @@ -44,16 +44,14 @@ - - Added LiveConsoleRegion for retained live output on one pipe. - - Added Color and AnsiToken as the preferred styled-output color model. - - Added token-based color support across ProgressBar, Spinner, TypeWrite, and live-region progress rendering. - - Added Windows ANSI capability detection for styled output. - - BREAKING: Markup and AnsiColors now expose guarded AnsiToken values instead of raw strings. + - Updated the shipped PrettyConsole skill and README guidance to match the v6 API surface. + - Removed the stale packaged v5 skill reference and added payload cleanup for existing consumers. + - Clarified LiveConsoleRegion lifecycle guidance, including when Dispose versus Clear should be used. - + @@ -62,6 +60,9 @@ PrettyConsoleExpert .agents/skills/pretty-console-expert + + PrettyConsoleExpert + diff --git a/README.md b/README.md index e34121d..950bcd6 100755 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ if (!Console.TryReadLine(out DayOfWeek day, ignoreCase: true, $"Day? ")) { var apiKey = Console.ReadLine($"Enter API key ({DarkGray}optional{Default}): "); ``` -All input helpers work with `IParsable` and enums, respect the active culture, and honor `OutputPipe` when prompts are colored. +All input helpers work with `IParsable` and enums, respect the active culture, and render prompts through PrettyConsole's normal output path. ### Advanced inputs @@ -223,7 +223,7 @@ Always call `Console.ClearNextLines(totalLines, pipe)` once after the last `Over ### Live console regions -`LiveConsoleRegion` is useful when status lines should continue streaming normally while a pinned transient line keeps updating at the bottom. +`LiveConsoleRegion` is useful when status lines should continue streaming normally while a pinned transient line keeps updating at the bottom. In normal usage, disposing the region removes the retained snapshot for you, so a `using` block is usually all the cleanup you need. Call `Clear()` only when you want the pinned region to disappear before the region instance itself goes out of scope and you still plan to reuse that same instance later. ```csharp using var live = new LiveConsoleRegion(OutputPipe.Error); @@ -234,12 +234,10 @@ live.WriteLine($"Updated package-b"); live.RenderProgress(42, (builder, out handler) => handler = builder.Build(OutputPipe.Error, $"Compiling")); - live.Render($"Linking {elapsed:duration}"); -live.Clear(); ``` -Use `WriteLine` for lines that should scroll above the live region, `Render` for transient snapshots, and `RenderProgress` when you want the built-in progress bar inside the region. In interactive CLIs, `OutputPipe.Error` is usually the right pipe so stdout stays machine-friendly. +Use `WriteLine` for lines that should scroll above the live region, `Render` for transient snapshots, and `RenderProgress` when you want the built-in progress bar inside the region. `Dispose()` is the usual end-of-life cleanup and clears the retained snapshot before the region becomes unusable. `Clear()` is different: it removes the current snapshot but leaves the region usable for a later `Render(...)` or `RenderProgress(...)`, which is mainly useful when one phase should temporarily remove the pinned region before a later phase reuses the same instance. In interactive CLIs, `OutputPipe.Error` is usually the right pipe so stdout stays machine-friendly. ### Menus and tables diff --git a/Versions.md b/Versions.md index da8b923..faa08a9 100755 --- a/Versions.md +++ b/Versions.md @@ -1,5 +1,14 @@ # Versions +## v6.0.1 + +### Changed + +- Updated the shipped `pretty-console-expert` skill and its references so the packaged guidance reflects the v6 API surface. +- Removed the stale packaged `v5-api-map.md` skill reference and added package cleanup for consumers that already received it. +- Clarified `LiveConsoleRegion` lifecycle docs so examples use `Dispose()` as the normal cleanup path and describe `Clear()` as the reusable mid-scope hide case. +- Refreshed README and file-based example guidance to match the current `Color`/`Markup`/`AnsiToken`-first model and the current package version. + ## v6.0.0 ### Added @@ -48,7 +57,7 @@ - Is now passed by `ref` to accepting methods. - Added `SkipLines` which can be used to move the cursor `n` amount of lines forward. This can be used to keep the output of overwritten lines, like progress bars, spinners, `OverWrite` and so on and forth. - `Confirm(trueValues, ref handler, bool emptyIsTrue = true)` parameters were reordered, `emptyIsTrue` is now the last parameter. -- `IndeterminateProgressBar` overloads with the `Func` now use `PrettyConsoleInterpolatedStringHandlerFactory` instead, and usage is now `(builder, out handler) => handler = PrettyConsoleInterpolatedStringHandler.Build(...)`. This was required to reduce compiler created struct copies and increase safety. +- `IndeterminateProgressBar` overloads with the `Func` now use `PrettyConsoleInterpolatedStringHandlerFactory` instead, and usage is now `(builder, out handler) => handler = builder.Build(OutputPipe.Error, $"...")`. This was required to reduce compiler created struct copies and increase safety. - Building custom handlers is now done with `PrettyConsoleInterpolatedStringHandlerBuilder` which contains a thread-safe singleton; `PrettyConsoleInterpolatedStringHandler.Build` was removed in favor of using the builder. - `AnsiColors` which provides static utilities to convert `ConsoleColor` to `ANSI` sequences is now public (was previously internal) @@ -62,8 +71,8 @@ - `Console.WriteInterpolated` and `Console.WriteLineInterpolated` now return a `int` that contains the number of characters written using the handler. This could be used to help calculate paddings or other things when creating structured output. - It will ignore escape sequences that were added using the handler like `ConsoleColor`, `Color`, `Markup`, or any guarded `AnsiToken`, but if you hardcode your own they might be taken into account. As such, if you do this, I recommend first checking the length without using those helpers, then using this result for the calculation. -- `PrettyConsoleExtensions` that contains the `Out`, `Err`, `In`, etc... was renamed to `ConsoleContext`. -- The standard `Out`, `Err`, `In` streams now have a public setter, so end users could mock it in their own tests. +- `PrettyConsoleExtensions` that contains the `Out`, `Error`, `In`, etc... was renamed to `ConsoleContext`. +- The standard `Out`, `Error`, `In` streams now have a public setter, so end users could mock them in their own tests. - `Console.WriteWhiteSpaces(length, OutputPipe)` was added to reduce the complexity of using the `TextWriter` extension. ## v5.0.0 - .NET 10+