Add analyzers and XML documentation

This commit is contained in:
Patrik Svensson 2021-05-30 23:56:55 +02:00
Родитель 41757f1847
Коммит ec6ec083c0
34 изменённых файлов: 589 добавлений и 56 удалений

Двоичные данные
resources/gfx/large-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 600 KiB

Двоичные данные
resources/gfx/medium-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 30 KiB

Двоичные данные
resources/gfx/small-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.5 KiB

95
src/.editorconfig Normal file
Просмотреть файл

@ -0,0 +1,95 @@
root = false
[*.cs]
# IDE0055: Fix formatting
dotnet_diagnostic.IDE0055.severity = warning
# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none
# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none
# SA1201: Elements should appear in the correct order
dotnet_diagnostic.SA1201.severity = none
# SA1202: Public members should come before private members
dotnet_diagnostic.SA1202.severity = none
# SA1309: Field names should not begin with underscore
dotnet_diagnostic.SA1309.severity = none
# SA1404: Code analysis suppressions should have justification
dotnet_diagnostic.SA1404.severity = none
# SA1516: Elements should be separated by a blank line
dotnet_diagnostic.SA1516.severity = none
# CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = none
# CSA1204: Static members should appear before non-static members
dotnet_diagnostic.SA1204.severity = none
# IDE0052: Remove unread private members
dotnet_diagnostic.IDE0052.severity = warning
# IDE0063: Use simple 'using' statement
csharp_prefer_simple_using_statement = false:suggestion
# IDE0018: Variable declaration can be inlined
dotnet_diagnostic.IDE0018.severity = warning
# SA1625: Element documenation should not be copied and pasted
dotnet_diagnostic.SA1625.severity = none
# IDE0005: Using directive is unnecessary
dotnet_diagnostic.IDE0005.severity = warning
# SA1117: Parameters should be on same line or separate lines
dotnet_diagnostic.SA1117.severity = none
# SA1404: Code analysis suppression should have justification
dotnet_diagnostic.SA1404.severity = none
# SA1101: Prefix local calls with this
dotnet_diagnostic.SA1101.severity = none
# SA1633: File should have header
dotnet_diagnostic.SA1633.severity = none
# SA1649: File name should match first type name
dotnet_diagnostic.SA1649.severity = none
# SA1402: File may only contain a single type
dotnet_diagnostic.SA1402.severity = none
# CA1814: Prefer jagged arrays over multidimensional
dotnet_diagnostic.CA1814.severity = none
# RCS1194: Implement exception constructors.
dotnet_diagnostic.RCS1194.severity = none
# CA1032: Implement standard exception constructors
dotnet_diagnostic.CA1032.severity = none
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
dotnet_diagnostic.CA1826.severity = none
# RCS1079: Throwing of new NotImplementedException.
dotnet_diagnostic.RCS1079.severity = warning
# RCS1057: Add empty line between declarations.
dotnet_diagnostic.RCS1057.severity = none
# RCS1057: Validate arguments correctly
dotnet_diagnostic.RCS1227.severity = none
# IDE0004: Remove Unnecessary Cast
dotnet_diagnostic.IDE0004.severity = warning
# CA1810: Initialize reference type static fields inline
dotnet_diagnostic.CA1810.severity = none
# IDE0044: Add readonly modifier
dotnet_diagnostic.IDE0044.severity = warning

47
src/Directory.Build.props Normal file
Просмотреть файл

@ -0,0 +1,47 @@
<Project>
<PropertyGroup Label="Settings">
<Deterministic>true</Deterministic>
<LangVersion>9.0</LangVersion>
<DebugSymbols>true</DebugSymbols>
<DebugType>embedded</DebugType>
<MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup Label="Deterministic Build" Condition="'$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<PropertyGroup Label="Package Information">
<Description>A terminal abstraction with platform specific drivers.</Description>
<Copyright>Patrik Svensson, Phil Scott</Copyright>
<Authors>Patrik Svensson, Phil Scott</Authors>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/spectreconsole/terminal</RepositoryUrl>
<PackageIcon>small-logo.png</PackageIcon>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/spectreconsole/terminal</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Label="Source Link">
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup Label="Package References">
<PackageReference Include="MinVer" PrivateAssets="All" Version="2.4.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="1.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.312">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="3.0.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,8 @@
<Project>
<Target Name="Versioning" BeforeTargets="MinVer">
<PropertyGroup Label="Build">
<MinVerDefaultPreReleasePhase>preview</MinVerDefaultPreReleasePhase>
<MinVerVerbosity>normal</MinVerVerbosity>
</PropertyGroup>
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,35 @@
root = false
[*.cs]
# Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules'
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none
# CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none
# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none
# SA1601: Partial elements should be documented
dotnet_diagnostic.SA1601.severity = none
# SA1200: Using directives should be placed correctly
dotnet_diagnostic.SA1200.severity = none
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = none
# SA1210: Using directives should be ordered alphabetically by namespace
dotnet_diagnostic.SA1210.severity = none
# CA1034: Nested types should not be visible
dotnet_diagnostic.CA1034.severity = none
# CA2000: Dispose objects before losing scope
dotnet_diagnostic.CA2000.severity = none
# SA1118: Parameter should not span multiple lines
dotnet_diagnostic.SA1118.severity = none
# CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = none

