PrettyConsole 4.0.0
See the version list below for details.
dotnet add package PrettyConsole --version 4.0.0
NuGet\Install-Package PrettyConsole -Version 4.0.0
<PackageReference Include="PrettyConsole" Version="4.0.0" />
<PackageVersion Include="PrettyConsole" Version="4.0.0" />
<PackageReference Include="PrettyConsole" />
paket add PrettyConsole --version 4.0.0
#r "nuget: PrettyConsole, 4.0.0"
#:package PrettyConsole@4.0.0
#addin nuget:?package=PrettyConsole&version=4.0.0
#tool nuget:?package=PrettyConsole&version=4.0.0
PrettyConsole
An abstraction over System.Console that adds new input and output methods, colors and advanced outputs like progress bars and menus. And everything is ansi supported so it works on legacy systems and terminals.
Features
- 🚀 High performance, low allocations and span-first APIs
- 🪶 Very lightweight (no external dependencies)
- ✨ Zero-allocation interpolated string handler for inline colors and formatting
- 💾 Supports legacy ANSI terminals (like Windows 7)
- 🔥 Complete NativeAOT compatibility
- Supports all major platforms (Windows, Linux, Mac)
- ⛓ Uses original output pipes, so that your CLI's can be piped properly
Installation 
dotnet add package PrettyConsole
Usage
Everything starts off with the using statements, I recommend using the Console statically
using static PrettyConsole.Console; // Access to all Console methods
using PrettyConsole; // Access to the Color struct and OutputPipe enum
Interpolated Strings
PrettyConsoleInterpolatedStringHandler lets you stream interpolated text directly to the selected pipe without allocating intermediate strings, while still using the familiar $"..." syntax.
Write($"Hello {Color.Green}world{Color.Default}!");
Write(OutputPipe.Error, $"{Color.Yellow}Warning:{Color.Default} {message}");
if (!TryReadLine(out int choice, $"Pick option {Color.Cyan}1-5{Color.Default}: ")) {
WriteLine($"{Color.Red}Not a number.{Color.Default}");
}
Colors reset automatically at the end of each call. Use Color.Default (or explicit background tuples) when you need to restore colors mid-string.
ColoredOutput
PrettyConsole uses an equation inspired syntax to colorize text. The syntax is as follows:
WriteLine("Test" * Color.Red / Color.Blue);
i.e TEXT * FOREGROUND / BACKGROUND
Any the 2 colors can be played with just like a real equation, omit the foreground and the default will be used, same goes for the background.
Basic Outputs
The most basic method for outputting is Write, which has multiple overloads. All equivalents exist for WriteLine:
// Usage + overload highlights:
Write($"Interpolated {Color.Blue}string{Color.Default}");
Write(OutputPipe.Error, $"...");
Write(ColoredOutput output, OutputPipe pipe = OutputPipe.Out);
Write(ReadOnlySpan<ColoredOutput> outputs, OutputPipe pipe = OutputPipe.Out);
Write(ReadOnlySpan<char> span, OutputPipe pipe, ConsoleColor foreground);
Write(ReadOnlySpan<char> span, OutputPipe pipe, ConsoleColor foreground, ConsoleColor background);
Write<T>(T value, OutputPipe pipe = OutputPipe.Out) where T : ISpanFormattable;
Write<T>(T value, OutputPipe pipe, ConsoleColor foreground, ConsoleColor background,
ReadOnlySpan<char> format, IFormatProvider? provider);
Overload for WriteLine are available with the same parameters
Basic Inputs
These are the methods for reading user input:
// Examples:
string? ReadLine(); // ReadLine<string>
string? ReadLine(ReadOnlySpan<ColoredOutput>);
string? ReadLine($"Prompt {Color.Green}text{Color.Default}: ");
T? ReadLine<T>(ReadOnlySpan<ColoredOutput>); // T : IParsable<T>
T? ReadLine<T>($"Prompt {Color.Cyan}text{Color.Default}: ");
T ReadLine<T>(ReadOnlySpan<ColoredOutput>, T @default); // @default will be returned if parsing fails
T ReadLine<T>(T @default, $"Prompt {Color.Cyan}text{Color.Default}: ");
bool TryReadLine<T>(ReadOnlySpan<ColoredOutput>, out T?); // T : IParsable<T>
bool TryReadLine<T>(out T?, $"Prompt {Color.Cyan}text{Color.Default}: ");
bool TryReadLine<T>(ReadOnlySpan<ColoredOutput>, T @default, out T); // @default will be returned if parsing fails
bool TryReadLine<T>(out T, T @default, $"Prompt {Color.Cyan}text{Color.Default}: ");
bool TryReadLine<TEnum>(ReadOnlySpan<ColoredOutput>, bool ignoreCase, out TEnum?); // TEnum : struct, Enum
bool TryReadLine<TEnum>(out TEnum, bool ignoreCase, $"Prompt {Color.Cyan}text{Color.Default}: "); // TEnum : struct, Enum
bool TryReadLine<TEnum>(ReadOnlySpan<ColoredOutput>, bool ignoreCase, TEnum @default, out TEnum); // @default will be returned if parsing fails
bool TryReadLine<TEnum>(out TEnum, bool ignoreCase, TEnum @default, $"Prompt {Color.Cyan}text{Color.Default}: ");
I always recommend using TryReadLine instead of ReadLine as you need to maintain less null checks and the result,
especially with @default is much more concise.
Advanced Inputs
These are some special methods for inputs:
// These will wait for the user to press any key
void RequestAnyInput(string message = "Press any key to continue...");
void RequestAnyInput(ReadOnlySpan<ColoredOutput> output);
RequestAnyInput($"Press {Color.Yellow}any key{Color.Default} to continue...");
// These request confirmation by special input from user
bool Confirm(ReadOnlySpan<ColoredOutput> message); // uses the default values ["y", "yes"]
// the default values can also be used by you at Console.DefaultConfirmValues
bool Confirm(ReadOnlySpan<ColoredOutput> message, ReadOnlySpan<string> trueValues, bool emptyIsTrue = true);
bool Confirm($"Deploy to production? ({Color.Green}y{Color.Default}/{Color.Red}n{Color.Default}) ");
bool Confirm(ReadOnlySpan<string> trueValues, bool emptyIsTrue, $"Overwrite existing files? ");
Rendering Controls
To aid in rendering and building your own complex outputs, there are many methods that simplify some processes.
ClearNextLines(int lines, OutputPipe pipe = OutputPipe.Error); // clears the next lines
NewLine(OutputPipe pipe = OutputPipe.Out); // outputs a new line
SetColors(ConsoleColor foreground, ConsoleColor background); // sets the colors of the console output
ResetColors(); // resets the colors of the console output
int GetCurrentLine(); // returns the current line number
GoToLine(int line); // moves the cursor to the specified line
Combining ClearNextLines with GoToLine will enable you to efficiently use the same space in the console for continuous output, such as progress outputting, for some cases there are also built-in methods for this, more on that later.
Advanced Outputs
// This method will essentially write a line, clear it, go back to same position
// This allows a form of text-only progress bar
void OverwriteCurrentLine(ReadOnlySpan<ColoredOutput> output, OutputPipe pipe = OutputPipe.Error);
void Overwrite(Action action, int lines = 1, OutputPipe pipe = OutputPipe.Error);
void Overwrite<TState>(TState state, Action<TState> action, int lines = 1, OutputPipe pipe = OutputPipe.Error)
where TState : allows ref struct;
// This methods will write a character at a time, with a delay between each character
async Task TypeWrite(ColoredOutput output, int delay = TypeWriteDefaultDelay);
async Task TypeWriteLine(ColoredOutput output, int delay = TypeWriteDefaultDelay);
Menus
// This prints an index view of the list, allows the user to select by index
// returns the actual choice that corresponds to the index
string Selection<TList>(ReadOnlySpan<ColoredOutput> title, TList choices) where TList : IList<string> {}
// Same as selection but allows the user to select multiple indexes
// Separated by spaces, and returns an array of the actual choices that correspond to the indexes
string[] MultiSelection<TList>(ReadOnlySpan<ColoredOutput> title, TList choices) where TList : IList<string> {}
// This prints a tree menu of 2 levels, allows the user to select the index
// Of the first and second level and returns the corresponding choices
(string option, string subOption) TreeMenu<TList>(ReadOnlySpan<ColoredOutput> title,
Dictionary<string, TList> menu) where TList : IList<string> {}
// This prints a table with headers, and columns for each list
void Table<TList>(TList headers, ReadOnlySpan<TList> columns) where TList : IList<string> {}
Progress Bars
There are two types of progress bars here, they both are implemented using a class to maintain states.
IndeterminateProgressBar
var prg = new IndeterminateProgressBar(); // this setups the internal states
// Then you need to provide either a Task or Task</T>, the progress bar binds to it and runs until the task completes
await prg.RunAsync(task, "Running...", cancellationToken); // There are also overloads without header
// if the task is not started before being passed to the progress bar, it will be started automatically
// It is even better this way to synchronize the runtime of the progress bar with the task
prg.AnimationSequence = IndeterminateProgressBar.Patterns.CarriageReturn; // customize the animation
ProgressBar
ProgressBar is a more powerful version, but requires a percentage of progress.
// ProgressBar implements IDisposable
var prg = new ProgressBar();
// then on each time the progress percentage is actually changed, you call Update
Update(percentage, ReadOnlySpan<char> status);
// There are also overloads without header, and percentage can be either int or double (0-100)
// Also, you can change some of the visual properties of the progress bar after initialization
// by using the properties of the ProgressBar class
prg.ProgressChar = '■'; // Character to fill the progress bar
prg.ForegroundColor = Color.Red; // Color of the empty part
prg.ProgressColor = Color.Blue; // The color of the filled part
Pipes
Console wraps over System.Console and uses its In, Out, and Error streams. Since the names of the classes are identical, combining them in usage is somewhat painful as the compiler doesn't know which overloads to use. To aid in most cases,
Console exposes those streams as static properties, and you can use them directly.
In rare cases, you will need something that there is in System.Console but not in Console, such as ReadKey, or SetCursorPosition, some events or otherwise, then you can simply call System.Console, this added verbosity is a worthy trade-off.
Contributing
This project uses an MIT license, if you want to contribute, you can do so by forking the repository and creating a pull request.
If you have feature requests or bug reports, please create an issue.
Contact
For bug reports, feature requests or offers of support/sponsorship contact dusrdev@gmail.com
This project is proudly made in Israel 🇮🇱 for the benefit of mankind.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 5.4.0 | 0 | 12/11/2025 | |
| 5.3.0 | 199 | 12/4/2025 | |
| 5.2.0 | 103 | 11/29/2025 | |
| 5.1.0 | 189 | 11/24/2025 | |
| 5.0.0 | 165 | 11/15/2025 | |
| 4.1.0 | 144 | 10/25/2025 | |
| 4.0.0 | 174 | 10/21/2025 | |
| 3.1.0 | 456 | 11/14/2024 | |
| 3.0.0 | 3,717 | 10/21/2024 | |
| 3.0.0-rc.2 | 98 | 10/16/2024 | |
| 3.0.0-rc.1 | 91 | 10/11/2024 | |
| 2.1.1 | 238 | 8/25/2024 | |
| 2.1.0 | 235 | 8/23/2024 | |
| 2.0.0 | 294 | 3/2/2024 | |
| 1.6.1 | 379 | 6/30/2023 | |
| 1.6.0 | 337 | 6/26/2023 | |
| 1.5.2 | 385 | 4/14/2023 | |
| 1.5.1 | 499 | 12/21/2022 | |
| 1.5.0 | 547 | 12/4/2022 | |
| 1.4.0 | 638 | 8/4/2022 | |
| 1.3.0 | 599 | 7/14/2022 | |
| 1.2.0 | 587 | 7/5/2022 | |
| 1.1.0 | 598 | 6/18/2022 | |
| 1.0.2 | 633 | 6/14/2022 | |
| 1.0.1 | 647 | 6/14/2022 | |
| 1.0.0 | 654 | 6/12/2022 |
- Dropped Sharpify as a dependency - PrettyConsole is now self-sufficient.
- Many overloads were added that support the new PrettyConsoleInterpolatedStringHandler,
enabling zero allocation formatted outputs.
- Fixed issue that could sometimes cause writing into buffers beyond their bounds -
throwing an exception.
- IndeterminateProgressBar will now allow customization of the animated sequence via
the property AnimationSequence, and it also includes an inner class Patterns that
contains some constant sequences that could be used with it.
- IndeterminateProgressBar.UpdateRate is 200 ms by default.
- IndeterminateProgressBar header is now positioned right of the animation. Similar to
common CLIs.
- ProgressBar had numeral optimizations and should perform better in all scenarios.
- Color received 2 new implicit operators, enabling it to convert a combination with any object
to ColoredOutput, which means you can write much less verbose statements with .ToString() calls.
- Internal buffer pooling system was upgraded to further reduce allocations and relief more pressure from the GC.
- Write/WriteLine overload for T, will no longer throw an exception when a capacity above 256 characters is required to format the type, and also support ref structs.