mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-15 00:12:50 +08:00
Add support for moving the cursor
This commit is contained in:
parent
93d1971f48
commit
a1d11e9d0c
@ -15,7 +15,7 @@
|
||||
]
|
||||
},
|
||||
"dotnet-example": {
|
||||
"version": "0.8.0",
|
||||
"version": "0.10.0",
|
||||
"commands": [
|
||||
"dotnet-example"
|
||||
]
|
||||
|
15
examples/Cursor/Cursor.csproj
Normal file
15
examples/Cursor/Cursor.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Title>Cursor</Title>
|
||||
<Description>Demonstrates how to move the cursor.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
21
examples/Cursor/Program.cs
Normal file
21
examples/Cursor/Program.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace Cursor
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
AnsiConsole.Write("Hello");
|
||||
|
||||
// Move the cursor 3 cells to the right
|
||||
AnsiConsole.Cursor.Move(CursorDirection.Right, 3);
|
||||
AnsiConsole.Write("World");
|
||||
|
||||
// Move the cursor 5 cells to the left.
|
||||
AnsiConsole.Cursor.Move(CursorDirection.Left, 5);
|
||||
AnsiConsole.WriteLine("Universe");
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ namespace Spectre.Console.Tests
|
||||
public Encoding Encoding => _console.Encoding;
|
||||
public int Width { get; }
|
||||
public int Height => _console.Height;
|
||||
public IAnsiConsoleCursor Cursor => _console.Cursor;
|
||||
|
||||
public TestableAnsiConsole(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes, int width = 80)
|
||||
{
|
||||
@ -37,6 +38,11 @@ namespace Spectre.Console.Tests
|
||||
_writer?.Dispose();
|
||||
}
|
||||
|
||||
public void Clear(bool home)
|
||||
{
|
||||
_console.Clear(home);
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
_console.Write(segment);
|
||||
|
@ -14,6 +14,7 @@ namespace Spectre.Console.Tests.Tools
|
||||
|
||||
public Capabilities Capabilities => _console.Capabilities;
|
||||
public Encoding Encoding => _console.Encoding;
|
||||
public IAnsiConsoleCursor Cursor => _console.Cursor;
|
||||
public int Width { get; }
|
||||
public int Height => _console.Height;
|
||||
|
||||
@ -36,6 +37,11 @@ namespace Spectre.Console.Tests.Tools
|
||||
_writer?.Dispose();
|
||||
}
|
||||
|
||||
public void Clear(bool home)
|
||||
{
|
||||
_console.Clear(home);
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
_console.Write(segment);
|
||||
|
@ -11,6 +11,7 @@ namespace Spectre.Console.Tests
|
||||
{
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
public IAnsiConsoleCursor Cursor => throw new NotSupportedException();
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
@ -42,6 +43,10 @@ namespace Spectre.Console.Tests
|
||||
Writer.Dispose();
|
||||
}
|
||||
|
||||
public void Clear(bool home)
|
||||
{
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
if (segment is null)
|
||||
|
@ -48,6 +48,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calendars", "..\examples\Ca
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rules", "..\examples\Rules\Rules.csproj", "{8622A261-02C6-40CA-9797-E3F01ED87D6B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cursor", "..\examples\Cursor\Cursor.csproj", "{75C608C3-ABB4-4168-A229-7F8250B946D1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -226,6 +228,18 @@ Global
|
||||
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8622A261-02C6-40CA-9797-E3F01ED87D6B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -244,6 +258,7 @@ Global
|
||||
{C3E2CB5C-1517-4C75-B59A-93D4E22BEC8D} = {20595AD4-8D75-4AF8-B6BC-9C38C160423F}
|
||||
{57691C7D-683D-46E6-AA4F-57A8C5F65D25} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||
{8622A261-02C6-40CA-9797-E3F01ED87D6B} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||
{75C608C3-ABB4-4168-A229-7F8250B946D1} = {F0575243-121F-4DEE-9F6B-246E26DC0844}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
|
||||
|
@ -27,6 +27,11 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
public static IAnsiConsole Console => _recorder ?? _console.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IAnsiConsoleCursor"/>.
|
||||
/// </summary>
|
||||
public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console's capabilities.
|
||||
/// </summary>
|
||||
@ -56,7 +61,7 @@ namespace Spectre.Console
|
||||
/// <returns>An <see cref="IAnsiConsole"/> instance.</returns>
|
||||
public static IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
{
|
||||
return AnsiConsoleBuilder.Build(settings);
|
||||
return BackendBuilder.Build(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
src/Spectre.Console/CursorDirection.cs
Normal file
28
src/Spectre.Console/CursorDirection.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents cursor direction.
|
||||
/// </summary>
|
||||
public enum CursorDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// Up
|
||||
/// </summary>
|
||||
Up,
|
||||
|
||||
/// <summary>
|
||||
/// Down
|
||||
/// </summary>
|
||||
Down,
|
||||
|
||||
/// <summary>
|
||||
/// Left
|
||||
/// </summary>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// Right
|
||||
/// </summary>
|
||||
Right,
|
||||
}
|
||||
}
|
152
src/Spectre.Console/Extensions/CursorExtensions.cs
Normal file
152
src/Spectre.Console/Extensions/CursorExtensions.cs
Normal file
@ -0,0 +1,152 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for <see cref="IAnsiConsoleCursor"/>.
|
||||
/// </summary>
|
||||
public static class CursorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the cursor.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void Show(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Show(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides the cursor.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void Hide(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Show(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor up.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void MoveUp(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Up, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor up.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
/// <param name="steps">The number of steps to move the cursor.</param>
|
||||
public static void MoveUp(this IAnsiConsoleCursor cursor, int steps)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Up, steps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor down.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void MoveDown(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Down, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor down.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
/// <param name="steps">The number of steps to move the cursor.</param>
|
||||
public static void MoveDown(this IAnsiConsoleCursor cursor, int steps)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Down, steps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the left.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void MoveLeft(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Left, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the left.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
/// <param name="steps">The number of steps to move the cursor.</param>
|
||||
public static void MoveLeft(this IAnsiConsoleCursor cursor, int steps)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Left, steps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the right.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
public static void MoveRight(this IAnsiConsoleCursor cursor)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Right, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the right.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor.</param>
|
||||
/// <param name="steps">The number of steps to move the cursor.</param>
|
||||
public static void MoveRight(this IAnsiConsoleCursor cursor, int steps)
|
||||
{
|
||||
if (cursor is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(cursor));
|
||||
}
|
||||
|
||||
cursor.Move(CursorDirection.Right, steps);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
|
@ -18,6 +18,11 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
Encoding Encoding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console cursor.
|
||||
/// </summary>
|
||||
IAnsiConsoleCursor Cursor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer width of the console.
|
||||
/// </summary>
|
||||
@ -28,6 +33,12 @@ namespace Spectre.Console
|
||||
/// </summary>
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Clears the console.
|
||||
/// </summary>
|
||||
/// <param name="home">If the cursor should be moved to the home position.</param>
|
||||
void Clear(bool home);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string followed by a line terminator to the console.
|
||||
/// </summary>
|
||||
|
28
src/Spectre.Console/IAnsiConsoleCursor.cs
Normal file
28
src/Spectre.Console/IAnsiConsoleCursor.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the console's cursor.
|
||||
/// </summary>
|
||||
public interface IAnsiConsoleCursor
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows or hides the cursor.
|
||||
/// </summary>
|
||||
/// <param name="show"><c>true</c> to show the cursor, <c>false</c> to hide it.</param>
|
||||
void Show(bool show);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the cursor position.
|
||||
/// </summary>
|
||||
/// <param name="column">The column to move the cursor to.</param>
|
||||
/// <param name="line">The line to move the cursor to.</param>
|
||||
void SetPosition(int column, int line);
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor relative to the current position.
|
||||
/// </summary>
|
||||
/// <param name="direction">The direction to move the cursor.</param>
|
||||
/// <param name="steps">The number of steps to move the cursor.</param>
|
||||
void Move(CursorDirection direction, int steps);
|
||||
}
|
||||
}
|
@ -5,13 +5,15 @@ using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class AnsiConsoleRenderer : IAnsiConsole
|
||||
internal sealed class AnsiBackend : IAnsiConsole
|
||||
{
|
||||
private readonly TextWriter _out;
|
||||
private readonly AnsiBuilder _ansiBuilder;
|
||||
private readonly AnsiCursor _cursor;
|
||||
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
public IAnsiConsoleCursor Cursor => _cursor;
|
||||
|
||||
public int Width
|
||||
{
|
||||
@ -39,7 +41,7 @@ namespace Spectre.Console.Internal
|
||||
}
|
||||
}
|
||||
|
||||
public AnsiConsoleRenderer(TextWriter @out, Capabilities capabilities, ILinkIdentityGenerator? linkHasher)
|
||||
public AnsiBackend(TextWriter @out, Capabilities capabilities, ILinkIdentityGenerator? linkHasher)
|
||||
{
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
|
||||
@ -47,6 +49,17 @@ namespace Spectre.Console.Internal
|
||||
Encoding = _out.IsStandardOut() ? System.Console.OutputEncoding : Encoding.UTF8;
|
||||
|
||||
_ansiBuilder = new AnsiBuilder(Capabilities, linkHasher);
|
||||
_cursor = new AnsiCursor(this);
|
||||
}
|
||||
|
||||
public void Clear(bool home)
|
||||
{
|
||||
Write(Segment.Control("\u001b[2J"));
|
||||
|
||||
if (home)
|
||||
{
|
||||
Cursor.SetPosition(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
56
src/Spectre.Console/Internal/Backends/Ansi/AnsiCursor.cs
Normal file
56
src/Spectre.Console/Internal/Backends/Ansi/AnsiCursor.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class AnsiCursor : IAnsiConsoleCursor
|
||||
{
|
||||
private readonly AnsiBackend _renderer;
|
||||
|
||||
public AnsiCursor(AnsiBackend renderer)
|
||||
{
|
||||
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
public void Show(bool show)
|
||||
{
|
||||
if (show)
|
||||
{
|
||||
_renderer.Write(Segment.Control("\u001b[?25h"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer.Write(Segment.Control("\u001b[?25l"));
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(CursorDirection direction, int steps)
|
||||
{
|
||||
if (steps == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case CursorDirection.Up:
|
||||
_renderer.Write(Segment.Control($"\u001b[{steps}A"));
|
||||
break;
|
||||
case CursorDirection.Down:
|
||||
_renderer.Write(Segment.Control($"\u001b[{steps}B"));
|
||||
break;
|
||||
case CursorDirection.Right:
|
||||
_renderer.Write(Segment.Control($"\u001b[{steps}C"));
|
||||
break;
|
||||
case CursorDirection.Left:
|
||||
_renderer.Write(Segment.Control($"\u001b[{steps}D"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPosition(int column, int line)
|
||||
{
|
||||
_renderer.Write(Segment.Control($"\u001b[{line};{column}H"));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class AnsiConsoleBuilder
|
||||
internal static class BackendBuilder
|
||||
{
|
||||
public static IAnsiConsole Build(AnsiConsoleSettings settings)
|
||||
{
|
||||
@ -60,11 +60,11 @@ namespace Spectre.Console.Internal
|
||||
// Create the renderer
|
||||
if (supportsAnsi)
|
||||
{
|
||||
return new AnsiConsoleRenderer(buffer, capabilities, settings.LinkIdentityGenerator);
|
||||
return new AnsiBackend(buffer, capabilities, settings.LinkIdentityGenerator);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FallbackConsoleRenderer(buffer, capabilities);
|
||||
return new FallbackBackend(buffer, capabilities);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class FallbackBackend : IAnsiConsole
|
||||
{
|
||||
private readonly ColorSystem _system;
|
||||
private readonly FallbackCursor _cursor;
|
||||
private Style? _lastStyle;
|
||||
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
public IAnsiConsoleCursor Cursor => _cursor;
|
||||
|
||||
public int Width
|
||||
{
|
||||
get { return ConsoleHelper.GetSafeBufferWidth(Constants.DefaultBufferWidth); }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get { return ConsoleHelper.GetSafeBufferHeight(Constants.DefaultBufferHeight); }
|
||||
}
|
||||
|
||||
public FallbackBackend(TextWriter @out, Capabilities capabilities)
|
||||
{
|
||||
if (capabilities == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(capabilities));
|
||||
}
|
||||
|
||||
_system = capabilities.ColorSystem;
|
||||
_cursor = new FallbackCursor();
|
||||
|
||||
if (@out != System.Console.Out)
|
||||
{
|
||||
System.Console.SetOut(@out ?? throw new ArgumentNullException(nameof(@out)));
|
||||
}
|
||||
|
||||
Encoding = System.Console.OutputEncoding;
|
||||
Capabilities = capabilities;
|
||||
}
|
||||
|
||||
public void Clear(bool home)
|
||||
{
|
||||
var (x, y) = (System.Console.CursorLeft, System.Console.CursorTop);
|
||||
|
||||
System.Console.Clear();
|
||||
|
||||
if (!home)
|
||||
{
|
||||
// Set the cursor position
|
||||
System.Console.SetCursorPosition(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
if (_lastStyle?.Equals(segment.Style) != true)
|
||||
{
|
||||
SetStyle(segment.Style);
|
||||
}
|
||||
|
||||
System.Console.Write(segment.Text.NormalizeLineEndings(native: true));
|
||||
}
|
||||
|
||||
private void SetStyle(Style style)
|
||||
{
|
||||
_lastStyle = style;
|
||||
|
||||
System.Console.ResetColor();
|
||||
|
||||
var background = Color.ToConsoleColor(style.Background);
|
||||
if (_system != ColorSystem.NoColors && (int)background != -1)
|
||||
{
|
||||
System.Console.BackgroundColor = background;
|
||||
}
|
||||
|
||||
var foreground = Color.ToConsoleColor(style.Foreground);
|
||||
if (_system != ColorSystem.NoColors && (int)foreground != -1)
|
||||
{
|
||||
System.Console.ForegroundColor = foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class FallbackCursor : IAnsiConsoleCursor
|
||||
{
|
||||
public void Show(bool show)
|
||||
{
|
||||
System.Console.CursorVisible = show;
|
||||
}
|
||||
|
||||
public void Move(CursorDirection direction, int steps)
|
||||
{
|
||||
if (steps == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case CursorDirection.Up:
|
||||
System.Console.CursorTop -= steps;
|
||||
break;
|
||||
case CursorDirection.Down:
|
||||
System.Console.CursorTop += steps;
|
||||
break;
|
||||
case CursorDirection.Left:
|
||||
System.Console.CursorLeft -= steps;
|
||||
break;
|
||||
case CursorDirection.Right:
|
||||
System.Console.CursorLeft += steps;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPosition(int x, int y)
|
||||
{
|
||||
System.Console.CursorLeft = x;
|
||||
System.Console.CursorTop = y;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Internal.Collections
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class ListWithCallback<T> : IList<T>, IReadOnlyList<T>
|
||||
{
|
||||
|
@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal static class ExceptionFormatter
|
||||
{
|
||||
|
@ -1,97 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Internal
|
||||
{
|
||||
internal sealed class FallbackConsoleRenderer : IAnsiConsole
|
||||
{
|
||||
private readonly TextWriter _out;
|
||||
private readonly ColorSystem _system;
|
||||
private Style? _lastStyle;
|
||||
|
||||
public Capabilities Capabilities { get; }
|
||||
public Encoding Encoding { get; }
|
||||
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return ConsoleHelper.GetSafeBufferWidth(Constants.DefaultBufferWidth);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
return ConsoleHelper.GetSafeBufferHeight(Constants.DefaultBufferHeight);
|
||||
}
|
||||
|
||||
return Constants.DefaultBufferHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public FallbackConsoleRenderer(TextWriter @out, Capabilities capabilities)
|
||||
{
|
||||
if (capabilities == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(capabilities));
|
||||
}
|
||||
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
_system = capabilities.ColorSystem;
|
||||
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
Encoding = System.Console.OutputEncoding;
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
Capabilities = capabilities;
|
||||
}
|
||||
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
if (_lastStyle?.Equals(segment.Style) != true)
|
||||
{
|
||||
SetStyle(segment.Style);
|
||||
}
|
||||
|
||||
_out.Write(segment.Text.NormalizeLineEndings(native: true));
|
||||
}
|
||||
|
||||
private void SetStyle(Style style)
|
||||
{
|
||||
_lastStyle = style;
|
||||
|
||||
if (_out.IsStandardOut())
|
||||
{
|
||||
System.Console.ResetColor();
|
||||
|
||||
var background = Color.ToConsoleColor(style.Background);
|
||||
if (_system != ColorSystem.NoColors && _out.IsStandardOut() && (int)background != -1)
|
||||
{
|
||||
System.Console.BackgroundColor = background;
|
||||
}
|
||||
|
||||
var foreground = Color.ToConsoleColor(style.Foreground);
|
||||
if (_system != ColorSystem.NoColors && _out.IsStandardOut() && (int)foreground != -1)
|
||||
{
|
||||
System.Console.ForegroundColor = foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,9 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
public Encoding Encoding => _console.Encoding;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAnsiConsoleCursor Cursor => _console.Cursor;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Width => _console.Width;
|
||||
|
||||
@ -41,10 +44,26 @@ namespace Spectre.Console
|
||||
// Only used for scoping.
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Clear(bool home)
|
||||
{
|
||||
_console.Clear(home);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Write(Segment segment)
|
||||
{
|
||||
_recorded.Add(segment);
|
||||
if (segment is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(segment));
|
||||
}
|
||||
|
||||
// Don't record control codes.
|
||||
if (!segment.IsControlCode)
|
||||
{
|
||||
_recorded.Add(segment);
|
||||
}
|
||||
|
||||
_console.Write(segment);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,12 @@ namespace Spectre.Console.Rendering
|
||||
/// </summary>
|
||||
public bool IsWhiteSpace { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not his is a
|
||||
/// control code such as cursor movement.
|
||||
/// </summary>
|
||||
public bool IsControlCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the segment style.
|
||||
/// </summary>
|
||||
@ -39,12 +45,12 @@ namespace Spectre.Console.Rendering
|
||||
/// <summary>
|
||||
/// Gets a segment representing a line break.
|
||||
/// </summary>
|
||||
public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true);
|
||||
public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true, false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty segment.
|
||||
/// </summary>
|
||||
public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain, false);
|
||||
public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain, false, false);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Segment"/> class.
|
||||
@ -61,16 +67,27 @@ namespace Spectre.Console.Rendering
|
||||
/// <param name="text">The segment text.</param>
|
||||
/// <param name="style">The segment style.</param>
|
||||
public Segment(string text, Style style)
|
||||
: this(text, style, false)
|
||||
: this(text, style, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
private Segment(string text, Style style, bool lineBreak)
|
||||
private Segment(string text, Style style, bool lineBreak, bool control)
|
||||
{
|
||||
Text = text?.NormalizeLineEndings() ?? throw new ArgumentNullException(nameof(text));
|
||||
Style = style ?? throw new ArgumentNullException(nameof(style));
|
||||
IsLineBreak = lineBreak;
|
||||
IsWhiteSpace = string.IsNullOrWhiteSpace(text);
|
||||
IsControlCode = control;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a control segment.
|
||||
/// </summary>
|
||||
/// <param name="control">The control code.</param>
|
||||
/// <returns>A segment representing a control code.</returns>
|
||||
public static Segment Control(string control)
|
||||
{
|
||||
return new Segment(control, Style.Plain, false, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Internal.Collections;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal.Collections;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Internal;
|
||||
using Spectre.Console.Rendering;
|
||||
using Spectre.Console.Widgets;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
|
@ -3,7 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Widgets
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a table row.
|
||||
|
Loading…
x
Reference in New Issue
Block a user