Просмотреть файл

@ -50,12 +50,12 @@ namespace Spectre.Terminals.Tests
protected override void ShowCursor(ShowCursor instruction, StringBuilder state)
{
state.Append($"[ShowCursor]");
state.Append("[ShowCursor]");
}
protected override void HideCursor(HideCursor instruction, StringBuilder state)
{
state.Append($"[HideCursor]");
state.Append("[HideCursor]");
}
}
}

Просмотреть файл

@ -5,6 +5,10 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Shouldly" Version="4.0.3" />

Просмотреть файл

@ -0,0 +1,20 @@
root = false
[*.cs]
# Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules'
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none
# CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none
# SA1600: Elements should be documented
dotnet_diagnostic.SA1600.severity = none
# SA1601: Partial elements should be documented
dotnet_diagnostic.SA1601.severity = none
# SA1200: Using directives should be placed correctly
dotnet_diagnostic.SA1200.severity = none
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = none

Просмотреть файл

@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Spectre.Terminals.Ansi
{
public sealed class EnableAlternativeBuffer : AnsiInstruction

Просмотреть файл

@ -1,9 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Spectre.Terminals.Ansi
{
public sealed class HideCursor : AnsiInstruction

Просмотреть файл

@ -90,7 +90,7 @@ namespace Spectre.Terminals.Ansi
{
return new HideCursor();
}
else if(value == 1049)
else if (value == 1049)
{
return new DisableAlternativeBuffer();
}

Просмотреть файл

@ -5,7 +5,7 @@ namespace Spectre.Terminals.Ansi
{
internal static class AnsiSequenceSplitter
{
public static List<(ReadOnlyMemory<char>, bool)> Split(ReadOnlyMemory<char> buffer)
public static List<(ReadOnlyMemory<char> Text, bool IsSequence)> Split(ReadOnlyMemory<char> buffer)
{
var index = 0;
var end = 0;

Просмотреть файл

@ -1,10 +1,29 @@
namespace Spectre.Terminals
{
/// <summary>
/// Represents different ways of clearing a display.
/// </summary>
public enum ClearDisplay
{
/// <summary>
/// Clears the whole display.
/// </summary>
Everything = 0,
/// <summary>
/// Clears the whole display, including the
/// scrollback buffer.
/// </summary>
EverythingAndScrollbackBuffer = 1,
/// <summary>
/// Clears everything before the cursor.
/// </summary>
BeforeCursor = 2,
/// <summary>
/// Clears everything after the cursor.
/// </summary>
AfterCursor = 3,
}
}

Просмотреть файл

@ -1,9 +1,23 @@
namespace Spectre.Terminals
{
/// <summary>
/// Represents different ways of clearing a line.
/// </summary>
public enum ClearLine
{
/// <summary>
/// Clears the whole line.
/// </summary>
WholeLine = 0,
/// <summary>
/// Clears everything before the cursor.
/// </summary>
BeforeCursor = 1,
/// <summary>
/// Clears everything after the cursor.
/// </summary>
AfterCursor = 2,
}
}

Просмотреть файл

@ -1,10 +1,28 @@
namespace Spectre.Terminals
{
/// <summary>
/// Represents a cursor direction.
/// </summary>
public enum CursorDirection
{
/// <summary>
/// Moves the cursor forward.
/// </summary>
Forward = 0,
/// <summary>
/// Moves the cursor backwards.
/// </summary>
Back = 1,
/// <summary>
/// Moves the cursor up.
/// </summary>
Up = 2,
/// <summary>
/// Moves the cursor down.
/// </summary>
Down = 3,
}
}

Просмотреть файл

@ -1,7 +1,6 @@
using System;
using Spectre.Terminals.Ansi;
using Microsoft.Windows.Sdk;
using System.Runtime.InteropServices;
using Spectre.Terminals.Ansi;
namespace Spectre.Terminals.Windows
{
@ -94,13 +93,13 @@ namespace Spectre.Terminals.Windows
{
// Delete everything before the cursor
var length = (info.dwCursorPosition.Y * info.dwSize.X) + info.dwCursorPosition.X;
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)length, new COORD(), out _);
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)length, default(COORD), out _);
}
else if (op.Mode == 2 || op.Mode == 3)
{
// Delete everything
var terminalSize = info.dwSize.X * info.dwSize.Y;
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)terminalSize, new COORD(), out _);
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)terminalSize, default(COORD), out _);
}
}
@ -117,14 +116,14 @@ namespace Spectre.Terminals.Windows
var length = info.dwSize.X - info.dwCursorPosition.X;
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)length, info.dwCursorPosition, out _);
}
if (op.Mode == 1)
else if (op.Mode == 1)
{
// Delete line before the cursor
var length = info.dwCursorPosition.X;
var pos = new COORD { X = 0, Y = info.dwCursorPosition.Y };
PInvoke.FillConsoleOutputCharacter(state.Handle, ' ', (uint)length, pos, out _);
}
if (op.Mode == 2)
else if (op.Mode == 2)
{
// Delete whole line
var pos = new COORD { X = 0, Y = info.dwCursorPosition.Y };

Просмотреть файл

@ -0,0 +1,46 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Microsoft.Windows.Sdk;
namespace Spectre.Terminals.Windows
{
/// <summary>
/// Represents a Windows writer.
/// </summary>
internal interface IWindowsTerminalWriter : ITerminalWriter, IDisposable
{
/// <summary>
/// Gets the handle.
/// </summary>
SafeHandle Handle { get; }
/// <summary>
/// Writes the specified data to the specified handle.
/// </summary>
/// <param name="handle">The handle to write to.</param>
/// <param name="buffer">The buffer to write.</param>
void Write(SafeHandle handle, ReadOnlySpan<byte> buffer);
/// <summary>
/// Gets the <see cref="CONSOLE_MODE"/> for the writer.
/// </summary>
/// <param name="mode">The resulting <see cref="CONSOLE_MODE"/>, or <c>null</c> if the operation failed.</param>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool GetMode([NotNullWhen(true)] out CONSOLE_MODE? mode);
/// <summary>
/// Adds the specified <see cref="CONSOLE_MODE"/>.
/// </summary>
/// <param name="mode">The <see cref="CONSOLE_MODE"/> to add.</param>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool AddMode(CONSOLE_MODE mode);
/// <summary>
/// Removes the specified <see cref="CONSOLE_MODE"/>.
/// </summary>
/// <param name="mode">The <see cref="CONSOLE_MODE"/> to remove.</param>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool RemoveMode(CONSOLE_MODE mode);
}
}

Просмотреть файл

@ -1,5 +1,8 @@
using System.Diagnostics.CodeAnalysis;
namespace Spectre.Terminals.Windows
{
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
internal static class WindowsConstants
{
public const int ERROR_HANDLE_EOF = 38;

Просмотреть файл

@ -1,11 +1,14 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Windows.Sdk;
namespace Spectre.Terminals.Windows
{
public sealed class WindowsDriver : ITerminalDriver, IDisposable
internal sealed class WindowsDriver : ITerminalDriver, IDisposable
{
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
private const CONSOLE_MODE IN_MODE = CONSOLE_MODE.ENABLE_PROCESSED_INPUT | CONSOLE_MODE.ENABLE_LINE_INPUT | CONSOLE_MODE.ENABLE_ECHO_INPUT;
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore")]
private const CONSOLE_MODE OUT_MODE = CONSOLE_MODE.DISABLE_NEWLINE_AUTO_RETURN;
private readonly WindowsTerminalReader _input;

Просмотреть файл

@ -1,7 +1,7 @@
using Microsoft.Windows.Sdk;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Microsoft.Windows.Sdk;
namespace Spectre.Terminals.Windows
{

Просмотреть файл

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Windows.Sdk;
using System.Runtime.InteropServices;
namespace Spectre.Terminals.Windows
{

Просмотреть файл

@ -1,22 +1,10 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Windows.Sdk;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
namespace Spectre.Terminals.Windows
{
internal interface IWindowsTerminalWriter : ITerminalWriter, IDisposable
{
SafeHandle Handle { get; }
void Write(SafeHandle handle, ReadOnlySpan<byte> buffer);
bool GetMode([NotNullWhen(true)] out CONSOLE_MODE? mode);
bool AddMode(CONSOLE_MODE mode);
bool RemoveMode(CONSOLE_MODE mode);
}
internal sealed class WindowsTerminalWriter : WindowsTerminalHandle, IWindowsTerminalWriter
{
public Encoding Encoding { get; }

Просмотреть файл

@ -1,14 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Spectre.Terminals
{
/// <summary>
/// Contains extension methods for <see cref="ITerminal"/>.
/// </summary>
public static partial class ITerminalExtensions
{
public static void MoveCursor(this ITerminal terminal, CursorDirection direction, int count)
/// <summary>
/// Moves the cursor.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="direction">The direction to move the cursor.</param>
/// <param name="count">The number of steps to move the cursor.</param>
public static void MoveCursor(this ITerminal terminal, CursorDirection direction, int count = 1)
{
if (count <= 0)
{
@ -32,6 +37,12 @@ namespace Spectre.Terminals
}
}
/// <summary>
/// Sets the cursor position.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="row">The row.</param>
/// <param name="column">The column.</param>
public static void SetCursorProsition(this ITerminal terminal, int row, int column)
{
row = Math.Max(0, row);
@ -40,6 +51,11 @@ namespace Spectre.Terminals
terminal.Write($"\u001b[{row};{column}H");
}
/// <summary>
/// Moves the cursor down and resets the column position.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="count">The number of lines to move down.</param>
public static void MoveCursorToNextLine(this ITerminal terminal, int count)
{
if (count <= 0)
@ -50,6 +66,11 @@ namespace Spectre.Terminals
terminal.Write($"\u001b[{count}E");
}
/// <summary>
/// Moves the cursor up and resets the column position.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="count">The number of lines to move up.</param>
public static void MoveCursorToPreviousLine(this ITerminal terminal, int count)
{
if (count <= 0)
@ -60,6 +81,11 @@ namespace Spectre.Terminals
terminal.Write($"\u001b[{count}F");
}
/// <summary>
/// Moves the cursor to the specified column.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="column">The column to move to.</param>
public static void MoveCursorToColumn(this ITerminal terminal, int column)
{
if (column <= 0)
@ -70,49 +96,67 @@ namespace Spectre.Terminals
terminal.Write($"\u001b[{column}G");
}
public static void Clear(this ITerminal terminal, ClearDisplay option)
/// <summary>
/// Clears the display.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="option">The clear options.</param>
public static void Clear(this ITerminal terminal, ClearDisplay option = ClearDisplay.Everything)
{
switch (option)
{
case ClearDisplay.AfterCursor:
terminal.Write($"\u001b[0J");
terminal.Write("\u001b[0J");
break;
case ClearDisplay.BeforeCursor:
terminal.Write($"\u001b[1J");
terminal.Write("\u001b[1J");
break;
case ClearDisplay.Everything:
terminal.Write($"\u001b[2J");
terminal.Write("\u001b[2J");
break;
case ClearDisplay.EverythingAndScrollbackBuffer:
terminal.Write($"\u001b[3J");
terminal.Write("\u001b[3J");
break;
}
}
/// <summary>
/// Clears the current line.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="option">The clear options.</param>
public static void Clear(this ITerminal terminal, ClearLine option)
{
switch (option)
{
case ClearLine.AfterCursor:
terminal.Write($"\u001b[0K");
terminal.Write("\u001b[0K");
break;
case ClearLine.BeforeCursor:
terminal.Write($"\u001b[1K");
terminal.Write("\u001b[1K");
break;
case ClearLine.WholeLine:
terminal.Write($"\u001b[2K");
terminal.Write("\u001b[2K");
break;
}
}
/// <summary>
/// Saves the cursor position.
/// </summary>
/// <param name="terminal">The terminal.</param>
public static void SaveCursorPosition(this ITerminal terminal)
{
terminal.Write($"\u001b[s");
terminal.Write("\u001b[s");
}
/// <summary>
/// Restores the cursor position.
/// </summary>
/// <param name="terminal">The terminal.</param>
public static void RestoreCursorPosition(this ITerminal terminal)
{
terminal.Write($"\u001b[u");
terminal.Write("\u001b[u");
}
}
}

Просмотреть файл

@ -2,8 +2,17 @@ using System;
namespace Spectre.Terminals
{
/// <summary>
/// Contains extension methods for <see cref="ITerminal"/>.
/// </summary>
public static partial class ITerminalExtensions
{
/// <summary>
/// Reads a single <see cref="byte"/> from the terminal's input handle.
/// </summary>
/// <remarks>Puts the terminal temporary in raw mode while reading occurs.</remarks>
/// <param name="terminal">The terminal.</param>
/// <returns>The read <see cref="byte"/>, or <c>null</c> if there was nothing to read.</returns>
public static byte? ReadRaw(this ITerminal terminal)
{
try
@ -18,26 +27,43 @@ namespace Spectre.Terminals
}
}
/// <summary>
/// Writes the specified buffer to the terminal's output handle.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="value">The value to write.</param>
public static void Write(this ITerminal terminal, ReadOnlySpan<char> value)
{
terminal.Output.Write(value);
}
/// <summary>
/// Writes the specified text to the terminal's output handle.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="value">The value to write.</param>
public static void Write(this ITerminal terminal, string? value)
{
terminal.Output.Write(value);
}
/// <summary>
/// Writes an empty line to the terminal's output handle.
/// </summary>
/// <param name="terminal">The terminal.</param>
public static void WriteLine(this ITerminal terminal)
{
terminal.Output.WriteLine();
}
/// <summary>
/// Writes the specified text followed by a line break to the terminal's output handle.
/// </summary>
/// <param name="terminal">The terminal.</param>
/// <param name="value">The value to write.</param>
public static void WriteLine(this ITerminal terminal, string? value)
{
terminal.Output.WriteLine(value);
}
}
}

Просмотреть файл

@ -3,8 +3,16 @@ using System.Buffers;
namespace Spectre.Terminals
{
/// <summary>
/// Contains extension methods for <see cref="ITerminalWriter"/>.
/// </summary>
public static class ITerminalWriterExtensions
{
/// <summary>
/// Writes the specified buffer.
/// </summary>
/// <param name="writer">The writer.</param>
/// <param name="value">The value to write.</param>
public static void Write(this ITerminalWriter writer, ReadOnlySpan<char> value)
{
_ = writer ?? throw new ArgumentNullException(nameof(writer));
@ -24,16 +32,30 @@ namespace Spectre.Terminals
}
}
/// <summary>
/// Writes the specified text.
/// </summary>
/// <param name="writer">The writer.</param>
/// <param name="value">The value to write.</param>
public static void Write(this ITerminalWriter writer, string? value)
{
Write(writer, value.AsSpan());
}
/// <summary>
/// Writes an empty line.
/// </summary>
/// <param name="writer">The writer.</param>
public static void WriteLine(this ITerminalWriter writer)
{
Write(writer, Environment.NewLine);
}
/// <summary>
/// Writes the specified text followed by a line break.
/// </summary>
/// <param name="writer">The writer.</param>
/// <param name="value">The value to write.</param>
public static void WriteLine(this ITerminalWriter writer, string? value)
{
Write(writer, value.AsSpan());

Просмотреть файл

@ -2,16 +2,46 @@ using System;
namespace Spectre.Terminals
{
/// <summary>
/// Represents a terminal.
/// </summary>
public interface ITerminal : IDisposable
{
/// <summary>
/// Gets the name of the terminal driver.
/// </summary>
string Name { get; }
/// <summary>
/// Gets a value indicating whether or not the terminal is in raw mode.
/// </summary>
bool IsRawMode { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDIN</c>.
/// </summary>
ITerminalReader Input { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDOUT</c>.
/// </summary>
ITerminalWriter Output { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDERR</c>.
/// </summary>
ITerminalWriter Error { get; }
/// <summary>
/// Enables raw mode.
/// </summary>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool EnableRawMode();
/// <summary>
/// Disables raw mode.
/// </summary>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool DisableRawMode();
}
}

Просмотреть файл

@ -2,16 +2,46 @@ using System;
namespace Spectre.Terminals
{
/// <summary>
/// Represent a terminal driver.
/// </summary>
public interface ITerminalDriver : IDisposable
{
/// <summary>
/// Gets the name of the terminal driver.
/// </summary>
string Name { get; }
/// <summary>
/// Gets a value indicating whether or not the terminal is in raw mode.
/// </summary>
bool IsRawMode { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDIN</c>.
/// </summary>
ITerminalReader Input { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDOUT</c>.
/// </summary>
ITerminalWriter Output { get; }
/// <summary>
/// Gets a <see cref="ITerminalWriter"/> for <c>STDERR</c>.
/// </summary>
ITerminalWriter Error { get; }
/// <summary>
/// Enables raw mode.
/// </summary>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool EnableRawMode();
/// <summary>
/// Disables raw mode.
/// </summary>
/// <returns><c>true</c> if the operation succeeded, otherwise <c>false</c>.</returns>
bool DisableRawMode();
}
}

Просмотреть файл

@ -3,10 +3,34 @@ using System.Text;
namespace Spectre.Terminals
{
/// <summary>
/// Represents a reader.
/// </summary>
public interface ITerminalReader
{
/// <summary>
/// Gets the encoding.
/// </summary>
Encoding Encoding { get; }
/// <summary>
/// Gets a value indicating whether or not the reader has been redirected.
/// </summary>
bool IsRedirected { get; }
/// <summary>
/// Reads a sequence of bytes from the current reader.
/// </summary>
/// <param name="buffer">
/// A region of memory. When this method returns, the contents of this region are
/// replaced by the bytes read from the current source.
/// </param>
/// <returns>
/// The total number of bytes read into the buffer.
/// This can be less than the number of bytes allocated in the buffer if
/// that many bytes are not currently available, or zero (0) if the end
/// of the stream has been reached.
/// </returns>
int Read(Span<byte> buffer);
}
}

Просмотреть файл

@ -3,10 +3,25 @@ using System.Text;
namespace Spectre.Terminals
{
/// <summary>
/// Represents a writer.
/// </summary>
public interface ITerminalWriter
{
/// <summary>
/// Gets the encoding.
/// </summary>
Encoding Encoding { get; }
/// <summary>
/// Gets a value indicating whether or not the writer has been redirected.
/// </summary>
bool IsRedirected { get; }
/// <summary>
/// Writes a sequence of bytes to the current writer.
/// </summary>
/// <param name="buffer">A region of memory. This method copies the contents of this region to the writer.</param>
void Write(ReadOnlySpan<byte> buffer);
}
}

Просмотреть файл

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -7,6 +7,10 @@
<NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0-preview.1.21102.12" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.422-beta">

Просмотреть файл

@ -2,19 +2,34 @@ using System;
namespace Spectre.Terminals
{
/// <summary>
/// Represents a terminal.
/// </summary>
public sealed class Terminal : ITerminal
{
private static readonly Lazy<ITerminal> _instance;
/// <summary>
/// Gets a lazily constructed, shared <see cref="ITerminal"/> instance.
/// </summary>
public static ITerminal Shared => _instance.Value;
private readonly ITerminalDriver _driver;
private readonly object _lock;
/// <inheritdoc/>
public string Name => _driver.Name;
/// <inheritdoc/>
public bool IsRawMode { get; private set; }
/// <inheritdoc/>
public ITerminalReader Input { get; }
/// <inheritdoc/>
public ITerminalWriter Output { get; }
/// <inheritdoc/>
public ITerminalWriter Error { get; }
static Terminal()
@ -22,6 +37,10 @@ namespace Spectre.Terminals
_instance = new Lazy<ITerminal>(() => TerminalFactory.Create());
}
/// <summary>
/// Initializes a new instance of the <see cref="Terminal"/> class.
/// </summary>
/// <param name="driver">The terminal driver.</param>
public Terminal(ITerminalDriver driver)
{
_driver = driver ?? throw new ArgumentNullException(nameof(driver));
@ -32,11 +51,15 @@ namespace Spectre.Terminals
Error = new TerminalOutput(_driver.Error);
}
/// <summary>
/// Finalizes an instance of the <see cref="Terminal"/> class.
/// </summary>
~Terminal()
{
Dispose();
}
/// <inheritdoc/>
public void Dispose()
{
GC.SuppressFinalize(this);
@ -45,6 +68,7 @@ namespace Spectre.Terminals
_driver.Dispose();
}
/// <inheritdoc/>
public bool EnableRawMode()
{
lock (_lock)
@ -59,6 +83,7 @@ namespace Spectre.Terminals
}
}
/// <inheritdoc/>
public bool DisableRawMode()
{
lock (_lock)

26
src/stylecop.json Normal file
Просмотреть файл

@ -0,0 +1,26 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"documentExposedElements": true,
"documentInternalElements": false,
"documentPrivateElements": false,
"documentPrivateFields": false
},
"layoutRules": {
"newlineAtEndOfFile": "allow",
"allowConsecutiveUsings": true
},
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace",
"systemUsingDirectivesFirst": true,
"elementOrder": [
"kind",
"accessibility",
"constant",
"static",
"readonly"
]
}
}
}