From ae32785f2177ecf1bebe37ac455f3b78344e3e09 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Fri, 27 Nov 2020 08:12:29 +0100 Subject: [PATCH] Add progress task list support --- .github/workflows/ci.yaml | 9 +- docs/input/assets/images/progress.gif | Bin 0 -> 168006 bytes docs/input/assets/images/progress.png | Bin 0 -> 13910 bytes .../input/assets/images/progress_fallback.png | Bin 0 -> 33656 bytes docs/input/progress.md | 78 +++++ examples/Info/Program.cs | 3 +- examples/Progress/DescriptionGenerator.cs | 45 +++ examples/Progress/Program.cs | 75 +++++ examples/Progress/Progress.csproj | 19 ++ examples/Prompt/Program.cs | 7 + src/.editorconfig | 5 +- ...ts.Should_Render_Progress_Bar.verified.txt | 1 + .../Tools/PlainConsole.cs | 17 +- .../Tools/TestableAnsiConsole.cs | 20 +- .../Unit/ProgressTests.cs | 58 ++++ .../Unit/RenderHookTests.cs | 34 +++ src/Spectre.Console.sln | 15 + src/Spectre.Console/AnsiConsole.Progress.cs | 17 ++ src/Spectre.Console/AnsiConsoleSettings.cs | 6 + src/Spectre.Console/Capabilities.cs | 9 +- src/Spectre.Console/ColorSystemSupport.cs | 12 +- .../AnsiConsoleExtensions.Markup.cs | 3 +- .../AnsiConsoleExtensions.Progress.cs | 25 ++ .../AnsiConsoleExtensions.Rendering.cs | 29 +- .../Extensions/AnsiConsoleExtensions.cs | 39 ++- .../Columns/PercentageColumnExtensions.cs | 54 ++++ .../Columns/ProgressBarColumnExtensions.cs | 76 +++++ .../Columns/RemainingTimeColumnExtensions.cs | 32 +++ .../Columns/SpinnerColumnExtensions.cs | 32 +++ .../Extensions/PanelExtensions.cs | 2 +- .../Extensions/ProgressExtensions.cs | 79 ++++++ .../Extensions/ProgressTaskExtensions.cs | 44 +++ .../Extensions/StringBuilderExtensions.cs | 2 +- .../Extensions/StringExtensions.cs | 11 +- src/Spectre.Console/IAnsiConsole.cs | 12 +- src/Spectre.Console/InteractionSupport.cs | 24 ++ .../Internal/Ansi/AnsiDetector.cs | 2 + .../Internal/Backends/Ansi/AnsiBackend.cs | 49 +++- .../Internal/Backends/BackendBuilder.cs | 8 +- .../Backends/Fallback/FallbackBackend.cs | 23 +- src/Spectre.Console/Internal/HtmlEncoder.cs | 5 + .../Internal/InteractivityDetector.cs | 52 ++++ .../Internal/ResourceReader.cs | 2 +- src/Spectre.Console/Internal/TextEncoder.cs | 5 + .../Progress/Columns/PercentageColumn.cs | 32 +++ .../Progress/Columns/ProgressBarColumn.cs | 45 +++ .../Progress/Columns/RemainingTimeColumn.cs | 28 ++ .../Progress/Columns/SpinnerColumn.cs | 44 +++ .../Progress/Columns/TaskDescriptionColumn.cs | 18 ++ src/Spectre.Console/Progress/Progress.cs | 121 ++++++++ .../Progress/ProgressColumn.cs | 25 ++ .../Progress/ProgressContext.cs | 70 +++++ .../Progress/ProgressRefreshThread.cs | 58 ++++ .../Progress/ProgressRenderer.cs | 22 ++ .../Progress/ProgressSample.cs | 16 ++ src/Spectre.Console/Progress/ProgressTask.cs | 267 ++++++++++++++++++ .../Progress/ProgressTaskSettings.cs | 20 ++ .../Progress/ProgressTaskState.cs | 81 ++++++ .../Renderers/InteractiveProgressRenderer.cs | 109 +++++++ .../NonInteractiveProgressRenderer.cs | 122 ++++++++ src/Spectre.Console/Recorder.cs | 37 ++- src/Spectre.Console/Rendering/IRenderHook.cs | 18 ++ .../Rendering/LiveRenderable.cs | 81 ++++++ .../Rendering/RenderContext.cs | 2 +- .../Rendering/RenderHookScope.cs | 31 ++ .../Rendering/RenderPipeline.cs | 66 +++++ src/Spectre.Console/Rendering/Segment.cs | 25 +- .../Widgets/ControlSequence.cs | 25 ++ src/Spectre.Console/Widgets/ProgressBar.cs | 41 +++ src/Spectre.Console/Widgets/Rule.cs | 2 +- src/Spectre.Console/Widgets/Table.cs | 10 +- 71 files changed, 2350 insertions(+), 106 deletions(-) create mode 100644 docs/input/assets/images/progress.gif create mode 100644 docs/input/assets/images/progress.png create mode 100644 docs/input/assets/images/progress_fallback.png create mode 100644 docs/input/progress.md create mode 100644 examples/Progress/DescriptionGenerator.cs create mode 100644 examples/Progress/Program.cs create mode 100644 examples/Progress/Progress.csproj create mode 100644 src/Spectre.Console.Tests/Expectations/ProgressBarTests.Should_Render_Progress_Bar.verified.txt create mode 100644 src/Spectre.Console.Tests/Unit/ProgressTests.cs create mode 100644 src/Spectre.Console.Tests/Unit/RenderHookTests.cs create mode 100644 src/Spectre.Console/AnsiConsole.Progress.cs create mode 100644 src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs create mode 100644 src/Spectre.Console/Extensions/Columns/PercentageColumnExtensions.cs create mode 100644 src/Spectre.Console/Extensions/Columns/ProgressBarColumnExtensions.cs create mode 100644 src/Spectre.Console/Extensions/Columns/RemainingTimeColumnExtensions.cs create mode 100644 src/Spectre.Console/Extensions/Columns/SpinnerColumnExtensions.cs create mode 100644 src/Spectre.Console/Extensions/ProgressExtensions.cs create mode 100644 src/Spectre.Console/Extensions/ProgressTaskExtensions.cs create mode 100644 src/Spectre.Console/InteractionSupport.cs create mode 100644 src/Spectre.Console/Internal/InteractivityDetector.cs create mode 100644 src/Spectre.Console/Progress/Columns/PercentageColumn.cs create mode 100644 src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs create mode 100644 src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs create mode 100644 src/Spectre.Console/Progress/Columns/SpinnerColumn.cs create mode 100644 src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs create mode 100644 src/Spectre.Console/Progress/Progress.cs create mode 100644 src/Spectre.Console/Progress/ProgressColumn.cs create mode 100644 src/Spectre.Console/Progress/ProgressContext.cs create mode 100644 src/Spectre.Console/Progress/ProgressRefreshThread.cs create mode 100644 src/Spectre.Console/Progress/ProgressRenderer.cs create mode 100644 src/Spectre.Console/Progress/ProgressSample.cs create mode 100644 src/Spectre.Console/Progress/ProgressTask.cs create mode 100644 src/Spectre.Console/Progress/ProgressTaskSettings.cs create mode 100644 src/Spectre.Console/Progress/ProgressTaskState.cs create mode 100644 src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs create mode 100644 src/Spectre.Console/Progress/Renderers/NonInteractiveProgressRenderer.cs create mode 100644 src/Spectre.Console/Rendering/IRenderHook.cs create mode 100644 src/Spectre.Console/Rendering/LiveRenderable.cs create mode 100644 src/Spectre.Console/Rendering/RenderHookScope.cs create mode 100644 src/Spectre.Console/Rendering/RenderPipeline.cs create mode 100644 src/Spectre.Console/Widgets/ControlSequence.cs create mode 100644 src/Spectre.Console/Widgets/ProgressBar.cs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c67b41a..d116ede 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -69,14 +69,7 @@ jobs: shell: bash run: | dotnet tool restore - dotnet example info - dotnet example tables - dotnet example grids - dotnet example panels - dotnet example colors - dotnet example emojis - dotnet example exceptions - dotnet example calendars + dotnet example --all - name: Build shell: bash diff --git a/docs/input/assets/images/progress.gif b/docs/input/assets/images/progress.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ec3868935bede92543af9a439abc6abe4941516 GIT binary patch literal 168006 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ⅆ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 literal 0 HcmV?d00001 diff --git a/docs/input/progress.md b/docs/input/progress.md new file mode 100644 index 0000000..ccfbbec --- /dev/null +++ b/docs/input/progress.md @@ -0,0 +1,78 @@ +Title: Progress +Order: 5 +--- + +Spectre.Console can display information about long running tasks in the console. + + + +If the current terminal isn't considered "interactive", such as when running +in a continuous integration system, or the terminal can't display +ANSI control sequence, any progress will be displayed in a simpler way. + + + +# Usage + +```csharp +// Synchronous +AnsiConsole.Progress() + .Start(ctx => + { + // Define tasks + var task1 = ctx.AddTask("[green]Reticulating splines[/]"); + var task2 = ctx.AddTask("[green]Folding space[/]"); + + while(!ctx.IsFinished) + { + task1.Increment(1.5); + task2.Increment(0.5); + } + }); +``` + +## Asynchronous progress + +If you prefer to use async/await, you can use `StartAsync` instead of `Start`. + +```csharp +// Asynchronous +await AnsiConsole.Progress() + .StartAsync(async ctx => + { + // Define tasks + var task1 = ctx.AddTask("[green]Reticulating splines[/]"); + var task2 = ctx.AddTask("[green]Folding space[/]"); + + while (!ctx.IsFinished) + { + // Simulate some work + await Task.Delay(250); + + // Increment + task1.Increment(1.5); + task2.Increment(0.5); + } + }); +``` + +# Configure + +```csharp +// Asynchronous +AnsiConsole.Progress() + .AutoRefresh(false) // Turn off auto refresh + .AutoClear(false) // Do not remove the task list when done + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), // Task description + new ProgressBarColumn(), // Progress bar + new PercentageColumn(), // Percentage + new RemainingTimeColumn(), // Remaining time + new SpinnerColumn(), // Spinner + }) + .Start(ctx => + { + // Omitted + }); +``` \ No newline at end of file diff --git a/examples/Info/Program.cs b/examples/Info/Program.cs index 4aa82d4..0c2f624 100644 --- a/examples/Info/Program.cs +++ b/examples/Info/Program.cs @@ -1,4 +1,3 @@ -using System; using Spectre.Console; namespace InfoExample @@ -13,7 +12,7 @@ namespace InfoExample .AddRow("[b]Color system[/]", $"{AnsiConsole.Capabilities.ColorSystem}") .AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Capabilities.SupportsAnsi)}") .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Capabilities.LegacyConsole)}") - .AddRow("[b]Interactive?[/]", $"{YesNo(Environment.UserInteractive)}") + .AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Capabilities.SupportsInteraction)}") .AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Width}") .AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Height}"); diff --git a/examples/Progress/DescriptionGenerator.cs b/examples/Progress/DescriptionGenerator.cs new file mode 100644 index 0000000..a4f7861 --- /dev/null +++ b/examples/Progress/DescriptionGenerator.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; + +namespace ProgressExample +{ + public static class DescriptionGenerator + { + private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" }; + private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" }; + + private static readonly Random _random; + private static readonly HashSet _used; + + static DescriptionGenerator() + { + _random = new Random(DateTime.Now.Millisecond); + _used = new HashSet(); + } + + public static bool TryGenerate(out string name) + { + var iterations = 0; + while (iterations < 25) + { + name = Generate(); + if (!_used.Contains(name)) + { + _used.Add(name); + return true; + } + + iterations++; + } + + name = Generate(); + return false; + } + + public static string Generate() + { + return _verbs[_random.Next(0, _verbs.Length)] + + " " + _nouns[_random.Next(0, _nouns.Length)]; + } + } +} diff --git a/examples/Progress/Program.cs b/examples/Progress/Program.cs new file mode 100644 index 0000000..6215b9b --- /dev/null +++ b/examples/Progress/Program.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Spectre.Console; + +namespace ProgressExample +{ + public static class Program + { + public static void Main() + { + AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); + + // Show progress + AnsiConsole.Progress() + .AutoClear(false) + .Columns(new ProgressColumn[] + { + new TaskDescriptionColumn(), // Task description + new ProgressBarColumn(), // Progress bar + new PercentageColumn(), // Percentage + new RemainingTimeColumn(), // Remaining time + new SpinnerColumn(), // Spinner + }) + .Start(ctx => + { + var random = new Random(DateTime.Now.Millisecond); + var tasks = CreateTasks(ctx, random); + + while (!ctx.IsFinished) + { + // Increment progress + foreach (var (task, increment) in tasks) + { + task.Increment(random.NextDouble() * increment); + } + + // Write some random things to the terminal + if (random.NextDouble() < 0.1) + { + WriteLogMessage(); + } + + // Simulate some delay + Thread.Sleep(100); + } + }); + + // Done + AnsiConsole.MarkupLine("[green]Done![/]"); + } + + private static List<(ProgressTask, int)> CreateTasks(ProgressContext progress, Random random) + { + var tasks = new List<(ProgressTask, int)>(); + while (tasks.Count < 5) + { + if (DescriptionGenerator.TryGenerate(out var name)) + { + tasks.Add((progress.AddTask(name), random.Next(2, 10))); + } + } + + return tasks; + } + + private static void WriteLogMessage() + { + AnsiConsole.MarkupLine( + "[grey]LOG:[/] " + + DescriptionGenerator.Generate() + + "[grey]...[/]"); + } + } +} diff --git a/examples/Progress/Progress.csproj b/examples/Progress/Progress.csproj new file mode 100644 index 0000000..f84c230 --- /dev/null +++ b/examples/Progress/Progress.csproj @@ -0,0 +1,19 @@ + + + + Exe + net5.0 + false + Progress + Demonstrates how to show progress bars. + + + + + + + + + + + diff --git a/examples/Prompt/Program.cs b/examples/Prompt/Program.cs index 4cb42d8..86728e5 100644 --- a/examples/Prompt/Program.cs +++ b/examples/Prompt/Program.cs @@ -6,6 +6,13 @@ namespace Cursor { public static void Main(string[] args) { + // Check if we can accept key strokes + if (!AnsiConsole.Capabilities.SupportsInteraction) + { + AnsiConsole.MarkupLine("[red]Environment does not support interaction.[/]"); + return; + } + // Confirmation if (!AnsiConsole.Confirm("Run prompt example?")) { diff --git a/src/.editorconfig b/src/.editorconfig index 449cd6c..54af1cb 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -89,4 +89,7 @@ dotnet_diagnostic.RCS1227.severity = none dotnet_diagnostic.IDE0004.severity = warning # CA1810: Initialize reference type static fields inline -dotnet_diagnostic.CA1810.severity = none \ No newline at end of file +dotnet_diagnostic.CA1810.severity = none + +# IDE0044: Add readonly modifier +dotnet_diagnostic.IDE0044.severity = warning \ No newline at end of file diff --git a/src/Spectre.Console.Tests/Expectations/ProgressBarTests.Should_Render_Progress_Bar.verified.txt b/src/Spectre.Console.Tests/Expectations/ProgressBarTests.Should_Render_Progress_Bar.verified.txt new file mode 100644 index 0000000..d9aadad --- /dev/null +++ b/src/Spectre.Console.Tests/Expectations/ProgressBarTests.Should_Render_Progress_Bar.verified.txt @@ -0,0 +1 @@ +━━━━━━━━━━━━━━━━━━━━ \ No newline at end of file diff --git a/src/Spectre.Console.Tests/Tools/PlainConsole.cs b/src/Spectre.Console.Tests/Tools/PlainConsole.cs index f076db4..12b7c84 100644 --- a/src/Spectre.Console.Tests/Tools/PlainConsole.cs +++ b/src/Spectre.Console.Tests/Tools/PlainConsole.cs @@ -18,6 +18,7 @@ namespace Spectre.Console.Tests public int Height { get; } IAnsiConsoleInput IAnsiConsole.Input => Input; + public RenderPipeline Pipeline { get; } public Decoration Decoration { get; set; } public Color Foreground { get; set; } @@ -31,14 +32,15 @@ namespace Spectre.Console.Tests public PlainConsole( int width = 80, int height = 9000, Encoding encoding = null, bool supportsAnsi = true, ColorSystem colorSystem = ColorSystem.Standard, - bool legacyConsole = false) + bool legacyConsole = false, bool interactive = true) { - Capabilities = new Capabilities(supportsAnsi, colorSystem, legacyConsole); + Capabilities = new Capabilities(supportsAnsi, colorSystem, legacyConsole, interactive); Encoding = encoding ?? Encoding.UTF8; Width = width; Height = height; Writer = new StringWriter(); Input = new TestableConsoleInput(); + Pipeline = new RenderPipeline(); } public void Dispose() @@ -50,14 +52,17 @@ namespace Spectre.Console.Tests { } - public void Write(Segment segment) + public void Write(IEnumerable segments) { - if (segment is null) + if (segments is null) { - throw new ArgumentNullException(nameof(segment)); + return; } - Writer.Write(segment.Text); + foreach (var segment in segments) + { + Writer.Write(segment.Text); + } } public string WriteNormalizedException(Exception ex, ExceptionFormats formats = ExceptionFormats.Default) diff --git a/src/Spectre.Console.Tests/Tools/TestableAnsiConsole.cs b/src/Spectre.Console.Tests/Tools/TestableAnsiConsole.cs index ba986e5..0cd8122 100644 --- a/src/Spectre.Console.Tests/Tools/TestableAnsiConsole.cs +++ b/src/Spectre.Console.Tests/Tools/TestableAnsiConsole.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using Spectre.Console.Rendering; @@ -19,16 +20,21 @@ namespace Spectre.Console.Tests public int Height => _console.Height; public IAnsiConsoleCursor Cursor => _console.Cursor; public TestableConsoleInput Input { get; } + public RenderPipeline Pipeline => _console.Pipeline; IAnsiConsoleInput IAnsiConsole.Input => Input; - public TestableAnsiConsole(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, int width = 80) + public TestableAnsiConsole( + ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, + InteractionSupport interaction = InteractionSupport.Yes, + int width = 80) { _writer = new StringWriter(); _console = AnsiConsole.Create(new AnsiConsoleSettings { Ansi = ansi, ColorSystem = (ColorSystemSupport)system, + Interactive = interaction, Out = _writer, LinkIdentityGenerator = new TestLinkIdentityGenerator(), }); @@ -47,9 +53,17 @@ namespace Spectre.Console.Tests _console.Clear(home); } - public void Write(Segment segment) + public void Write(IEnumerable segments) { - _console.Write(segment); + if (segments is null) + { + return; + } + + foreach (var segment in segments) + { + _console.Write(segment); + } } } } diff --git a/src/Spectre.Console.Tests/Unit/ProgressTests.cs b/src/Spectre.Console.Tests/Unit/ProgressTests.cs new file mode 100644 index 0000000..ac330c2 --- /dev/null +++ b/src/Spectre.Console.Tests/Unit/ProgressTests.cs @@ -0,0 +1,58 @@ +using Shouldly; +using Xunit; + +namespace Spectre.Console.Tests.Unit +{ + public sealed class ProgressTests + { + [Fact] + public void Should_Render_Task_Correctly() + { + // Given + var console = new TestableAnsiConsole(ColorSystem.TrueColor, width: 10); + + var progress = new Progress(console) + .Columns(new[] { new ProgressBarColumn() }) + .AutoRefresh(false) + .AutoClear(true); + + // When + progress.Start(ctx => ctx.AddTask("foo")); + + // Then + console.Output + .NormalizeLineEndings() + .ShouldBe( + "[?25l" + // Hide cursor + " \n" + // Top padding + "━━━━━━━━━━\n" + // Task + " " + // Bottom padding + "[?25h"); // Clear + show cursor + } + + [Fact] + public void Should_Not_Auto_Clear_If_Specified() + { + // Given + var console = new TestableAnsiConsole(ColorSystem.TrueColor, width: 10); + + var progress = new Progress(console) + .Columns(new[] { new ProgressBarColumn() }) + .AutoRefresh(false) + .AutoClear(false); + + // When + progress.Start(ctx => ctx.AddTask("foo")); + + // Then + console.Output + .NormalizeLineEndings() + .ShouldBe( + "[?25l" + // Hide cursor + " \n" + // Top padding + "━━━━━━━━━━\n" + // Task + " \n" + // Bottom padding + "[?25h"); // show cursor + } + } +} diff --git a/src/Spectre.Console.Tests/Unit/RenderHookTests.cs b/src/Spectre.Console.Tests/Unit/RenderHookTests.cs new file mode 100644 index 0000000..eeee8ec --- /dev/null +++ b/src/Spectre.Console.Tests/Unit/RenderHookTests.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; +using Shouldly; +using Spectre.Console.Rendering; +using Xunit; + +namespace Spectre.Console.Tests.Unit +{ + public sealed class RenderHookTests + { + private sealed class HelloRenderHook : IRenderHook + { + public IEnumerable Process(RenderContext context, IEnumerable renderables) + { + return new IRenderable[] { new Text("Hello\n") }.Concat(renderables); + } + } + + [Fact] + public void Should_Inject_Renderable_Before_Writing_To_Console() + { + // Given + var console = new PlainConsole(); + console.Pipeline.Attach(new HelloRenderHook()); + + // When + console.Render(new Text("World")); + + // Then + console.Lines[0].ShouldBe("Hello"); + console.Lines[1].ShouldBe("World"); + } + } +} diff --git a/src/Spectre.Console.sln b/src/Spectre.Console.sln index a1af2ed..c4ef646 100644 --- a/src/Spectre.Console.sln +++ b/src/Spectre.Console.sln @@ -58,6 +58,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canvas", "..\examples\Canva EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.ImageSharp", "Spectre.Console.ImageSharp\Spectre.Console.ImageSharp.csproj", "{0EFE694D-0770-4E71-BF4E-EC2B41362F79}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Progress", "..\examples\Progress\Progress.csproj", "{2B712A52-40F1-4C1C-833E-7C869ACA91F3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -296,6 +298,18 @@ Global {0EFE694D-0770-4E71-BF4E-EC2B41362F79}.Release|x64.Build.0 = Release|Any CPU {0EFE694D-0770-4E71-BF4E-EC2B41362F79}.Release|x86.ActiveCfg = Release|Any CPU {0EFE694D-0770-4E71-BF4E-EC2B41362F79}.Release|x86.Build.0 = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|x64.Build.0 = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Debug|x86.Build.0 = Debug|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|Any CPU.Build.0 = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|x64.ActiveCfg = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|x64.Build.0 = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|x86.ActiveCfg = Release|Any CPU + {2B712A52-40F1-4C1C-833E-7C869ACA91F3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -318,6 +332,7 @@ Global {6351C70F-F368-46DB-BAED-9B87CCD69353} = {F0575243-121F-4DEE-9F6B-246E26DC0844} {45BF6302-6553-4E52-BF0F-B10D1AA9A6D1} = {F0575243-121F-4DEE-9F6B-246E26DC0844} {5693761A-754A-40A8-9144-36510D6A4D69} = {F0575243-121F-4DEE-9F6B-246E26DC0844} + {2B712A52-40F1-4C1C-833E-7C869ACA91F3} = {F0575243-121F-4DEE-9F6B-246E26DC0844} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C} diff --git a/src/Spectre.Console/AnsiConsole.Progress.cs b/src/Spectre.Console/AnsiConsole.Progress.cs new file mode 100644 index 0000000..835fcec --- /dev/null +++ b/src/Spectre.Console/AnsiConsole.Progress.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. + /// + /// A instance. + public static Progress Progress() + { + return Console.Progress(); + } + } +} diff --git a/src/Spectre.Console/AnsiConsoleSettings.cs b/src/Spectre.Console/AnsiConsoleSettings.cs index 4d3dc37..83db057 100644 --- a/src/Spectre.Console/AnsiConsoleSettings.cs +++ b/src/Spectre.Console/AnsiConsoleSettings.cs @@ -18,6 +18,12 @@ namespace Spectre.Console /// public ColorSystemSupport ColorSystem { get; set; } + /// + /// Gets or sets a value indicating whether or + /// not the console is interactive. + /// + public InteractionSupport Interactive { get; set; } + /// /// Gets or sets the link identity generator. /// diff --git a/src/Spectre.Console/Capabilities.cs b/src/Spectre.Console/Capabilities.cs index 284999c..ef4c9a6 100644 --- a/src/Spectre.Console/Capabilities.cs +++ b/src/Spectre.Console/Capabilities.cs @@ -36,17 +36,24 @@ namespace Spectre.Console /// public bool LegacyConsole { get; } + /// + /// Gets or sets a value indicating whether or not the console supports interaction. + /// + public bool SupportsInteraction { get; set; } + /// /// Initializes a new instance of the class. /// /// Whether or not ANSI escape sequences are supported. /// The color system that is supported. /// Whether or not this is a legacy console. - public Capabilities(bool supportsAnsi, ColorSystem colorSystem, bool legacyConsole) + /// Whether or not the console supports interaction. + public Capabilities(bool supportsAnsi, ColorSystem colorSystem, bool legacyConsole, bool supportsInteraction) { SupportsAnsi = supportsAnsi; ColorSystem = colorSystem; LegacyConsole = legacyConsole; + SupportsInteraction = supportsInteraction; } /// diff --git a/src/Spectre.Console/ColorSystemSupport.cs b/src/Spectre.Console/ColorSystemSupport.cs index cdff656..37f4aa5 100644 --- a/src/Spectre.Console/ColorSystemSupport.cs +++ b/src/Spectre.Console/ColorSystemSupport.cs @@ -8,31 +8,31 @@ namespace Spectre.Console /// /// Try to detect the color system. /// - Detect = -1, + Detect = 0, /// /// No colors. /// - NoColors = 0, + NoColors = 1, /// /// Legacy, 3-bit mode. /// - Legacy = 1, + Legacy = 2, /// /// Standard, 4-bit mode. /// - Standard = 2, + Standard = 3, /// /// 8-bit mode. /// - EightBit = 3, + EightBit = 4, /// /// 24-bit mode. /// - TrueColor = 4, + TrueColor = 5, } } diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs index 0a9ceb1..45ea97e 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs @@ -52,8 +52,7 @@ namespace Spectre.Console /// An array of objects to write. public static void MarkupLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) { - Markup(console, provider, format, args); - console.WriteLine(); + Markup(console, provider, format + Environment.NewLine, args); } } } diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs new file mode 100644 index 0000000..69a82dc --- /dev/null +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs @@ -0,0 +1,25 @@ +using System; + +namespace Spectre.Console +{ + /// + /// Contains extension methods for . + /// + public static partial class AnsiConsoleExtensions + { + /// + /// Creates a new instance for the console. + /// + /// The console. + /// A instance. + public static Progress Progress(this IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + return new Progress(console); + } + } +} diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs index 72d92b4..1d2f35a 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs @@ -1,5 +1,5 @@ using System; -using System.Linq; +using System.Collections.Generic; using Spectre.Console.Rendering; namespace Spectre.Console @@ -26,19 +26,26 @@ namespace Spectre.Console throw new ArgumentNullException(nameof(renderable)); } - var options = new RenderContext(console.Encoding, console.Capabilities.LegacyConsole); - var segments = renderable.Render(options, console.Width).ToArray(); - segments = Segment.Merge(segments).ToArray(); + var context = new RenderContext(console.Encoding, console.Capabilities.LegacyConsole); + var renderables = console.Pipeline.Process(context, new[] { renderable }); - foreach (var segment in segments) + Render(console, context, renderables); + } + + private static void Render(IAnsiConsole console, RenderContext options, IEnumerable renderables) + { + if (renderables is null) { - if (string.IsNullOrEmpty(segment.Text)) - { - continue; - } - - console.Write(segment.Text, segment.Style); + return; } + + var result = new List(); + foreach (var renderable in renderables) + { + result.AddRange(renderable.Render(options, console.Width)); + } + + console.Write(Segment.Merge(result)); } } } diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs index aac10f7..acbf72f 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs @@ -18,6 +18,26 @@ namespace Spectre.Console return new Recorder(console); } + /// + /// Writes the specified string value to the console. + /// + /// The console to write to. + /// The segment to write. + public static void Write(this IAnsiConsole console, Segment segment) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + if (segment is null) + { + throw new ArgumentNullException(nameof(segment)); + } + + console.Write(new[] { segment }); + } + /// /// Writes the specified string value to the console. /// @@ -25,7 +45,7 @@ namespace Spectre.Console /// The text to write. public static void Write(this IAnsiConsole console, string text) { - Write(console, text, Style.Plain); + Render(console, new Text(text, Style.Plain)); } /// @@ -36,17 +56,7 @@ namespace Spectre.Console /// The text style. public static void Write(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(new Segment(text, style)); + Render(console, new Text(text, style)); } /// @@ -60,7 +70,7 @@ namespace Spectre.Console throw new ArgumentNullException(nameof(console)); } - console.Write(Environment.NewLine, Style.Plain); + Render(console, new Text(Environment.NewLine, Style.Plain)); } /// @@ -91,8 +101,7 @@ namespace Spectre.Console throw new ArgumentNullException(nameof(text)); } - console.Write(new Segment(text, style)); - console.WriteLine(); + console.Write(text + Environment.NewLine, style); } } } diff --git a/src/Spectre.Console/Extensions/Columns/PercentageColumnExtensions.cs b/src/Spectre.Console/Extensions/Columns/PercentageColumnExtensions.cs new file mode 100644 index 0000000..9d68752 --- /dev/null +++ b/src/Spectre.Console/Extensions/Columns/PercentageColumnExtensions.cs @@ -0,0 +1,54 @@ +using System; + +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; + } + } +} diff --git a/src/Spectre.Console/Extensions/Columns/ProgressBarColumnExtensions.cs b/src/Spectre.Console/Extensions/Columns/ProgressBarColumnExtensions.cs new file mode 100644 index 0000000..a58eb0f --- /dev/null +++ b/src/Spectre.Console/Extensions/Columns/ProgressBarColumnExtensions.cs @@ -0,0 +1,76 @@ +using System; + +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; + } + } +} diff --git a/src/Spectre.Console/Extensions/Columns/RemainingTimeColumnExtensions.cs b/src/Spectre.Console/Extensions/Columns/RemainingTimeColumnExtensions.cs new file mode 100644 index 0000000..a33a31b --- /dev/null +++ b/src/Spectre.Console/Extensions/Columns/RemainingTimeColumnExtensions.cs @@ -0,0 +1,32 @@ +using System; + +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; + } + } +} diff --git a/src/Spectre.Console/Extensions/Columns/SpinnerColumnExtensions.cs b/src/Spectre.Console/Extensions/Columns/SpinnerColumnExtensions.cs new file mode 100644 index 0000000..c33c792 --- /dev/null +++ b/src/Spectre.Console/Extensions/Columns/SpinnerColumnExtensions.cs @@ -0,0 +1,32 @@ +using System; + +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)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.Style = style; + return column; + } + } +} diff --git a/src/Spectre.Console/Extensions/PanelExtensions.cs b/src/Spectre.Console/Extensions/PanelExtensions.cs index e1901dc..9505fe5 100644 --- a/src/Spectre.Console/Extensions/PanelExtensions.cs +++ b/src/Spectre.Console/Extensions/PanelExtensions.cs @@ -27,7 +27,7 @@ namespace Spectre.Console } alignment ??= panel.Header?.Alignment; - return Header(panel, new PanelHeader(text, alignment)); + return Header(panel, new PanelHeader(text, alignment)); } /// diff --git a/src/Spectre.Console/Extensions/ProgressExtensions.cs b/src/Spectre.Console/Extensions/ProgressExtensions.cs new file mode 100644 index 0000000..cf8d8a9 --- /dev/null +++ b/src/Spectre.Console/Extensions/ProgressExtensions.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; + +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, 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 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; + } + } +} diff --git a/src/Spectre.Console/Extensions/ProgressTaskExtensions.cs b/src/Spectre.Console/Extensions/ProgressTaskExtensions.cs new file mode 100644 index 0000000..63ba2b0 --- /dev/null +++ b/src/Spectre.Console/Extensions/ProgressTaskExtensions.cs @@ -0,0 +1,44 @@ +using System; + +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; + } + } +} diff --git a/src/Spectre.Console/Extensions/StringBuilderExtensions.cs b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs index ff394f6..0a970e0 100644 --- a/src/Spectre.Console/Extensions/StringBuilderExtensions.cs +++ b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text; -namespace Spectre.Console +namespace Spectre.Console.Internal { internal static class StringBuilderExtensions { diff --git a/src/Spectre.Console/Extensions/StringExtensions.cs b/src/Spectre.Console/Extensions/StringExtensions.cs index e17649a..7d5a02f 100644 --- a/src/Spectre.Console/Extensions/StringExtensions.cs +++ b/src/Spectre.Console/Extensions/StringExtensions.cs @@ -62,10 +62,15 @@ namespace Spectre.Console return text; } - internal static string NormalizeLineEndings(this string? text, bool native = false) + 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 = text?.ReplaceExact("\r", string.Empty); text ??= string.Empty; if (native && !_alreadyNormalized) @@ -78,7 +83,7 @@ namespace Spectre.Console internal static string[] SplitLines(this string text) { - var result = text?.NormalizeLineEndings()?.Split(new[] { '\n' }, StringSplitOptions.None); + var result = text?.NormalizeNewLines()?.Split(new[] { '\n' }, StringSplitOptions.None); return result ?? Array.Empty(); } diff --git a/src/Spectre.Console/IAnsiConsole.cs b/src/Spectre.Console/IAnsiConsole.cs index 58c87e5..12785a0 100644 --- a/src/Spectre.Console/IAnsiConsole.cs +++ b/src/Spectre.Console/IAnsiConsole.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Text; using Spectre.Console.Rendering; @@ -28,6 +29,11 @@ namespace Spectre.Console /// IAnsiConsoleInput Input { get; } + /// + /// Gets the render pipeline. + /// + RenderPipeline Pipeline { get; } + /// /// Gets the buffer width of the console. /// @@ -45,9 +51,9 @@ namespace Spectre.Console void Clear(bool home); /// - /// Writes a string followed by a line terminator to the console. + /// Writes multiple segments to the console. /// - /// The segment to write. - void Write(Segment segment); + /// The segments to write. + void Write(IEnumerable segments); } } diff --git a/src/Spectre.Console/InteractionSupport.cs b/src/Spectre.Console/InteractionSupport.cs new file mode 100644 index 0000000..4fb2747 --- /dev/null +++ b/src/Spectre.Console/InteractionSupport.cs @@ -0,0 +1,24 @@ +namespace Spectre.Console +{ + /// + /// Determines interactivity support. + /// + public enum InteractionSupport + { + /// + /// Interaction support should be + /// detected by the system. + /// + Detect = 0, + + /// + /// Interactivity is supported. + /// + Yes = 1, + + /// + /// Interactivity is not supported. + /// + No = 2, + } +} diff --git a/src/Spectre.Console/Internal/Ansi/AnsiDetector.cs b/src/Spectre.Console/Internal/Ansi/AnsiDetector.cs index d678e71..5f4b132 100644 --- a/src/Spectre.Console/Internal/Ansi/AnsiDetector.cs +++ b/src/Spectre.Console/Internal/Ansi/AnsiDetector.cs @@ -121,6 +121,8 @@ namespace Spectre.Console.Internal // Enabling failed. return false; } + + isLegacy = false; } return true; diff --git a/src/Spectre.Console/Internal/Backends/Ansi/AnsiBackend.cs b/src/Spectre.Console/Internal/Backends/Ansi/AnsiBackend.cs index 9a101d8..c41494a 100644 --- a/src/Spectre.Console/Internal/Backends/Ansi/AnsiBackend.cs +++ b/src/Spectre.Console/Internal/Backends/Ansi/AnsiBackend.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using Spectre.Console.Rendering; @@ -11,9 +12,11 @@ namespace Spectre.Console.Internal private readonly AnsiBuilder _ansiBuilder; private readonly AnsiCursor _cursor; private readonly ConsoleInput _input; + private readonly object _lock; public Capabilities Capabilities { get; } public Encoding Encoding { get; } + public RenderPipeline Pipeline { get; } public IAnsiConsoleCursor Cursor => _cursor; public IAnsiConsoleInput Input => _input; @@ -49,35 +52,59 @@ namespace Spectre.Console.Internal Capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities)); Encoding = _out.IsStandardOut() ? System.Console.OutputEncoding : Encoding.UTF8; + Pipeline = new RenderPipeline(); _ansiBuilder = new AnsiBuilder(Capabilities, linkHasher); _cursor = new AnsiCursor(this); _input = new ConsoleInput(); + _lock = new object(); } public void Clear(bool home) { - Write(Segment.Control("\u001b[2J")); - - if (home) + lock (_lock) { - Cursor.SetPosition(0, 0); + Write(new[] { Segment.Control("\u001b[2J") }); + + if (home) + { + Cursor.SetPosition(0, 0); + } } } - public void Write(Segment segment) + public void Write(IEnumerable segments) { - var parts = segment.Text.NormalizeLineEndings().Split(new[] { '\n' }); - foreach (var (_, _, last, part) in parts.Enumerate()) + lock (_lock) { - if (!string.IsNullOrEmpty(part)) + var builder = new StringBuilder(); + foreach (var segment in segments) { - _out.Write(_ansiBuilder.GetAnsi(part, segment.Style)); + if (segment.IsControlCode) + { + builder.Append(segment.Text); + continue; + } + + var parts = segment.Text.NormalizeNewLines().Split(new[] { '\n' }); + foreach (var (_, _, last, part) in parts.Enumerate()) + { + if (!string.IsNullOrEmpty(part)) + { + builder.Append(_ansiBuilder.GetAnsi(part, segment.Style)); + } + + if (!last) + { + builder.Append(Environment.NewLine); + } + } } - if (!last) + if (builder.Length > 0) { - _out.Write(Environment.NewLine); + _out.Write(builder.ToString()); + _out.Flush(); } } } diff --git a/src/Spectre.Console/Internal/Backends/BackendBuilder.cs b/src/Spectre.Console/Internal/Backends/BackendBuilder.cs index 6069e2a..a2f51e2 100644 --- a/src/Spectre.Console/Internal/Backends/BackendBuilder.cs +++ b/src/Spectre.Console/Internal/Backends/BackendBuilder.cs @@ -50,12 +50,18 @@ namespace Spectre.Console.Internal } } + var supportsInteraction = settings.Interactive == InteractionSupport.Yes; + if (settings.Interactive == InteractionSupport.Detect) + { + supportsInteraction = InteractivityDetector.IsInteractive(); + } + var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect ? ColorSystemDetector.Detect(supportsAnsi) : (ColorSystem)settings.ColorSystem; // Get the capabilities - var capabilities = new Capabilities(supportsAnsi, colorSystem, legacyConsole); + var capabilities = new Capabilities(supportsAnsi, colorSystem, legacyConsole, supportsInteraction); // Create the renderer if (supportsAnsi) diff --git a/src/Spectre.Console/Internal/Backends/Fallback/FallbackBackend.cs b/src/Spectre.Console/Internal/Backends/Fallback/FallbackBackend.cs index 81aff14..569db39 100644 --- a/src/Spectre.Console/Internal/Backends/Fallback/FallbackBackend.cs +++ b/src/Spectre.Console/Internal/Backends/Fallback/FallbackBackend.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Text; using Spectre.Console.Rendering; @@ -14,6 +15,7 @@ namespace Spectre.Console.Internal public Capabilities Capabilities { get; } public Encoding Encoding { get; } + public RenderPipeline Pipeline { get; } public IAnsiConsoleCursor Cursor => _cursor; public IAnsiConsoleInput Input => _input; @@ -43,8 +45,9 @@ namespace Spectre.Console.Internal System.Console.SetOut(@out ?? throw new ArgumentNullException(nameof(@out))); } - Encoding = System.Console.OutputEncoding; Capabilities = capabilities; + Encoding = System.Console.OutputEncoding; + Pipeline = new RenderPipeline(); } public void Clear(bool home) @@ -60,14 +63,22 @@ namespace Spectre.Console.Internal } } - public void Write(Segment segment) + public void Write(IEnumerable segments) { - if (_lastStyle?.Equals(segment.Style) != true) + foreach (var segment in segments) { - SetStyle(segment.Style); - } + if (segment.IsControlCode) + { + continue; + } - System.Console.Write(segment.Text.NormalizeLineEndings(native: true)); + if (_lastStyle?.Equals(segment.Style) != true) + { + SetStyle(segment.Style); + } + + System.Console.Write(segment.Text.NormalizeNewLines(native: true)); + } } private void SetStyle(Style style) diff --git a/src/Spectre.Console/Internal/HtmlEncoder.cs b/src/Spectre.Console/Internal/HtmlEncoder.cs index 074a344..26b7668 100644 --- a/src/Spectre.Console/Internal/HtmlEncoder.cs +++ b/src/Spectre.Console/Internal/HtmlEncoder.cs @@ -15,6 +15,11 @@ namespace Spectre.Console.Internal foreach (var (_, first, _, segment) in segments.Enumerate()) { + if (segment.IsControlCode) + { + continue; + } + if (segment.Text == "\n" && !first) { builder.Append('\n'); diff --git a/src/Spectre.Console/Internal/InteractivityDetector.cs b/src/Spectre.Console/Internal/InteractivityDetector.cs new file mode 100644 index 0000000..c91f296 --- /dev/null +++ b/src/Spectre.Console/Internal/InteractivityDetector.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +namespace Spectre.Console.Internal +{ + internal static class InteractivityDetector + { + private static readonly Dictionary> _environmentVariables; + + static InteractivityDetector() + { + _environmentVariables = new Dictionary> + { + { "APPVEYOR", v => !string.IsNullOrWhiteSpace(v) }, + { "bamboo_buildNumber", v => !string.IsNullOrWhiteSpace(v) }, + { "BITBUCKET_REPO_OWNER", v => !string.IsNullOrWhiteSpace(v) }, + { "BITBUCKET_REPO_SLUG", v => !string.IsNullOrWhiteSpace(v) }, + { "BITBUCKET_COMMIT", v => !string.IsNullOrWhiteSpace(v) }, + { "BITRISE_BUILD_URL", v => !string.IsNullOrWhiteSpace(v) }, + { "ContinuaCI.Version", v => !string.IsNullOrWhiteSpace(v) }, + { "CI_SERVER", v => v.Equals("yes", StringComparison.OrdinalIgnoreCase) }, // GitLab + { "GITHUB_ACTIONS", v => v.Equals("true", StringComparison.OrdinalIgnoreCase) }, + { "GO_SERVER_URL", v => !string.IsNullOrWhiteSpace(v) }, + { "JENKINS_URL", v => !string.IsNullOrWhiteSpace(v) }, + { "BuildRunner", v => v.Equals("MyGet", StringComparison.OrdinalIgnoreCase) }, + { "TEAMCITY_VERSION", v => !string.IsNullOrWhiteSpace(v) }, + { "TF_BUILD", v => !string.IsNullOrWhiteSpace(v) }, // TFS and Azure + { "TRAVIS", v => !string.IsNullOrWhiteSpace(v) }, + }; + } + + public static bool IsInteractive() + { + if (!Environment.UserInteractive) + { + return false; + } + + foreach (var variable in _environmentVariables) + { + var func = variable.Value; + var value = Environment.GetEnvironmentVariable(variable.Key); + if (!string.IsNullOrWhiteSpace(value) && variable.Value(value)) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/Spectre.Console/Internal/ResourceReader.cs b/src/Spectre.Console/Internal/ResourceReader.cs index 908707b..e41efbe 100644 --- a/src/Spectre.Console/Internal/ResourceReader.cs +++ b/src/Spectre.Console/Internal/ResourceReader.cs @@ -24,7 +24,7 @@ namespace Spectre.Console.Internal using (var reader = new StreamReader(stream)) { - return reader.ReadToEnd().NormalizeLineEndings(); + return reader.ReadToEnd().NormalizeNewLines(); } } } diff --git a/src/Spectre.Console/Internal/TextEncoder.cs b/src/Spectre.Console/Internal/TextEncoder.cs index 2bc3adf..7261c90 100644 --- a/src/Spectre.Console/Internal/TextEncoder.cs +++ b/src/Spectre.Console/Internal/TextEncoder.cs @@ -12,6 +12,11 @@ namespace Spectre.Console.Internal foreach (var segment in Segment.Merge(segments)) { + if (segment.IsControlCode) + { + continue; + } + builder.Append(segment.Text); } diff --git a/src/Spectre.Console/Progress/Columns/PercentageColumn.cs b/src/Spectre.Console/Progress/Columns/PercentageColumn.cs new file mode 100644 index 0000000..382751c --- /dev/null +++ b/src/Spectre.Console/Progress/Columns/PercentageColumn.cs @@ -0,0 +1,32 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// A column showing task progress in percentage. + /// + public sealed class PercentageColumn : ProgressColumn + { + /// + protected internal override int? ColumnWidth => 4; + + /// + /// Gets or sets the style for a non-complete task. + /// + public Style Style { get; set; } = Style.Plain; + + /// + /// Gets or sets the style for a completed task. + /// + public Style CompletedStyle { get; set; } = new Style(foreground: Color.Green); + + /// + public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) + { + var percentage = (int)task.Percentage; + var style = percentage == 100 ? CompletedStyle : Style ?? Style.Plain; + return new Text($"{percentage}%", style).RightAligned(); + } + } +} diff --git a/src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs b/src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs new file mode 100644 index 0000000..1164325 --- /dev/null +++ b/src/Spectre.Console/Progress/Columns/ProgressBarColumn.cs @@ -0,0 +1,45 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// A column showing task progress as a progress bar. + /// + public sealed class ProgressBarColumn : ProgressColumn + { + /// + /// Gets or sets the width of the column. + /// + public int? Width { get; set; } = 40; + + /// + /// Gets or sets the style of completed portions of the progress bar. + /// + public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow); + + /// + /// Gets or sets the style of a finished progress bar. + /// + public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green); + + /// + /// Gets or sets the style of remaining portions of the progress bar. + /// + public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey); + + /// + public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) + { + return new ProgressBar + { + MaxValue = task.MaxValue, + Value = task.Value, + Width = Width, + CompletedStyle = CompletedStyle, + FinishedStyle = FinishedStyle, + RemainingStyle = RemainingStyle, + }; + } + } +} diff --git a/src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs b/src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs new file mode 100644 index 0000000..7c0a970 --- /dev/null +++ b/src/Spectre.Console/Progress/Columns/RemainingTimeColumn.cs @@ -0,0 +1,28 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// A column showing the remaining time of a task. + /// + public sealed class RemainingTimeColumn : ProgressColumn + { + /// + /// Gets or sets the style of the remaining time text. + /// + public Style Style { get; set; } = new Style(foreground: Color.Blue); + + /// + public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) + { + var remaining = task.RemainingTime; + if (remaining == null) + { + return new Markup("-:--:--"); + } + + return new Text($"{remaining.Value:h\\:mm\\:ss}", Style ?? Style.Plain); + } + } +} diff --git a/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs b/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs new file mode 100644 index 0000000..b32d711 --- /dev/null +++ b/src/Spectre.Console/Progress/Columns/SpinnerColumn.cs @@ -0,0 +1,44 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// A column showing a spinner. + /// + public sealed class SpinnerColumn : ProgressColumn + { + private const string ACCUMULATED = "SPINNER_ACCUMULATED"; + private const string INDEX = "SPINNER_INDEX"; + + private readonly string _ansiSequence = "⣷⣯⣟⡿⢿⣻⣽⣾"; + private readonly string _asciiSequence = "-\\|/-\\|/"; + + /// + /// Gets or sets the style of the spinner. + /// + public Style Style { get; set; } = new Style(foreground: Color.Yellow); + + /// + public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) + { + if (!task.IsStarted || task.IsFinished) + { + return new Markup(" "); + } + + var accumulated = task.State.Update(ACCUMULATED, acc => acc + deltaTime.TotalMilliseconds); + if (accumulated >= 100) + { + task.State.Update(ACCUMULATED, _ => 0); + task.State.Update(INDEX, index => index + 1); + } + + var useAscii = context.LegacyConsole || !context.Unicode; + var sequence = useAscii ? _asciiSequence : _ansiSequence; + + var index = task.State.Get(INDEX); + return new Markup(sequence[index % sequence.Length].ToString(), Style ?? Style.Plain); + } + } +} diff --git a/src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs b/src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs new file mode 100644 index 0000000..eac611f --- /dev/null +++ b/src/Spectre.Console/Progress/Columns/TaskDescriptionColumn.cs @@ -0,0 +1,18 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// A column showing the task description. + /// + public sealed class TaskDescriptionColumn : ProgressColumn + { + /// + public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime) + { + var text = task.Description?.RemoveNewLines()?.Trim(); + return new Markup(text ?? string.Empty).RightAligned(); + } + } +} diff --git a/src/Spectre.Console/Progress/Progress.cs b/src/Spectre.Console/Progress/Progress.cs new file mode 100644 index 0000000..8fde020 --- /dev/null +++ b/src/Spectre.Console/Progress/Progress.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Spectre.Console.Internal; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// Represents a task list. + /// + public sealed class Progress + { + private readonly IAnsiConsole _console; + + /// + /// Gets or sets a value indicating whether or not task list should auto refresh. + /// Defaults to true. + /// + public bool AutoRefresh { get; set; } = true; + + /// + /// Gets or sets a value indicating whether or not the task list should + /// be cleared once it completes. + /// Defaults to false. + /// + public bool AutoClear { get; set; } + + internal List Columns { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The console to render to. + public Progress(IAnsiConsole console) + { + _console = console ?? throw new ArgumentNullException(nameof(console)); + + // Initialize with default columns + Columns = new List + { + new TaskDescriptionColumn(), + new ProgressBarColumn(), + new PercentageColumn(), + }; + } + + /// + /// Starts the progress task list. + /// + /// The action to execute. + public void Start(Action action) + { + var task = StartAsync(ctx => + { + action(ctx); + return Task.CompletedTask; + }); + + task.GetAwaiter().GetResult(); + } + + /// + /// Starts the progress task list. + /// + /// The action to execute. + /// A representing the asynchronous operation. + public async Task StartAsync(Func action) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + var renderer = CreateRenderer(); + renderer.Started(); + + try + { + using (new RenderHookScope(_console, renderer)) + { + var context = new ProgressContext(_console, renderer); + + if (AutoRefresh) + { + using (var thread = new ProgressRefreshThread(context, renderer.RefreshRate)) + { + await action(context).ConfigureAwait(false); + } + } + else + { + await action(context).ConfigureAwait(false); + } + + context.Refresh(); + } + } + finally + { + renderer.Completed(AutoClear); + } + } + + private ProgressRenderer CreateRenderer() + { + var caps = _console.Capabilities; + var interactive = caps.SupportsInteraction && caps.SupportsAnsi; + + if (interactive) + { + var columns = new List(Columns); + return new InteractiveProgressRenderer(_console, columns); + } + else + { + return new NonInteractiveProgressRenderer(); + } + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressColumn.cs b/src/Spectre.Console/Progress/ProgressColumn.cs new file mode 100644 index 0000000..e72585a --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressColumn.cs @@ -0,0 +1,25 @@ +using System; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + /// + /// Represents a progress column. + /// + public abstract class ProgressColumn + { + /// + /// Gets the requested column width for the column. + /// + protected internal virtual int? ColumnWidth { get; } + + /// + /// Gets a renderable representing the column. + /// + /// The render context. + /// The task. + /// The elapsed time since last call. + /// A renderable representing the column. + public abstract IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime); + } +} diff --git a/src/Spectre.Console/Progress/ProgressContext.cs b/src/Spectre.Console/Progress/ProgressContext.cs new file mode 100644 index 0000000..4b57c2c --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressContext.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Spectre.Console.Internal; + +namespace Spectre.Console +{ + /// + /// Represents a context that can be used to interact with a . + /// + public sealed class ProgressContext + { + private readonly List _tasks; + private readonly object _taskLock; + private readonly IAnsiConsole _console; + private readonly ProgressRenderer _renderer; + private int _taskId; + + /// + /// Gets a value indicating whether or not all tasks have completed. + /// + public bool IsFinished => _tasks.All(task => task.IsFinished); + + internal ProgressContext(IAnsiConsole console, ProgressRenderer renderer) + { + _tasks = new List(); + _taskLock = new object(); + _console = console ?? throw new ArgumentNullException(nameof(console)); + _renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); + } + + /// + /// Adds a task. + /// + /// The task description. + /// The task settings. + /// The task's ID. + public ProgressTask AddTask(string description, ProgressTaskSettings? settings = null) + { + lock (_taskLock) + { + settings ??= new ProgressTaskSettings(); + var task = new ProgressTask(_taskId++, description, settings.MaxValue, settings.AutoStart); + + _tasks.Add(task); + return task; + } + } + + /// + /// Refreshes the current progress. + /// + public void Refresh() + { + _renderer.Update(this); + _console.Render(new ControlSequence(string.Empty)); + } + + internal void EnumerateTasks(Action action) + { + lock (_taskLock) + { + foreach (var task in _tasks) + { + action(task); + } + } + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressRefreshThread.cs b/src/Spectre.Console/Progress/ProgressRefreshThread.cs new file mode 100644 index 0000000..35cd09e --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressRefreshThread.cs @@ -0,0 +1,58 @@ +using System; +using System.Threading; + +namespace Spectre.Console.Internal +{ + internal sealed class ProgressRefreshThread : IDisposable + { + private readonly ProgressContext _context; + private readonly TimeSpan _refreshRate; + private readonly ManualResetEvent _running; + private readonly ManualResetEvent _stopped; + private readonly Thread? _thread; + + public ProgressRefreshThread(ProgressContext context, TimeSpan refreshRate) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _refreshRate = refreshRate; + _running = new ManualResetEvent(false); + _stopped = new ManualResetEvent(false); + + _thread = new Thread(Run); + _thread.IsBackground = true; + _thread.Start(); + } + + public void Dispose() + { + if (_thread == null || !_running.WaitOne(0)) + { + return; + } + + _stopped.Set(); + _thread.Join(); + + _stopped.Dispose(); + _running.Dispose(); + } + + private void Run() + { + _running.Set(); + + try + { + while (!_stopped.WaitOne(_refreshRate)) + { + _context.Refresh(); + } + } + finally + { + _stopped.Reset(); + _running.Reset(); + } + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressRenderer.cs b/src/Spectre.Console/Progress/ProgressRenderer.cs new file mode 100644 index 0000000..14fc8d4 --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressRenderer.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using Spectre.Console.Rendering; + +namespace Spectre.Console.Internal +{ + internal abstract class ProgressRenderer : IRenderHook + { + public abstract TimeSpan RefreshRate { get; } + + public virtual void Started() + { + } + + public virtual void Completed(bool clear) + { + } + + public abstract void Update(ProgressContext context); + public abstract IEnumerable Process(RenderContext context, IEnumerable renderables); + } +} diff --git a/src/Spectre.Console/Progress/ProgressSample.cs b/src/Spectre.Console/Progress/ProgressSample.cs new file mode 100644 index 0000000..b8fc57f --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressSample.cs @@ -0,0 +1,16 @@ +using System; + +namespace Spectre.Console.Internal +{ + internal readonly struct ProgressSample + { + public double Value { get; } + public DateTime Timestamp { get; } + + public ProgressSample(DateTime timestamp, double value) + { + Timestamp = timestamp; + Value = value; + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressTask.cs b/src/Spectre.Console/Progress/ProgressTask.cs new file mode 100644 index 0000000..58c3c83 --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressTask.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Spectre.Console.Internal; + +namespace Spectre.Console +{ + /// + /// Represents a progress task. + /// + public sealed class ProgressTask + { + private readonly List _samples; + private readonly object _lock; + + private double _maxValue; + private string _description; + + /// + /// Gets the task ID. + /// + public int Id { get; } + + /// + /// Gets or sets the task description. + /// + public string Description + { + get => _description; + set => Update(description: value); + } + + /// + /// Gets or sets the max value of the task. + /// + public double MaxValue + { + get => _maxValue; + set => Update(maxValue: value); + } + + /// + /// Gets the value of the task. + /// + public double Value { get; private set; } + + /// + /// Gets the start time of the task. + /// + public DateTime? StartTime { get; private set; } + + /// + /// Gets the stop time of the task. + /// + public DateTime? StopTime { get; private set; } + + /// + /// Gets the task state. + /// + public ProgressTaskState State { get; } + + /// + /// Gets a value indicating whether or not the task has started. + /// + public bool IsStarted => StartTime != null; + + /// + /// Gets a value indicating whether or not the task has finished. + /// + public bool IsFinished => Value >= MaxValue; + + /// + /// Gets the percentage done of the task. + /// + public double Percentage => GetPercentage(); + + /// + /// Gets the speed measured in steps/second. + /// + public double? Speed => GetSpeed(); + + /// + /// Gets the elapsed time. + /// + public TimeSpan? ElapsedTime => GetElapsedTime(); + + /// + /// Gets the remaining time. + /// + public TimeSpan? RemainingTime => GetRemainingTime(); + + internal ProgressTask(int id, string description, double maxValue, bool autoStart) + { + _samples = new List(); + _lock = new object(); + _maxValue = maxValue; + + _description = description?.RemoveNewLines()?.Trim() ?? throw new ArgumentNullException(nameof(description)); + if (string.IsNullOrWhiteSpace(_description)) + { + throw new ArgumentException("Task name cannot be empty", nameof(description)); + } + + Id = id; + State = new ProgressTaskState(); + Value = 0; + StartTime = autoStart ? DateTime.Now : null; + } + + /// + /// Starts the task. + /// + public void StartTask() + { + lock (_lock) + { + StartTime = DateTime.Now; + StopTime = null; + } + } + + /// + /// Stops the task. + /// + public void StopTask() + { + lock (_lock) + { + var now = DateTime.Now; + if (StartTime == null) + { + StartTime = now; + } + + StopTime = now; + } + } + + /// + /// Increments the task's value. + /// + /// The value to increment with. + public void Increment(double value) + { + Update(increment: value); + } + + private void Update( + string? description = null, + double? maxValue = null, + double? increment = null) + { + lock (_lock) + { + var startValue = Value; + + if (description != null) + { + description = description?.RemoveNewLines()?.Trim(); + if (string.IsNullOrWhiteSpace(description)) + { + throw new InvalidOperationException("Task name cannot be empty."); + } + + _description = description; + } + + if (maxValue != null) + { + _maxValue += maxValue.Value; + } + + if (increment != null) + { + Value += increment.Value; + } + + var timestamp = DateTime.Now; + var threshold = timestamp - TimeSpan.FromSeconds(30); + + // Remove samples that's too old + while (_samples.Count > 0 && _samples[0].Timestamp < threshold) + { + _samples.RemoveAt(0); + } + + // Keep maximum of 1000 samples + while (_samples.Count > 1000) + { + _samples.RemoveAt(0); + } + + _samples.Add(new ProgressSample(timestamp, Value - startValue)); + } + } + + private double GetPercentage() + { + var percentage = (Value / MaxValue) * 100; + percentage = Math.Min(100, Math.Max(0, percentage)); + return percentage; + } + + private double? GetSpeed() + { + lock (_lock) + { + if (StartTime == null) + { + return null; + } + + if (_samples.Count == 0) + { + return null; + } + + var totalTime = _samples.Last().Timestamp - _samples[0].Timestamp; + if (totalTime == TimeSpan.Zero) + { + return null; + } + + var totalCompleted = _samples.Sum(x => x.Value); + return totalCompleted / totalTime.TotalSeconds; + } + } + + private TimeSpan? GetElapsedTime() + { + lock (_lock) + { + if (StartTime == null) + { + return null; + } + + if (StopTime != null) + { + return StopTime - StartTime; + } + + return DateTime.Now - StartTime; + } + } + + private TimeSpan? GetRemainingTime() + { + lock (_lock) + { + if (IsFinished) + { + return TimeSpan.Zero; + } + + var speed = GetSpeed(); + if (speed == null) + { + return null; + } + + var estimate = (MaxValue - Value) / speed.Value; + return TimeSpan.FromSeconds(estimate); + } + } + } +} diff --git a/src/Spectre.Console/Progress/ProgressTaskSettings.cs b/src/Spectre.Console/Progress/ProgressTaskSettings.cs new file mode 100644 index 0000000..3ceb0fb --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressTaskSettings.cs @@ -0,0 +1,20 @@ +namespace Spectre.Console +{ + /// + /// Represents settings for a progress task. + /// + public sealed class ProgressTaskSettings + { + /// + /// Gets or sets the task's max value. + /// Defaults to 100. + /// + public double MaxValue { get; set; } = 100; + + /// + /// Gets or sets a value indicating whether or not the task + /// will be auto started. Defaults to true. + /// + public bool AutoStart { get; set; } = true; + } +} diff --git a/src/Spectre.Console/Progress/ProgressTaskState.cs b/src/Spectre.Console/Progress/ProgressTaskState.cs new file mode 100644 index 0000000..9e8a2dc --- /dev/null +++ b/src/Spectre.Console/Progress/ProgressTaskState.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; + +namespace Spectre.Console +{ + /// + /// Represents progress task state. + /// + public sealed class ProgressTaskState + { + private readonly Dictionary _state; + private readonly object _lock; + + /// + /// Initializes a new instance of the class. + /// + public ProgressTaskState() + { + _state = new Dictionary(); + _lock = new object(); + } + + /// + /// Gets the state value for the specified key. + /// + /// The state value type. + /// The state key. + /// The value for the specified key. + public T Get(string key) + where T : struct + { + lock (_lock) + { + if (!_state.TryGetValue(key, out var value)) + { + return default; + } + + if (!(value is T)) + { + throw new InvalidOperationException("State value is of the wrong type."); + } + + return (T)value; + } + } + + /// + /// Updates a task state value. + /// + /// The state value type. + /// The key. + /// The transformation function. + /// The updated value. + public T Update(string key, Func func) + where T : struct + { + lock (_lock) + { + if (func is null) + { + throw new ArgumentNullException(nameof(func)); + } + + var old = default(T); + if (_state.TryGetValue(key, out var value)) + { + if (!(value is T)) + { + throw new InvalidOperationException("State value is of the wrong type."); + } + + old = (T)value; + } + + _state[key] = func(old); + return (T)_state[key]; + } + } + } +} diff --git a/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs b/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs new file mode 100644 index 0000000..7860239 --- /dev/null +++ b/src/Spectre.Console/Progress/Renderers/InteractiveProgressRenderer.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Spectre.Console.Rendering; + +namespace Spectre.Console.Internal +{ + internal sealed class InteractiveProgressRenderer : ProgressRenderer + { + private readonly IAnsiConsole _console; + private readonly List _columns; + private readonly LiveRenderable _live; + private readonly object _lock; + private readonly Stopwatch _stopwatch; + private TimeSpan _lastUpdate; + + public override TimeSpan RefreshRate => TimeSpan.FromMilliseconds(100); + + public InteractiveProgressRenderer(IAnsiConsole console, List columns) + { + _console = console ?? throw new ArgumentNullException(nameof(console)); + _columns = columns ?? throw new ArgumentNullException(nameof(columns)); + _live = new LiveRenderable(); + _lock = new object(); + _stopwatch = new Stopwatch(); + _lastUpdate = TimeSpan.Zero; + } + + public override void Started() + { + _console.Cursor.Hide(); + } + + public override void Completed(bool clear) + { + lock (_lock) + { + if (clear) + { + _console.Render(_live.RestoreCursor()); + } + else + { + _console.WriteLine(); + } + + _console.Cursor.Show(); + } + } + + public override void Update(ProgressContext context) + { + lock (_lock) + { + if (!_stopwatch.IsRunning) + { + _stopwatch.Start(); + } + + var delta = _stopwatch.Elapsed - _lastUpdate; + _lastUpdate = _stopwatch.Elapsed; + + var grid = new Grid(); + for (var columnIndex = 0; columnIndex < _columns.Count; columnIndex++) + { + var column = new GridColumn().PadRight(1); + if (_columns[columnIndex].ColumnWidth != null) + { + column.Width = _columns[columnIndex].ColumnWidth; + } + + // Last column? + if (columnIndex == _columns.Count - 1) + { + column.PadRight(0); + } + + grid.AddColumn(column); + } + + // Add rows + var renderContext = new RenderContext(_console.Encoding, _console.Capabilities.LegacyConsole); + context.EnumerateTasks(task => + { + var columns = _columns.Select(column => column.Render(renderContext, task, delta)); + grid.AddRow(columns.ToArray()); + }); + + _live.SetRenderable(new Padder(grid, new Padding(0, 1))); + } + } + + public override IEnumerable Process(RenderContext context, IEnumerable renderables) + { + lock (_lock) + { + yield return _live.PositionCursor(); + + foreach (var renderable in renderables) + { + yield return renderable; + } + + yield return _live; + } + } + } +} diff --git a/src/Spectre.Console/Progress/Renderers/NonInteractiveProgressRenderer.cs b/src/Spectre.Console/Progress/Renderers/NonInteractiveProgressRenderer.cs new file mode 100644 index 0000000..a15f09c --- /dev/null +++ b/src/Spectre.Console/Progress/Renderers/NonInteractiveProgressRenderer.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using Spectre.Console.Rendering; + +namespace Spectre.Console.Internal +{ + internal sealed class NonInteractiveProgressRenderer : ProgressRenderer + { + private const double FirstMilestone = 25; + private static readonly double?[] _milestones = new double?[] { FirstMilestone, 50, 75, 95, 96, 97, 98, 99, 100 }; + + private readonly Dictionary _taskMilestones; + private readonly object _lock; + private IRenderable? _renderable; + private DateTime _lastUpdate; + + public override TimeSpan RefreshRate => TimeSpan.FromSeconds(1); + + public NonInteractiveProgressRenderer() + { + _taskMilestones = new Dictionary(); + _lock = new object(); + } + + public override void Update(ProgressContext context) + { + lock (_lock) + { + var hasStartedTasks = false; + var updates = new List<(string, double)>(); + + context.EnumerateTasks(task => + { + if (!task.IsStarted || task.IsFinished) + { + return; + } + + hasStartedTasks = true; + + if (TryAdvance(task.Id, task.Percentage)) + { + updates.Add((task.Description, task.Percentage)); + } + }); + + // Got started tasks but no updates for 30 seconds? + if (hasStartedTasks && updates.Count == 0 && (DateTime.Now - _lastUpdate) > TimeSpan.FromSeconds(30)) + { + context.EnumerateTasks(task => updates.Add((task.Description, task.Percentage))); + } + + if (updates.Count > 0) + { + _lastUpdate = DateTime.Now; + } + + _renderable = BuildTaskGrid(updates); + } + } + + public override IEnumerable Process(RenderContext context, IEnumerable renderables) + { + lock (_lock) + { + var result = new List(); + result.AddRange(renderables); + + if (_renderable != null) + { + result.Add(_renderable); + } + + _renderable = null; + + return result; + } + } + + private bool TryAdvance(int task, double percentage) + { + if (!_taskMilestones.TryGetValue(task, out var milestone)) + { + _taskMilestones.Add(task, FirstMilestone); + return true; + } + + if (percentage > milestone) + { + var nextMilestone = GetNextMilestone(percentage); + if (nextMilestone != null && _taskMilestones[task] != nextMilestone) + { + _taskMilestones[task] = nextMilestone.Value; + return true; + } + } + + return false; + } + + private static double? GetNextMilestone(double percentage) + { + return Array.Find(_milestones, p => p > percentage); + } + + private static IRenderable? BuildTaskGrid(List<(string Name, double Percentage)> updates) + { + if (updates.Count > 0) + { + var renderables = new List(); + foreach (var (name, percentage) in updates) + { + renderables.Add(new Markup($"[blue]{name}[/]: {(int)percentage}%")); + } + + return new Rows(renderables); + } + + return null; + } + } +} diff --git a/src/Spectre.Console/Recorder.cs b/src/Spectre.Console/Recorder.cs index 11271a1..f1ffadb 100644 --- a/src/Spectre.Console/Recorder.cs +++ b/src/Spectre.Console/Recorder.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Text; using Spectre.Console.Rendering; @@ -8,7 +10,8 @@ namespace Spectre.Console /// /// A console recorder used to record output from a console. /// - public sealed class Recorder : IAnsiConsole, IDisposable + [SuppressMessage("Design", "CA1063:Implement IDisposable Correctly")] + public class Recorder : IAnsiConsole, IDisposable { private readonly IAnsiConsole _console; private readonly List _recorded; @@ -31,6 +34,14 @@ namespace Spectre.Console /// public int Height => _console.Height; + /// + public RenderPipeline Pipeline => _console.Pipeline; + + /// + /// Gets a list containing all recorded segments. + /// + protected List Recorded => _recorded; + /// /// Initializes a new instance of the class. /// @@ -42,6 +53,7 @@ namespace Spectre.Console } /// + [SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize")] public void Dispose() { // Only used for scoping. @@ -54,20 +66,25 @@ namespace Spectre.Console } /// - public void Write(Segment segment) + public void Write(IEnumerable segments) { - if (segment is null) + if (segments is null) { - throw new ArgumentNullException(nameof(segment)); + throw new ArgumentNullException(nameof(segments)); } - // Don't record control codes. - if (!segment.IsControlCode) - { - _recorded.Add(segment); - } + Record(segments); - _console.Write(segment); + _console.Write(segments); + } + + /// + /// Records the specified segments. + /// + /// The segments to be recorded. + protected virtual void Record(IEnumerable segments) + { + Recorded.AddRange(segments.Where(s => !s.IsControlCode)); } /// diff --git a/src/Spectre.Console/Rendering/IRenderHook.cs b/src/Spectre.Console/Rendering/IRenderHook.cs new file mode 100644 index 0000000..64ed57a --- /dev/null +++ b/src/Spectre.Console/Rendering/IRenderHook.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a render hook. + /// + public interface IRenderHook + { + /// + /// Processes the specified renderables. + /// + /// The render context. + /// The renderables to process. + /// The processed renderables. + IEnumerable Process(RenderContext context, IEnumerable renderables); + } +} diff --git a/src/Spectre.Console/Rendering/LiveRenderable.cs b/src/Spectre.Console/Rendering/LiveRenderable.cs new file mode 100644 index 0000000..fad49f8 --- /dev/null +++ b/src/Spectre.Console/Rendering/LiveRenderable.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Linq; +using Spectre.Console.Internal; +using Spectre.Console.Rendering; + +namespace Spectre.Console.Rendering +{ + internal sealed class LiveRenderable : Renderable + { + private readonly object _lock = new object(); + private IRenderable? _renderable; + private int? _height; + + public void SetRenderable(IRenderable renderable) + { + lock (_lock) + { + _renderable = renderable; + } + } + + public IRenderable PositionCursor() + { + lock (_lock) + { + if (_height == null) + { + return new ControlSequence(string.Empty); + } + + return new ControlSequence("\r" + "\u001b[1A".Repeat(_height.Value - 1)); + } + } + + public IRenderable RestoreCursor() + { + lock (_lock) + { + if (_height == null) + { + return new ControlSequence(string.Empty); + } + + return new ControlSequence("\r\u001b[2K" + "\u001b[1A\u001b[2K".Repeat(_height.Value - 1)); + } + } + + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + lock (_lock) + { + if (_renderable != null) + { + var segments = _renderable.Render(context, maxWidth); + var lines = Segment.SplitLines(context, segments); + + _height = lines.Count; + + var result = new List(); + foreach (var (_, _, last, line) in lines.Enumerate()) + { + foreach (var item in line) + { + result.Add(item); + } + + if (!last) + { + result.Add(Segment.LineBreak); + } + } + + return result; + } + + _height = 0; + return Enumerable.Empty(); + } + } + } +} diff --git a/src/Spectre.Console/Rendering/RenderContext.cs b/src/Spectre.Console/Rendering/RenderContext.cs index 644b443..c50ca6c 100644 --- a/src/Spectre.Console/Rendering/RenderContext.cs +++ b/src/Spectre.Console/Rendering/RenderContext.cs @@ -49,7 +49,7 @@ namespace Spectre.Console.Rendering Encoding = encoding ?? throw new System.ArgumentNullException(nameof(encoding)); LegacyConsole = legacyConsole; Justification = justification; - Unicode = Encoding == Encoding.UTF8 || Encoding == Encoding.Unicode; + Unicode = Encoding.EncodingName.ContainsExact("Unicode"); SingleLine = singleLine; } diff --git a/src/Spectre.Console/Rendering/RenderHookScope.cs b/src/Spectre.Console/Rendering/RenderHookScope.cs new file mode 100644 index 0000000..c646bfb --- /dev/null +++ b/src/Spectre.Console/Rendering/RenderHookScope.cs @@ -0,0 +1,31 @@ +using System; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents a render hook scope. + /// + public sealed class RenderHookScope : IDisposable + { + private readonly IAnsiConsole _console; + private readonly IRenderHook _hook; + + /// + /// Initializes a new instance of the class. + /// + /// The console to attach the render hook to. + /// The render hook. + public RenderHookScope(IAnsiConsole console, IRenderHook hook) + { + _console = console ?? throw new ArgumentNullException(nameof(console)); + _hook = hook ?? throw new ArgumentNullException(nameof(hook)); + _console.Pipeline.Attach(_hook); + } + + /// + public void Dispose() + { + _console.Pipeline.Detach(_hook); + } + } +} diff --git a/src/Spectre.Console/Rendering/RenderPipeline.cs b/src/Spectre.Console/Rendering/RenderPipeline.cs new file mode 100644 index 0000000..c20ce1a --- /dev/null +++ b/src/Spectre.Console/Rendering/RenderPipeline.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; + +namespace Spectre.Console.Rendering +{ + /// + /// Represents the render pipeline. + /// + public sealed class RenderPipeline + { + private readonly List _hooks; + private readonly object _lock; + + /// + /// Initializes a new instance of the class. + /// + public RenderPipeline() + { + _hooks = new List(); + _lock = new object(); + } + + /// + /// Attaches a new render hook onto the pipeline. + /// + /// The render hook to attach. + public void Attach(IRenderHook hook) + { + lock (_lock) + { + _hooks.Add(hook); + } + } + + /// + /// Detaches a render hook from the pipeline. + /// + /// The render hook to detach. + public void Detach(IRenderHook hook) + { + lock (_lock) + { + _hooks.Remove(hook); + } + } + + /// + /// Processes the specified renderables. + /// + /// The render context. + /// The renderables to process. + /// The processed renderables. + public IEnumerable Process(RenderContext context, IEnumerable renderables) + { + lock (_lock) + { + var current = renderables; + for (var index = _hooks.Count - 1; index >= 0; index--) + { + current = _hooks[index].Process(context, current); + } + + return current; + } + } + } +} diff --git a/src/Spectre.Console/Rendering/Segment.cs b/src/Spectre.Console/Rendering/Segment.cs index 0c3073e..46fcacd 100644 --- a/src/Spectre.Console/Rendering/Segment.cs +++ b/src/Spectre.Console/Rendering/Segment.cs @@ -72,7 +72,7 @@ namespace Spectre.Console.Rendering private Segment(string text, Style style, bool lineBreak, bool control) { - Text = text?.NormalizeLineEndings() ?? throw new ArgumentNullException(nameof(text)); + Text = text?.NormalizeNewLines() ?? throw new ArgumentNullException(nameof(text)); Style = style ?? throw new ArgumentNullException(nameof(style)); IsLineBreak = lineBreak; IsWhiteSpace = string.IsNullOrWhiteSpace(text); @@ -102,6 +102,11 @@ namespace Spectre.Console.Rendering throw new ArgumentNullException(nameof(context)); } + if (IsControlCode) + { + return 0; + } + return Text.CellLength(context); } @@ -477,16 +482,22 @@ namespace Spectre.Console.Rendering continue; } + // Both control codes? + if (segment.IsControlCode && previous.IsControlCode) + { + previous = Control(previous.Text + segment.Text); + continue; + } + // Same style? - if (previous.Style.Equals(segment.Style) && !previous.IsLineBreak) + if (previous.Style.Equals(segment.Style) && !previous.IsLineBreak && !previous.IsControlCode) { previous = new Segment(previous.Text + segment.Text, previous.Style); + continue; } - else - { - result.Add(previous); - previous = segment; - } + + result.Add(previous); + previous = segment; } if (previous != null) diff --git a/src/Spectre.Console/Widgets/ControlSequence.cs b/src/Spectre.Console/Widgets/ControlSequence.cs new file mode 100644 index 0000000..a577f15 --- /dev/null +++ b/src/Spectre.Console/Widgets/ControlSequence.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + internal sealed class ControlSequence : Renderable + { + private readonly Segment _segment; + + public ControlSequence(string control) + { + _segment = Segment.Control(control); + } + + protected override Measurement Measure(RenderContext context, int maxWidth) + { + return new Measurement(0, 0); + } + + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + yield return _segment; + } + } +} diff --git a/src/Spectre.Console/Widgets/ProgressBar.cs b/src/Spectre.Console/Widgets/ProgressBar.cs new file mode 100644 index 0000000..3c4e742 --- /dev/null +++ b/src/Spectre.Console/Widgets/ProgressBar.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Spectre.Console.Rendering; + +namespace Spectre.Console +{ + internal sealed class ProgressBar : Renderable + { + public double Value { get; set; } + public double MaxValue { get; set; } = 100; + + public int? Width { get; set; } + + public Style CompletedStyle { get; set; } = new Style(foreground: Color.Yellow); + public Style FinishedStyle { get; set; } = new Style(foreground: Color.Green); + public Style RemainingStyle { get; set; } = new Style(foreground: Color.Grey); + + protected override Measurement Measure(RenderContext context, int maxWidth) + { + var width = Math.Min(Width ?? maxWidth, maxWidth); + return new Measurement(4, width); + } + + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + var width = Math.Min(Width ?? maxWidth, maxWidth); + var completed = Math.Min(MaxValue, Math.Max(0, Value)); + + var token = !context.Unicode || context.LegacyConsole ? '-' : '━'; + var style = completed >= MaxValue ? FinishedStyle : CompletedStyle; + + var bars = Math.Max(0, (int)(width * (completed / MaxValue))); + yield return new Segment(new string(token, bars), style); + + if (bars < width) + { + yield return new Segment(new string(token, width - bars), RemainingStyle); + } + } + } +} diff --git a/src/Spectre.Console/Widgets/Rule.cs b/src/Spectre.Console/Widgets/Rule.cs index c3b9c2f..1078e2e 100644 --- a/src/Spectre.Console/Widgets/Rule.cs +++ b/src/Spectre.Console/Widgets/Rule.cs @@ -95,7 +95,7 @@ namespace Spectre.Console private IEnumerable GetTitleSegments(RenderContext context, string title, int width) { - title = title.NormalizeLineEndings().ReplaceExact("\n", " ").Trim(); + title = title.NormalizeNewLines().ReplaceExact("\n", " ").Trim(); var markup = new Markup(title, Style); return ((IRenderable)markup).Render(context.WithSingleLine(), width); } diff --git a/src/Spectre.Console/Widgets/Table.cs b/src/Spectre.Console/Widgets/Table.cs index f9c297b..e98f61e 100644 --- a/src/Spectre.Console/Widgets/Table.cs +++ b/src/Spectre.Console/Widgets/Table.cs @@ -16,8 +16,8 @@ namespace Spectre.Console private readonly List _columns; private readonly List _rows; - private static Style _defaultHeadingStyle = new Style(Color.Silver); - private static Style _defaultCaptionStyle = new Style(Color.Grey); + private static readonly Style _defaultHeadingStyle = new Style(Color.Silver); + private static readonly Style _defaultCaptionStyle = new Style(Color.Grey); /// /// Gets the table columns. @@ -447,12 +447,10 @@ namespace Spectre.Console private (int Min, int Max) MeasureColumn(TableColumn column, RenderContext options, int maxWidth) { - var padding = column.Padding?.GetWidth() ?? 0; - // Predetermined width? if (column.Width != null) { - return (column.Width.Value + padding, column.Width.Value + padding); + return (column.Width.Value, column.Width.Value); } var columnIndex = _columns.IndexOf(column); @@ -474,6 +472,8 @@ namespace Spectre.Console maxWidths.Add(rowMeasure.Max); } + var padding = column.Padding?.GetWidth() ?? 0; + return (minWidths.Count > 0 ? minWidths.Max() : padding, maxWidths.Count > 0 ? maxWidths.Max() : maxWidth); }