Add CursorLeft and CursorTop to IConsole

Closes #25
This commit is contained in:
Alexey Golub
2020-05-11 16:29:54 +03:00
parent 6e7742a4f3
commit 802bbfccc6
5 changed files with 55 additions and 14 deletions

View File

@@ -3,11 +3,16 @@ using System.Linq;
using CliFx.Utilities; using CliFx.Utilities;
using FluentAssertions; using FluentAssertions;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace CliFx.Tests namespace CliFx.Tests
{ {
public class UtilitiesSpecs public class UtilitiesSpecs
{ {
private readonly ITestOutputHelper _output;
public UtilitiesSpecs(ITestOutputHelper output) => _output = output;
[Fact] [Fact]
public void Progress_ticker_can_be_used_to_report_progress_to_console() public void Progress_ticker_can_be_used_to_report_progress_to_console()
{ {
@@ -28,6 +33,8 @@ namespace CliFx.Tests
// Assert // Assert
stdOutData.Should().ContainAll(progressStringValues); stdOutData.Should().ContainAll(progressStringValues);
_output.WriteLine(stdOutData);
} }
[Fact] [Fact]
@@ -49,6 +56,8 @@ namespace CliFx.Tests
// Assert // Assert
stdOutData.Should().BeEmpty(); stdOutData.Should().BeEmpty();
_output.WriteLine(stdOutData);
} }
} }
} }

View File

@@ -54,6 +54,16 @@ namespace CliFx
/// </summary> /// </summary>
void ResetColor(); void ResetColor();
/// <summary>
/// Cursor left offset.
/// </summary>
int CursorLeft { get; set; }
/// <summary>
/// Cursor top offset.
/// </summary>
int CursorTop { get; set; }
/// <summary> /// <summary>
/// Provides a token that signals when application cancellation is requested. /// Provides a token that signals when application cancellation is requested.
/// Subsequent calls return the same token. /// Subsequent calls return the same token.

View File

@@ -56,6 +56,20 @@ namespace CliFx
/// <inheritdoc /> /// <inheritdoc />
public void ResetColor() => Console.ResetColor(); public void ResetColor() => Console.ResetColor();
/// <inheritdoc />
public int CursorLeft
{
get => Console.CursorLeft;
set => Console.CursorLeft = value;
}
/// <inheritdoc />
public int CursorTop
{
get => Console.CursorTop;
set => Console.CursorTop = value;
}
/// <inheritdoc /> /// <inheritdoc />
public CancellationToken GetCancellationToken() public CancellationToken GetCancellationToken()
{ {

View File

@@ -9,26 +9,29 @@ namespace CliFx.Utilities
{ {
private readonly IConsole _console; private readonly IConsole _console;
private string _lastOutput = ""; private int? _originalCursorLeft;
private int? _originalCursorTop;
/// <summary> /// <summary>
/// Initializes an instance of <see cref="ProgressTicker"/>. /// Initializes an instance of <see cref="ProgressTicker"/>.
/// </summary> /// </summary>
public ProgressTicker(IConsole console) public ProgressTicker(IConsole console) => _console = console;
{
_console = console;
}
private void EraseLastOutput()
{
for (var i = 0; i < _lastOutput.Length; i++)
_console.Output.Write('\b');
}
private void RenderProgress(double progress) private void RenderProgress(double progress)
{ {
_lastOutput = progress.ToString("P2", _console.Output.FormatProvider); if (_originalCursorLeft != null && _originalCursorTop != null)
_console.Output.Write(_lastOutput); {
_console.CursorLeft = _originalCursorLeft.Value;
_console.CursorTop = _originalCursorTop.Value;
}
else
{
_originalCursorLeft = _console.CursorLeft;
_originalCursorTop = _console.CursorTop;
}
var str = progress.ToString("P2", _console.Output.FormatProvider);
_console.Output.Write(str);
} }
/// <summary> /// <summary>
@@ -41,7 +44,6 @@ namespace CliFx.Utilities
// when there's no active console window. // when there's no active console window.
if (!_console.IsOutputRedirected) if (!_console.IsOutputRedirected)
{ {
EraseLastOutput();
RenderProgress(progress); RenderProgress(progress);
} }
} }

View File

@@ -44,6 +44,12 @@ namespace CliFx
BackgroundColor = ConsoleColor.Black; BackgroundColor = ConsoleColor.Black;
} }
/// <inheritdoc />
public int CursorLeft { get; set; }
/// <inheritdoc />
public int CursorTop { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public CancellationToken GetCancellationToken() => _cancellationToken; public CancellationToken GetCancellationToken() => _cancellationToken;