diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 61af9540..df0f204a 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,8 +1,5 @@ # Use file scoped namespace declarations 7b2da0a4f63bf3ceab99d2c88535e74155f2b99c -# Fix line-endings +# fix line-endings e2ad4b1ea5555e701cda4fd400bb6592e318e1ff - -# Modernization of code base (extension blocks) -3f57df5af667beeaab128d865a8818c246af8ea1 \ No newline at end of file diff --git a/build.cs b/build.cs index a4dae10a..81da16f4 100644 --- a/build.cs +++ b/build.cs @@ -21,7 +21,10 @@ Task("Clean") Task("Lint") .Does(ctx => { - ctx.DotNetFormatStyle(solution); + ctx.DotNetFormatStyle(solution, new DotNetFormatSettings + { + VerifyNoChanges = true, + }); }); Task("Build") diff --git a/src/.editorconfig b/src/.editorconfig index 3372de8b..bf817945 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -1,12 +1,6 @@ -[*.cs] -# ======================================================== -# Temporarily disable warnings related to extension blocks -# ======================================================== -dotnet_diagnostic.RCS1139.severity = none -dotnet_diagnostic.RCS1263.severity = none -dotnet_diagnostic.CS1572.severity = none -dotnet_diagnostic.CA1510.severity = warning +root = false +[*.cs] # Prefer file scoped namespace declarations csharp_style_namespace_declarations = file_scoped:warning diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 12edbf01..0eecf4ad 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,4 +1,4 @@ - + true 14 @@ -14,12 +14,6 @@ true $(MSBuildThisFileDirectory)\..\resources\spectre.snk 00240000048000009400000006020000002400005253413100040000010001006146d3789d31477cf4a3b508dcf772ff9ccad8613f6bd6b17b9c4a960a7a7b551ecd22e4f4119ced70ee8bbdf3ca0a117c99fd6248c16255ea9033110c2233d42e74e81bf4f3f7eb09bfe8b53ad399d957514f427171a86f5fe9fe0014be121d571c80c4a0cfc3531bdbf5a2900d936d93f2c94171b9134f7644a1ac3612a0d0 - true - - - - - $(NoWarn);AD0001 diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index d799e93d..e5b973e6 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -4,7 +4,7 @@ - + @@ -18,12 +18,12 @@ - + - + diff --git a/src/Extensions/Spectre.Console.ImageSharp/CanvasImageExtensions.cs b/src/Extensions/Spectre.Console.ImageSharp/CanvasImageExtensions.cs index 5b0e93ae..0da36c36 100644 --- a/src/Extensions/Spectre.Console.ImageSharp/CanvasImageExtensions.cs +++ b/src/Extensions/Spectre.Console.ImageSharp/CanvasImageExtensions.cs @@ -8,100 +8,127 @@ namespace Spectre.Console; /// public static class CanvasImageExtensions { + /// + /// Sets the maximum width of the rendered image. + /// /// The canvas image. - extension(CanvasImage image) + /// The maximum width. + /// The same instance so that multiple calls can be chained. + public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) { - /// - /// Sets the maximum width of the rendered image. - /// - /// The maximum width. - /// The same instance so that multiple calls can be chained. - public CanvasImage MaxWidth(int? maxWidth) + if (image is null) { - ArgumentNullException.ThrowIfNull(image); - - image.MaxWidth = maxWidth; - return image; + throw new ArgumentNullException(nameof(image)); } - /// - /// Disables the maximum width of the rendered image. - /// - /// The same instance so that multiple calls can be chained. - public CanvasImage NoMaxWidth() - { - ArgumentNullException.ThrowIfNull(image); + image.MaxWidth = maxWidth; + return image; + } - image.MaxWidth = null; - return image; + /// + /// Disables the maximum width of the rendered image. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage NoMaxWidth(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); } - /// - /// Sets the pixel width. - /// - /// The pixel width. - /// The same instance so that multiple calls can be chained. - public CanvasImage PixelWidth(int width) - { - ArgumentNullException.ThrowIfNull(image); + image.MaxWidth = null; + return image; + } - image.PixelWidth = width; - return image; + /// + /// Sets the pixel width. + /// + /// The canvas image. + /// The pixel width. + /// The same instance so that multiple calls can be chained. + public static CanvasImage PixelWidth(this CanvasImage image, int width) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); } - /// - /// Mutates the underlying image. - /// - /// The action that mutates the underlying image. - /// The same instance so that multiple calls can be chained. - public CanvasImage Mutate(Action action) + image.PixelWidth = width; + return image; + } + + /// + /// Mutates the underlying image. + /// + /// The canvas image. + /// The action that mutates the underlying image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage Mutate(this CanvasImage image, Action action) + { + if (image is null) { - ArgumentNullException.ThrowIfNull(image); - - ArgumentNullException.ThrowIfNull(action); - - image.Image.Mutate(action); - return image; + throw new ArgumentNullException(nameof(image)); } - /// - /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). - /// - /// The same instance so that multiple calls can be chained. - public CanvasImage BicubicResampler() + if (action is null) { - ArgumentNullException.ThrowIfNull(image); - - image.Resampler = KnownResamplers.Bicubic; - return image; + throw new ArgumentNullException(nameof(action)); } - /// - /// Uses a bilinear sampler. This interpolation algorithm - /// can be used where perfect image transformation with pixel matching is impossible, - /// so that one can calculate and assign appropriate intensity values to pixels. - /// - /// The same instance so that multiple calls can be chained. - public CanvasImage BilinearResampler() - { - ArgumentNullException.ThrowIfNull(image); + image.Image.Mutate(action); + return image; + } - image.Resampler = KnownResamplers.Triangle; - return image; + /// + /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage BicubicResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); } - /// - /// Uses a Nearest-Neighbour sampler that implements the nearest neighbor algorithm. - /// This uses a very fast, unscaled filter which will select the closest pixel to - /// the new pixels position. - /// - /// The same instance so that multiple calls can be chained. - public CanvasImage NearestNeighborResampler() - { - ArgumentNullException.ThrowIfNull(image); + image.Resampler = KnownResamplers.Bicubic; + return image; + } - image.Resampler = KnownResamplers.NearestNeighbor; - return image; + /// + /// Uses a bilinear sampler. This interpolation algorithm + /// can be used where perfect image transformation with pixel matching is impossible, + /// so that one can calculate and assign appropriate intensity values to pixels. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage BilinearResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); } + + image.Resampler = KnownResamplers.Triangle; + return image; + } + + /// + /// Uses a Nearest-Neighbour sampler that implements the nearest neighbor algorithm. + /// This uses a very fast, unscaled filter which will select the closest pixel to + /// the new pixels position. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage NearestNeighborResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.Resampler = KnownResamplers.NearestNeighbor; + return image; } } \ No newline at end of file diff --git a/src/Extensions/Spectre.Console.Json/JsonTextExtensions.cs b/src/Extensions/Spectre.Console.Json/JsonTextExtensions.cs index db8b46e7..634d72ac 100644 --- a/src/Extensions/Spectre.Console.Json/JsonTextExtensions.cs +++ b/src/Extensions/Spectre.Console.Json/JsonTextExtensions.cs @@ -5,241 +5,309 @@ namespace Spectre.Console.Json; /// public static class JsonTextExtensions { + /// + /// Sets the style used for braces. + /// /// The JSON text instance. - extension(JsonText text) + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BracesStyle(this JsonText text, Style? style) { - /// - /// Sets the style used for braces. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText BracesStyle(Style style) + if (text == null) { - ArgumentNullException.ThrowIfNull(text); - - text.BracesStyle = style; - return text; + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for brackets. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText BracketStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.BracesStyle = style; + return text; + } - text.BracketsStyle = style; - return text; + /// + /// Sets the style used for brackets. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BracketStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for member names. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText MemberStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.BracketsStyle = style; + return text; + } - text.MemberStyle = style; - return text; + /// + /// Sets the style used for member names. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText MemberStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for colons. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText ColonStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.MemberStyle = style; + return text; + } - text.ColonStyle = style; - return text; + /// + /// Sets the style used for colons. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText ColonStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for commas. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText CommaStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.ColonStyle = style; + return text; + } - text.CommaStyle = style; - return text; + /// + /// Sets the style used for commas. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText CommaStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for string literals. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText StringStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.CommaStyle = style; + return text; + } - text.StringStyle = style; - return text; + /// + /// Sets the style used for string literals. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText StringStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for number literals. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText NumberStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.StringStyle = style; + return text; + } - text.NumberStyle = style; - return text; + /// + /// Sets the style used for number literals. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText NumberStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for boolean literals. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText BooleanStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.NumberStyle = style; + return text; + } - text.BooleanStyle = style; - return text; + /// + /// Sets the style used for boolean literals. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BooleanStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the style used for null literals. - /// - /// The style to set. - /// The same instance so that multiple calls can be chained. - public JsonText NullStyle(Style? style) - { - ArgumentNullException.ThrowIfNull(text); + text.BooleanStyle = style; + return text; + } - text.NullStyle = style; - return text; + /// + /// Sets the style used for null literals. + /// + /// The JSON text instance. + /// The style to set. + /// The same instance so that multiple calls can be chained. + public static JsonText NullStyle(this JsonText text, Style? style) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for braces. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText BracesColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.NullStyle = style; + return text; + } - text.BracesStyle = new Style(color); - return text; + /// + /// Sets the color used for braces. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BracesColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for brackets. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText BracketColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.BracesStyle = new Style(color); + return text; + } - text.BracketsStyle = new Style(color); - return text; + /// + /// Sets the color used for brackets. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BracketColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for member names. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText MemberColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.BracketsStyle = new Style(color); + return text; + } - text.MemberStyle = new Style(color); - return text; + /// + /// Sets the color used for member names. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText MemberColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for colons. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText ColonColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.MemberStyle = new Style(color); + return text; + } - text.ColonStyle = new Style(color); - return text; + /// + /// Sets the color used for colons. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText ColonColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for commas. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText CommaColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.ColonStyle = new Style(color); + return text; + } - text.CommaStyle = new Style(color); - return text; + /// + /// Sets the color used for commas. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText CommaColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for string literals. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText StringColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.CommaStyle = new Style(color); + return text; + } - text.StringStyle = new Style(color); - return text; + /// + /// Sets the color used for string literals. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText StringColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for number literals. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText NumberColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.StringStyle = new Style(color); + return text; + } - text.NumberStyle = new Style(color); - return text; + /// + /// Sets the color used for number literals. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText NumberColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for boolean literals. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText BooleanColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.NumberStyle = new Style(color); + return text; + } - text.BooleanStyle = new Style(color); - return text; + /// + /// Sets the color used for boolean literals. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText BooleanColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the color used for null literals. - /// - /// The color to set. - /// The same instance so that multiple calls can be chained. - public JsonText NullColor(Color color) - { - ArgumentNullException.ThrowIfNull(text); + text.BooleanStyle = new Style(color); + return text; + } - text.NullStyle = new Style(color); - return text; + /// + /// Sets the color used for null literals. + /// + /// The JSON text instance. + /// The color to set. + /// The same instance so that multiple calls can be chained. + public static JsonText NullColor(this JsonText text, Color color) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); } + + text.NullStyle = new Style(color); + return text; } } \ No newline at end of file diff --git a/src/Extensions/Spectre.Console.Json/Properties/Usings.cs b/src/Extensions/Spectre.Console.Json/Properties/Usings.cs index 22d00926..bd90d278 100644 --- a/src/Extensions/Spectre.Console.Json/Properties/Usings.cs +++ b/src/Extensions/Spectre.Console.Json/Properties/Usings.cs @@ -1,3 +1,4 @@ global using System.Text; +global using Spectre.Console.Internal; global using Spectre.Console.Json.Syntax; global using Spectre.Console.Rendering; \ No newline at end of file diff --git a/src/Extensions/Spectre.Console.Json/Spectre.Console.Json.csproj b/src/Extensions/Spectre.Console.Json/Spectre.Console.Json.csproj index cbf71ca5..13c4279f 100644 --- a/src/Extensions/Spectre.Console.Json/Spectre.Console.Json.csproj +++ b/src/Extensions/Spectre.Console.Json/Spectre.Console.Json.csproj @@ -11,20 +11,13 @@ true - - Internal\Polyfills.cs - - - + + - - - - diff --git a/src/Polyfills.cs b/src/Polyfills.cs deleted file mode 100644 index 53adf145..00000000 --- a/src/Polyfills.cs +++ /dev/null @@ -1,15 +0,0 @@ -#if NETSTANDARD -namespace Spectre.Console; - -internal static class Polyfills -{ - extension(CancellationTokenSource cts) - { - public Task CancelAsync() - { - cts.Cancel(); - return Task.CompletedTask; - } - } -} -#endif \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Extensions/ShouldlyExtensions.cs b/src/Spectre.Console.Testing/Extensions/ShouldlyExtensions.cs index 4cb6cc52..4f1d8172 100644 --- a/src/Spectre.Console.Testing/Extensions/ShouldlyExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/ShouldlyExtensions.cs @@ -5,25 +5,25 @@ namespace Spectre.Console.Testing; /// public static class ShouldlyExtensions { - /// The object to operate on. + /// + /// Performs the specified action on the given object and then returns the object. + /// Useful for fluent testing patterns where additional assertions or operations + /// are chained together in a readable manner. + /// /// The type of the object. - extension(T item) + /// The object to operate on. + /// An action to perform on the object. + /// The original object, to allow further chaining. + /// Thrown if is null. + [DebuggerStepThrough] + public static T And(this T item, Action action) { - /// - /// Performs the specified action on the given object and then returns the object. - /// Useful for fluent testing patterns where additional assertions or operations - /// are chained together in a readable manner. - /// - /// An action to perform on the object. - /// The original object, to allow further chaining. - /// Thrown if is null. - [DebuggerStepThrough] - public T And(Action action) + if (action == null) { - ArgumentNullException.ThrowIfNull(action); - - action(item); - return item; + throw new ArgumentNullException(nameof(action)); } + + action(item); + return item; } } \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Extensions/StringExtensions.cs b/src/Spectre.Console.Testing/Extensions/StringExtensions.cs index dc56063c..72c0cd86 100644 --- a/src/Spectre.Console.Testing/Extensions/StringExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/StringExtensions.cs @@ -5,42 +5,40 @@ namespace Spectre.Console.Testing; /// public static class StringExtensions { + /// + /// Returns a new string with all lines trimmed of trailing whitespace. + /// /// The string to trim. - extension(string value) + /// A new string with all lines trimmed of trailing whitespace. + public static string TrimLines(this string value) { - /// - /// Returns a new string with all lines trimmed of trailing whitespace. - /// - /// A new string with all lines trimmed of trailing whitespace. - public string TrimLines() + if (value is null) { - if (value is null) - { - return string.Empty; - } - - var result = new List(); - foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) - { - result.Add(line.TrimEnd()); - } - - return string.Join("\n", result); - } - - /// - /// Returns a new string with normalized line endings. - /// - /// A new string with normalized line endings. - public string NormalizeLineEndings() - { - if (value != null) - { - value = value.Replace("\r\n", "\n"); - return value.Replace("\r", string.Empty); - } - return string.Empty; } + + var result = new List(); + foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) + { + result.Add(line.TrimEnd()); + } + + return string.Join("\n", result); + } + + /// + /// Returns a new string with normalized line endings. + /// + /// The string to normalize line endings for. + /// A new string with normalized line endings. + public static string NormalizeLineEndings(this string value) + { + if (value != null) + { + value = value.Replace("\r\n", "\n"); + return value.Replace("\r", string.Empty); + } + + return string.Empty; } } \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs b/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs index 1405cc26..24168042 100644 --- a/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs @@ -5,23 +5,20 @@ namespace Spectre.Console.Testing; /// public static class StyleExtensions { + /// + /// Sets the foreground or background color of the specified style. + /// /// The style. - extension(Style style) + /// The color. + /// Whether or not to set the foreground color. + /// The same instance so that multiple calls can be chained. + public static Style SetColor(this Style style, Color color, bool foreground) { - /// - /// Sets the foreground or background color of the specified style. - /// - /// The color. - /// Whether or not to set the foreground color. - /// The same instance so that multiple calls can be chained. - public Style SetColor(Color color, bool foreground) + if (foreground) { - if (foreground) - { - return style.Foreground(color); - } - - return style.Background(color); + return style.Foreground(color); } + + return style.Background(color); } } \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Extensions/TestConsoleExtensions.cs b/src/Spectre.Console.Testing/Extensions/TestConsoleExtensions.cs index 88692068..ffe6a8b1 100644 --- a/src/Spectre.Console.Testing/Extensions/TestConsoleExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/TestConsoleExtensions.cs @@ -5,84 +5,87 @@ namespace Spectre.Console.Testing; /// public static partial class TestConsoleExtensions { + /// + /// Sets the console's color system. + /// /// The console. - extension(TestConsole console) + /// The color system to use. + /// The same instance so that multiple calls can be chained. + public static TestConsole Colors(this TestConsole console, ColorSystem colors) { - /// - /// Sets the console's color system. - /// - /// The color system to use. - /// The same instance so that multiple calls can be chained. - public TestConsole Colors(ColorSystem colors) - { - console.Profile.Capabilities.ColorSystem = colors; - return console; - } + console.Profile.Capabilities.ColorSystem = colors; + return console; + } - /// - /// Sets whether or not ANSI is supported. - /// - /// Whether or not VT/ANSI control codes are supported. - /// The same instance so that multiple calls can be chained. - public TestConsole SupportsAnsi(bool enable) - { - console.Profile.Capabilities.Ansi = enable; - return console; - } + /// + /// Sets whether or not ANSI is supported. + /// + /// The console. + /// Whether or not VT/ANSI control codes are supported. + /// The same instance so that multiple calls can be chained. + public static TestConsole SupportsAnsi(this TestConsole console, bool enable) + { + console.Profile.Capabilities.Ansi = enable; + return console; + } - /// - /// Makes the console interactive. - /// - /// The same instance so that multiple calls can be chained. - public TestConsole Interactive() - { - console.Profile.Capabilities.Interactive = true; - return console; - } + /// + /// Makes the console interactive. + /// + /// The console. + /// The same instance so that multiple calls can be chained. + public static TestConsole Interactive(this TestConsole console) + { + console.Profile.Capabilities.Interactive = true; + return console; + } - /// - /// Sets the console width. - /// - /// The console width. - /// The same instance so that multiple calls can be chained. - public TestConsole Width(int width) - { - console.Profile.Width = width; - return console; - } + /// + /// Sets the console width. + /// + /// The console. + /// The console width. + /// The same instance so that multiple calls can be chained. + public static TestConsole Width(this TestConsole console, int width) + { + console.Profile.Width = width; + return console; + } - /// - /// Sets the console height. - /// - /// The console height. - /// The same instance so that multiple calls can be chained. - public TestConsole Height(int width) - { - console.Profile.Height = width; - return console; - } + /// + /// Sets the console height. + /// + /// The console. + /// The console height. + /// The same instance so that multiple calls can be chained. + public static TestConsole Height(this TestConsole console, int width) + { + console.Profile.Height = width; + return console; + } - /// - /// Sets the console size. - /// - /// The console size. - /// The same instance so that multiple calls can be chained. - public TestConsole Size(Size size) - { - console.Profile.Width = size.Width; - console.Profile.Height = size.Height; - return console; - } + /// + /// Sets the console size. + /// + /// The console. + /// The console size. + /// The same instance so that multiple calls can be chained. + public static TestConsole Size(this TestConsole console, Size size) + { + console.Profile.Width = size.Width; + console.Profile.Height = size.Height; + return console; + } - /// - /// Turns on emitting of VT/ANSI sequences. - /// - /// The same instance so that multiple calls can be chained. - public TestConsole EmitAnsiSequences() - { - console.SetCursor(null); - console.EmitAnsiSequences = true; - return console; - } + /// + /// Turns on emitting of VT/ANSI sequences. + /// + /// The console. + /// The same instance so that multiple calls can be chained. + public static TestConsole EmitAnsiSequences(this TestConsole console) + { + console.SetCursor(null); + console.EmitAnsiSequences = true; + return console; } } \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Spectre.Console.Testing.csproj b/src/Spectre.Console.Testing/Spectre.Console.Testing.csproj index 2854dad0..367360f4 100644 --- a/src/Spectre.Console.Testing/Spectre.Console.Testing.csproj +++ b/src/Spectre.Console.Testing/Spectre.Console.Testing.csproj @@ -10,15 +10,5 @@ - - - - - - - - Extensions\Polyfills.cs - - diff --git a/src/Spectre.Console.Testing/TestCapabilities.cs b/src/Spectre.Console.Testing/TestCapabilities.cs index 6d75f54d..d4f702b8 100644 --- a/src/Spectre.Console.Testing/TestCapabilities.cs +++ b/src/Spectre.Console.Testing/TestCapabilities.cs @@ -33,7 +33,10 @@ public sealed class TestCapabilities : IReadOnlyCapabilities /// A with the same capabilities as this instace. public RenderOptions CreateRenderContext(IAnsiConsole console) { - ArgumentNullException.ThrowIfNull(console); + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } return RenderOptions.Create(console, this); } diff --git a/src/Spectre.Console.Testing/TestConsoleInput.cs b/src/Spectre.Console.Testing/TestConsoleInput.cs index 178f743d..e471d30e 100644 --- a/src/Spectre.Console.Testing/TestConsoleInput.cs +++ b/src/Spectre.Console.Testing/TestConsoleInput.cs @@ -21,7 +21,10 @@ public sealed class TestConsoleInput : IAnsiConsoleInput /// The input string. public void PushText(string input) { - ArgumentNullException.ThrowIfNull(input); + if (input is null) + { + throw new ArgumentNullException(nameof(input)); + } foreach (var character in input) { diff --git a/src/Spectre.Console.Tests/Extensions/ConsoleKeyExtensions.cs b/src/Spectre.Console.Tests/Extensions/ConsoleKeyExtensions.cs index 735332c2..fee4ec22 100644 --- a/src/Spectre.Console.Tests/Extensions/ConsoleKeyExtensions.cs +++ b/src/Spectre.Console.Tests/Extensions/ConsoleKeyExtensions.cs @@ -2,17 +2,14 @@ namespace Spectre.Console.Tests; public static class ConsoleKeyExtensions { - extension(ConsoleKey key) + public static ConsoleKeyInfo ToConsoleKeyInfo(this ConsoleKey key) { - public ConsoleKeyInfo ToConsoleKeyInfo() + var ch = (char)key; + if (char.IsControl(ch)) { - var ch = (char)key; - if (char.IsControl(ch)) - { - ch = '\0'; - } - - return new ConsoleKeyInfo(ch, key, false, false, false); + ch = '\0'; } + + return new ConsoleKeyInfo(ch, key, false, false, false); } } \ No newline at end of file diff --git a/src/Spectre.Console.Tests/Extensions/StreamExtensions.cs b/src/Spectre.Console.Tests/Extensions/StreamExtensions.cs index fd1527fc..0eed3b87 100644 --- a/src/Spectre.Console.Tests/Extensions/StreamExtensions.cs +++ b/src/Spectre.Console.Tests/Extensions/StreamExtensions.cs @@ -2,16 +2,16 @@ namespace Spectre.Console.Tests; public static class StreamExtensions { - extension(Stream stream) + public static string ReadText(this Stream stream) { - public string ReadText() + if (stream is null) { - ArgumentNullException.ThrowIfNull(stream); + throw new ArgumentNullException(nameof(stream)); + } - using (var reader = new StreamReader(stream)) - { - return reader.ReadToEnd(); - } + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); } } } \ No newline at end of file diff --git a/src/Spectre.Console.Tests/Unit/BackwardsCompatibilityTests.cs b/src/Spectre.Console.Tests/Unit/BackwardsCompatibilityTests.cs index 1e275cbc..093a0041 100644 --- a/src/Spectre.Console.Tests/Unit/BackwardsCompatibilityTests.cs +++ b/src/Spectre.Console.Tests/Unit/BackwardsCompatibilityTests.cs @@ -1,9 +1,3 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Shouldly; -using Xunit; - namespace Spectre.Console.Tests.Unit; /// diff --git a/src/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs b/src/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs index 5400bafd..2b0163f0 100644 --- a/src/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs +++ b/src/Spectre.Console.Tests/Unit/Widgets/AlignTests.cs @@ -1,3 +1,5 @@ +using Spectre.Console.Extensions; + namespace Spectre.Console.Tests.Unit; [ExpectationPath("Widgets/Align")] diff --git a/src/Spectre.Console.Tests/Utilities/EmbeddedResourceReader.cs b/src/Spectre.Console.Tests/Utilities/EmbeddedResourceReader.cs index bb10c3c5..8d74d9e6 100644 --- a/src/Spectre.Console.Tests/Utilities/EmbeddedResourceReader.cs +++ b/src/Spectre.Console.Tests/Utilities/EmbeddedResourceReader.cs @@ -4,7 +4,10 @@ public static class EmbeddedResourceReader { public static Stream LoadResourceStream(string resourceName) { - ArgumentNullException.ThrowIfNull(resourceName); + if (resourceName is null) + { + throw new ArgumentNullException(nameof(resourceName)); + } var assembly = Assembly.GetCallingAssembly(); resourceName = resourceName.Replace("/", "."); @@ -20,9 +23,15 @@ public static class EmbeddedResourceReader public static Stream LoadResourceStream(Assembly assembly, string resourceName) { - ArgumentNullException.ThrowIfNull(assembly); + if (assembly is null) + { + throw new ArgumentNullException(nameof(assembly)); + } - ArgumentNullException.ThrowIfNull(resourceName); + if (resourceName is null) + { + throw new ArgumentNullException(nameof(resourceName)); + } resourceName = resourceName.Replace("/", "."); var stream = assembly.GetManifestResourceStream(resourceName); diff --git a/src/Spectre.Console.Tests/Utilities/TestConsoleExtensions.cs b/src/Spectre.Console.Tests/Utilities/TestConsoleExtensions.cs index 777bcf41..9e020fa3 100644 --- a/src/Spectre.Console.Tests/Utilities/TestConsoleExtensions.cs +++ b/src/Spectre.Console.Tests/Utilities/TestConsoleExtensions.cs @@ -6,25 +6,22 @@ public static class TestConsoleExtensions private static readonly Regex _filenameRegex = new Regex("\\sin\\s.*cs:nn", RegexOptions.Multiline); private static readonly Regex _pathSeparatorRegex = new Regex(@"[/\\]+"); - extension(TestConsole console) + public static string WriteNormalizedException(this TestConsole console, Exception ex, ExceptionFormats formats = ExceptionFormats.Default) { - public string WriteNormalizedException(Exception ex, ExceptionFormats formats = ExceptionFormats.Default) + if (!string.IsNullOrWhiteSpace(console.Output)) { - if (!string.IsNullOrWhiteSpace(console.Output)) - { - throw new InvalidOperationException("Output buffer is not empty."); - } - - console.WriteException(ex, formats); - - return string.Join("\n", NormalizeStackTrace(console.Output) - .NormalizeLineEndings() - .Split(['\n']) - .Select(line => line.TrimEnd())); + throw new InvalidOperationException("Output buffer is not empty."); } + + console.WriteException(ex, formats); + + return string.Join("\n", NormalizeStackTrace(console.Output) + .NormalizeLineEndings() + .Split(['\n']) + .Select(line => line.TrimEnd())); } - private static string NormalizeStackTrace(string text) + public static string NormalizeStackTrace(string text) { // First normalize line numbers text = _lineNumberRegex.Replace(text, ":nn"); diff --git a/src/Spectre.Console/AnsiConsole.Exceptions.cs b/src/Spectre.Console/AnsiConsole.Exceptions.cs new file mode 100644 index 00000000..de3a4733 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Exceptions.cs @@ -0,0 +1,29 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Writes an exception to the console. + /// + /// The exception to write to the console. + /// The exception format options. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) + { + Console.WriteException(exception, format); + } + + /// + /// Writes an exception to the console. + /// + /// The exception to write to the console. + /// The exception settings. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static void WriteException(Exception exception, ExceptionSettings settings) + { + Console.WriteException(exception, settings); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Live.cs b/src/Spectre.Console/AnsiConsole.Live.cs new file mode 100644 index 00000000..3d3e4b8f --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Live.cs @@ -0,0 +1,17 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Creates a new instance. + /// + /// The target renderable to update. + /// A instance. + public static LiveDisplay Live(IRenderable target) + { + return Console.Live(target); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Markup.cs b/src/Spectre.Console/AnsiConsole.Markup.cs new file mode 100644 index 00000000..b9d47f09 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Markup.cs @@ -0,0 +1,141 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Writes the specified markup to the console. + /// + /// The value to write. + public static void Markup(string value) + { + Console.Markup(value); + } + + /// + /// Writes the specified markup to the console. + /// + /// A composite format string. + /// An array of objects to write. + public static void Markup(string format, params object[] args) + { + Console.Markup(format, args); + } + + /// + /// Writes the specified markup to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// AnsiConsole.MarkupInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// The interpolated string value to write. + public static void MarkupInterpolated(FormattableString value) + { + Console.MarkupInterpolated(value); + } + + /// + /// Writes the specified markup to the console. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void Markup(IFormatProvider provider, string format, params object[] args) + { + Console.Markup(provider, format, args); + } + + /// + /// Writes the specified markup to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// AnsiConsole.MarkupInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// An object that supplies culture-specific formatting information. + /// The interpolated string value to write. + public static void MarkupInterpolated(IFormatProvider provider, FormattableString value) + { + Console.MarkupInterpolated(provider, value); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void MarkupLine(string value) + { + Console.MarkupLine(value); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(string format, params object[] args) + { + Console.MarkupLine(format, args); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// AnsiConsole.MarkupLineInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// The interpolated string value to write. + public static void MarkupLineInterpolated(FormattableString value) + { + Console.MarkupLineInterpolated(value); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(IFormatProvider provider, string format, params object[] args) + { + Console.MarkupLine(provider, format, args); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// AnsiConsole.MarkupLineInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// An object that supplies culture-specific formatting information. + /// The interpolated string value to write. + public static void MarkupLineInterpolated(IFormatProvider provider, FormattableString value) + { + Console.MarkupLineInterpolated(provider, value); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Progress.cs b/src/Spectre.Console/AnsiConsole.Progress.cs new file mode 100644 index 00000000..144c923b --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Progress.cs @@ -0,0 +1,25 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Creates a new instance. + /// + /// A instance. + public static Progress Progress() + { + return Console.Progress(); + } + + /// + /// Creates a new instance. + /// + /// A instance. + public static Status Status() + { + return Console.Status(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Prompt.cs b/src/Spectre.Console/AnsiConsole.Prompt.cs new file mode 100644 index 00000000..d51577c6 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Prompt.cs @@ -0,0 +1,123 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The prompt to display. + /// The prompt input result. + public static T Prompt(IPrompt prompt) + { + if (prompt is null) + { + throw new ArgumentNullException(nameof(prompt)); + } + + return prompt.Show(Console); + } + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The prompt to display. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task PromptAsync(IPrompt prompt, CancellationToken cancellationToken = default) + { + if (prompt is null) + { + throw new ArgumentNullException(nameof(prompt)); + } + + return prompt.ShowAsync(Console, cancellationToken); + } + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The prompt markup text. + /// The prompt input result. + public static T Ask(string prompt) + { + return new TextPrompt(prompt).Show(Console); + } + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The prompt markup text. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task AskAsync(string prompt, CancellationToken cancellationToken = default) + { + return new TextPrompt(prompt).ShowAsync(Console, cancellationToken); + } + + /// + /// Displays a prompt to the user with a given default. + /// + /// The prompt result type. + /// The prompt markup text. + /// The default value. + /// The prompt input result. + public static T Ask(string prompt, T defaultValue) + { + return new TextPrompt(prompt) + .DefaultValue(defaultValue) + .Show(Console); + } + + /// + /// Displays a prompt to the user with a given default. + /// + /// The prompt result type. + /// The prompt markup text. + /// The default value. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task AskAsync(string prompt, T defaultValue, CancellationToken cancellationToken = default) + { + return new TextPrompt(prompt) + .DefaultValue(defaultValue) + .ShowAsync(Console, cancellationToken); + } + + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The prompt markup text. + /// Specifies the default answer. + /// true if the user selected "yes", otherwise false. + public static bool Confirm(string prompt, bool defaultValue = true) + { + return new ConfirmationPrompt(prompt) + { + DefaultValue = defaultValue, + } + .Show(Console); + } + + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The prompt markup text. + /// Specifies the default answer. + /// The token to monitor for cancellation requests. + /// true if the user selected "yes", otherwise false. + public static Task ConfirmAsync(string prompt, bool defaultValue = true, CancellationToken cancellationToken = default) + { + return new ConfirmationPrompt(prompt) + { + DefaultValue = defaultValue, + } + .ShowAsync(Console, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Recording.cs b/src/Spectre.Console/AnsiConsole.Recording.cs new file mode 100644 index 00000000..a398a374 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Recording.cs @@ -0,0 +1,66 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Starts recording the console output. + /// + public static void Record() + { + if (_recorder == null) + { + _recorder = new Recorder(Console); + } + } + + /// + /// Exports all recorded console output as text. + /// + /// The recorded output as text. + public static string ExportText() + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); + } + + return _recorder.ExportText(); + } + + /// + /// Exports all recorded console output as HTML text. + /// + /// The recorded output as HTML text. + public static string ExportHtml() + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); + } + + return _recorder.ExportHtml(); + } + + /// + /// Exports all recorded console output using a custom encoder. + /// + /// The encoder to use. + /// The recorded output. + public static string ExportCustom(IAnsiConsoleEncoder encoder) + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); + } + + if (encoder is null) + { + throw new ArgumentNullException(nameof(encoder)); + } + + return _recorder.Export(encoder); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Rendering.cs b/src/Spectre.Console/AnsiConsole.Rendering.cs new file mode 100644 index 00000000..ca56a900 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Rendering.cs @@ -0,0 +1,31 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Renders the specified object to the console. + /// + /// The object to render. + [Obsolete("Consider using AnsiConsole.Write instead.")] + public static void Render(IRenderable renderable) + { + Write(renderable); + } + + /// + /// Renders the specified to the console. + /// + /// The object to render. + public static void Write(IRenderable renderable) + { + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + Console.Write(renderable); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Screen.cs b/src/Spectre.Console/AnsiConsole.Screen.cs new file mode 100644 index 00000000..f89fd594 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Screen.cs @@ -0,0 +1,16 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Switches to an alternate screen buffer if the terminal supports it. + /// + /// The action to execute within the alternate screen buffer. + public static void AlternateScreen(Action action) + { + Console.AlternateScreen(action); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.State.cs b/src/Spectre.Console/AnsiConsole.State.cs new file mode 100644 index 00000000..ca6e209e --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.State.cs @@ -0,0 +1,62 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + internal static Style CurrentStyle { get; private set; } = Style.Plain; + internal static bool Created { get; private set; } + + /// + /// Gets or sets the foreground color. + /// + public static Color Foreground + { + get => CurrentStyle.Foreground; + set => CurrentStyle = CurrentStyle.Foreground(value); + } + + /// + /// Gets or sets the background color. + /// + public static Color Background + { + get => CurrentStyle.Background; + set => CurrentStyle = CurrentStyle.Background(value); + } + + /// + /// Gets or sets the text decoration. + /// + public static Decoration Decoration + { + get => CurrentStyle.Decoration; + set => CurrentStyle = CurrentStyle.Decoration(value); + } + + /// + /// Resets colors and text decorations. + /// + public static void Reset() + { + ResetColors(); + ResetDecoration(); + } + + /// + /// Resets the current applied text decorations. + /// + public static void ResetDecoration() + { + Decoration = Decoration.None; + } + + /// + /// Resets the current applied foreground and background colors. + /// + public static void ResetColors() + { + CurrentStyle = Style.Plain; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Write.cs b/src/Spectre.Console/AnsiConsole.Write.cs new file mode 100644 index 00000000..8d40819a --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Write.cs @@ -0,0 +1,249 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Writes the specified string value to the console. + /// + /// The value to write. + public static void Write(string value) + { + Write(value, CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit + /// signed integer value to the console. + /// + /// The value to write. + public static void Write(int value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit + /// signed integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, int value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit + /// unsigned integer value to the console. + /// + /// The value to write. + public static void Write(uint value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit + /// unsigned integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, uint value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit + /// signed integer value to the console. + /// + /// The value to write. + public static void Write(long value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit + /// signed integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, long value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit + /// unsigned integer value to the console. + /// + /// The value to write. + public static void Write(ulong value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit + /// unsigned integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, ulong value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified single-precision + /// floating-point value to the console. + /// + /// The value to write. + public static void Write(float value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified single-precision + /// floating-point value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, float value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified double-precision + /// floating-point value to the console. + /// + /// The value to write. + public static void Write(double value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified double-precision + /// floating-point value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, double value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified decimal value, to the console. + /// + /// The value to write. + public static void Write(decimal value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified decimal value, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, decimal value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified boolean value to the console. + /// + /// The value to write. + public static void Write(bool value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified boolean value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, bool value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified Unicode character to the console. + /// + /// The value to write. + public static void Write(char value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified Unicode character to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, char value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified array of Unicode characters to the console. + /// + /// The value to write. + public static void Write(char[] value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified array of Unicode characters to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, char[] value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + for (var index = 0; index < value.Length; index++) + { + Console.Write(value[index].ToString(provider), CurrentStyle); + } + } + + /// + /// Writes the text representation of the specified array of objects, + /// to the console using the specified format information. + /// + /// A composite format string. + /// An array of objects to write. + public static void Write(string format, params object[] args) + { + Write(CultureInfo.CurrentCulture, format, args); + } + + /// + /// Writes the text representation of the specified array of objects, + /// to the console using the specified format information. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void Write(IFormatProvider provider, string format, params object[] args) + { + Console.Write(string.Format(provider, format, args), CurrentStyle); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.WriteLine.cs b/src/Spectre.Console/AnsiConsole.WriteLine.cs new file mode 100644 index 00000000..57ba6b77 --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.WriteLine.cs @@ -0,0 +1,269 @@ +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + /// + /// Writes an empty line to the console. + /// + public static void WriteLine() + { + Console.WriteLine(); + } + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(string value) + { + Console.WriteLine(value, CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(int value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, int value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(uint value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, uint value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(long value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, long value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(ulong value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, ulong value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified single-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(float value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified single-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, float value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified double-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(double value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified double-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, double value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified decimal value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(decimal value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified decimal value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, decimal value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified boolean value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(bool value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified boolean value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, bool value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified Unicode character, followed by the current + /// line terminator, value to the console. + /// + /// The value to write. + public static void WriteLine(char value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified Unicode character, followed by the current + /// line terminator, value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, char value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified array of Unicode characters, followed by the current + /// line terminator, value to the console. + /// + /// The value to write. + public static void WriteLine(char[] value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified array of Unicode characters, followed by the current + /// line terminator, value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, char[] value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + for (var index = 0; index < value.Length; index++) + { + Console.Write(value[index].ToString(provider), CurrentStyle); + } + + Console.WriteLine(); + } + + /// + /// Writes the text representation of the specified array of objects, + /// followed by the current line terminator, to the console + /// using the specified format information. + /// + /// A composite format string. + /// An array of objects to write. + public static void WriteLine(string format, params object[] args) + { + WriteLine(CultureInfo.CurrentCulture, format, args); + } + + /// + /// Writes the text representation of the specified array of objects, + /// followed by the current line terminator, to the console + /// using the specified format information. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void WriteLine(IFormatProvider provider, string format, params object[] args) + { + Console.WriteLine(string.Format(provider, format, args), CurrentStyle); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.cs b/src/Spectre.Console/AnsiConsole.cs index 929d8c49..090434de 100644 --- a/src/Spectre.Console/AnsiConsole.cs +++ b/src/Spectre.Console/AnsiConsole.cs @@ -9,11 +9,7 @@ public static partial class AnsiConsole private static readonly AnsiConsoleFactory _factory = new AnsiConsoleFactory(); #pragma warning restore CS0618 - internal static Style CurrentStyle { get; set; } = Style.Plain; - internal static Recorder? Recorder { get; set; } - - internal static bool Created { get; private set; } - + private static Recorder? _recorder; private static Lazy _console = new Lazy( () => { @@ -35,12 +31,18 @@ public static partial class AnsiConsole { get { - return Recorder ?? _console.Value; + return _recorder ?? _console.Value; } set { _console = new Lazy(() => value); - Recorder = Recorder?.Clone(value); // Recreate the recorder + + if (_recorder != null) + { + // Recreate the recorder + _recorder = _recorder.Clone(value); + } + Created = true; } } @@ -48,7 +50,7 @@ public static partial class AnsiConsole /// /// Gets the . /// - public static IAnsiConsoleCursor Cursor => Recorder?.Cursor ?? _console.Value.Cursor; + public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor; /// /// Gets the console profile. @@ -65,99 +67,12 @@ public static partial class AnsiConsole { return _factory.Create(settings); } -} - -// TODO: This is here temporary due to a bug in the .NET SDK -// See issue: https://github.com/dotnet/roslyn/issues/80024 -public static partial class AnsiConsole -{ - /// - /// Writes the text representation of the specified array of objects, - /// to the console using the specified format information. - /// - /// A composite format string. - /// An array of objects to write. - public static void Write(string format, params object[] args) - { - Write(CultureInfo.CurrentCulture, format, args); - } /// - /// Writes the text representation of the specified array of objects, - /// to the console using the specified format information. + /// Clears the console. /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void Write(IFormatProvider provider, string format, params object[] args) + public static void Clear() { - Console.Write(string.Format(provider, format, args), CurrentStyle); - } - - /// - /// Writes the text representation of the specified array of objects, - /// followed by the current line terminator, to the console - /// using the specified format information. - /// - /// A composite format string. - /// An array of objects to write. - public static void WriteLine(string format, params object[] args) - { - WriteLine(CultureInfo.CurrentCulture, format, args); - } - - /// - /// Writes the text representation of the specified array of objects, - /// followed by the current line terminator, to the console - /// using the specified format information. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void WriteLine(IFormatProvider provider, string format, params object[] args) - { - Console.WriteLine(string.Format(provider, format, args), CurrentStyle); - } - - /// - /// Writes the specified markup to the console. - /// - /// A composite format string. - /// An array of objects to write. - public static void Markup(string format, params object[] args) - { - Console.Markup(format, args); - } - - /// - /// Writes the specified markup to the console. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void Markup(IFormatProvider provider, string format, params object[] args) - { - Console.Markup(provider, format, args); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(string format, params object[] args) - { - Console.MarkupLine(format, args); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(IFormatProvider provider, string format, params object[] args) - { - Console.MarkupLine(provider, format, args); + Console.Clear(); } } \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsoleFactory.cs b/src/Spectre.Console/AnsiConsoleFactory.cs index 266a84ea..b4406b3e 100644 --- a/src/Spectre.Console/AnsiConsoleFactory.cs +++ b/src/Spectre.Console/AnsiConsoleFactory.cs @@ -13,7 +13,10 @@ public sealed class AnsiConsoleFactory /// An implementation of . public IAnsiConsole Create(AnsiConsoleSettings settings) { - ArgumentNullException.ThrowIfNull(settings); + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out); if (output.Writer == null) diff --git a/src/Spectre.Console/BoxBorder.cs b/src/Spectre.Console/BoxBorder.cs index 50960548..e30d5f31 100644 --- a/src/Spectre.Console/BoxBorder.cs +++ b/src/Spectre.Console/BoxBorder.cs @@ -16,31 +16,4 @@ public abstract partial class BoxBorder /// The part to get the character representation for. /// A character representation of the specified border part. public abstract string GetPart(BoxBorderPart part); -} - -/// -/// Contains extension methods for . -/// -public static class BoxExtensions -{ - /// The border to get the safe border for. - extension(BoxBorder border) - { - /// - /// Gets the safe border for a border. - /// - /// Whether or not to return the safe border. - /// The safe border if one exist, otherwise the original border. - public BoxBorder GetSafeBorder(bool safe) - { - ArgumentNullException.ThrowIfNull(border); - - if (safe && border.SafeBorder != null) - { - border = border.SafeBorder; - } - - return border; - } - } } \ No newline at end of file diff --git a/src/Spectre.Console/Color.cs b/src/Spectre.Console/Color.cs index 9934ec63..9c87d62f 100644 --- a/src/Spectre.Console/Color.cs +++ b/src/Spectre.Console/Color.cs @@ -220,7 +220,10 @@ public partial struct Color : IEquatable /// The color created from the hexadecimal string. public static Color FromHex(string hex) { - ArgumentNullException.ThrowIfNull(hex); + if (hex is null) + { + throw new ArgumentNullException(nameof(hex)); + } if (hex.StartsWith("#")) { diff --git a/src/Spectre.Console/Emoji.cs b/src/Spectre.Console/Emoji.cs index 95273e11..aaea7467 100644 --- a/src/Spectre.Console/Emoji.cs +++ b/src/Spectre.Console/Emoji.cs @@ -19,9 +19,15 @@ public static partial class Emoji /// The emoji. public static void Remap(string tag, string emoji) { - ArgumentNullException.ThrowIfNull(tag); + if (tag is null) + { + throw new ArgumentNullException(nameof(tag)); + } - ArgumentNullException.ThrowIfNull(emoji); + if (emoji is null) + { + throw new ArgumentNullException(nameof(emoji)); + } tag = tag.TrimStart(':').TrimEnd(':'); emoji = emoji.TrimStart(':').TrimEnd(':'); @@ -106,4 +112,16 @@ public static partial class Emoji value = string.Empty; return false; } + + private static int IndexOf(this ReadOnlySpan span, char value, int startIndex) + { + var indexInSlice = span.Slice(startIndex).IndexOf(value); + + if (indexInSlice == -1) + { + return -1; + } + + return startIndex + indexInSlice; + } } \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/ProfileEnricher.cs b/src/Spectre.Console/Enrichment/ProfileEnricher.cs index 4632d781..7ae68f34 100644 --- a/src/Spectre.Console/Enrichment/ProfileEnricher.cs +++ b/src/Spectre.Console/Enrichment/ProfileEnricher.cs @@ -25,7 +25,10 @@ internal static class ProfileEnricher ProfileEnrichment settings, IDictionary? environmentVariables) { - ArgumentNullException.ThrowIfNull(profile); + if (profile is null) + { + throw new ArgumentNullException(nameof(profile)); + } settings ??= new ProfileEnrichment(); diff --git a/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs b/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs index 253b9ea5..5df87d48 100644 --- a/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs @@ -3,36 +3,34 @@ namespace Spectre.Console.Advanced; /// /// Contains extension methods for . /// -[Obsolete("Use methods on IAnsiConsole instead")] public static class AnsiConsoleExtensions { + /// + /// Writes a VT/Ansi control code sequence to the console (if supported). + /// /// The console to write to. - extension(IAnsiConsole console) + /// The VT/Ansi control code sequence to write. + public static void WriteAnsi(this IAnsiConsole console, string sequence) { - /// - /// Writes a VT/Ansi control code sequence to the console (if supported). - /// - /// The VT/Ansi control code sequence to write. - [Obsolete("Use Spectre.Console.IAnsiConsole.WriteAnsi instead")] - public void WriteAnsi(string sequence) + if (console is null) { - ArgumentNullException.ThrowIfNull(console); - - if (console.Profile.Capabilities.Ansi) - { - console.Write(new ControlCode(sequence)); - } + throw new ArgumentNullException(nameof(console)); } - /// - /// Gets the VT/ANSI control code sequence for a . - /// - /// The renderable to the VT/ANSI control code sequence for. - /// The VT/ANSI control code sequence. - [Obsolete("Use Spectre.Console.IAnsiConsole.ToAnsi instead")] - public string ToAnsi(IRenderable renderable) + if (console.Profile.Capabilities.Ansi) { - return AnsiBuilder.Build(console, renderable); + console.Write(new ControlCode(sequence)); } } + + /// + /// Gets the VT/ANSI control code sequence for a . + /// + /// The console. + /// The renderable to the VT/ANSI control code sequence for. + /// The VT/ANSI control code sequence. + public static string ToAnsi(this IAnsiConsole console, IRenderable renderable) + { + return AnsiBuilder.Build(console, renderable); + } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AlignExtensions.cs b/src/Spectre.Console/Extensions/AlignExtensions.cs new file mode 100644 index 00000000..ad0413b7 --- /dev/null +++ b/src/Spectre.Console/Extensions/AlignExtensions.cs @@ -0,0 +1,106 @@ +namespace Spectre.Console.Extensions; + +/// +/// Contains extension methods for . +/// +public static class AlignExtensions +{ + /// + /// Sets the width. + /// + /// The object. + /// The width, or null for no explicit width. + /// The same instance so that multiple calls can be chained. + public static Align Width(this Align align, int? width) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Width = width; + return align; + } + + /// + /// Sets the height. + /// + /// The object. + /// The height, or null for no explicit height. + /// The same instance so that multiple calls can be chained. + public static Align Height(this Align align, int? height) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Height = height; + return align; + } + + /// + /// Sets the vertical alignment. + /// + /// The object. + /// The vertical alignment, or null for no vertical alignment. + /// The same instance so that multiple calls can be chained. + public static Align VerticalAlignment(this Align align, VerticalAlignment? vertical) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Vertical = vertical; + return align; + } + + /// + /// Sets the object to be top aligned. + /// + /// The object. + /// The same instance so that multiple calls can be chained. + public static Align TopAligned(this Align align) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Vertical = Console.VerticalAlignment.Top; + return align; + } + + /// + /// Sets the object to be middle aligned. + /// + /// The object. + /// The same instance so that multiple calls can be chained. + public static Align MiddleAligned(this Align align) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Vertical = Console.VerticalAlignment.Middle; + return align; + } + + /// + /// Sets the object to be bottom aligned. + /// + /// The object. + /// The same instance so that multiple calls can be chained. + public static Align BottomAligned(this Align align) + { + if (align is null) + { + throw new ArgumentNullException(nameof(align)); + } + + align.Vertical = Console.VerticalAlignment.Bottom; + return align; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AlignableExtensions.cs b/src/Spectre.Console/Extensions/AlignableExtensions.cs new file mode 100644 index 00000000..4efc934a --- /dev/null +++ b/src/Spectre.Console/Extensions/AlignableExtensions.cs @@ -0,0 +1,80 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class AlignableExtensions +{ + /// + /// Sets the alignment for an object. + /// + /// The alignable object type. + /// The alignable object. + /// The alignment. + /// The same instance so that multiple calls can be chained. + public static T Alignment(this T obj, Justify? alignment) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = alignment; + return obj; + } + + /// + /// Sets the object to be left aligned. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T LeftAligned(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Left; + return obj; + } + + /// + /// Sets the object to be centered. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T Centered(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Center; + return obj; + } + + /// + /// Sets the object to be right aligned. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T RightAligned(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Right; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Ansi.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Ansi.cs deleted file mode 100644 index 44a74ce1..00000000 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Ansi.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Spectre.Console; - -public static partial class AnsiConsoleExtensions -{ - extension(AnsiConsole) - { - /// - /// Writes a VT/Ansi control code sequence to the console (if supported). - /// - /// The VT/Ansi control code sequence to write. - public static void WriteAnsi(string sequence) - { - AnsiConsole.Console.WriteAnsi(sequence); - } - - /// - /// Gets the VT/ANSI control code sequence for a . - /// - /// The renderable to the VT/ANSI control code sequence for. - /// The VT/ANSI control code sequence. - public static string ToAnsi(IRenderable renderable) - { - return AnsiConsole.Console.ToAnsi(renderable); - } - } - - extension(IAnsiConsole console) - { - /// - /// Writes a VT/Ansi control code sequence to the console (if supported). - /// - /// The VT/Ansi control code sequence to write. - public void WriteAnsi(string sequence) - { - ArgumentNullException.ThrowIfNull(console); - - if (console.Profile.Capabilities.Ansi) - { - console.Write(new ControlCode(sequence)); - } - } - - /// - /// Gets the VT/ANSI control code sequence for a . - /// - /// The renderable to the VT/ANSI control code sequence for. - /// The VT/ANSI control code sequence. - public string ToAnsi(IRenderable renderable) - { - return AnsiBuilder.Build(console, renderable); - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Async.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Async.cs new file mode 100644 index 00000000..34504880 --- /dev/null +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Async.cs @@ -0,0 +1,92 @@ +namespace Spectre.Console.Extensions; + +/// +/// Provides extension methods for running tasks with a spinner animation. +/// +public static class SpinnerExtensions +{ + /// + /// Runs a task with a spinner animation. + /// + /// The task to run. + /// The spinner to use. + /// The style to apply to the spinner. + /// The console to write to. + /// The result of the task. + public static async Task Spinner(this Task task, Spinner? spinner = null, Style? style = null, IAnsiConsole? ansiConsole = null) + { + await SpinnerInternal(task, spinner ?? Console.Spinner.Known.Default, style, ansiConsole); + } + + /// + /// Runs a task with a spinner animation. + /// + /// The type of the task result. + /// The task to run. + /// The spinner to use. + /// The style to apply to the spinner. + /// The console to write to. + /// The result of the task. + public static async Task Spinner(this Task task, Spinner? spinner = null, Style? style = null, IAnsiConsole? ansiConsole = null) + { + return (await SpinnerInternal(task, spinner ?? Console.Spinner.Known.Default, style, ansiConsole))!; + } + + private static async Task SpinnerInternal(Task task, Spinner spinner, Style? style = null, IAnsiConsole? ansiConsole = null) + { + ansiConsole ??= AnsiConsole.Console; + + style ??= Style.Plain; + var currentFrame = 0; + var cancellationTokenSource = new CancellationTokenSource(); + + // Start spinner animation in background + var spinnerTask = Task.Run( + async () => + { + while (!cancellationTokenSource.Token.IsCancellationRequested) + { + ansiConsole.Cursor.Show(false); + + var spinnerFrame = spinner.Frames[currentFrame]; + + // Write the spinner frame + ansiConsole.Write(new Text(spinnerFrame, style)); + ansiConsole.Write(new ControlCode(AnsiSequences.CUB(spinnerFrame.Length))); + + currentFrame = (currentFrame + 1) % spinner.Frames.Count; + await Task.Delay(spinner.Interval, cancellationTokenSource.Token); + } + }, cancellationTokenSource.Token); + + try + { + // Wait for the actual task to complete + if (task is Task taskWithResult) + { + var result = await taskWithResult; + await cancellationTokenSource.CancelAsync(); + await spinnerTask.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnCanceled); + + return result; + } + else + { + await task; + await cancellationTokenSource.CancelAsync(); + await spinnerTask.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnCanceled); + + return default; + } + } + finally + { + var spinnerFrame = spinner.Frames[currentFrame]; + + ansiConsole.Write(new string(' ', spinnerFrame.Length)); + ansiConsole.Write(new ControlCode(AnsiSequences.CUB(spinnerFrame.Length))); + ansiConsole.Cursor.Show(); + await cancellationTokenSource.CancelAsync(); + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs index dd97e59c..6b91559d 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs @@ -1,55 +1,31 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) + /// + /// Writes an exception to the console. + /// + /// The console. + /// The exception to write to the console. + /// The exception format options. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default) { - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception format options. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) - { - AnsiConsole.Console.WriteException(exception, format); - } - - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception settings. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public static void WriteException(Exception exception, ExceptionSettings settings) - { - AnsiConsole.Console.WriteException(exception, settings); - } + console.Write(exception.GetRenderable(format)); } + /// + /// Writes an exception to the console. + /// /// The console. - extension(IAnsiConsole console) + /// The exception to write to the console. + /// The exception settings. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings) { - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception format options. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) - { - console.Write(exception.GetRenderable(format)); - } - - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception settings. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public void WriteException(Exception exception, ExceptionSettings settings) - { - console.Write(exception.GetRenderable(settings)); - } + console.Write(exception.GetRenderable(settings)); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs index 91f22285..160a635e 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs @@ -1,30 +1,31 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { + /// + /// Runs the specified function in exclusive mode. + /// + /// The result type. /// The console. - extension(IAnsiConsole console) + /// The func to run in exclusive mode. + /// The result of the function. + public static T RunExclusive(this IAnsiConsole console, Func func) { - /// - /// Runs the specified function in exclusive mode. - /// - /// The result type. - /// The func to run in exclusive mode. - /// The result of the function. - public T RunExclusive(Func func) - { - return console.ExclusivityMode.Run(func); - } + return console.ExclusivityMode.Run(func); + } - /// - /// Runs the specified function in exclusive mode asynchronously. - /// - /// The result type. - /// The func to run in exclusive mode. - /// The result of the function. - public Task RunExclusive(Func> func) - { - return console.ExclusivityMode.RunAsync(func); - } + /// + /// Runs the specified function in exclusive mode asynchronously. + /// + /// The result type. + /// The console. + /// The func to run in exclusive mode. + /// The result of the function. + public static Task RunExclusive(this IAnsiConsole console, Func> func) + { + return console.ExclusivityMode.RunAsync(func); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs index b6d65124..2d6a4cb0 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs @@ -1,81 +1,81 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(IAnsiConsole console) + internal static async Task ReadLine(this IAnsiConsole console, Style? style, bool secret, char? mask, IEnumerable? items = null, CancellationToken cancellationToken = default) { - internal async Task ReadLine( - Style style, bool secret, char? mask, - IEnumerable? items = null, - CancellationToken cancellationToken = default) + if (console is null) { - ArgumentNullException.ThrowIfNull(console); + throw new ArgumentNullException(nameof(console)); + } - style ??= Style.Plain; - var text = string.Empty; + style ??= Style.Plain; + var text = string.Empty; - var autocomplete = new List(items ?? Enumerable.Empty()); + var autocomplete = new List(items ?? Enumerable.Empty()); - while (true) + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + var rawKey = await console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false); + if (rawKey == null) { - cancellationToken.ThrowIfCancellationRequested(); - var rawKey = await console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false); - if (rawKey == null) + continue; + } + + var key = rawKey.Value; + if (key.Key == ConsoleKey.Enter) + { + return text; + } + + if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0) + { + var autoCompleteDirection = key.Modifiers.HasFlag(ConsoleModifiers.Shift) + ? AutoCompleteDirection.Backward + : AutoCompleteDirection.Forward; + var replace = AutoComplete(autocomplete, text, autoCompleteDirection); + if (!string.IsNullOrEmpty(replace)) { + // Render the suggestion + console.Write("\b \b".Repeat(text.Length), style); + console.Write(replace); + text = replace; continue; } + } - var key = rawKey.Value; - if (key.Key == ConsoleKey.Enter) + if (key.Key == ConsoleKey.Backspace) + { + if (text.Length > 0) { - return text; - } + var lastChar = text.Last(); + text = text.Substring(0, text.Length - 1); - if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0) - { - var autoCompleteDirection = key.Modifiers.HasFlag(ConsoleModifiers.Shift) - ? AutoCompleteDirection.Backward - : AutoCompleteDirection.Forward; - var replace = AutoComplete(autocomplete, text, autoCompleteDirection); - if (!string.IsNullOrEmpty(replace)) + if (mask != null) { - // Render the suggestion - console.Write("\b \b".Repeat(text.Length), style); - console.Write(replace); - text = replace; - continue; - } - } - - if (key.Key == ConsoleKey.Backspace) - { - if (text.Length > 0) - { - var lastChar = text.Last(); - text = text.Substring(0, text.Length - 1); - - if (mask != null) + if (UnicodeCalculator.GetWidth(lastChar) == 1) { - if (UnicodeCalculator.GetWidth(lastChar) == 1) - { - console.Write("\b \b"); - } - else if (UnicodeCalculator.GetWidth(lastChar) == 2) - { - console.Write("\b \b\b \b"); - } + console.Write("\b \b"); + } + else if (UnicodeCalculator.GetWidth(lastChar) == 2) + { + console.Write("\b \b\b \b"); } } - - continue; } - if (!char.IsControl(key.KeyChar)) - { - text += key.KeyChar.ToString(); - var output = key.KeyChar.ToString(); - console.Write(secret ? output.Mask(mask) : output, style); - } + continue; + } + + if (!char.IsControl(key.KeyChar)) + { + text += key.KeyChar.ToString(); + var output = key.KeyChar.ToString(); + console.Write(secret ? output.Mask(mask) : output, style); } } } diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs index 8e862d9d..d9451bb4 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs @@ -1,35 +1,28 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) - { - /// - /// Creates a new instance. - /// - /// The target renderable to update. - /// A instance. - public static LiveDisplay Live(IRenderable target) - { - return AnsiConsole.Console.Live(target); - } - } - + /// + /// Creates a new instance for the console. + /// /// The console. - extension(IAnsiConsole console) + /// The target renderable to update. + /// A instance. + public static LiveDisplay Live(this IAnsiConsole console, IRenderable target) { - /// - /// Creates a new instance for the console. - /// - /// The target renderable to update. - /// A instance. - public LiveDisplay Live(IRenderable target) + if (console is null) { - ArgumentNullException.ThrowIfNull(console); - - ArgumentNullException.ThrowIfNull(target); - - return new LiveDisplay(console, target); + throw new ArgumentNullException(nameof(console)); } + + if (target is null) + { + throw new ArgumentNullException(nameof(target)); + } + + return new LiveDisplay(console, target); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs index 150aa060..dc5023de 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs @@ -1,5 +1,8 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { /// @@ -10,12 +13,28 @@ public static partial class AnsiConsoleExtensions /// An array of objects to write. public static void Markup(this IAnsiConsole console, string format, params object[] args) { - // TODO: This is here temporary due to a bug in the .NET SDK - // See issue: https://github.com/dotnet/roslyn/issues/80024 - Markup(console, CultureInfo.CurrentCulture, format, args); } + /// + /// Writes the specified markup to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// console.MarkupInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// The console to write to. + /// The interpolated string value to write. + public static void MarkupInterpolated(this IAnsiConsole console, FormattableString value) + { + MarkupInterpolated(console, CultureInfo.CurrentCulture, value); + } + /// /// Writes the specified markup to the console. /// @@ -25,12 +44,39 @@ public static partial class AnsiConsoleExtensions /// An array of objects to write. public static void Markup(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) { - // TODO: This is here temporary due to a bug in the .NET SDK - // See issue: https://github.com/dotnet/roslyn/issues/80024 - Markup(console, string.Format(provider, format, args)); } + /// + /// Writes the specified markup to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// console.MarkupInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// The console to write to. + /// An object that supplies culture-specific formatting information. + /// The interpolated string value to write. + public static void MarkupInterpolated(this IAnsiConsole console, IFormatProvider provider, FormattableString value) + { + Markup(console, Console.Markup.EscapeInterpolated(provider, value)); + } + + /// + /// Writes the specified markup to the console. + /// + /// The console to write to. + /// The value to write. + public static void Markup(this IAnsiConsole console, string value) + { + console.Write(MarkupParser.Parse(value)); + } + /// /// Writes the specified markup, followed by the current line terminator, to the console. /// @@ -39,12 +85,38 @@ public static partial class AnsiConsoleExtensions /// An array of objects to write. public static void MarkupLine(this IAnsiConsole console, string format, params object[] args) { - // TODO: This is here temporary due to a bug in the .NET SDK - // See issue: https://github.com/dotnet/roslyn/issues/80024 - MarkupLine(console, CultureInfo.CurrentCulture, format, args); } + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// console.MarkupLineInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// + /// The console to write to. + /// The interpolated string value to write. + public static void MarkupLineInterpolated(this IAnsiConsole console, FormattableString value) + { + MarkupLineInterpolated(console, CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The value to write. + public static void MarkupLine(this IAnsiConsole console, string value) + { + Markup(console, value + Environment.NewLine); + } + /// /// Writes the specified markup, followed by the current line terminator, to the console. /// @@ -54,200 +126,26 @@ public static partial class AnsiConsoleExtensions /// An array of objects to write. public static void MarkupLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) { - // TODO: This is here temporary due to a bug in the .NET SDK - // See issue: https://github.com/dotnet/roslyn/issues/80024 - Markup(console, provider, format + Environment.NewLine, args); } - extension(AnsiConsole) - { - /// - /// Writes the specified markup to the console. - /// - /// The value to write. - public static void Markup(string value) - { - AnsiConsole.Console.Markup(value); - } - - /// - /// Writes the specified markup to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// AnsiConsole.MarkupInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// The interpolated string value to write. - public static void MarkupInterpolated(FormattableString value) - { - AnsiConsole.Console.MarkupInterpolated(value); - } - - /// - /// Writes the specified markup to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// AnsiConsole.MarkupInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// An object that supplies culture-specific formatting information. - /// The interpolated string value to write. - public static void MarkupInterpolated(IFormatProvider provider, FormattableString value) - { - AnsiConsole.Console.MarkupInterpolated(provider, value); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void MarkupLine(string value) - { - AnsiConsole.Console.MarkupLine(value); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// AnsiConsole.MarkupLineInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// The interpolated string value to write. - public static void MarkupLineInterpolated(FormattableString value) - { - AnsiConsole.Console.MarkupLineInterpolated(value); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// AnsiConsole.MarkupLineInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// An object that supplies culture-specific formatting information. - /// The interpolated string value to write. - public static void MarkupLineInterpolated(IFormatProvider provider, FormattableString value) - { - AnsiConsole.Console.MarkupLineInterpolated(provider, value); - } - } - + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// All interpolation holes which contain a string are automatically escaped so you must not call . + /// + /// + /// + /// string input = args[0]; + /// string output = Process(input); + /// console.MarkupLineInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); + /// + /// /// The console to write to. - extension(IAnsiConsole console) + /// An object that supplies culture-specific formatting information. + /// The interpolated string value to write. + public static void MarkupLineInterpolated(this IAnsiConsole console, IFormatProvider provider, FormattableString value) { - /// - /// Writes the specified markup to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// console.MarkupInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// The interpolated string value to write. - public void MarkupInterpolated(FormattableString value) - { - MarkupInterpolated(console, CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified markup to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// console.MarkupInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// An object that supplies culture-specific formatting information. - /// The interpolated string value to write. - public void MarkupInterpolated(IFormatProvider provider, FormattableString value) - { - Markup(console, Console.Markup.EscapeInterpolated(provider, value)); - } - - /// - /// Writes the specified markup to the console. - /// - /// The value to write. - public void Markup(string value) - { - console.Write(MarkupParser.Parse(value)); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// console.MarkupLineInterpolated($"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// The interpolated string value to write. - public void MarkupLineInterpolated(FormattableString value) - { - MarkupLineInterpolated(console, CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The value to write. - public void MarkupLine(string value) - { - Markup(console, value + Environment.NewLine); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// All interpolation holes which contain a string are automatically escaped so you must not call . - /// - /// - /// - /// string input = args[0]; - /// string output = Process(input); - /// console.MarkupLineInterpolated(CultureInfo.InvariantCulture, $"[blue]{input}[/] -> [green]{output}[/]"); - /// - /// - /// An object that supplies culture-specific formatting information. - /// The interpolated string value to write. - public void MarkupLineInterpolated(IFormatProvider provider, FormattableString value) - { - MarkupLine(console, Console.Markup.EscapeInterpolated(provider, value)); - } + MarkupLine(console, Console.Markup.EscapeInterpolated(provider, value)); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs index 19d28ffa..efabdbe7 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs @@ -1,51 +1,37 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) + /// + /// Creates a new instance for the console. + /// + /// The console. + /// A instance. + public static Progress Progress(this IAnsiConsole console) { - /// - /// Creates a new instance. - /// - /// A instance. - public static Progress Progress() + if (console is null) { - return AnsiConsole.Console.Progress(); + throw new ArgumentNullException(nameof(console)); } - /// - /// Creates a new instance. - /// - /// A instance. - public static Status Status() - { - return AnsiConsole.Console.Status(); - } + return new Progress(console); } + /// + /// Creates a new instance for the console. + /// /// The console. - extension(IAnsiConsole console) + /// A instance. + public static Status Status(this IAnsiConsole console) { - /// - /// Creates a new instance for the console. - /// - /// A instance. - public Progress Progress() + if (console is null) { - ArgumentNullException.ThrowIfNull(console); - - return new Progress(console); + throw new ArgumentNullException(nameof(console)); } - /// - /// Creates a new instance for the console. - /// - /// A instance. - public Status Status() - { - ArgumentNullException.ThrowIfNull(console); - - return new Status(console); - } + return new Status(console); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs index 1e8166bc..d3e88575 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs @@ -1,233 +1,131 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt to display. + /// The prompt input result. + public static T Prompt(this IAnsiConsole console, IPrompt prompt) { - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt to display. - /// The prompt input result. - public static T Prompt(IPrompt prompt) + if (prompt is null) { - ArgumentNullException.ThrowIfNull(prompt); - - return prompt.Show(AnsiConsole.Console); + throw new ArgumentNullException(nameof(prompt)); } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt to display. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public static Task PromptAsync(IPrompt prompt, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(prompt); - - return prompt.ShowAsync(AnsiConsole.Console, cancellationToken); - } - - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// The prompt input result. - public static T Ask(string prompt) - { - return new TextPrompt(prompt).Show(AnsiConsole.Console); - } - - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public static Task AskAsync(string prompt, CancellationToken cancellationToken = default) - { - return new TextPrompt(prompt).ShowAsync(AnsiConsole.Console, cancellationToken); - } - - /// - /// Displays a prompt to the user with a given default. - /// - /// The prompt result type. - /// The prompt markup text. - /// The default value. - /// The prompt input result. - public static T Ask(string prompt, T defaultValue) - { - return new TextPrompt(prompt) - .DefaultValue(defaultValue) - .Show(AnsiConsole.Console); - } - - /// - /// Displays a prompt to the user with a given default. - /// - /// The prompt result type. - /// The prompt markup text. - /// The default value. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public static Task AskAsync(string prompt, T defaultValue, CancellationToken cancellationToken = default) - { - return new TextPrompt(prompt) - .DefaultValue(defaultValue) - .ShowAsync(AnsiConsole.Console, cancellationToken); - } - - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The prompt markup text. - /// Specifies the default answer. - /// true if the user selected "yes", otherwise false. - public static bool Confirm(string prompt, bool defaultValue = true) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .Show(AnsiConsole.Console); - } - - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The prompt markup text. - /// Specifies the default answer. - /// The token to monitor for cancellation requests. - /// true if the user selected "yes", otherwise false. - public static Task ConfirmAsync(string prompt, bool defaultValue = true, - CancellationToken cancellationToken = default) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .ShowAsync(AnsiConsole.Console, cancellationToken); - } + return prompt.Show(console); } + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. /// The console. - extension(IAnsiConsole console) + /// The prompt markup text. + /// The prompt input result. + public static T Ask(this IAnsiConsole console, string prompt) { - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt to display. - /// The prompt input result. - public T Prompt(IPrompt prompt) - { - ArgumentNullException.ThrowIfNull(prompt); + return new TextPrompt(prompt).Show(console); + } - return prompt.Show(console); + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt markup text. + /// Specific CultureInfo to use when converting input. + /// The prompt input result. + public static T Ask(this IAnsiConsole console, string prompt, CultureInfo? culture) + { + var textPrompt = new TextPrompt(prompt); + textPrompt.Culture = culture; + return textPrompt.Show(console); + } + + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The console. + /// The prompt markup text. + /// Specifies the default answer. + /// true if the user selected "yes", otherwise false. + public static bool Confirm(this IAnsiConsole console, string prompt, bool defaultValue = true) + { + return new ConfirmationPrompt(prompt) + { + DefaultValue = defaultValue, + } + .Show(console); + } + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt to display. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task PromptAsync(this IAnsiConsole console, IPrompt prompt, CancellationToken cancellationToken = default) + { + if (prompt is null) + { + throw new ArgumentNullException(nameof(prompt)); } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// The prompt input result. - public T Ask(string prompt) - { - return new TextPrompt(prompt).Show(console); - } + return prompt.ShowAsync(console, cancellationToken); + } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// Specific CultureInfo to use when converting input. - /// The prompt input result. - public T Ask(string prompt, CultureInfo? culture) - { - var textPrompt = new TextPrompt(prompt); - textPrompt.Culture = culture; - return textPrompt.Show(console); - } + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt markup text. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task AskAsync(this IAnsiConsole console, string prompt, CancellationToken cancellationToken = default) + { + return new TextPrompt(prompt).ShowAsync(console, cancellationToken); + } - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The prompt markup text. - /// Specifies the default answer. - /// true if the user selected "yes", otherwise false. - public bool Confirm(string prompt, bool defaultValue = true) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .Show(console); - } + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt markup text. + /// Specific CultureInfo to use when converting input. + /// The token to monitor for cancellation requests. + /// The prompt input result. + public static Task AskAsync(this IAnsiConsole console, string prompt, CultureInfo? culture, CancellationToken cancellationToken = default) + { + var textPrompt = new TextPrompt(prompt); + textPrompt.Culture = culture; + return textPrompt.ShowAsync(console, cancellationToken); + } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt to display. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public Task PromptAsync(IPrompt prompt, CancellationToken cancellationToken = default) + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The console. + /// The prompt markup text. + /// Specifies the default answer. + /// The token to monitor for cancellation requests. + /// true if the user selected "yes", otherwise false. + public static Task ConfirmAsync(this IAnsiConsole console, string prompt, bool defaultValue = true, CancellationToken cancellationToken = default) + { + return new ConfirmationPrompt(prompt) { - ArgumentNullException.ThrowIfNull(prompt); - - return prompt.ShowAsync(console, cancellationToken); - } - - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public Task AskAsync(string prompt, CancellationToken cancellationToken = default) - { - return new TextPrompt(prompt).ShowAsync(console, cancellationToken); - } - - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// Specific CultureInfo to use when converting input. - /// The token to monitor for cancellation requests. - /// The prompt input result. - public Task AskAsync(string prompt, CultureInfo? culture, CancellationToken cancellationToken = default) - { - var textPrompt = new TextPrompt(prompt); - textPrompt.Culture = culture; - return textPrompt.ShowAsync(console, cancellationToken); - } - - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The prompt markup text. - /// Specifies the default answer. - /// The token to monitor for cancellation requests. - /// true if the user selected "yes", otherwise false. - public Task ConfirmAsync(string prompt, bool defaultValue = true, - CancellationToken cancellationToken = default) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .ShowAsync(console, cancellationToken); + DefaultValue = defaultValue, } + .ShowAsync(console, cancellationToken); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Recorder.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Recorder.cs deleted file mode 100644 index 67af4f7f..00000000 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Recorder.cs +++ /dev/null @@ -1,76 +0,0 @@ -namespace Spectre.Console; - -public static partial class AnsiConsoleExtensions -{ - extension(AnsiConsole) - { - /// - /// Creates a recorder for the specified console. - /// - /// A recorder for the specified console. - public static Recorder CreateRecorder() - { - return new Recorder(AnsiConsole.Console); - } - - /// - /// Starts recording the console output. - /// - [Obsolete("Use AnsiConsole.CreateRecorder instead")] - public static void Record() - { - if (AnsiConsole.Recorder == null) - { - AnsiConsole.Recorder = new Recorder(AnsiConsole.Console); - } - } - - /// - /// Exports all recorded console output as text. - /// - /// The recorded output as text. - [Obsolete("Use recorder from AnsiConsole.CreateRecorder instead")] - public static string ExportText() - { - if (AnsiConsole.Recorder == null) - { - throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); - } - - return AnsiConsole.Recorder.ExportText(); - } - - /// - /// Exports all recorded console output as HTML text. - /// - /// The recorded output as HTML text. - [Obsolete("Use recorder from AnsiConsole.CreateRecorder instead")] - public static string ExportHtml() - { - if (AnsiConsole.Recorder == null) - { - throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); - } - - return AnsiConsole.Recorder.ExportHtml(); - } - - /// - /// Exports all recorded console output using a custom encoder. - /// - /// The encoder to use. - /// The recorded output. - [Obsolete("Use recorder from AnsiConsole.CreateRecorder instead")] - public static string ExportCustom(IAnsiConsoleEncoder encoder) - { - if (AnsiConsole.Recorder == null) - { - throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); - } - - ArgumentNullException.ThrowIfNull(encoder); - - return AnsiConsole.Recorder.Export(encoder); - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs index 370e0568..5c482380 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs @@ -1,46 +1,28 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) - { - /// - /// Renders the specified object to the console. - /// - /// The object to render. - [Obsolete("Consider using AnsiConsole.Write instead.")] - public static void Render(IRenderable renderable) - { - Write(renderable); - } - - /// - /// Renders the specified to the console. - /// - /// The object to render. - public static void Write(IRenderable renderable) - { - ArgumentNullException.ThrowIfNull(renderable); - - AnsiConsole.Console.Write(renderable); - } - } - + /// + /// Renders the specified object to the console. + /// /// The console to render to. - extension(IAnsiConsole console) + /// The object to render. + [Obsolete("Consider using IAnsiConsole.Write instead.")] + public static void Render(this IAnsiConsole console, IRenderable renderable) { - /// - /// Renders the specified object to the console. - /// - /// The object to render. - [Obsolete("Consider using IAnsiConsole.Write instead.")] - public void Render(IRenderable renderable) + if (console is null) { - ArgumentNullException.ThrowIfNull(console); - - ArgumentNullException.ThrowIfNull(renderable); - - console.Write(renderable); + throw new ArgumentNullException(nameof(console)); } + + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + console.Write(renderable); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs index 88fce844..e562cba0 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs @@ -1,54 +1,44 @@ namespace Spectre.Console; +/// +/// Contains extension methods for . +/// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) - { - /// - /// Switches to an alternate screen buffer if the terminal supports it. - /// - /// The action to execute within the alternate screen buffer. - public static void AlternateScreen(Action action) - { - AnsiConsole.Console.AlternateScreen(action); - } - } - + /// + /// Switches to an alternate screen buffer if the terminal supports it. + /// /// The console. - extension(IAnsiConsole console) + /// The action to execute within the alternate screen buffer. + public static void AlternateScreen(this IAnsiConsole console, Action action) { - /// - /// Switches to an alternate screen buffer if the terminal supports it. - /// - /// The action to execute within the alternate screen buffer. - public void AlternateScreen(Action action) + if (console is null) { - ArgumentNullException.ThrowIfNull(console); + throw new ArgumentNullException(nameof(console)); + } - if (!console.Profile.Capabilities.Ansi) - { - throw new NotSupportedException( - "Alternate buffers are not supported since your terminal does not support ANSI."); - } + if (!console.Profile.Capabilities.Ansi) + { + throw new NotSupportedException("Alternate buffers are not supported since your terminal does not support ANSI."); + } - if (!console.Profile.Capabilities.AlternateBuffer) - { - throw new NotSupportedException("Alternate buffers are not supported by your terminal."); - } + if (!console.Profile.Capabilities.AlternateBuffer) + { + throw new NotSupportedException("Alternate buffers are not supported by your terminal."); + } - // Switch to alternate screen - console.Write(new ControlCode("\u001b[?1049h\u001b[H")); + // Switch to alternate screen + console.Write(new ControlCode("\u001b[?1049h\u001b[H")); - try - { - // Execute custom action - action(); - } - finally - { - // Switch back to primary screen - console.Write(new ControlCode("\u001b[?1049l")); - } + try + { + // Execute custom action + action(); + } + finally + { + // Switch back to primary screen + console.Write(new ControlCode("\u001b[?1049l")); } } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.State.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.State.cs deleted file mode 100644 index 5bd36285..00000000 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.State.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace Spectre.Console; - -public static partial class AnsiConsoleExtensions -{ - extension(AnsiConsole) - { - /// - /// Gets or sets the foreground color. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static Color Foreground - { - get => AnsiConsole.CurrentStyle.Foreground; - set => AnsiConsole.CurrentStyle = AnsiConsole.CurrentStyle.Foreground(value); - } - - /// - /// Gets or sets the background color. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static Color Background - { - get => AnsiConsole.CurrentStyle.Background; - set => AnsiConsole.CurrentStyle = AnsiConsole.CurrentStyle.Background(value); - } - - /// - /// Gets or sets the text decoration. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static Decoration Decoration - { - get => AnsiConsole.CurrentStyle.Decoration; - set => AnsiConsole.CurrentStyle = AnsiConsole.CurrentStyle.Decoration(value); - } - - /// - /// Resets colors and text decorations. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static void Reset() - { - ResetColors(); - ResetDecoration(); - } - - /// - /// Resets the current applied text decorations. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static void ResetDecoration() - { - AnsiConsole.Decoration = Decoration.None; - } - - /// - /// Resets the current applied foreground and background colors. - /// - [Obsolete("Static global state has been obsolete and will be removed in a future version")] - public static void ResetColors() - { - AnsiConsole.CurrentStyle = Style.Plain; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Write.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Write.cs deleted file mode 100644 index 39d8c3f2..00000000 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Write.cs +++ /dev/null @@ -1,249 +0,0 @@ -namespace Spectre.Console; - -public static partial class AnsiConsoleExtensions -{ - extension(AnsiConsole) - { - /// - /// Writes the specified string value to the console. - /// - /// The value to write. - public static void Write(string value) - { - AnsiConsole.Write(value, AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit - /// signed integer value to the console. - /// - /// The value to write. - public static void Write(int value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit - /// signed integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, int value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit - /// unsigned integer value to the console. - /// - /// The value to write. - public static void Write(uint value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit - /// unsigned integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, uint value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit - /// signed integer value to the console. - /// - /// The value to write. - public static void Write(long value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit - /// signed integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, long value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit - /// unsigned integer value to the console. - /// - /// The value to write. - public static void Write(ulong value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit - /// unsigned integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, ulong value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified single-precision - /// floating-point value to the console. - /// - /// The value to write. - public static void Write(float value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified single-precision - /// floating-point value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, float value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified double-precision - /// floating-point value to the console. - /// - /// The value to write. - public static void Write(double value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified double-precision - /// floating-point value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, double value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified decimal value, to the console. - /// - /// The value to write. - public static void Write(decimal value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified decimal value, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, decimal value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified boolean value to the console. - /// - /// The value to write. - public static void Write(bool value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified boolean value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, bool value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the specified Unicode character to the console. - /// - /// The value to write. - public static void Write(char value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified Unicode character to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, char value) - { - AnsiConsole.Console.Write(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the specified array of Unicode characters to the console. - /// - /// The value to write. - public static void Write(char[] value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified array of Unicode characters to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, char[] value) - { - ArgumentNullException.ThrowIfNull(value); - - for (var index = 0; index < value.Length; index++) - { - AnsiConsole.Console.Write(value[index].ToString(provider), AnsiConsole.CurrentStyle); - } - } - } - - extension(IAnsiConsole console) - { - /// - /// Writes the specified string value to the console. - /// - /// The text to write. - public void Write(string text) - { - ArgumentNullException.ThrowIfNull(console); - - console.Write(new Text(text, Style.Plain)); - } - - /// - /// Writes the specified string value to the console. - /// - /// The text to write. - /// The text style or if . - public void Write(string text, Style? style) - { - ArgumentNullException.ThrowIfNull(console); - - console.Write(new Text(text, style)); - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.WriteLine.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.WriteLine.cs deleted file mode 100644 index 6790f42f..00000000 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.WriteLine.cs +++ /dev/null @@ -1,277 +0,0 @@ -namespace Spectre.Console; - -public static partial class AnsiConsoleExtensions -{ - extension(AnsiConsole) - { - /// - /// Writes an empty line to the console. - /// - public static void WriteLine() - { - AnsiConsole.Console.WriteLine(); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(string value) - { - AnsiConsole.Console.WriteLine(value, AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(int value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, int value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(uint value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, uint value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(long value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, long value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(ulong value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, ulong value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified single-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(float value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified single-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, float value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified double-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(double value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified double-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, double value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified decimal value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(decimal value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified decimal value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, decimal value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the text representation of the specified boolean value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(bool value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified boolean value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, bool value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the specified Unicode character, followed by the current - /// line terminator, value to the console. - /// - /// The value to write. - public static void WriteLine(char value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified Unicode character, followed by the current - /// line terminator, value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, char value) - { - AnsiConsole.Console.WriteLine(value.ToString(provider), AnsiConsole.CurrentStyle); - } - - /// - /// Writes the specified array of Unicode characters, followed by the current - /// line terminator, value to the console. - /// - /// The value to write. - public static void WriteLine(char[] value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified array of Unicode characters, followed by the current - /// line terminator, value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, char[] value) - { - ArgumentNullException.ThrowIfNull(value); - - for (var index = 0; index < value.Length; index++) - { - AnsiConsole.Console.Write(value[index].ToString(provider), AnsiConsole.CurrentStyle); - } - - AnsiConsole.Console.WriteLine(); - } - } - - extension(IAnsiConsole console) - { - /// - /// Writes an empty line to the console. - /// - public void WriteLine() - { - ArgumentNullException.ThrowIfNull(console); - - console.Write(Text.NewLine); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The text to write. - public void WriteLine(string text) - { - WriteLine(console, text, Style.Plain); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The text to write. - /// The text style or if . - public void WriteLine(string text, Style? style) - { - ArgumentNullException.ThrowIfNull(console); - - ArgumentNullException.ThrowIfNull(text); - - console.Write(text + Environment.NewLine, style); - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs index 51483962..3b7f18b8 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs @@ -5,28 +5,103 @@ namespace Spectre.Console; /// public static partial class AnsiConsoleExtensions { - extension(AnsiConsole) + /// + /// Creates a recorder for the specified console. + /// + /// The console to record. + /// A recorder for the specified console. + public static Recorder CreateRecorder(this IAnsiConsole console) { - /// - /// Clears the console. - /// - public static void Clear() - { - AnsiConsole.Console.Clear(); - } + return new Recorder(console); } - /// The console to record. - extension(IAnsiConsole console) + /// + /// Clears the console. + /// + /// The console to clear. + public static void Clear(this IAnsiConsole console) { - /// - /// Clears the console. - /// - public void Clear() + if (console is null) { - ArgumentNullException.ThrowIfNull(console); - - console.Clear(true); + throw new ArgumentNullException(nameof(console)); } + + console.Clear(true); + } + + /// + /// Writes the specified string value to the console. + /// + /// The console to write to. + /// The text to write. + public static void Write(this IAnsiConsole console, string text) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(new Text(text, Style.Plain)); + } + + /// + /// Writes the specified string value to the console. + /// + /// The console to write to. + /// The text to write. + /// The text style or if . + public static void Write(this IAnsiConsole console, string text, Style? style) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(new Text(text, style)); + } + + /// + /// Writes an empty line to the console. + /// + /// The console to write to. + public static void WriteLine(this IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(Text.NewLine); + } + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The text to write. + public static void WriteLine(this IAnsiConsole console, string text) + { + WriteLine(console, text, Style.Plain); + } + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The text to write. + /// The text style or if . + public static void WriteLine(this IAnsiConsole console, string text, Style? style) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + console.Write(text + Environment.NewLine, style); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BarChartExtensions.cs b/src/Spectre.Console/Extensions/BarChartExtensions.cs new file mode 100644 index 00000000..80299817 --- /dev/null +++ b/src/Spectre.Console/Extensions/BarChartExtensions.cs @@ -0,0 +1,292 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class BarChartExtensions +{ + /// + /// Adds an item to the bar chart. + /// + /// The bar chart. + /// The item label. + /// The item value. + /// The item color. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItem(this BarChart chart, string label, double value, Color? color = null) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Data.Add(new BarChartItem(label, value, color)); + return chart; + } + + /// + /// Adds an item to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The item. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItem(this BarChart chart, T item) + where T : IBarChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (item is BarChartItem barChartItem) + { + chart.Data.Add(barChartItem); + } + else + { + chart.Data.Add( + new BarChartItem( + item.Label, + item.Value, + item.Color)); + } + + return chart; + } + + /// + /// Adds multiple items to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The items. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItems(this BarChart chart, IEnumerable items) + where T : IBarChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + foreach (var item in items) + { + AddItem(chart, item); + } + + return chart; + } + + /// + /// Adds multiple items to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The items. + /// The converter that converts instances of T to . + /// The same instance so that multiple calls can be chained. + public static BarChart AddItems(this BarChart chart, IEnumerable items, Func converter) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + if (converter is null) + { + throw new ArgumentNullException(nameof(converter)); + } + + foreach (var item in items) + { + chart.Data.Add(converter(item)); + } + + return chart; + } + + /// + /// Sets the value formatter for the bar chart using culture info. + /// + /// The bar chart. + /// The value formatter function with culture info. + /// The same instance so that multiple calls can be chained. + public static BarChart UseValueFormatter(this BarChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func; + return chart; + } + + /// + /// Sets the value formatter for the bar chart. + /// + /// The bar chart. + /// The value formatter to use. + /// The same instance so that multiple calls can be chained. + public static BarChart UseValueFormatter(this BarChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func != null + ? (value, _) => func(value) + : null; + + return chart; + } + + /// + /// Sets the width of the bar chart. + /// + /// The bar chart. + /// The bar chart width. + /// The same instance so that multiple calls can be chained. + public static BarChart Width(this BarChart chart, int? width) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Width = width; + return chart; + } + + /// + /// Sets the label of the bar chart. + /// + /// The bar chart. + /// The bar chart label. + /// The same instance so that multiple calls can be chained. + public static BarChart Label(this BarChart chart, string? label) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Label = label; + return chart; + } + + /// + /// Shows values next to each bar in the bar chart. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart ShowValues(this BarChart chart) + { + return ShowValues(chart, true); + } + + /// + /// Hides values next to each bar in the bar chart. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart HideValues(this BarChart chart) + { + return ShowValues(chart, false); + } + + /// + /// Sets whether or not values should be shown + /// next to each bar. + /// + /// The bar chart. + /// Whether or not values should be shown next to each bar. + /// The same instance so that multiple calls can be chained. + public static BarChart ShowValues(this BarChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ShowValues = show; + return chart; + } + + /// + /// Aligns the label to the left. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart LeftAlignLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Left; + return chart; + } + + /// + /// Centers the label. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart CenterLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Center; + return chart; + } + + /// + /// Aligns the label to the right. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart RightAlignLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Right; + return chart; + } + + /// + /// Sets the max fixed value for the chart. + /// + /// The bar chart. + /// Max value for the chart. + /// The same instance so that multiple calls can be chained. + public static BarChart WithMaxValue(this BarChart chart, double maxValue) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.MaxValue = maxValue; + return chart; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/CharExtensions.cs b/src/Spectre.Console/Extensions/Bcl/CharExtensions.cs deleted file mode 100644 index c0d0615c..00000000 --- a/src/Spectre.Console/Extensions/Bcl/CharExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Spectre.Console; - -/// -/// Contains extension methods for . -/// -public static partial class CharExtensions -{ - /// The character to get the cell width of. - extension(char character) - { -#if WCWIDTH - /// - /// Gets the cell width of a character. - /// - /// The cell width of the character. - public int GetCellWidth() - { - return Cell.GetCellLength(character); - } -#endif - - internal bool IsDigit(int min = 0) - { - return char.IsDigit(character) && character >= (char)min; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/DayOfWeekExtensions.cs b/src/Spectre.Console/Extensions/Bcl/DayOfWeekExtensions.cs deleted file mode 100644 index 69d13b86..00000000 --- a/src/Spectre.Console/Extensions/Bcl/DayOfWeekExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Spectre.Console; - -internal static class DayOfWeekExtensions -{ - extension(DayOfWeek day) - { - public string GetAbbreviatedDayName(CultureInfo culture) - { - culture ??= CultureInfo.InvariantCulture; - return culture.DateTimeFormat - .GetAbbreviatedDayName(day) - .CapitalizeFirstLetter(culture); - } - - public DayOfWeek GetNextWeekDay() - { - var next = (int)day + 1; - if (next > (int)DayOfWeek.Saturday) - { - return DayOfWeek.Sunday; - } - - return (DayOfWeek)next; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/DictionaryExtensions.cs b/src/Spectre.Console/Extensions/Bcl/DictionaryExtensions.cs deleted file mode 100644 index bb0393ff..00000000 --- a/src/Spectre.Console/Extensions/Bcl/DictionaryExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Spectre.Console; - -internal static class DictionaryExtensions -{ - extension(KeyValuePair tuple) - { - public void Deconstruct(out T1 key, out T2 value) - { - key = tuple.Key; - value = tuple.Value; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/ExceptionExtensions.cs b/src/Spectre.Console/Extensions/Bcl/ExceptionExtensions.cs deleted file mode 100644 index bd16edec..00000000 --- a/src/Spectre.Console/Extensions/Bcl/ExceptionExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Spectre.Console; - -/// -/// Contains extension methods for . -/// -public static class ExceptionExtensions -{ - /// The exception to format. - extension(Exception exception) - { - /// - /// Gets a representation of the exception. - /// - /// The exception format options. - /// A representing the exception. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public IRenderable GetRenderable(ExceptionFormats format = ExceptionFormats.Default) - { - ArgumentNullException.ThrowIfNull(exception); - - return GetRenderable(exception, new ExceptionSettings - { - Format = format, - }); - } - - /// - /// Gets a representation of the exception. - /// - /// The exception settings. - /// A representing the exception. - [RequiresDynamicCode(ExceptionFormatter.AotWarning)] - public IRenderable GetRenderable(ExceptionSettings settings) - { - ArgumentNullException.ThrowIfNull(exception); - - ArgumentNullException.ThrowIfNull(settings); - - return ExceptionFormatter.Format(exception, settings); - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/Int32Extensions.cs b/src/Spectre.Console/Extensions/Bcl/Int32Extensions.cs deleted file mode 100644 index 6210e0f0..00000000 --- a/src/Spectre.Console/Extensions/Bcl/Int32Extensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Spectre.Console; - -internal static class Int32Extensions -{ - extension(int value) - { - public int Clamp(int min, int max) - { - if (value <= min) - { - return min; - } - - if (value >= max) - { - return max; - } - - return value; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/ListExtensions.cs b/src/Spectre.Console/Extensions/Bcl/ListExtensions.cs deleted file mode 100644 index bdf90a4f..00000000 --- a/src/Spectre.Console/Extensions/Bcl/ListExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Spectre.Console; - -internal static class ListExtensions -{ - extension(List list) - { - public void RemoveLast() - { - ArgumentNullException.ThrowIfNull(list); - - if (list.Count > 0) - { - list.RemoveAt(list.Count - 1); - } - } - - public void AddOrReplaceLast(T item) - { - ArgumentNullException.ThrowIfNull(list); - - if (list.Count == 0) - { - list.Add(item); - } - else - { - list[list.Count - 1] = item; - } - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/ReadOnlySpanExtensions.cs b/src/Spectre.Console/Extensions/Bcl/ReadOnlySpanExtensions.cs deleted file mode 100644 index c35e6038..00000000 --- a/src/Spectre.Console/Extensions/Bcl/ReadOnlySpanExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Spectre.Console; - -internal static class ReadOnlySpanExtensions -{ - extension(ReadOnlySpan span) - where T : IEquatable - { - public int IndexOf(T value, int startIndex) - { - var indexInSlice = span[startIndex..].IndexOf(value); - if (indexInSlice == -1) - { - return -1; - } - - return startIndex + indexInSlice; - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/StackExtensions.cs b/src/Spectre.Console/Extensions/Bcl/StackExtensions.cs deleted file mode 100644 index 6ce53938..00000000 --- a/src/Spectre.Console/Extensions/Bcl/StackExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Spectre.Console; - -internal static class StackExtensions -{ - extension(Stack stack) - { - public void PushRange(IEnumerable source) - { - ArgumentNullException.ThrowIfNull(stack); - - if (source != null) - { - foreach (var item in source) - { - stack.Push(item); - } - } - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/StringBuilderExtensions.cs b/src/Spectre.Console/Extensions/Bcl/StringBuilderExtensions.cs deleted file mode 100644 index cc8566d8..00000000 --- a/src/Spectre.Console/Extensions/Bcl/StringBuilderExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Spectre.Console; - -internal static class StringBuilderExtensions -{ - extension(StringBuilder builder) - { - public StringBuilder AppendWithStyle(Style? style, int? value) - { - return AppendWithStyle(builder, style, value?.ToString(CultureInfo.InvariantCulture)); - } - } - - extension(StringBuilder builder) - { - public StringBuilder AppendWithStyle(Style? style, string? value) - { - value ??= string.Empty; - - if (style != null) - { - return builder.Append('[') - .Append(style.ToMarkup()) - .Append(']') - .Append(value.EscapeMarkup()) - .Append("[/]"); - } - - return builder.Append(value); - } - - public void AppendSpan(ReadOnlySpan span) - { - // NetStandard 2 lacks the override for StringBuilder to add the span. We'll need to convert the span - // to a string for it, but for .NET 6.0 or newer we'll use the override. -#if NETSTANDARD2_0 - builder.Append(span.ToString()); -#else - builder.Append(span); -#endif - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/StringExtensions.cs b/src/Spectre.Console/Extensions/Bcl/StringExtensions.cs deleted file mode 100644 index 6192ba7c..00000000 --- a/src/Spectre.Console/Extensions/Bcl/StringExtensions.cs +++ /dev/null @@ -1,332 +0,0 @@ -namespace Spectre.Console; - -/// -/// Contains extension methods for . -/// -public static class StringExtensions -{ - // Cache whether or not internally normalized line endings - // already are normalized. No reason to do yet another replace if it is. - private static readonly bool _alreadyNormalized - = Environment.NewLine.Equals("\n", StringComparison.OrdinalIgnoreCase); - - /// The text to escape. - extension(string? text) - { - /// - /// Escapes text so that it won’t be interpreted as markup. - /// - /// A string that is safe to use in markup. - public string EscapeMarkup() - { - if (text == null) - { - return string.Empty; - } - - return text - .ReplaceExact("[", "[[") - .ReplaceExact("]", "]]"); - } - - /// - /// Removes markup from the specified string. - /// - /// A string that does not have any markup. - public string RemoveMarkup() - { - if (string.IsNullOrWhiteSpace(text)) - { - return string.Empty; - } - - var result = new StringBuilder(); - - var tokenizer = new MarkupTokenizer(text); - while (tokenizer.MoveNext() && tokenizer.Current != null) - { - if (tokenizer.Current.Kind == MarkupTokenKind.Text) - { - result.Append(tokenizer.Current.Value); - } - } - - return result.ToString(); - } - - internal bool TryGetUri([NotNullWhen(true)] out Uri? result) - { - try - { - if (!Uri.TryCreate(text, UriKind.Absolute, out var uri)) - { - result = null; - return false; - } - - if (uri.Scheme == "file") - { - // For local files, we need to append - // the host name. Otherwise the terminal - // will most probably not allow it. - var builder = new UriBuilder(uri) - { - Host = Dns.GetHostName(), - }; - - uri = builder.Uri; - } - - result = uri; - return true; - } - catch - { - result = null; - return false; - } - } - - internal string CapitalizeFirstLetter(CultureInfo? culture = null) - { - if (text == null) - { - return string.Empty; - } - - culture ??= CultureInfo.InvariantCulture; - - if (text.Length > 0 && char.IsLower(text[0])) - { - text = string.Format(culture, "{0}{1}", char.ToUpper(text[0], culture), text.Substring(1)); - } - - return text; - } - - internal string? RemoveNewLines() - { - return text?.ReplaceExact("\r\n", string.Empty) - ?.ReplaceExact("\n", string.Empty); - } - - internal string NormalizeNewLines(bool native = false) - { - text = text?.ReplaceExact("\r\n", "\n"); - text ??= string.Empty; - - if (native && !_alreadyNormalized) - { - text = text.ReplaceExact("\n", Environment.NewLine); - } - - return text; - } - } - - extension(string text) - { - /// - /// Gets the cell width of the specified text. - /// - /// The text to get the cell width of. - /// The cell width of the text. - public int GetCellWidth() - { - return Cell.GetCellLength(text); - } - - internal string[] SplitLines() - { - var result = text?.NormalizeNewLines()?.Split(new[] { '\n' }, StringSplitOptions.None); - return result ?? Array.Empty(); - } - - internal string[] SplitWords(StringSplitOptions options = StringSplitOptions.None) - { - var result = new List(); - - static string Read(StringBuffer reader, Func criteria) - { - var buffer = new StringBuilder(); - while (!reader.Eof) - { - var current = reader.Peek(); - if (!criteria(current)) - { - break; - } - - buffer.Append(reader.Read()); - } - - return buffer.ToString(); - } - - using (var reader = new StringBuffer(text)) - { - while (!reader.Eof) - { - var current = reader.Peek(); - if (char.IsWhiteSpace(current)) - { - var x = Read(reader, c => char.IsWhiteSpace(c)); - if (options != StringSplitOptions.RemoveEmptyEntries) - { - result.Add(x); - } - } - else - { - result.Add(Read(reader, c => !char.IsWhiteSpace(c))); - } - } - } - - return result.ToArray(); - } - - internal string Repeat(int count) - { - ArgumentNullException.ThrowIfNull(text); - - if (count <= 0) - { - return string.Empty; - } - - if (count == 1) - { - return text; - } - - return string.Concat(Enumerable.Repeat(text, count)); - } - - /// - /// "Masks" every character in a string. - /// - /// String value to mask. - /// Character to use for masking. - /// Masked string. - public string Mask(char? mask) - { - if (mask is null) - { - return string.Empty; - } - - return new string(mask.Value, text.Length); - } - - /// - /// Highlights the first text match in provided value. - /// - /// Input value. - /// Text to search for. - /// The style to apply to the matched text. - /// Markup of input with the first matched text highlighted. - internal string Highlight(string searchText, Style? highlightStyle) - { - ArgumentNullException.ThrowIfNull(text); - - ArgumentNullException.ThrowIfNull(searchText); - - ArgumentNullException.ThrowIfNull(highlightStyle); - - if (searchText.Length == 0) - { - return text; - } - - var foundSearchPattern = false; - var builder = new StringBuilder(); - using var tokenizer = new MarkupTokenizer(text); - while (tokenizer.MoveNext()) - { - var token = tokenizer.Current!; - - switch (token.Kind) - { - case MarkupTokenKind.Text: - { - var tokenValue = token.Value; - if (tokenValue.Length == 0) - { - break; - } - - if (foundSearchPattern) - { - builder.Append(tokenValue); - break; - } - - var index = tokenValue.IndexOf(searchText, StringComparison.OrdinalIgnoreCase); - if (index == -1) - { - builder.Append(tokenValue); - break; - } - - foundSearchPattern = true; - var before = tokenValue.Substring(0, index); - var match = tokenValue.Substring(index, searchText.Length); - var after = tokenValue.Substring(index + searchText.Length); - - builder - .Append(before) - .AppendWithStyle(highlightStyle, match) - .Append(after); - - break; - } - - case MarkupTokenKind.Open: - { - builder.Append("[" + token.Value + "]"); - break; - } - - case MarkupTokenKind.Close: - { - builder.Append("[/]"); - break; - } - - default: - { - throw new InvalidOperationException("Unknown markup token kind."); - } - } - } - - return builder.ToString(); - } - - internal string ReplaceExact(string oldValue, string? newValue) - { -#if NETSTANDARD2_0 - return text.Replace(oldValue, newValue); -#else - return text.Replace(oldValue, newValue, StringComparison.Ordinal); -#endif - } - - internal bool ContainsExact(string value) - { -#if NETSTANDARD2_0 - return text.Contains(value); -#else - return text.Contains(value, StringComparison.Ordinal); -#endif - } - -#if NETSTANDARD2_0 - internal bool Contains(string value, System.StringComparison comparisonType) - { - return text.IndexOf(value, comparisonType) != -1; - } -#endif - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Bcl/TextWriterExtensions.cs b/src/Spectre.Console/Extensions/Bcl/TextWriterExtensions.cs deleted file mode 100644 index 92522e4c..00000000 --- a/src/Spectre.Console/Extensions/Bcl/TextWriterExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Spectre.Console; - -internal static class TextWriterExtensions -{ - extension(TextWriter writer) - { - public bool IsStandardOut() - { - try - { - return writer == System.Console.Out; - } - catch - { - return false; - } - } - - public bool IsStandardError() - { - try - { - return writer == System.Console.Error; - } - catch - { - return false; - } - } - } -} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BoxExtensions.cs b/src/Spectre.Console/Extensions/BoxExtensions.cs new file mode 100644 index 00000000..49250ec7 --- /dev/null +++ b/src/Spectre.Console/Extensions/BoxExtensions.cs @@ -0,0 +1,28 @@ +namespace Spectre.Console.Rendering; + +/// +/// Contains extension methods for . +/// +public static class BoxExtensions +{ + /// + /// Gets the safe border for a border. + /// + /// The border to get the safe border for. + /// Whether or not to return the safe border. + /// The safe border if one exist, otherwise the original border. + public static BoxBorder GetSafeBorder(this BoxBorder border, bool safe) + { + if (border is null) + { + throw new ArgumentNullException(nameof(border)); + } + + if (safe && border.SafeBorder != null) + { + border = border.SafeBorder; + } + + return border; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs b/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs new file mode 100644 index 00000000..ed3610f4 --- /dev/null +++ b/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs @@ -0,0 +1,317 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class BreakdownChartExtensions +{ + /// + /// Adds an item to the breakdown chart. + /// + /// The breakdown chart. + /// The item label. + /// The item value. + /// The item color. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItem(this BreakdownChart chart, string label, double value, Color color) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Data.Add(new BreakdownChartItem(label, value, color)); + return chart; + } + + /// + /// Adds an item to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The item. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItem(this BreakdownChart chart, T item) + where T : IBreakdownChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (item is BreakdownChartItem chartItem) + { + chart.Data.Add(chartItem); + } + else + { + chart.Data.Add( + new BreakdownChartItem( + item.Label, + item.Value, + item.Color)); + } + + return chart; + } + + /// + /// Adds multiple items to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The items. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items) + where T : IBreakdownChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + foreach (var item in items) + { + AddItem(chart, item); + } + + return chart; + } + + /// + /// Adds multiple items to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The items. + /// The converter that converts instances of T to . + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items, Func converter) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + if (converter is null) + { + throw new ArgumentNullException(nameof(converter)); + } + + foreach (var item in items) + { + chart.Data.Add(converter(item)); + } + + return chart; + } + + /// + /// Sets the width of the breakdown chart. + /// + /// The breakdown chart. + /// The breakdown chart width. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Width(this BreakdownChart chart, int? width) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Width = width; + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The value formatter to use. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func; + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The value formatter to use. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func != null + ? (value, _) => func(value) + : null; + + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowPercentage(this BreakdownChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = (value, culture) => string.Format(culture, "{0}%", value); + + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTags(this BreakdownChart chart) + { + return ShowTags(chart, true); + } + + /// + /// Tags will be not be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart HideTags(this BreakdownChart chart) + { + return ShowTags(chart, false); + } + + /// + /// Sets whether or not tags will be shown. + /// + /// The breakdown chart. + /// Whether or not tags will be shown. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTags(this BreakdownChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ShowTags = show; + return chart; + } + + /// + /// Tag values will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTagValues(this BreakdownChart chart) + { + return ShowTagValues(chart, true); + } + + /// + /// Tag values will be not be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart HideTagValues(this BreakdownChart chart) + { + return ShowTagValues(chart, false); + } + + /// + /// Sets whether or not tag values will be shown. + /// + /// The breakdown chart. + /// Whether or not tag values will be shown. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTagValues(this BreakdownChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ShowTagValues = show; + return chart; + } + + /// + /// Chart and tags is rendered in compact mode. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Compact(this BreakdownChart chart) + { + return Compact(chart, true); + } + + /// + /// Chart and tags is rendered in full size mode. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart FullSize(this BreakdownChart chart) + { + return Compact(chart, false); + } + + /// + /// Sets whether or not the chart and tags should be rendered in compact mode. + /// + /// The breakdown chart. + /// Whether or not the chart and tags should be rendered in compact mode. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Compact(this BreakdownChart chart, bool compact) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Compact = compact; + return chart; + } + + /// + /// Sets the . + /// + /// The breakdown chart. + /// The to set. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart WithValueColor(this BreakdownChart chart, Color color) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueColor = color; + return chart; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CalendarExtensions.cs b/src/Spectre.Console/Extensions/CalendarExtensions.cs new file mode 100644 index 00000000..7ea93583 --- /dev/null +++ b/src/Spectre.Console/Extensions/CalendarExtensions.cs @@ -0,0 +1,133 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CalendarExtensions +{ + /// + /// Adds a calendar event. + /// + /// The calendar to add the calendar event to. + /// The calendar event date. + /// The calendar event custom highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date, Style? customEventHighlightStyle = null) + { + return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day, customEventHighlightStyle); + } + + /// + /// Adds a calendar event. + /// + /// The calendar to add the calendar event to. + /// The calendar event description. + /// The calendar event date. + /// The calendar event custom highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date, Style? customEventHighlightStyle = null) + { + return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day, customEventHighlightStyle); + } + + /// + /// Adds a calendar event. + /// + /// The calendar to add the calendar event to. + /// The year of the calendar event. + /// The month of the calendar event. + /// The day of the calendar event. + /// The calendar event custom highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day, Style? customEventHighlightStyle = null) + { + return AddCalendarEvent(calendar, string.Empty, year, month, day, customEventHighlightStyle); + } + + /// + /// Adds a calendar event. + /// + /// The calendar. + /// The calendar event description. + /// The year of the calendar event. + /// The month of the calendar event. + /// The day of the calendar event. + /// The calendar event custom highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day, Style? customEventHighlightStyle = null) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day, customEventHighlightStyle)); + return calendar; + } + + /// + /// Sets the calendar's highlight . + /// + /// The calendar. + /// The default highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar HighlightStyle(this Calendar calendar, Style? style) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.HighlightStyle = style ?? Style.Plain; + return calendar; + } + + /// + /// Sets the calendar's header . + /// + /// The calendar. + /// The header style. + /// The same instance so that multiple calls can be chained. + public static Calendar HeaderStyle(this Calendar calendar, Style? style) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.HeaderStyle = style ?? Style.Plain; + return calendar; + } + + /// + /// Shows the calendar header. + /// + /// The calendar. + /// The same instance so that multiple calls can be chained. + public static Calendar ShowHeader(this Calendar calendar) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.ShowHeader = true; + return calendar; + } + + /// + /// Hides the calendar header. + /// + /// The calendar. + /// The same instance so that multiple calls can be chained. + public static Calendar HideHeader(this Calendar calendar) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.ShowHeader = false; + return calendar; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CharExtensions.cs b/src/Spectre.Console/Extensions/CharExtensions.cs new file mode 100644 index 00000000..268a2dfa --- /dev/null +++ b/src/Spectre.Console/Extensions/CharExtensions.cs @@ -0,0 +1,17 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class CharExtensions +{ + /// + /// Gets the cell width of a character. + /// + /// The character to get the cell width of. + /// The cell width of the character. + public static int GetCellWidth(this char character) + { + return Cell.GetCellLength(character); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ColumnExtensions.cs b/src/Spectre.Console/Extensions/ColumnExtensions.cs new file mode 100644 index 00000000..6a0e4dc0 --- /dev/null +++ b/src/Spectre.Console/Extensions/ColumnExtensions.cs @@ -0,0 +1,44 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ColumnExtensions +{ + /// + /// Prevents a column from wrapping. + /// + /// An object implementing . + /// The column. + /// The same instance so that multiple calls can be chained. + public static T NoWrap(this T obj) + where T : class, IColumn + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.NoWrap = true; + return obj; + } + + /// + /// Sets the width of the column. + /// + /// An object implementing . + /// The column. + /// The column width. + /// The same instance so that multiple calls can be chained. + public static T Width(this T obj, int? width) + where T : class, IColumn + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Width = width; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs b/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs new file mode 100644 index 00000000..5fd4bda6 --- /dev/null +++ b/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs @@ -0,0 +1,166 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ConfirmationPromptExtensions +{ + /// + /// Show or hide choices. + /// + /// The prompt. + /// Whether or not the choices should be visible. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj, bool show) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.ShowChoices = show; + return obj; + } + + /// + /// Shows choices. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj) + { + return ShowChoices(obj, true); + } + + /// + /// Hides choices. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt HideChoices(this ConfirmationPrompt obj) + { + return ShowChoices(obj, false); + } + + /// + /// Sets the style in which the list of choices is displayed. + /// + /// The confirmation prompt. + /// The style to use for displaying the choices or to use the default style (blue). + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ChoicesStyle(this ConfirmationPrompt obj, Style? style) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.ChoicesStyle = style; + return obj; + } + + /// + /// Show or hide the default value. + /// + /// The prompt. + /// Whether or not the default value should be visible. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj, bool show) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.ShowDefaultValue = show; + return obj; + } + + /// + /// Shows the default value. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj) + { + return ShowDefaultValue(obj, true); + } + + /// + /// Hides the default value. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt HideDefaultValue(this ConfirmationPrompt obj) + { + return ShowDefaultValue(obj, false); + } + + /// + /// Sets the style in which the default value is displayed. + /// + /// The confirmation prompt. + /// The default value style or to use the default style (green). + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt DefaultValueStyle(this ConfirmationPrompt obj, Style? style) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.DefaultValueStyle = style; + return obj; + } + + /// + /// Sets the "invalid choice" message for the prompt. + /// + /// The prompt. + /// The "invalid choice" message. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt InvalidChoiceMessage(this ConfirmationPrompt obj, string message) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.InvalidChoiceMessage = message; + return obj; + } + + /// + /// Sets the character to interpret as "yes". + /// + /// The confirmation prompt. + /// The character to interpret as "yes". + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt Yes(this ConfirmationPrompt obj, char character) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Yes = character; + return obj; + } + + /// + /// Sets the character to interpret as "no". + /// + /// The confirmation prompt. + /// The character to interpret as "no". + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt No(this ConfirmationPrompt obj, char character) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.No = character; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CursorExtensions.cs b/src/Spectre.Console/Extensions/CursorExtensions.cs new file mode 100644 index 00000000..f7eb159f --- /dev/null +++ b/src/Spectre.Console/Extensions/CursorExtensions.cs @@ -0,0 +1,151 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CursorExtensions +{ + /// + /// Shows the cursor. + /// + /// The cursor. + public static void Show(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Show(true); + } + + /// + /// Hides the cursor. + /// + /// The cursor. + public static void Hide(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Show(false); + } + + /// + /// Moves the cursor up. + /// + /// The cursor. + public static void MoveUp(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Up, 1); + } + + /// + /// Moves the cursor up. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveUp(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Up, steps); + } + + /// + /// Moves the cursor down. + /// + /// The cursor. + public static void MoveDown(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Down, 1); + } + + /// + /// Moves the cursor down. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveDown(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Down, steps); + } + + /// + /// Moves the cursor to the left. + /// + /// The cursor. + public static void MoveLeft(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Left, 1); + } + + /// + /// Moves the cursor to the left. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveLeft(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Left, steps); + } + + /// + /// Moves the cursor to the right. + /// + /// The cursor. + public static void MoveRight(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Right, 1); + } + + /// + /// Moves the cursor to the right. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveRight(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Right, steps); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs b/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs new file mode 100644 index 00000000..607cab48 --- /dev/null +++ b/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs @@ -0,0 +1,23 @@ +namespace Spectre.Console; + +internal static class DayOfWeekExtensions +{ + public static string GetAbbreviatedDayName(this DayOfWeek day, CultureInfo culture) + { + culture ??= CultureInfo.InvariantCulture; + return culture.DateTimeFormat + .GetAbbreviatedDayName(day) + .CapitalizeFirstLetter(culture); + } + + public static DayOfWeek GetNextWeekDay(this DayOfWeek day) + { + var next = (int)day + 1; + if (next > (int)DayOfWeek.Saturday) + { + return DayOfWeek.Sunday; + } + + return (DayOfWeek)next; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/DictionaryExtensions.cs b/src/Spectre.Console/Extensions/DictionaryExtensions.cs new file mode 100644 index 00000000..d4c2d57e --- /dev/null +++ b/src/Spectre.Console/Extensions/DictionaryExtensions.cs @@ -0,0 +1,10 @@ +namespace Spectre.Console; + +internal static class DictionaryExtensions +{ + public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value) + { + key = tuple.Key; + value = tuple.Value; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ExceptionExtensions.cs b/src/Spectre.Console/Extensions/ExceptionExtensions.cs new file mode 100644 index 00000000..913162c3 --- /dev/null +++ b/src/Spectre.Console/Extensions/ExceptionExtensions.cs @@ -0,0 +1,49 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ExceptionExtensions +{ + /// + /// Gets a representation of the exception. + /// + /// The exception to format. + /// The exception format options. + /// A representing the exception. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.Default) + { + if (exception is null) + { + throw new ArgumentNullException(nameof(exception)); + } + + return GetRenderable(exception, new ExceptionSettings + { + Format = format, + }); + } + + /// + /// Gets a representation of the exception. + /// + /// The exception to format. + /// The exception settings. + /// A representing the exception. + [RequiresDynamicCode(ExceptionFormatter.AotWarning)] + public static IRenderable GetRenderable(this Exception exception, ExceptionSettings settings) + { + if (exception is null) + { + throw new ArgumentNullException(nameof(exception)); + } + + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } + + return ExceptionFormatter.Format(exception, settings); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ExpandableExtensions.cs b/src/Spectre.Console/Extensions/ExpandableExtensions.cs new file mode 100644 index 00000000..ca72b823 --- /dev/null +++ b/src/Spectre.Console/Extensions/ExpandableExtensions.cs @@ -0,0 +1,44 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ExpandableExtensions +{ + /// + /// Tells the specified object to not expand to the available area + /// but take as little space as possible. + /// + /// The expandable object. + /// The object to collapse. + /// The same instance so that multiple calls can be chained. + public static T Collapse(this T obj) + where T : class, IExpandable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Expand = false; + return obj; + } + + /// + /// Tells the specified object to expand to the available area. + /// + /// The expandable object. + /// The object to expand. + /// The same instance so that multiple calls can be chained. + public static T Expand(this T obj) + where T : class, IExpandable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Expand = true; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/FigletTextExtensions.cs b/src/Spectre.Console/Extensions/FigletTextExtensions.cs new file mode 100644 index 00000000..e789d914 --- /dev/null +++ b/src/Spectre.Console/Extensions/FigletTextExtensions.cs @@ -0,0 +1,24 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class FigletTextExtensions +{ + /// + /// Sets the color of the FIGlet text. + /// + /// The text. + /// The color. + /// The same instance so that multiple calls can be chained. + public static FigletText Color(this FigletText text, Color? color) + { + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + text.Color = color ?? Console.Color.Default; + return text; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/GridExtensions.cs b/src/Spectre.Console/Extensions/GridExtensions.cs new file mode 100644 index 00000000..d9cbcb53 --- /dev/null +++ b/src/Spectre.Console/Extensions/GridExtensions.cs @@ -0,0 +1,112 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class GridExtensions +{ + /// + /// Adds a column to the grid. + /// + /// The grid to add the column to. + /// The number of columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddColumns(this Grid grid, int count) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + for (var index = 0; index < count; index++) + { + grid.AddColumn(new GridColumn()); + } + + return grid; + } + + /// + /// Adds a column to the grid. + /// + /// The grid to add the column to. + /// The columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddColumns(this Grid grid, params GridColumn[] columns) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + foreach (var column in columns) + { + grid.AddColumn(column); + } + + return grid; + } + + /// + /// Adds an empty row to the grid. + /// + /// The grid to add the row to. + /// The same instance so that multiple calls can be chained. + public static Grid AddEmptyRow(this Grid grid) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + var columns = new IRenderable[grid.Columns.Count]; + Enumerable.Range(0, grid.Columns.Count).ForEach(index => columns[index] = Text.Empty); + grid.AddRow(columns); + + return grid; + } + + /// + /// Adds a new row to the grid. + /// + /// The grid to add the row to. + /// The columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddRow(this Grid grid, params string[] columns) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + grid.AddRow(columns.Select(column => new Markup(column)).ToArray()); + return grid; + } + + /// + /// Sets the grid width. + /// + /// The grid. + /// The width. + /// The same instance so that multiple calls can be chained. + public static Grid Width(this Grid grid, int? width) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + grid.Width = width; + return grid; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBorderExtensions.cs new file mode 100644 index 00000000..460a9428 --- /dev/null +++ b/src/Spectre.Console/Extensions/HasBorderExtensions.cs @@ -0,0 +1,81 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasBorderExtensions +{ + /// + /// Enables the safe border. + /// + /// An object type with a border. + /// The object to enable the safe border for. + /// The same instance so that multiple calls can be chained. + public static T SafeBorder(this T obj) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.UseSafeBorder = true; + return obj; + } + + /// + /// Disables the safe border. + /// + /// An object type with a border. + /// The object to disable the safe border for. + /// The same instance so that multiple calls can be chained. + public static T NoSafeBorder(this T obj) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.UseSafeBorder = false; + return obj; + } + + /// + /// Sets the border style. + /// + /// An object type with a border. + /// The object to set the border style for. + /// The border style to set. + /// The same instance so that multiple calls can be chained. + public static T BorderStyle(this T obj, Style style) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.BorderStyle = style; + return obj; + } + + /// + /// Sets the border color. + /// + /// An object type with a border. + /// The object to set the border color for. + /// The border color to set. + /// The same instance so that multiple calls can be chained. + public static T BorderColor(this T obj, Color color) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).Foreground(color); + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs new file mode 100644 index 00000000..a79f9819 --- /dev/null +++ b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs @@ -0,0 +1,98 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasBoxBorderExtensions +{ + /// + /// Sets the border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T Border(this T obj, BoxBorder border) + where T : class, IHasBoxBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Border = border; + return obj; + } + + /// + /// Do not display a border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.None); + } + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Ascii); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Rounded); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Heavy); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Double); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasCultureExtensions.cs b/src/Spectre.Console/Extensions/HasCultureExtensions.cs new file mode 100644 index 00000000..32d05bde --- /dev/null +++ b/src/Spectre.Console/Extensions/HasCultureExtensions.cs @@ -0,0 +1,62 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasCultureExtensions +{ + /// + /// Sets the culture. + /// + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, CultureInfo culture) + where T : class, IHasCulture + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (culture is null) + { + throw new ArgumentNullException(nameof(culture)); + } + + obj.Culture = culture; + return obj; + } + + /// + /// Sets the culture. + /// + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, string name) + where T : class, IHasCulture + { + if (name is null) + { + throw new ArgumentNullException(nameof(name)); + } + + return Culture(obj, CultureInfo.GetCultureInfo(name)); + } + + /// + /// Sets the culture. + /// + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, int culture) + where T : class, IHasCulture + { + return Culture(obj, CultureInfo.GetCultureInfo(culture)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasJustificationExtensions.cs b/src/Spectre.Console/Extensions/HasJustificationExtensions.cs new file mode 100644 index 00000000..63b8c4df --- /dev/null +++ b/src/Spectre.Console/Extensions/HasJustificationExtensions.cs @@ -0,0 +1,80 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasJustificationExtensions +{ + /// + /// Sets the justification for an object. + /// + /// The type that can be justified. + /// The alignable object. + /// The alignment. + /// The same instance so that multiple calls can be chained. + public static T Justify(this T obj, Justify? alignment) + where T : class, IHasJustification + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Justification = alignment; + return obj; + } + + /// + /// Sets the object to be left justified. + /// + /// The type that can be justified. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T LeftJustified(this T obj) + where T : class, IHasJustification + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Justification = Console.Justify.Left; + return obj; + } + + /// + /// Sets the object to be centered. + /// + /// The type that can be justified. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T Centered(this T obj) + where T : class, IHasJustification + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Justification = Console.Justify.Center; + return obj; + } + + /// + /// Sets the object to be right justified. + /// + /// The type that can be justified. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T RightJustified(this T obj) + where T : class, IHasJustification + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Justification = Console.Justify.Right; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs new file mode 100644 index 00000000..fc5705ac --- /dev/null +++ b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs @@ -0,0 +1,242 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasTableBorderExtensions +{ + /// + /// Do not display a border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.None); + } + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Ascii); + } + + /// + /// Display another ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T Ascii2Border(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Ascii2); + } + + /// + /// Display an ASCII border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.AsciiDoubleHead); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Rounded); + } + + /// + /// Display a minimal border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Minimal); + } + + /// + /// Display a minimal border with a heavy head. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalHeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.MinimalHeavyHead); + } + + /// + /// Display a minimal border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.MinimalDoubleHead); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Simple); + } + + /// + /// Display a simple border with heavy lines. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleHeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.SimpleHeavy); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HorizontalBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Horizontal); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Heavy); + } + + /// + /// Display a border with a heavy edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.HeavyEdge); + } + + /// + /// Display a border with a heavy header. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.HeavyHead); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Double); + } + + /// + /// Display a border with a double edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.DoubleEdge); + } + + /// + /// Display a markdown border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MarkdownBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Markdown); + } + + /// + /// Sets the border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T Border(this T obj, TableBorder border) + where T : class, IHasTableBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Border = border; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs new file mode 100644 index 00000000..ae2f8030 --- /dev/null +++ b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs @@ -0,0 +1,211 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasTreeNodeExtensions +{ + /// + /// Adds a tree node. + /// + /// An object with tree nodes. + /// The object to add the tree node to. + /// The node's markup text. + /// The added tree node. + public static TreeNode AddNode(this T obj, string markup) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (markup is null) + { + throw new ArgumentNullException(nameof(markup)); + } + + return AddNode(obj, new Markup(markup)); + } + + /// + /// Adds a tree node. + /// + /// An object with tree nodes. + /// The object to add the tree node to. + /// The renderable to add. + /// The added tree node. + public static TreeNode AddNode(this T obj, IRenderable renderable) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + var node = new TreeNode(renderable); + obj.Nodes.Add(node); + return node; + } + + /// + /// Adds a tree node. + /// + /// An object with tree nodes. + /// The object to add the tree node to. + /// The tree node to add. + /// The added tree node. + public static TreeNode AddNode(this T obj, TreeNode node) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (node is null) + { + throw new ArgumentNullException(nameof(node)); + } + + obj.Nodes.Add(node); + return node; + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params string[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params IRenderable[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params TreeNode[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Int32Extensions.cs b/src/Spectre.Console/Extensions/Int32Extensions.cs new file mode 100644 index 00000000..8ef25a87 --- /dev/null +++ b/src/Spectre.Console/Extensions/Int32Extensions.cs @@ -0,0 +1,19 @@ +namespace Spectre.Console; + +internal static class Int32Extensions +{ + public static int Clamp(this int value, int min, int max) + { + if (value <= min) + { + return min; + } + + if (value >= max) + { + return max; + } + + return value; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/LayoutExtensions.cs b/src/Spectre.Console/Extensions/LayoutExtensions.cs new file mode 100644 index 00000000..995e6f09 --- /dev/null +++ b/src/Spectre.Console/Extensions/LayoutExtensions.cs @@ -0,0 +1,58 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class LayoutExtensions +{ + /// + /// Sets the ratio of the layout. + /// + /// The layout. + /// The ratio. + /// The same instance so that multiple calls can be chained. + public static Layout Ratio(this Layout layout, int ratio) + { + if (layout is null) + { + throw new ArgumentNullException(nameof(layout)); + } + + layout.Ratio = ratio; + return layout; + } + + /// + /// Sets the size of the layout. + /// + /// The layout. + /// The size. + /// The same instance so that multiple calls can be chained. + public static Layout Size(this Layout layout, int size) + { + if (layout is null) + { + throw new ArgumentNullException(nameof(layout)); + } + + layout.Size = size; + return layout; + } + + /// + /// Sets the minimum width of the layout. + /// + /// The layout. + /// The size. + /// The same instance so that multiple calls can be chained. + public static Layout MinimumSize(this Layout layout, int size) + { + if (layout is null) + { + throw new ArgumentNullException(nameof(layout)); + } + + layout.MinimumSize = size; + return layout; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ListExtensions.cs b/src/Spectre.Console/Extensions/ListExtensions.cs new file mode 100644 index 00000000..2a7862c1 --- /dev/null +++ b/src/Spectre.Console/Extensions/ListExtensions.cs @@ -0,0 +1,34 @@ +namespace Spectre.Console; + +internal static class ListExtensions +{ + public static void RemoveLast(this List list) + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + if (list.Count > 0) + { + list.RemoveAt(list.Count - 1); + } + } + + public static void AddOrReplaceLast(this List list, T item) + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + if (list.Count == 0) + { + list.Add(item); + } + else + { + list[list.Count - 1] = item; + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs b/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs new file mode 100644 index 00000000..123da4d9 --- /dev/null +++ b/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs @@ -0,0 +1,62 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class LiveDisplayExtensions +{ + /// + /// Sets whether or not auto clear is enabled. + /// If enabled, the live display will be cleared when done. + /// + /// The instance. + /// Whether or not auto clear is enabled. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay AutoClear(this LiveDisplay live, bool enabled) + { + if (live is null) + { + throw new ArgumentNullException(nameof(live)); + } + + live.AutoClear = enabled; + + return live; + } + + /// + /// Sets the vertical overflow strategy. + /// + /// The instance. + /// The overflow strategy to use. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay Overflow(this LiveDisplay live, VerticalOverflow overflow) + { + if (live is null) + { + throw new ArgumentNullException(nameof(live)); + } + + live.Overflow = overflow; + + return live; + } + + /// + /// Sets the vertical overflow cropping strategy. + /// + /// The instance. + /// The overflow cropping strategy to use. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay Cropping(this LiveDisplay live, VerticalOverflowCropping cropping) + { + if (live is null) + { + throw new ArgumentNullException(nameof(live)); + } + + live.Cropping = cropping; + + return live; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/OverflowableExtensions.cs b/src/Spectre.Console/Extensions/OverflowableExtensions.cs new file mode 100644 index 00000000..a8a47f29 --- /dev/null +++ b/src/Spectre.Console/Extensions/OverflowableExtensions.cs @@ -0,0 +1,77 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class OverflowableExtensions +{ + /// + /// Folds any overflowing text. + /// + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Fold(this T obj) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Overflow(obj, Console.Overflow.Fold); + } + + /// + /// Crops any overflowing text. + /// + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Crop(this T obj) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Overflow(obj, Console.Overflow.Crop); + } + + /// + /// Crops any overflowing text and adds an ellipsis to the end. + /// + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Ellipsis(this T obj) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Overflow(obj, Console.Overflow.Ellipsis); + } + + /// + /// Sets the overflow strategy. + /// + /// An object implementing . + /// The overflowable object instance. + /// The overflow strategy to use. + /// The same instance so that multiple calls can be chained. + public static T Overflow(this T obj, Overflow overflow) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Overflow = overflow; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PaddableExtensions.cs b/src/Spectre.Console/Extensions/PaddableExtensions.cs new file mode 100644 index 00000000..7cc01ad9 --- /dev/null +++ b/src/Spectre.Console/Extensions/PaddableExtensions.cs @@ -0,0 +1,128 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PaddableExtensions +{ + /// + /// Sets the left padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The left padding. + /// The same instance so that multiple calls can be chained. + public static T PadLeft(this T obj, int left) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(left, obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); + } + + /// + /// Sets the top padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The top padding. + /// The same instance so that multiple calls can be chained. + public static T PadTop(this T obj, int top) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), top, obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); + } + + /// + /// Sets the right padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The right padding. + /// The same instance so that multiple calls can be chained. + public static T PadRight(this T obj, int right) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), right, obj.Padding.GetBottomSafe())); + } + + /// + /// Sets the bottom padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The bottom padding. + /// The same instance so that multiple calls can be chained. + public static T PadBottom(this T obj, int bottom) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), bottom)); + } + + /// + /// Sets the left, top, right and bottom padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The left padding to apply. + /// The top padding to apply. + /// The right padding to apply. + /// The bottom padding to apply. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, int left, int top, int right, int bottom) + where T : class, IPaddable + { + return Padding(obj, new Padding(left, top, right, bottom)); + } + + /// + /// Sets the horizontal and vertical padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The left and right padding. + /// The top and bottom padding. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, int horizontal, int vertical) + where T : class, IPaddable + { + return Padding(obj, new Padding(horizontal, vertical)); + } + + /// + /// Sets the padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The padding to apply. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, Padding padding) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Padding = padding; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PaddingExtensions.cs b/src/Spectre.Console/Extensions/PaddingExtensions.cs new file mode 100644 index 00000000..9949092d --- /dev/null +++ b/src/Spectre.Console/Extensions/PaddingExtensions.cs @@ -0,0 +1,47 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PaddingExtensions +{ + /// + /// Gets the left padding. + /// + /// The padding. + /// The left padding or zero if padding is null. + public static int GetLeftSafe(this Padding? padding) + { + return padding?.Left ?? 0; + } + + /// + /// Gets the right padding. + /// + /// The padding. + /// The right padding or zero if padding is null. + public static int GetRightSafe(this Padding? padding) + { + return padding?.Right ?? 0; + } + + /// + /// Gets the top padding. + /// + /// The padding. + /// The top padding or zero if padding is null. + public static int GetTopSafe(this Padding? padding) + { + return padding?.Top ?? 0; + } + + /// + /// Gets the bottom padding. + /// + /// The padding. + /// The bottom padding or zero if padding is null. + public static int GetBottomSafe(this Padding? padding) + { + return padding?.Bottom ?? 0; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PanelExtensions.cs b/src/Spectre.Console/Extensions/PanelExtensions.cs new file mode 100644 index 00000000..d8374650 --- /dev/null +++ b/src/Spectre.Console/Extensions/PanelExtensions.cs @@ -0,0 +1,74 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PanelExtensions +{ + /// + /// Sets the panel header. + /// + /// The panel. + /// The header text. + /// The header alignment. + /// The same instance so that multiple calls can be chained. + public static Panel Header(this Panel panel, string text, Justify? alignment = null) + { + if (panel is null) + { + throw new ArgumentNullException(nameof(panel)); + } + + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + alignment ??= panel.Header?.Justification; + return Header(panel, new PanelHeader(text, alignment)); + } + + /// + /// Sets the panel header alignment. + /// + /// The panel. + /// The header alignment. + /// The same instance so that multiple calls can be chained. + public static Panel HeaderAlignment(this Panel panel, Justify alignment) + { + if (panel is null) + { + throw new ArgumentNullException(nameof(panel)); + } + + if (panel.Header != null) + { + // Update existing style + panel.Header.Justification = alignment; + } + else + { + // Create header + Header(panel, string.Empty, alignment); + } + + return panel; + } + + /// + /// Sets the panel header. + /// + /// The panel. + /// The header to use. + /// The same instance so that multiple calls can be chained. + public static Panel Header(this Panel panel, PanelHeader header) + { + if (panel is null) + { + throw new ArgumentNullException(nameof(panel)); + } + + panel.Header = header; + return panel; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs new file mode 100644 index 00000000..bd365a2d --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs @@ -0,0 +1,51 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PercentageColumnExtensions +{ + /// + /// Sets the style for a non-complete task. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static PercentageColumn Style(this PercentageColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.Style = style; + return column; + } + + /// + /// Sets the style for a completed task. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static PercentageColumn CompletedStyle(this PercentageColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.CompletedStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs new file mode 100644 index 00000000..4d46d0ee --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs @@ -0,0 +1,73 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressBarColumnExtensions +{ + /// + /// Sets the style of completed portions of the progress bar. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn CompletedStyle(this ProgressBarColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.CompletedStyle = style; + return column; + } + + /// + /// Sets the style of a finished progress bar. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn FinishedStyle(this ProgressBarColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.FinishedStyle = style; + return column; + } + + /// + /// Sets the style of remaining portions of the progress bar. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn RemainingStyle(this ProgressBarColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.RemainingStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs new file mode 100644 index 00000000..dc8cf01c --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs @@ -0,0 +1,108 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressExtensions +{ + /// + /// Sets the columns to be used for an instance. + /// + /// The instance. + /// The columns to use. + /// The same instance so that multiple calls can be chained. + public static Progress Columns(this Progress progress, params ProgressColumn[] columns) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + if (!columns.Any()) + { + throw new InvalidOperationException("At least one column must be specified."); + } + + progress.Columns.Clear(); + progress.Columns.AddRange(columns); + + return progress; + } + + /// + /// Sets an optional hook to intercept rendering. + /// + /// The instance. + /// The custom render function. + /// The same instance so that multiple calls can be chained. + public static Progress UseRenderHook(this Progress progress, Func, IRenderable> renderHook) + { + progress.RenderHook = renderHook; + + return progress; + } + + /// + /// Sets whether or not auto refresh is enabled. + /// If disabled, you will manually have to refresh the progress. + /// + /// The instance. + /// Whether or not auto refresh is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress AutoRefresh(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.AutoRefresh = enabled; + + return progress; + } + + /// + /// Sets whether or not auto clear is enabled. + /// If enabled, the task tabled will be removed once + /// all tasks have completed. + /// + /// The instance. + /// Whether or not auto clear is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress AutoClear(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.AutoClear = enabled; + + return progress; + } + + /// + /// Sets whether or not hide completed is enabled. + /// If enabled, the task tabled will be removed once it is + /// completed. + /// + /// The instance. + /// Whether or not hide completed is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress HideCompleted(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.HideCompleted = enabled; + + return progress; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs new file mode 100644 index 00000000..309ee861 --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs @@ -0,0 +1,75 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressTaskExtensions +{ + /// + /// Sets the task description. + /// + /// The task. + /// The description. + /// The same instance so that multiple calls can be chained. + public static ProgressTask Description(this ProgressTask task, string description) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.Description = description; + return task; + } + + /// + /// Sets the max value of the task. + /// + /// The task. + /// The max value. + /// The same instance so that multiple calls can be chained. + public static ProgressTask MaxValue(this ProgressTask task, double value) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.MaxValue = value; + return task; + } + + /// + /// Sets the value of the task. + /// + /// The task. + /// The value. + /// The same instance so that multiple calls can be chained. + public static ProgressTask Value(this ProgressTask task, double value) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.Value = value; + return task; + } + + /// + /// Sets whether the task is considered indeterminate or not. + /// + /// The task. + /// Whether the task is considered indeterminate or not. + /// The same instance so that multiple calls can be chained. + public static ProgressTask IsIndeterminate(this ProgressTask task, bool indeterminate = true) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.IsIndeterminate = indeterminate; + return task; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs new file mode 100644 index 00000000..a542b755 --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs @@ -0,0 +1,29 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RemainingTimeColumnExtensions +{ + /// + /// Sets the style of the remaining time text. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static RemainingTimeColumn Style(this RemainingTimeColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.Style = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs new file mode 100644 index 00000000..fcfeed23 --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs @@ -0,0 +1,59 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class SpinnerColumnExtensions +{ + /// + /// Sets the style of the spinner. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn Style(this SpinnerColumn column, Style? style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + column.Style = style; + return column; + } + + /// + /// Sets the text that should be shown instead of the spinner + /// once a task completes. + /// + /// The column. + /// The text. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn CompletedText(this SpinnerColumn column, string? text) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + column.CompletedText = text; + return column; + } + + /// + /// Sets the completed style of the spinner. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn CompletedStyle(this SpinnerColumn column, Style? style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + column.CompletedStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs b/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs new file mode 100644 index 00000000..6edcbb40 --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs @@ -0,0 +1,58 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StatusContextExtensions +{ + /// + /// Sets the status message. + /// + /// The status context. + /// The status message. + /// The same instance so that multiple calls can be chained. + public static StatusContext Status(this StatusContext context, string status) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.Status = status; + return context; + } + + /// + /// Sets the spinner. + /// + /// The status context. + /// The spinner. + /// The same instance so that multiple calls can be chained. + public static StatusContext Spinner(this StatusContext context, Spinner spinner) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.Spinner = spinner; + return context; + } + + /// + /// Sets the spinner style. + /// + /// The status context. + /// The spinner style. + /// The same instance so that multiple calls can be chained. + public static StatusContext SpinnerStyle(this StatusContext context, Style? style) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.SpinnerStyle = style; + return context; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs b/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs new file mode 100644 index 00000000..9b5c9e28 --- /dev/null +++ b/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs @@ -0,0 +1,59 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StatusExtensions +{ + /// + /// Sets whether or not auto refresh is enabled. + /// If disabled, you will manually have to refresh the progress. + /// + /// The instance. + /// Whether or not auto refresh is enabled. + /// The same instance so that multiple calls can be chained. + public static Status AutoRefresh(this Status status, bool enabled) + { + if (status is null) + { + throw new ArgumentNullException(nameof(status)); + } + + status.AutoRefresh = enabled; + return status; + } + + /// + /// Sets the spinner. + /// + /// The instance. + /// The spinner. + /// The same instance so that multiple calls can be chained. + public static Status Spinner(this Status status, Spinner spinner) + { + if (status is null) + { + throw new ArgumentNullException(nameof(status)); + } + + status.Spinner = spinner; + return status; + } + + /// + /// Sets the spinner style. + /// + /// The instance. + /// The spinner style. + /// The same instance so that multiple calls can be chained. + public static Status SpinnerStyle(this Status status, Style? style) + { + if (status is null) + { + throw new ArgumentNullException(nameof(status)); + } + + status.SpinnerStyle = style; + return status; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RecorderExtensions.cs b/src/Spectre.Console/Extensions/RecorderExtensions.cs new file mode 100644 index 00000000..459a2ec7 --- /dev/null +++ b/src/Spectre.Console/Extensions/RecorderExtensions.cs @@ -0,0 +1,40 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RecorderExtensions +{ + private static readonly TextEncoder _textEncoder = new TextEncoder(); + private static readonly HtmlEncoder _htmlEncoder = new HtmlEncoder(); + + /// + /// Exports the recorded content as text. + /// + /// The recorder. + /// The recorded content as text. + public static string ExportText(this Recorder recorder) + { + if (recorder is null) + { + throw new ArgumentNullException(nameof(recorder)); + } + + return recorder.Export(_textEncoder); + } + + /// + /// Exports the recorded content as HTML. + /// + /// The recorder. + /// The recorded content as HTML. + public static string ExportHtml(this Recorder recorder) + { + if (recorder is null) + { + throw new ArgumentNullException(nameof(recorder)); + } + + return recorder.Export(_htmlEncoder); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RenderOptionsExtensions.cs b/src/Spectre.Console/Extensions/RenderOptionsExtensions.cs new file mode 100644 index 00000000..a8a721eb --- /dev/null +++ b/src/Spectre.Console/Extensions/RenderOptionsExtensions.cs @@ -0,0 +1,10 @@ +namespace Spectre.Console; + +internal static class RenderOptionsExtensions +{ + public static BoxBorder GetSafeBorder(this RenderOptions options, T border) + where T : IHasBoxBorder, IHasBorder + { + return BoxExtensions.GetSafeBorder(border.Border, !options.Unicode && border.UseSafeBorder); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RenderableExtensions.cs b/src/Spectre.Console/Extensions/RenderableExtensions.cs new file mode 100644 index 00000000..4761b2a0 --- /dev/null +++ b/src/Spectre.Console/Extensions/RenderableExtensions.cs @@ -0,0 +1,42 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RenderableExtensions +{ + /// + /// Gets the segments for a renderable using the specified console. + /// + /// The renderable. + /// The console. + /// An enumerable containing segments representing the specified . + public static IEnumerable GetSegments(this IRenderable renderable, IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + var context = RenderOptions.Create(console, console.Profile.Capabilities); + var renderables = console.Pipeline.Process(context, new[] { renderable }); + + return GetSegments(console, context, renderables); + } + + private static IEnumerable GetSegments(IAnsiConsole console, RenderOptions options, IEnumerable renderables) + { + var result = new List(); + foreach (var renderable in renderables) + { + result.AddRange(renderable.Render(options, console.Profile.Width)); + } + + return Segment.Merge(result); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RuleExtensions.cs b/src/Spectre.Console/Extensions/RuleExtensions.cs new file mode 100644 index 00000000..02d474fa --- /dev/null +++ b/src/Spectre.Console/Extensions/RuleExtensions.cs @@ -0,0 +1,51 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RuleExtensions +{ + /// + /// Sets the rule title. + /// + /// The rule. + /// The title. + /// The same instance so that multiple calls can be chained. + public static Rule RuleTitle(this Rule rule, string title) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + if (title is null) + { + throw new ArgumentNullException(nameof(title)); + } + + rule.Title = title; + return rule; + } + + /// + /// Sets the rule style. + /// + /// The rule. + /// The rule style. + /// The same instance so that multiple calls can be chained. + public static Rule RuleStyle(this Rule rule, Style style) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + rule.Style = style; + return rule; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StackExtensions.cs b/src/Spectre.Console/Extensions/StackExtensions.cs new file mode 100644 index 00000000..a25143e8 --- /dev/null +++ b/src/Spectre.Console/Extensions/StackExtensions.cs @@ -0,0 +1,20 @@ +namespace Spectre.Console; + +internal static class StackExtensions +{ + public static void PushRange(this Stack stack, IEnumerable source) + { + if (stack is null) + { + throw new ArgumentNullException(nameof(stack)); + } + + if (source != null) + { + foreach (var item in source) + { + stack.Push(item); + } + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StringBuilderExtensions.cs b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs new file mode 100644 index 00000000..cba13aa6 --- /dev/null +++ b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs @@ -0,0 +1,36 @@ +namespace Spectre.Console; + +internal static class StringBuilderExtensions +{ + public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, int? value) + { + return AppendWithStyle(builder, style, value?.ToString(CultureInfo.InvariantCulture)); + } + + public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, string? value) + { + value ??= string.Empty; + + if (style != null) + { + return builder.Append('[') + .Append(style.ToMarkup()) + .Append(']') + .Append(value.EscapeMarkup()) + .Append("[/]"); + } + + return builder.Append(value); + } + + public static void AppendSpan(this StringBuilder builder, ReadOnlySpan span) + { + // NetStandard 2 lacks the override for StringBuilder to add the span. We'll need to convert the span + // to a string for it, but for .NET 6.0 or newer we'll use the override. +#if NETSTANDARD2_0 + builder.Append(span.ToString()); +#else + builder.Append(span); +#endif + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StringExtensions.cs b/src/Spectre.Console/Extensions/StringExtensions.cs new file mode 100644 index 00000000..0c324e4f --- /dev/null +++ b/src/Spectre.Console/Extensions/StringExtensions.cs @@ -0,0 +1,306 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StringExtensions +{ + // Cache whether or not internally normalized line endings + // already are normalized. No reason to do yet another replace if it is. + private static readonly bool _alreadyNormalized + = Environment.NewLine.Equals("\n", StringComparison.OrdinalIgnoreCase); + + /// + /// Escapes text so that it won’t be interpreted as markup. + /// + /// The text to escape. + /// A string that is safe to use in markup. + public static string EscapeMarkup(this string? text) + { + if (text == null) + { + return string.Empty; + } + + return text + .ReplaceExact("[", "[[") + .ReplaceExact("]", "]]"); + } + + /// + /// Removes markup from the specified string. + /// + /// The text to remove markup from. + /// A string that does not have any markup. + public static string RemoveMarkup(this string? text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return string.Empty; + } + + var result = new StringBuilder(); + + var tokenizer = new MarkupTokenizer(text); + while (tokenizer.MoveNext() && tokenizer.Current != null) + { + if (tokenizer.Current.Kind == MarkupTokenKind.Text) + { + result.Append(tokenizer.Current.Value); + } + } + + return result.ToString(); + } + + /// + /// Gets the cell width of the specified text. + /// + /// The text to get the cell width of. + /// The cell width of the text. + public static int GetCellWidth(this string text) + { + return Cell.GetCellLength(text); + } + + internal static string CapitalizeFirstLetter(this string? text, CultureInfo? culture = null) + { + if (text == null) + { + return string.Empty; + } + + culture ??= CultureInfo.InvariantCulture; + + if (text.Length > 0 && char.IsLower(text[0])) + { + text = string.Format(culture, "{0}{1}", char.ToUpper(text[0], culture), text.Substring(1)); + } + + return text; + } + + internal static string? RemoveNewLines(this string? text) + { + return text?.ReplaceExact("\r\n", string.Empty) + ?.ReplaceExact("\n", string.Empty); + } + + internal static string NormalizeNewLines(this string? text, bool native = false) + { + text = text?.ReplaceExact("\r\n", "\n"); + text ??= string.Empty; + + if (native && !_alreadyNormalized) + { + text = text.ReplaceExact("\n", Environment.NewLine); + } + + return text; + } + + internal static string[] SplitLines(this string text) + { + var result = text?.NormalizeNewLines()?.Split(new[] { '\n' }, StringSplitOptions.None); + return result ?? Array.Empty(); + } + + internal static string[] SplitWords(this string word, StringSplitOptions options = StringSplitOptions.None) + { + var result = new List(); + + static string Read(StringBuffer reader, Func criteria) + { + var buffer = new StringBuilder(); + while (!reader.Eof) + { + var current = reader.Peek(); + if (!criteria(current)) + { + break; + } + + buffer.Append(reader.Read()); + } + + return buffer.ToString(); + } + + using (var reader = new StringBuffer(word)) + { + while (!reader.Eof) + { + var current = reader.Peek(); + if (char.IsWhiteSpace(current)) + { + var x = Read(reader, c => char.IsWhiteSpace(c)); + if (options != StringSplitOptions.RemoveEmptyEntries) + { + result.Add(x); + } + } + else + { + result.Add(Read(reader, c => !char.IsWhiteSpace(c))); + } + } + } + + return result.ToArray(); + } + + internal static string Repeat(this string text, int count) + { + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + if (count <= 0) + { + return string.Empty; + } + + if (count == 1) + { + return text; + } + + return string.Concat(Enumerable.Repeat(text, count)); + } + + internal static string ReplaceExact(this string text, string oldValue, string? newValue) + { +#if NETSTANDARD2_0 + return text.Replace(oldValue, newValue); +#else + return text.Replace(oldValue, newValue, StringComparison.Ordinal); +#endif + } + + internal static bool ContainsExact(this string text, string value) + { +#if NETSTANDARD2_0 + return text.Contains(value); +#else + return text.Contains(value, StringComparison.Ordinal); +#endif + } + +#if NETSTANDARD2_0 + internal static bool Contains(this string target, string value, System.StringComparison comparisonType) + { + return target.IndexOf(value, comparisonType) != -1; + } +#endif + + /// + /// "Masks" every character in a string. + /// + /// String value to mask. + /// Character to use for masking. + /// Masked string. + public static string Mask(this string value, char? mask) + { + if (mask is null) + { + return string.Empty; + } + + return new string(mask.Value, value.Length); + } + + /// + /// Highlights the first text match in provided value. + /// + /// Input value. + /// Text to search for. + /// The style to apply to the matched text. + /// Markup of input with the first matched text highlighted. + internal static string Highlight(this string value, string searchText, Style? highlightStyle) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (searchText is null) + { + throw new ArgumentNullException(nameof(searchText)); + } + + if (highlightStyle is null) + { + throw new ArgumentNullException(nameof(highlightStyle)); + } + + if (searchText.Length == 0) + { + return value; + } + + var foundSearchPattern = false; + var builder = new StringBuilder(); + using var tokenizer = new MarkupTokenizer(value); + while (tokenizer.MoveNext()) + { + var token = tokenizer.Current!; + + switch (token.Kind) + { + case MarkupTokenKind.Text: + { + var tokenValue = token.Value; + if (tokenValue.Length == 0) + { + break; + } + + if (foundSearchPattern) + { + builder.Append(tokenValue); + break; + } + + var index = tokenValue.IndexOf(searchText, StringComparison.OrdinalIgnoreCase); + if (index == -1) + { + builder.Append(tokenValue); + break; + } + + foundSearchPattern = true; + var before = tokenValue.Substring(0, index); + var match = tokenValue.Substring(index, searchText.Length); + var after = tokenValue.Substring(index + searchText.Length); + + builder + .Append(before) + .AppendWithStyle(highlightStyle, match) + .Append(after); + + break; + } + + case MarkupTokenKind.Open: + { + builder.Append("[" + token.Value + "]"); + break; + } + + case MarkupTokenKind.Close: + { + builder.Append("[/]"); + break; + } + + default: + { + throw new InvalidOperationException("Unknown markup token kind."); + } + } + } + + return builder.ToString(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StyleExtensions.cs b/src/Spectre.Console/Extensions/StyleExtensions.cs new file mode 100644 index 00000000..1ddc4337 --- /dev/null +++ b/src/Spectre.Console/Extensions/StyleExtensions.cs @@ -0,0 +1,104 @@ +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StyleExtensions +{ + /// + /// Creates a new style from the specified one with + /// the specified foreground color. + /// + /// The style. + /// The foreground color. + /// The same instance so that multiple calls can be chained. + public static Style Foreground(this Style style, Color color) + { + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + return new Style( + foreground: color, + background: style.Background, + decoration: style.Decoration); + } + + /// + /// Creates a new style from the specified one with + /// the specified background color. + /// + /// The style. + /// The background color. + /// The same instance so that multiple calls can be chained. + public static Style Background(this Style style, Color color) + { + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + return new Style( + foreground: style.Foreground, + background: color, + decoration: style.Decoration); + } + + /// + /// Creates a new style from the specified one with + /// the specified text decoration. + /// + /// The style. + /// The text decoration. + /// The same instance so that multiple calls can be chained. + public static Style Decoration(this Style style, Decoration decoration) + { + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + return new Style( + foreground: style.Foreground, + background: style.Background, + decoration: decoration); + } + + /// + /// Creates a new style from the specified one with + /// the specified link. + /// + /// The style. + /// The link. + /// The same instance so that multiple calls can be chained. + public static Style Link(this Style style, string link) + { + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + return new Style( + foreground: style.Foreground, + background: style.Background, + decoration: style.Decoration, + link: link); + } + + internal static Style Combine(this Style style, IEnumerable