mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Use file scoped namespace declarations
This commit is contained in:

committed by
Phil Scott

parent
1dbaf50935
commit
ec1188b837
@ -1,30 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Writes an exception to the console.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="exception">The exception to write to the console.</param>
|
||||
/// <param name="format">The exception format options.</param>
|
||||
public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default)
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an exception to the console.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to write to the console.</param>
|
||||
/// <param name="format">The exception format options.</param>
|
||||
public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default)
|
||||
{
|
||||
Console.WriteException(exception, format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an exception to the console.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to write to the console.</param>
|
||||
/// <param name="settings">The exception settings.</param>
|
||||
public static void WriteException(Exception exception, ExceptionSettings settings)
|
||||
{
|
||||
Console.WriteException(exception, settings);
|
||||
}
|
||||
Console.WriteException(exception, format);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an exception to the console.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to write to the console.</param>
|
||||
/// <param name="settings">The exception settings.</param>
|
||||
public static void WriteException(Exception exception, ExceptionSettings settings)
|
||||
{
|
||||
Console.WriteException(exception, settings);
|
||||
}
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Creates a new <see cref="LiveDisplay"/> instance.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="target">The target renderable to update.</param>
|
||||
/// <returns>A <see cref="LiveDisplay"/> instance.</returns>
|
||||
public static LiveDisplay Live(IRenderable target)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="LiveDisplay"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="target">The target renderable to update.</param>
|
||||
/// <returns>A <see cref="LiveDisplay"/> instance.</returns>
|
||||
public static LiveDisplay Live(IRenderable target)
|
||||
{
|
||||
return Console.Live(target);
|
||||
}
|
||||
return Console.Live(target);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +1,69 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Markup(string value)
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Markup(string value)
|
||||
{
|
||||
Console.Markup(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(string format, params object[] args)
|
||||
{
|
||||
Console.Markup(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Markup(provider, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void MarkupLine(string value)
|
||||
{
|
||||
Console.MarkupLine(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(provider, format, args);
|
||||
}
|
||||
Console.Markup(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(string format, params object[] args)
|
||||
{
|
||||
Console.Markup(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Markup(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Markup(provider, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void MarkupLine(string value)
|
||||
{
|
||||
Console.MarkupLine(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void MarkupLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.MarkupLine(provider, format, args);
|
||||
}
|
||||
}
|
@ -1,26 +1,25 @@
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Creates a new <see cref="Progress"/> instance.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <returns>A <see cref="Progress"/> instance.</returns>
|
||||
public static Progress Progress()
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Progress"/> instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Progress"/> instance.</returns>
|
||||
public static Progress Progress()
|
||||
{
|
||||
return Console.Progress();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Status"/> instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Status"/> instance.</returns>
|
||||
public static Status Status()
|
||||
{
|
||||
return Console.Status();
|
||||
}
|
||||
return Console.Progress();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Status"/> instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Status"/> instance.</returns>
|
||||
public static Status Status()
|
||||
{
|
||||
return Console.Status();
|
||||
}
|
||||
}
|
@ -1,66 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Displays a prompt to the user.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt to display.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Prompt<T>(IPrompt<T> prompt)
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays a prompt to the user.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt to display.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Prompt<T>(IPrompt<T> prompt)
|
||||
if (prompt is null)
|
||||
{
|
||||
if (prompt is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(prompt));
|
||||
}
|
||||
|
||||
return prompt.Show(Console);
|
||||
throw new ArgumentNullException(nameof(prompt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt to the user.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Ask<T>(string prompt)
|
||||
{
|
||||
return new TextPrompt<T>(prompt).Show(Console);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt to the user with a given default.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <param name="defaultValue">The default value.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Ask<T>(string prompt, T defaultValue)
|
||||
{
|
||||
return new TextPrompt<T>(prompt)
|
||||
.DefaultValue(defaultValue)
|
||||
.Show(Console);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt with two choices, yes or no.
|
||||
/// </summary>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <param name="defaultValue">Specifies the default answer.</param>
|
||||
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
|
||||
public static bool Confirm(string prompt, bool defaultValue = true)
|
||||
{
|
||||
return new ConfirmationPrompt(prompt)
|
||||
{
|
||||
DefaultValue = defaultValue,
|
||||
}
|
||||
.Show(Console);
|
||||
}
|
||||
return prompt.Show(Console);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt to the user.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Ask<T>(string prompt)
|
||||
{
|
||||
return new TextPrompt<T>(prompt).Show(Console);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt to the user with a given default.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <param name="defaultValue">The default value.</param>
|
||||
/// <returns>The prompt input result.</returns>
|
||||
public static T Ask<T>(string prompt, T defaultValue)
|
||||
{
|
||||
return new TextPrompt<T>(prompt)
|
||||
.DefaultValue(defaultValue)
|
||||
.Show(Console);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a prompt with two choices, yes or no.
|
||||
/// </summary>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
/// <param name="defaultValue">Specifies the default answer.</param>
|
||||
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
|
||||
public static bool Confirm(string prompt, bool defaultValue = true)
|
||||
{
|
||||
return new ConfirmationPrompt(prompt)
|
||||
{
|
||||
DefaultValue = defaultValue,
|
||||
}
|
||||
.Show(Console);
|
||||
}
|
||||
}
|
@ -1,70 +1,69 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Starts recording the console output.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
public static void Record()
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts recording the console output.
|
||||
/// </summary>
|
||||
public static void Record()
|
||||
if (_recorder == null)
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
_recorder = new Recorder(Console);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output as text.
|
||||
/// </summary>
|
||||
/// <returns>The recorded output as text.</returns>
|
||||
public static string ExportText()
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export text since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
return _recorder.ExportText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output as HTML text.
|
||||
/// </summary>
|
||||
/// <returns>The recorded output as HTML text.</returns>
|
||||
public static string ExportHtml()
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
return _recorder.ExportHtml();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output using a custom encoder.
|
||||
/// </summary>
|
||||
/// <param name="encoder">The encoder to use.</param>
|
||||
/// <returns>The recorded output.</returns>
|
||||
public static string ExportCustom(IAnsiConsoleEncoder encoder)
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
if (encoder is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoder));
|
||||
}
|
||||
|
||||
return _recorder.Export(encoder);
|
||||
_recorder = new Recorder(Console);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output as text.
|
||||
/// </summary>
|
||||
/// <returns>The recorded output as text.</returns>
|
||||
public static string ExportText()
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export text since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
return _recorder.ExportText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output as HTML text.
|
||||
/// </summary>
|
||||
/// <returns>The recorded output as HTML text.</returns>
|
||||
public static string ExportHtml()
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
return _recorder.ExportHtml();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports all recorded console output using a custom encoder.
|
||||
/// </summary>
|
||||
/// <param name="encoder">The encoder to use.</param>
|
||||
/// <returns>The recorded output.</returns>
|
||||
public static string ExportCustom(IAnsiConsoleEncoder encoder)
|
||||
{
|
||||
if (_recorder == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started.");
|
||||
}
|
||||
|
||||
if (encoder is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoder));
|
||||
}
|
||||
|
||||
return _recorder.Export(encoder);
|
||||
}
|
||||
}
|
@ -1,35 +1,34 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Renders the specified object to the console.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
[Obsolete("Consider using AnsiConsole.Write instead.")]
|
||||
public static void Render(IRenderable renderable)
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the specified object to the console.
|
||||
/// </summary>
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
[Obsolete("Consider using AnsiConsole.Write instead.")]
|
||||
public static void Render(IRenderable renderable)
|
||||
{
|
||||
Write(renderable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the specified <see cref="IRenderable"/> to the console.
|
||||
/// </summary>
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
public static void Write(IRenderable renderable)
|
||||
{
|
||||
if (renderable is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderable));
|
||||
}
|
||||
|
||||
Console.Write(renderable);
|
||||
}
|
||||
Write(renderable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the specified <see cref="IRenderable"/> to the console.
|
||||
/// </summary>
|
||||
/// <param name="renderable">The object to render.</param>
|
||||
public static void Write(IRenderable renderable)
|
||||
{
|
||||
if (renderable is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(renderable));
|
||||
}
|
||||
|
||||
Console.Write(renderable);
|
||||
}
|
||||
}
|
@ -1,19 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Switches to an alternate screen buffer if the terminal supports it.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="action">The action to execute within the alternate screen buffer.</param>
|
||||
public static void AlternateScreen(Action action)
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to an alternate screen buffer if the terminal supports it.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to execute within the alternate screen buffer.</param>
|
||||
public static void AlternateScreen(Action action)
|
||||
{
|
||||
Console.AlternateScreen(action);
|
||||
}
|
||||
Console.AlternateScreen(action);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +1,62 @@
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
internal static Style CurrentStyle { get; private set; } = Style.Plain;
|
||||
internal static bool Created { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Gets or sets the foreground color.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
public static Color Foreground
|
||||
{
|
||||
internal static Style CurrentStyle { get; private set; } = Style.Plain;
|
||||
internal static bool Created { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground color.
|
||||
/// </summary>
|
||||
public static Color Foreground
|
||||
{
|
||||
get => CurrentStyle.Foreground;
|
||||
set => CurrentStyle = CurrentStyle.Foreground(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public static Color Background
|
||||
{
|
||||
get => CurrentStyle.Background;
|
||||
set => CurrentStyle = CurrentStyle.Background(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text decoration.
|
||||
/// </summary>
|
||||
public static Decoration Decoration
|
||||
{
|
||||
get => CurrentStyle.Decoration;
|
||||
set => CurrentStyle = CurrentStyle.Decoration(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets colors and text decorations.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
ResetColors();
|
||||
ResetDecoration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current applied text decorations.
|
||||
/// </summary>
|
||||
public static void ResetDecoration()
|
||||
{
|
||||
Decoration = Decoration.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current applied foreground and background colors.
|
||||
/// </summary>
|
||||
public static void ResetColors()
|
||||
{
|
||||
CurrentStyle = Style.Plain;
|
||||
}
|
||||
get => CurrentStyle.Foreground;
|
||||
set => CurrentStyle = CurrentStyle.Foreground(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public static Color Background
|
||||
{
|
||||
get => CurrentStyle.Background;
|
||||
set => CurrentStyle = CurrentStyle.Background(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text decoration.
|
||||
/// </summary>
|
||||
public static Decoration Decoration
|
||||
{
|
||||
get => CurrentStyle.Decoration;
|
||||
set => CurrentStyle = CurrentStyle.Decoration(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets colors and text decorations.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
ResetColors();
|
||||
ResetDecoration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current applied text decorations.
|
||||
/// </summary>
|
||||
public static void ResetDecoration()
|
||||
{
|
||||
Decoration = Decoration.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current applied foreground and background colors.
|
||||
/// </summary>
|
||||
public static void ResetColors()
|
||||
{
|
||||
CurrentStyle = Style.Plain;
|
||||
}
|
||||
}
|
@ -1,253 +1,252 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Writes the specified string value to the console.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(string value)
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the specified string value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(string value)
|
||||
Write(value, CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(int value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(uint value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(long value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(ulong value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(float value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(double value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(decimal value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(bool value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char[] value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
Write(value, CurrentStyle);
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(int value)
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(uint value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(long value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// signed integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(ulong value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit
|
||||
/// unsigned integer value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(float value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(double value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision
|
||||
/// floating-point value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(decimal value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(bool value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.Write(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(char[] value)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void Write(IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
Console.Write(value[index].ToString(provider), CurrentStyle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(string format, params object[] args)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Write(string.Format(provider, format, args), CurrentStyle);
|
||||
Console.Write(value[index].ToString(provider), CurrentStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(string format, params object[] args)
|
||||
{
|
||||
Write(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// to the console using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void Write(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.Write(string.Format(provider, format, args), CurrentStyle);
|
||||
}
|
||||
}
|
@ -1,273 +1,272 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
public static void WriteLine()
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an empty line to the console.
|
||||
/// </summary>
|
||||
public static void WriteLine()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified string value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(string value)
|
||||
{
|
||||
Console.WriteLine(value, CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(int value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(uint value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(long value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(ulong value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(float value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(double value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(decimal value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(bool value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char[] value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
Console.Write(value[index].ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(string format, params object[] args)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine(string.Format(provider, format, args), CurrentStyle);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified string value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(string value)
|
||||
{
|
||||
Console.WriteLine(value, CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(int value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, int value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(uint value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 32-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, uint value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(long value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit signed integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, long value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(ulong value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified 64-bit unsigned integer value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, ulong value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(float value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified single-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, float value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(double value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified double-precision floating-point
|
||||
/// value, followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, double value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(decimal value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified decimal value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, decimal value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(bool value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified boolean value,
|
||||
/// followed by the current line terminator, to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, bool value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified Unicode character, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char value)
|
||||
{
|
||||
Console.WriteLine(value.ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(char[] value)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified array of Unicode characters, followed by the current
|
||||
/// line terminator, value to the console.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, char[] value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
for (var index = 0; index < value.Length; index++)
|
||||
{
|
||||
Console.Write(value[index].ToString(provider), CurrentStyle);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(string format, params object[] args)
|
||||
{
|
||||
WriteLine(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the text representation of the specified array of objects,
|
||||
/// followed by the current line terminator, to the console
|
||||
/// using the specified format information.
|
||||
/// </summary>
|
||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||
/// <param name="format">A composite format string.</param>
|
||||
/// <param name="args">An array of objects to write.</param>
|
||||
public static void WriteLine(IFormatProvider provider, string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine(string.Format(provider, format, args), CurrentStyle);
|
||||
}
|
||||
}
|
@ -1,78 +1,77 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
private static Recorder? _recorder;
|
||||
private static Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>(
|
||||
() =>
|
||||
{
|
||||
var console = Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = AnsiSupport.Detect,
|
||||
ColorSystem = ColorSystemSupport.Detect,
|
||||
Out = new AnsiConsoleOutput(System.Console.Out),
|
||||
});
|
||||
namespace Spectre.Console;
|
||||
|
||||
Created = true;
|
||||
return console;
|
||||
/// <summary>
|
||||
/// A console capable of writing ANSI escape sequences.
|
||||
/// </summary>
|
||||
public static partial class AnsiConsole
|
||||
{
|
||||
private static Recorder? _recorder;
|
||||
private static Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>(
|
||||
() =>
|
||||
{
|
||||
var console = Create(new AnsiConsoleSettings
|
||||
{
|
||||
Ansi = AnsiSupport.Detect,
|
||||
ColorSystem = ColorSystemSupport.Detect,
|
||||
Out = new AnsiConsoleOutput(System.Console.Out),
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the underlying <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static IAnsiConsole Console
|
||||
Created = true;
|
||||
return console;
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the underlying <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public static IAnsiConsole Console
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return _recorder ?? _console.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_console = new Lazy<IAnsiConsole>(() => value);
|
||||
|
||||
if (_recorder != null)
|
||||
{
|
||||
// Recreate the recorder
|
||||
_recorder = _recorder.Clone(value);
|
||||
}
|
||||
|
||||
Created = true;
|
||||
}
|
||||
return _recorder ?? _console.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IAnsiConsoleCursor"/>.
|
||||
/// </summary>
|
||||
public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console profile.
|
||||
/// </summary>
|
||||
public static Profile Profile => Console.Profile;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="IAnsiConsole"/> instance
|
||||
/// from the provided settings.
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use.</param>
|
||||
/// <returns>An <see cref="IAnsiConsole"/> instance.</returns>
|
||||
public static IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
set
|
||||
{
|
||||
var factory = new AnsiConsoleFactory();
|
||||
return factory.Create(settings);
|
||||
}
|
||||
_console = new Lazy<IAnsiConsole>(() => value);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the console.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
Console.Clear();
|
||||
if (_recorder != null)
|
||||
{
|
||||
// Recreate the recorder
|
||||
_recorder = _recorder.Clone(value);
|
||||
}
|
||||
|
||||
Created = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IAnsiConsoleCursor"/>.
|
||||
/// </summary>
|
||||
public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the console profile.
|
||||
/// </summary>
|
||||
public static Profile Profile => Console.Profile;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="IAnsiConsole"/> instance
|
||||
/// from the provided settings.
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use.</param>
|
||||
/// <returns>An <see cref="IAnsiConsole"/> instance.</returns>
|
||||
public static IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
{
|
||||
var factory = new AnsiConsoleFactory();
|
||||
return factory.Create(settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the console.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
Console.Clear();
|
||||
}
|
||||
}
|
@ -3,110 +3,109 @@ using System.Runtime.InteropServices;
|
||||
using Spectre.Console.Enrichment;
|
||||
using Spectre.Console.Internal;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating an ANSI console.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory for creating an ANSI console.
|
||||
/// Creates an ANSI console.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleFactory
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An implementation of <see cref="IAnsiConsole"/>.</returns>
|
||||
public IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an ANSI console.
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An implementation of <see cref="IAnsiConsole"/>.</returns>
|
||||
public IAnsiConsole Create(AnsiConsoleSettings settings)
|
||||
if (settings is null)
|
||||
{
|
||||
if (settings is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out);
|
||||
if (output.Writer == null)
|
||||
{
|
||||
throw new InvalidOperationException("Output writer was null");
|
||||
}
|
||||
|
||||
// Detect if the terminal support ANSI or not
|
||||
var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer);
|
||||
|
||||
// Use console encoding or fall back to provided encoding
|
||||
var encoding = output.Writer.IsStandardOut() || output.Writer.IsStandardError()
|
||||
? System.Console.OutputEncoding : output.Writer.Encoding;
|
||||
|
||||
// Get the color system
|
||||
var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect
|
||||
? ColorSystemDetector.Detect(supportsAnsi)
|
||||
: (ColorSystem)settings.ColorSystem;
|
||||
|
||||
// Get whether or not we consider the terminal interactive
|
||||
var interactive = settings.Interactive == InteractionSupport.Yes;
|
||||
if (settings.Interactive == InteractionSupport.Detect)
|
||||
{
|
||||
interactive = Environment.UserInteractive;
|
||||
}
|
||||
|
||||
var profile = new Profile(output, encoding);
|
||||
|
||||
profile.Capabilities.ColorSystem = colorSystem;
|
||||
profile.Capabilities.Ansi = supportsAnsi;
|
||||
profile.Capabilities.Links = supportsAnsi && !legacyConsole;
|
||||
profile.Capabilities.Legacy = legacyConsole;
|
||||
profile.Capabilities.Interactive = interactive;
|
||||
profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode");
|
||||
profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole;
|
||||
|
||||
// Enrich the profile
|
||||
ProfileEnricher.Enrich(
|
||||
profile,
|
||||
settings.Enrichment,
|
||||
settings.EnvironmentVariables);
|
||||
|
||||
return new AnsiConsoleFacade(
|
||||
profile,
|
||||
settings.ExclusivityMode ?? new DefaultExclusivityMode());
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer)
|
||||
var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out);
|
||||
if (output.Writer == null)
|
||||
{
|
||||
var supportsAnsi = settings.Ansi == AnsiSupport.Yes;
|
||||
var legacyConsole = false;
|
||||
throw new InvalidOperationException("Output writer was null");
|
||||
}
|
||||
|
||||
if (settings.Ansi == AnsiSupport.Detect)
|
||||
// Detect if the terminal support ANSI or not
|
||||
var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer);
|
||||
|
||||
// Use console encoding or fall back to provided encoding
|
||||
var encoding = output.Writer.IsStandardOut() || output.Writer.IsStandardError()
|
||||
? System.Console.OutputEncoding : output.Writer.Encoding;
|
||||
|
||||
// Get the color system
|
||||
var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect
|
||||
? ColorSystemDetector.Detect(supportsAnsi)
|
||||
: (ColorSystem)settings.ColorSystem;
|
||||
|
||||
// Get whether or not we consider the terminal interactive
|
||||
var interactive = settings.Interactive == InteractionSupport.Yes;
|
||||
if (settings.Interactive == InteractionSupport.Detect)
|
||||
{
|
||||
interactive = Environment.UserInteractive;
|
||||
}
|
||||
|
||||
var profile = new Profile(output, encoding);
|
||||
|
||||
profile.Capabilities.ColorSystem = colorSystem;
|
||||
profile.Capabilities.Ansi = supportsAnsi;
|
||||
profile.Capabilities.Links = supportsAnsi && !legacyConsole;
|
||||
profile.Capabilities.Legacy = legacyConsole;
|
||||
profile.Capabilities.Interactive = interactive;
|
||||
profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode");
|
||||
profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole;
|
||||
|
||||
// Enrich the profile
|
||||
ProfileEnricher.Enrich(
|
||||
profile,
|
||||
settings.Enrichment,
|
||||
settings.EnvironmentVariables);
|
||||
|
||||
return new AnsiConsoleFacade(
|
||||
profile,
|
||||
settings.ExclusivityMode ?? new DefaultExclusivityMode());
|
||||
}
|
||||
|
||||
private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer)
|
||||
{
|
||||
var supportsAnsi = settings.Ansi == AnsiSupport.Yes;
|
||||
var legacyConsole = false;
|
||||
|
||||
if (settings.Ansi == AnsiSupport.Detect)
|
||||
{
|
||||
(supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true);
|
||||
|
||||
// Check whether or not this is a legacy console from the existing instance (if any).
|
||||
// We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
// on Windows, there is no way of detecting whether or not we're running on a legacy console or not.
|
||||
if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy)
|
||||
{
|
||||
(supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true);
|
||||
|
||||
// Check whether or not this is a legacy console from the existing instance (if any).
|
||||
// We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
// on Windows, there is no way of detecting whether or not we're running on a legacy console or not.
|
||||
if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy)
|
||||
{
|
||||
legacyConsole = AnsiConsole.Profile.Capabilities.Legacy;
|
||||
}
|
||||
legacyConsole = AnsiConsole.Profile.Capabilities.Legacy;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer.IsStandardOut() || buffer.IsStandardError())
|
||||
{
|
||||
if (buffer.IsStandardOut() || buffer.IsStandardError())
|
||||
// Are we running on Windows?
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
// Are we running on Windows?
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
// Not the first console we're creating?
|
||||
if (AnsiConsole.Created)
|
||||
{
|
||||
// Not the first console we're creating?
|
||||
if (AnsiConsole.Created)
|
||||
{
|
||||
legacyConsole = AnsiConsole.Profile.Capabilities.Legacy;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try detecting whether or not this is a legacy console
|
||||
(_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false);
|
||||
}
|
||||
legacyConsole = AnsiConsole.Profile.Capabilities.Legacy;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try detecting whether or not this is a legacy console
|
||||
(_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (supportsAnsi, legacyConsole);
|
||||
}
|
||||
|
||||
return (supportsAnsi, legacyConsole);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,57 +2,56 @@ using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Represents console output.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleOutput : IAnsiConsoleOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents console output.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleOutput : IAnsiConsoleOutput
|
||||
/// <inheritdoc/>
|
||||
public TextWriter Writer { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsTerminal
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public TextWriter Writer { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsTerminal
|
||||
get
|
||||
{
|
||||
get
|
||||
if (Writer.IsStandardOut())
|
||||
{
|
||||
if (Writer.IsStandardOut())
|
||||
{
|
||||
return !System.Console.IsOutputRedirected;
|
||||
}
|
||||
|
||||
if (Writer.IsStandardError())
|
||||
{
|
||||
return !System.Console.IsErrorRedirected;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !System.Console.IsOutputRedirected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnsiConsoleOutput"/> class.
|
||||
/// </summary>
|
||||
/// <param name="writer">The output writer.</param>
|
||||
public AnsiConsoleOutput(TextWriter writer)
|
||||
{
|
||||
Writer = writer ?? throw new ArgumentNullException(nameof(writer));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetEncoding(Encoding encoding)
|
||||
{
|
||||
if (Writer.IsStandardOut() || Writer.IsStandardError())
|
||||
if (Writer.IsStandardError())
|
||||
{
|
||||
System.Console.OutputEncoding = encoding;
|
||||
return !System.Console.IsErrorRedirected;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnsiConsoleOutput"/> class.
|
||||
/// </summary>
|
||||
/// <param name="writer">The output writer.</param>
|
||||
public AnsiConsoleOutput(TextWriter writer)
|
||||
{
|
||||
Writer = writer ?? throw new ArgumentNullException(nameof(writer));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetEncoding(Encoding encoding)
|
||||
{
|
||||
if (Writer.IsStandardOut() || Writer.IsStandardError())
|
||||
{
|
||||
System.Console.OutputEncoding = encoding;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Settings used when building a <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings used when building a <see cref="IAnsiConsole"/>.
|
||||
/// Gets or sets a value indicating whether or
|
||||
/// not ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
public sealed class AnsiConsoleSettings
|
||||
public AnsiSupport Ansi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color system to use.
|
||||
/// </summary>
|
||||
public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the out buffer.
|
||||
/// </summary>
|
||||
public IAnsiConsoleOutput? Out { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the
|
||||
/// terminal is interactive or not.
|
||||
/// </summary>
|
||||
public InteractionSupport Interactive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exclusivity mode.
|
||||
/// </summary>
|
||||
public IExclusivityMode? ExclusivityMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the profile enrichments settings.
|
||||
/// </summary>
|
||||
public ProfileEnrichment Enrichment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the environment variables.
|
||||
/// If not value is provided the default environment variables will be used.
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? EnvironmentVariables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnsiConsoleSettings"/> class.
|
||||
/// </summary>
|
||||
public AnsiConsoleSettings()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or
|
||||
/// not ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
public AnsiSupport Ansi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color system to use.
|
||||
/// </summary>
|
||||
public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the out buffer.
|
||||
/// </summary>
|
||||
public IAnsiConsoleOutput? Out { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the
|
||||
/// terminal is interactive or not.
|
||||
/// </summary>
|
||||
public InteractionSupport Interactive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exclusivity mode.
|
||||
/// </summary>
|
||||
public IExclusivityMode? ExclusivityMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the profile enrichments settings.
|
||||
/// </summary>
|
||||
public ProfileEnrichment Enrichment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the environment variables.
|
||||
/// If not value is provided the default environment variables will be used.
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? EnvironmentVariables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AnsiConsoleSettings"/> class.
|
||||
/// </summary>
|
||||
public AnsiConsoleSettings()
|
||||
{
|
||||
Enrichment = new ProfileEnrichment();
|
||||
}
|
||||
Enrichment = new ProfileEnrichment();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +1,23 @@
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Determines ANSI escape sequence support.
|
||||
/// </summary>
|
||||
public enum AnsiSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines ANSI escape sequence support.
|
||||
/// ANSI escape sequence support should
|
||||
/// be detected by the system.
|
||||
/// </summary>
|
||||
public enum AnsiSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// ANSI escape sequence support should
|
||||
/// be detected by the system.
|
||||
/// </summary>
|
||||
Detect = 0,
|
||||
Detect = 0,
|
||||
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
Yes = 1,
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are supported.
|
||||
/// </summary>
|
||||
Yes = 1,
|
||||
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are not supported.
|
||||
/// </summary>
|
||||
No = 2,
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// ANSI escape sequences are not supported.
|
||||
/// </summary>
|
||||
No = 2,
|
||||
}
|
@ -1,42 +1,41 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a border.
|
||||
/// </summary>
|
||||
public abstract partial class BoxBorder
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a border.
|
||||
/// Gets an invisible border.
|
||||
/// </summary>
|
||||
public abstract partial class BoxBorder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an invisible border.
|
||||
/// </summary>
|
||||
public static BoxBorder None { get; } = new NoBoxBorder();
|
||||
public static BoxBorder None { get; } = new NoBoxBorder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets an ASCII border.
|
||||
/// </summary>
|
||||
public static BoxBorder Ascii { get; } = new AsciiBoxBorder();
|
||||
/// <summary>
|
||||
/// Gets an ASCII border.
|
||||
/// </summary>
|
||||
public static BoxBorder Ascii { get; } = new AsciiBoxBorder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a double border.
|
||||
/// </summary>
|
||||
[SuppressMessage("Naming", "CA1720:Identifier contains type name")]
|
||||
public static BoxBorder Double { get; } = new DoubleBoxBorder();
|
||||
/// <summary>
|
||||
/// Gets a double border.
|
||||
/// </summary>
|
||||
[SuppressMessage("Naming", "CA1720:Identifier contains type name")]
|
||||
public static BoxBorder Double { get; } = new DoubleBoxBorder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a heavy border.
|
||||
/// </summary>
|
||||
public static BoxBorder Heavy { get; } = new HeavyBoxBorder();
|
||||
/// <summary>
|
||||
/// Gets a heavy border.
|
||||
/// </summary>
|
||||
public static BoxBorder Heavy { get; } = new HeavyBoxBorder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a rounded border.
|
||||
/// </summary>
|
||||
public static BoxBorder Rounded { get; } = new RoundedBoxBorder();
|
||||
/// <summary>
|
||||
/// Gets a rounded border.
|
||||
/// </summary>
|
||||
public static BoxBorder Rounded { get; } = new RoundedBoxBorder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a square border.
|
||||
/// </summary>
|
||||
public static BoxBorder Square { get; } = new SquareBoxBorder();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a square border.
|
||||
/// </summary>
|
||||
public static BoxBorder Square { get; } = new SquareBoxBorder();
|
||||
}
|
@ -1,22 +1,21 @@
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a border.
|
||||
/// </summary>
|
||||
public abstract partial class BoxBorder
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a border.
|
||||
/// Gets the safe border for this border or <c>null</c> if none exist.
|
||||
/// </summary>
|
||||
public abstract partial class BoxBorder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the safe border for this border or <c>null</c> if none exist.
|
||||
/// </summary>
|
||||
public virtual BoxBorder? SafeBorder { get; }
|
||||
public virtual BoxBorder? SafeBorder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation of the specified border part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get the character representation for.</param>
|
||||
/// <returns>A character representation of the specified border part.</returns>
|
||||
public abstract string GetPart(BoxBorderPart part);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the string representation of the specified border part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part to get the character representation for.</param>
|
||||
/// <returns>A character representation of the specified border part.</returns>
|
||||
public abstract string GetPart(BoxBorderPart part);
|
||||
}
|
@ -1,73 +1,72 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
/// <summary>
|
||||
/// Represents console capabilities.
|
||||
/// </summary>
|
||||
public sealed class Capabilities : IReadOnlyCapabilities
|
||||
{
|
||||
private readonly IAnsiConsoleOutput _out;
|
||||
|
||||
/// <summary>
|
||||
/// Represents console capabilities.
|
||||
/// Gets or sets the color system.
|
||||
/// </summary>
|
||||
public sealed class Capabilities : IReadOnlyCapabilities
|
||||
public ColorSystem ColorSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// the console supports VT/ANSI control codes.
|
||||
/// </summary>
|
||||
public bool Ansi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// the console support links.
|
||||
/// </summary>
|
||||
public bool Links { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// this is a legacy console (cmd.exe) on an OS
|
||||
/// prior to Windows 10.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only relevant when running on Microsoft Windows.
|
||||
/// </remarks>
|
||||
public bool Legacy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// the output is a terminal.
|
||||
/// </summary>
|
||||
[Obsolete("Use Profile.Out.IsTerminal instead")]
|
||||
public bool IsTerminal => _out.IsTerminal;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports interaction.
|
||||
/// </summary>
|
||||
public bool Interactive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports Unicode.
|
||||
/// </summary>
|
||||
public bool Unicode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports alternate buffers.
|
||||
/// </summary>
|
||||
public bool AlternateBuffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the
|
||||
/// <see cref="Capabilities"/> class.
|
||||
/// </summary>
|
||||
internal Capabilities(IAnsiConsoleOutput @out)
|
||||
{
|
||||
private readonly IAnsiConsoleOutput _out;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color system.
|
||||
/// </summary>
|
||||
public ColorSystem ColorSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// the console supports VT/ANSI control codes.
|
||||
/// </summary>
|
||||
public bool Ansi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// the console support links.
|
||||
/// </summary>
|
||||
public bool Links { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// this is a legacy console (cmd.exe) on an OS
|
||||
/// prior to Windows 10.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only relevant when running on Microsoft Windows.
|
||||
/// </remarks>
|
||||
public bool Legacy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether or not
|
||||
/// the output is a terminal.
|
||||
/// </summary>
|
||||
[Obsolete("Use Profile.Out.IsTerminal instead")]
|
||||
public bool IsTerminal => _out.IsTerminal;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports interaction.
|
||||
/// </summary>
|
||||
public bool Interactive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports Unicode.
|
||||
/// </summary>
|
||||
public bool Unicode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether
|
||||
/// or not the console supports alternate buffers.
|
||||
/// </summary>
|
||||
public bool AlternateBuffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the
|
||||
/// <see cref="Capabilities"/> class.
|
||||
/// </summary>
|
||||
internal Capabilities(IAnsiConsoleOutput @out)
|
||||
{
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
}
|
||||
_out = @out ?? throw new ArgumentNullException(nameof(@out));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +1,52 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute representing a command argument.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class CommandArgumentAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute representing a command argument.
|
||||
/// Gets the argument position.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class CommandArgumentAttribute : Attribute
|
||||
/// <value>The argument position.</value>
|
||||
public int Position { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value name of the argument.
|
||||
/// </summary>
|
||||
/// <value>The value name of the argument.</value>
|
||||
public string ValueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the argument is required.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the argument is required; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsRequired { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandArgumentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">The argument position.</param>
|
||||
/// <param name="template">The argument template.</param>
|
||||
public CommandArgumentAttribute(int position, string template)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the argument position.
|
||||
/// </summary>
|
||||
/// <value>The argument position.</value>
|
||||
public int Position { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value name of the argument.
|
||||
/// </summary>
|
||||
/// <value>The value name of the argument.</value>
|
||||
public string ValueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the argument is required.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the argument is required; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsRequired { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandArgumentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">The argument position.</param>
|
||||
/// <param name="template">The argument template.</param>
|
||||
public CommandArgumentAttribute(int position, string template)
|
||||
if (template == null)
|
||||
{
|
||||
if (template == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
// Parse the option template.
|
||||
var result = TemplateParser.ParseArgumentTemplate(template);
|
||||
|
||||
// Assign the result.
|
||||
Position = position;
|
||||
ValueName = result.Value;
|
||||
IsRequired = result.Required;
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
// Parse the option template.
|
||||
var result = TemplateParser.ParseArgumentTemplate(template);
|
||||
|
||||
// Assign the result.
|
||||
Position = position;
|
||||
ValueName = result.Value;
|
||||
IsRequired = result.Required;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,69 +2,68 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute representing a command option.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class CommandOptionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// An attribute representing a command option.
|
||||
/// Gets the long names of the option.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class CommandOptionAttribute : Attribute
|
||||
/// <value>The option's long names.</value>
|
||||
public IReadOnlyList<string> LongNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short names of the option.
|
||||
/// </summary>
|
||||
/// <value>The option's short names.</value>
|
||||
public IReadOnlyList<string> ShortNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value name of the option.
|
||||
/// </summary>
|
||||
/// <value>The option's value name.</value>
|
||||
public string? ValueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the value is optional.
|
||||
/// </summary>
|
||||
public bool ValueIsOptional { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this option is hidden from the help text.
|
||||
/// </summary>
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandOptionAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="template">The option template.</param>
|
||||
public CommandOptionAttribute(string template)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the long names of the option.
|
||||
/// </summary>
|
||||
/// <value>The option's long names.</value>
|
||||
public IReadOnlyList<string> LongNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short names of the option.
|
||||
/// </summary>
|
||||
/// <value>The option's short names.</value>
|
||||
public IReadOnlyList<string> ShortNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value name of the option.
|
||||
/// </summary>
|
||||
/// <value>The option's value name.</value>
|
||||
public string? ValueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the value is optional.
|
||||
/// </summary>
|
||||
public bool ValueIsOptional { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this option is hidden from the help text.
|
||||
/// </summary>
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandOptionAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="template">The option template.</param>
|
||||
public CommandOptionAttribute(string template)
|
||||
if (template == null)
|
||||
{
|
||||
if (template == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
// Parse the option template.
|
||||
var result = TemplateParser.ParseOptionTemplate(template);
|
||||
|
||||
// Assign the result.
|
||||
LongNames = result.LongNames;
|
||||
ShortNames = result.ShortNames;
|
||||
ValueName = result.Value;
|
||||
ValueIsOptional = result.ValueIsOptional;
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
internal bool IsMatch(string name)
|
||||
{
|
||||
return
|
||||
ShortNames.Contains(name, StringComparer.Ordinal) ||
|
||||
LongNames.Contains(name, StringComparer.Ordinal);
|
||||
}
|
||||
// Parse the option template.
|
||||
var result = TemplateParser.ParseOptionTemplate(template);
|
||||
|
||||
// Assign the result.
|
||||
LongNames = result.LongNames;
|
||||
ShortNames = result.ShortNames;
|
||||
ValueName = result.Value;
|
||||
ValueIsOptional = result.ValueIsOptional;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsMatch(string name)
|
||||
{
|
||||
return
|
||||
ShortNames.Contains(name, StringComparer.Ordinal) ||
|
||||
LongNames.Contains(name, StringComparer.Ordinal);
|
||||
}
|
||||
}
|
@ -1,31 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies what type to use as a pair deconstructor for
|
||||
/// the property this attribute is bound to.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class PairDeconstructorAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies what type to use as a pair deconstructor for
|
||||
/// the property this attribute is bound to.
|
||||
/// Gets the <see cref="string"/> that represents the type of the
|
||||
/// pair deconstructor class to use for data conversion for the
|
||||
/// object this attribute is bound to.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public sealed class PairDeconstructorAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="string"/> that represents the type of the
|
||||
/// pair deconstructor class to use for data conversion for the
|
||||
/// object this attribute is bound to.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PairDeconstructorAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A System.Type that represents the type of the pair deconstructor
|
||||
/// class to use for data conversion for the object this attribute is bound to.
|
||||
/// </param>
|
||||
public PairDeconstructorAttribute(Type type)
|
||||
{
|
||||
Type = type ?? throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PairDeconstructorAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A System.Type that represents the type of the pair deconstructor
|
||||
/// class to use for data conversion for the object this attribute is bound to.
|
||||
/// </param>
|
||||
public PairDeconstructorAttribute(Type type)
|
||||
{
|
||||
Type = type ?? throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// A base class attribute used for parameter validation.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public abstract class ParameterValidationAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class attribute used for parameter validation.
|
||||
/// Gets the validation error message.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
|
||||
public abstract class ParameterValidationAttribute : Attribute
|
||||
/// <value>The validation error message.</value>
|
||||
public string ErrorMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParameterValidationAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="errorMessage">The validation error message.</param>
|
||||
protected ParameterValidationAttribute(string errorMessage)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the validation error message.
|
||||
/// </summary>
|
||||
/// <value>The validation error message.</value>
|
||||
public string ErrorMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParameterValidationAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="errorMessage">The validation error message.</param>
|
||||
protected ParameterValidationAttribute(string errorMessage)
|
||||
{
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the parameter value.
|
||||
/// </summary>
|
||||
/// <param name="context">The parameter context.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public abstract ValidationResult Validate(CommandParameterContext context);
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the parameter value.
|
||||
/// </summary>
|
||||
/// <param name="context">The parameter context.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public abstract ValidationResult Validate(CommandParameterContext context);
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// A base class attribute used for parameter completion.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public abstract class ParameterValueProviderAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class attribute used for parameter completion.
|
||||
/// Gets a value for the parameter.
|
||||
/// </summary>
|
||||
/// <seealso cref="Attribute" />
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public abstract class ParameterValueProviderAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value for the parameter.
|
||||
/// </summary>
|
||||
/// <param name="context">The parameter context.</param>
|
||||
/// <param name="result">The resulting value.</param>
|
||||
/// <returns><c>true</c> if a value was provided; otherwise, <c>false</c>.</returns>
|
||||
public abstract bool TryGetValue(CommandParameterContext context, out object? result);
|
||||
}
|
||||
}
|
||||
/// <param name="context">The parameter context.</param>
|
||||
/// <param name="result">The resulting value.</param>
|
||||
/// <returns><c>true</c> if a value was provided; otherwise, <c>false</c>.</returns>
|
||||
public abstract bool TryGetValue(CommandParameterContext context, out object? result);
|
||||
}
|
@ -1,35 +1,34 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for an asynchronous command with no settings.
|
||||
/// </summary>
|
||||
public abstract class AsyncCommand : ICommand<EmptyCommandSettings>
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for an asynchronous command with no settings.
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
public abstract class AsyncCommand : ICommand<EmptyCommandSettings>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract Task<int> ExecuteAsync(CommandContext context);
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings)
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract Task<int> ExecuteAsync(CommandContext context);
|
||||
return ExecuteAsync(context);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings)
|
||||
{
|
||||
return ExecuteAsync(context);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ExecuteAsync(context);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ExecuteAsync(context);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
@ -1,51 +1,50 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for an asynchronous command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
public abstract class AsyncCommand<TSettings> : ICommand<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for an asynchronous command.
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
public abstract class AsyncCommand<TSettings> : ICommand<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate(CommandContext context, TSettings settings)
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate(CommandContext context, TSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract Task<int> ExecuteAsync(CommandContext context, TSettings settings);
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract Task<int> ExecuteAsync(CommandContext context, TSettings settings);
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Validate(context, (TSettings)settings);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Validate(context, (TSettings)settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
Debug.Assert(settings is TSettings, "Command settings is of unexpected type.");
|
||||
return ExecuteAsync(context, (TSettings)settings);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
Debug.Assert(settings is TSettings, "Command settings is of unexpected type.");
|
||||
return ExecuteAsync(context, (TSettings)settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings)
|
||||
{
|
||||
return ExecuteAsync(context, settings);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings)
|
||||
{
|
||||
return ExecuteAsync(context, settings);
|
||||
}
|
||||
}
|
@ -1,31 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents case sensitivity.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CaseSensitivity
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents case sensitivity.
|
||||
/// Nothing is case sensitive.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CaseSensitivity
|
||||
{
|
||||
/// <summary>
|
||||
/// Nothing is case sensitive.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Long options are case sensitive.
|
||||
/// </summary>
|
||||
LongOptions = 1,
|
||||
/// <summary>
|
||||
/// Long options are case sensitive.
|
||||
/// </summary>
|
||||
LongOptions = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Commands are case sensitive.
|
||||
/// </summary>
|
||||
Commands = 2,
|
||||
/// <summary>
|
||||
/// Commands are case sensitive.
|
||||
/// </summary>
|
||||
Commands = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Everything is case sensitive.
|
||||
/// </summary>
|
||||
All = LongOptions | Commands,
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Everything is case sensitive.
|
||||
/// </summary>
|
||||
All = LongOptions | Commands,
|
||||
}
|
@ -1,36 +1,35 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for a command without settings.
|
||||
/// </summary>
|
||||
/// <seealso cref="AsyncCommand"/>
|
||||
public abstract class Command : ICommand<EmptyCommandSettings>
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a command without settings.
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <seealso cref="AsyncCommand"/>
|
||||
public abstract class Command : ICommand<EmptyCommandSettings>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract int Execute(CommandContext context);
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings)
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract int Execute(CommandContext context);
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings)
|
||||
{
|
||||
return Task.FromResult(Execute(context));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Task.FromResult(Execute(context));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
return Task.FromResult(Execute(context));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Task.FromResult(Execute(context));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
@ -4,136 +4,136 @@ using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for a command line application.
|
||||
/// </summary>
|
||||
public sealed class CommandApp : ICommandApp
|
||||
{
|
||||
private readonly Configurator _configurator;
|
||||
private readonly CommandExecutor _executor;
|
||||
private bool _executed;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for a command line application.
|
||||
/// Initializes a new instance of the <see cref="CommandApp"/> class.
|
||||
/// </summary>
|
||||
public sealed class CommandApp : ICommandApp
|
||||
/// <param name="registrar">The registrar.</param>
|
||||
public CommandApp(ITypeRegistrar? registrar = null)
|
||||
{
|
||||
private readonly Configurator _configurator;
|
||||
private readonly CommandExecutor _executor;
|
||||
private bool _executed;
|
||||
registrar ??= new DefaultTypeRegistrar();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandApp"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrar">The registrar.</param>
|
||||
public CommandApp(ITypeRegistrar? registrar = null)
|
||||
_configurator = new Configurator(registrar);
|
||||
_executor = new CommandExecutor(registrar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public void Configure(Action<IConfigurator> configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
registrar ??= new DefaultTypeRegistrar();
|
||||
|
||||
_configurator = new Configurator(registrar);
|
||||
_executor = new CommandExecutor(registrar);
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public void Configure(Action<IConfigurator> configuration)
|
||||
configuration(_configurator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
public void SetDefaultCommand<TCommand>()
|
||||
where TCommand : class, ICommand
|
||||
{
|
||||
GetConfigurator().SetDefaultCommand<TCommand>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public int Run(IEnumerable<string> args)
|
||||
{
|
||||
return RunAsync(args).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public async Task<int> RunAsync(IEnumerable<string> args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (configuration == null)
|
||||
if (!_executed)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
// Add built-in (hidden) commands.
|
||||
_configurator.AddBranch(CliConstants.Commands.Branch, cli =>
|
||||
{
|
||||
cli.HideBranch();
|
||||
cli.AddCommand<VersionCommand>(CliConstants.Commands.Version);
|
||||
cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc);
|
||||
cli.AddCommand<ExplainCommand>(CliConstants.Commands.Explain);
|
||||
});
|
||||
|
||||
_executed = true;
|
||||
}
|
||||
|
||||
configuration(_configurator);
|
||||
return await _executor
|
||||
.Execute(_configurator, args)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
public void SetDefaultCommand<TCommand>()
|
||||
where TCommand : class, ICommand
|
||||
catch (Exception ex)
|
||||
{
|
||||
GetConfigurator().SetDefaultCommand<TCommand>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public int Run(IEnumerable<string> args)
|
||||
{
|
||||
return RunAsync(args).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public async Task<int> RunAsync(IEnumerable<string> args)
|
||||
{
|
||||
try
|
||||
// Should we always propagate when debugging?
|
||||
if (Debugger.IsAttached
|
||||
&& ex is CommandAppException appException
|
||||
&& appException.AlwaysPropagateWhenDebugging)
|
||||
{
|
||||
if (!_executed)
|
||||
{
|
||||
// Add built-in (hidden) commands.
|
||||
_configurator.AddBranch(CliConstants.Commands.Branch, cli =>
|
||||
{
|
||||
cli.HideBranch();
|
||||
cli.AddCommand<VersionCommand>(CliConstants.Commands.Version);
|
||||
cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc);
|
||||
cli.AddCommand<ExplainCommand>(CliConstants.Commands.Explain);
|
||||
});
|
||||
|
||||
_executed = true;
|
||||
}
|
||||
|
||||
return await _executor
|
||||
.Execute(_configurator, args)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Should we always propagate when debugging?
|
||||
if (Debugger.IsAttached
|
||||
&& ex is CommandAppException appException
|
||||
&& appException.AlwaysPropagateWhenDebugging)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (_configurator.Settings.PropagateExceptions)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (_configurator.Settings.ExceptionHandler != null)
|
||||
{
|
||||
return _configurator.Settings.ExceptionHandler(ex);
|
||||
}
|
||||
|
||||
// Render the exception.
|
||||
var pretty = GetRenderableErrorMessage(ex);
|
||||
if (pretty != null)
|
||||
{
|
||||
_configurator.Settings.Console.SafeRender(pretty);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal Configurator GetConfigurator()
|
||||
{
|
||||
return _configurator;
|
||||
}
|
||||
|
||||
private static List<IRenderable?>? GetRenderableErrorMessage(Exception ex, bool convert = true)
|
||||
{
|
||||
if (ex is CommandAppException renderable && renderable.Pretty != null)
|
||||
{
|
||||
return new List<IRenderable?> { renderable.Pretty };
|
||||
throw;
|
||||
}
|
||||
|
||||
if (convert)
|
||||
if (_configurator.Settings.PropagateExceptions)
|
||||
{
|
||||
var converted = new List<IRenderable?>
|
||||
throw;
|
||||
}
|
||||
|
||||
if (_configurator.Settings.ExceptionHandler != null)
|
||||
{
|
||||
return _configurator.Settings.ExceptionHandler(ex);
|
||||
}
|
||||
|
||||
// Render the exception.
|
||||
var pretty = GetRenderableErrorMessage(ex);
|
||||
if (pretty != null)
|
||||
{
|
||||
_configurator.Settings.Console.SafeRender(pretty);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal Configurator GetConfigurator()
|
||||
{
|
||||
return _configurator;
|
||||
}
|
||||
|
||||
private static List<IRenderable?>? GetRenderableErrorMessage(Exception ex, bool convert = true)
|
||||
{
|
||||
if (ex is CommandAppException renderable && renderable.Pretty != null)
|
||||
{
|
||||
return new List<IRenderable?> { renderable.Pretty };
|
||||
}
|
||||
|
||||
if (convert)
|
||||
{
|
||||
var converted = new List<IRenderable?>
|
||||
{
|
||||
new Composer()
|
||||
.Text("[red]Error:[/]")
|
||||
@ -142,20 +142,19 @@ namespace Spectre.Console.Cli
|
||||
.LineBreak(),
|
||||
};
|
||||
|
||||
// Got a renderable inner exception?
|
||||
if (ex.InnerException != null)
|
||||
// Got a renderable inner exception?
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false);
|
||||
if (innerRenderable != null)
|
||||
{
|
||||
var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false);
|
||||
if (innerRenderable != null)
|
||||
{
|
||||
converted.AddRange(innerRenderable);
|
||||
}
|
||||
converted.AddRange(innerRenderable);
|
||||
}
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
return null;
|
||||
return converted;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +1,29 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur during application execution.
|
||||
/// </summary>
|
||||
public abstract class CommandAppException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occur during application execution.
|
||||
/// Gets the pretty formatted exception message.
|
||||
/// </summary>
|
||||
public abstract class CommandAppException : Exception
|
||||
public IRenderable? Pretty { get; }
|
||||
|
||||
internal virtual bool AlwaysPropagateWhenDebugging => false;
|
||||
|
||||
internal CommandAppException(string message, IRenderable? pretty = null)
|
||||
: base(message)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the pretty formatted exception message.
|
||||
/// </summary>
|
||||
public IRenderable? Pretty { get; }
|
||||
Pretty = pretty;
|
||||
}
|
||||
|
||||
internal virtual bool AlwaysPropagateWhenDebugging => false;
|
||||
|
||||
internal CommandAppException(string message, IRenderable? pretty = null)
|
||||
: base(message)
|
||||
{
|
||||
Pretty = pretty;
|
||||
}
|
||||
|
||||
internal CommandAppException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex)
|
||||
{
|
||||
Pretty = pretty;
|
||||
}
|
||||
internal CommandAppException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex)
|
||||
{
|
||||
Pretty = pretty;
|
||||
}
|
||||
}
|
@ -2,54 +2,53 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for a command line application with a default command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDefaultCommand">The type of the default command.</typeparam>
|
||||
public sealed class CommandApp<TDefaultCommand> : ICommandApp
|
||||
where TDefaultCommand : class, ICommand
|
||||
{
|
||||
private readonly CommandApp _app;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for a command line application with a default command.
|
||||
/// Initializes a new instance of the <see cref="CommandApp{TDefaultCommand}"/> class.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDefaultCommand">The type of the default command.</typeparam>
|
||||
public sealed class CommandApp<TDefaultCommand> : ICommandApp
|
||||
where TDefaultCommand : class, ICommand
|
||||
/// <param name="registrar">The registrar.</param>
|
||||
public CommandApp(ITypeRegistrar? registrar = null)
|
||||
{
|
||||
private readonly CommandApp _app;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandApp{TDefaultCommand}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrar">The registrar.</param>
|
||||
public CommandApp(ITypeRegistrar? registrar = null)
|
||||
{
|
||||
_app = new CommandApp(registrar);
|
||||
_app.GetConfigurator().SetDefaultCommand<TDefaultCommand>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public void Configure(Action<IConfigurator> configuration)
|
||||
{
|
||||
_app.Configure(configuration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public int Run(IEnumerable<string> args)
|
||||
{
|
||||
return _app.Run(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public Task<int> RunAsync(IEnumerable<string> args)
|
||||
{
|
||||
return _app.RunAsync(args);
|
||||
}
|
||||
_app = new CommandApp(registrar);
|
||||
_app.GetConfigurator().SetDefaultCommand<TDefaultCommand>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public void Configure(Action<IConfigurator> configuration)
|
||||
{
|
||||
_app.Configure(configuration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public int Run(IEnumerable<string> args)
|
||||
{
|
||||
return _app.Run(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
public Task<int> RunAsync(IEnumerable<string> args)
|
||||
{
|
||||
return _app.RunAsync(args);
|
||||
}
|
||||
}
|
@ -2,80 +2,79 @@ using System;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur during configuration.
|
||||
/// </summary>
|
||||
public class CommandConfigurationException : CommandAppException
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occur during configuration.
|
||||
/// </summary>
|
||||
public class CommandConfigurationException : CommandAppException
|
||||
internal override bool AlwaysPropagateWhenDebugging => true;
|
||||
|
||||
internal CommandConfigurationException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
internal override bool AlwaysPropagateWhenDebugging => true;
|
||||
|
||||
internal CommandConfigurationException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException NoCommandConfigured()
|
||||
{
|
||||
return new CommandConfigurationException("No commands have been configured.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias)
|
||||
{
|
||||
return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options)
|
||||
{
|
||||
var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}"));
|
||||
if (options.Length > 1)
|
||||
{
|
||||
return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'.");
|
||||
}
|
||||
|
||||
return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " +
|
||||
"pair deconstructable, but the underlying type does not support that.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option)
|
||||
{
|
||||
return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException NoCommandConfigured()
|
||||
{
|
||||
return new CommandConfigurationException("No commands have been configured.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias)
|
||||
{
|
||||
return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options)
|
||||
{
|
||||
var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}"));
|
||||
if (options.Length > 1)
|
||||
{
|
||||
return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'.");
|
||||
}
|
||||
|
||||
return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command)
|
||||
{
|
||||
throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option)
|
||||
{
|
||||
return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " +
|
||||
"pair deconstructable, but the underlying type does not support that.");
|
||||
}
|
||||
|
||||
internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option)
|
||||
{
|
||||
return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value.");
|
||||
}
|
||||
}
|
@ -1,45 +1,44 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command context.
|
||||
/// </summary>
|
||||
public sealed class CommandContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command context.
|
||||
/// Gets the remaining arguments.
|
||||
/// </summary>
|
||||
public sealed class CommandContext
|
||||
/// <value>
|
||||
/// The remaining arguments.
|
||||
/// </value>
|
||||
public IRemainingArguments Remaining { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the command.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the command.
|
||||
/// </value>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data that was passed to the command during registration (if any).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The command data.
|
||||
/// </value>
|
||||
public object? Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="remaining">The remaining arguments.</param>
|
||||
/// <param name="name">The command name.</param>
|
||||
/// <param name="data">The command data.</param>
|
||||
public CommandContext(IRemainingArguments remaining, string name, object? data)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the remaining arguments.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The remaining arguments.
|
||||
/// </value>
|
||||
public IRemainingArguments Remaining { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the command.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the command.
|
||||
/// </value>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data that was passed to the command during registration (if any).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The command data.
|
||||
/// </value>
|
||||
public object? Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="remaining">The remaining arguments.</param>
|
||||
/// <param name="name">The command name.</param>
|
||||
/// <param name="data">The command data.</param>
|
||||
public CommandContext(IRemainingArguments remaining, string name, object? data)
|
||||
{
|
||||
Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining));
|
||||
Name = name ?? throw new System.ArgumentNullException(nameof(name));
|
||||
Data = data;
|
||||
}
|
||||
Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining));
|
||||
Name = name ?? throw new System.ArgumentNullException(nameof(name));
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,52 +2,51 @@ using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
/// <seealso cref="AsyncCommand{TSettings}"/>
|
||||
public abstract class Command<TSettings> : ICommand<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a command.
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
/// <seealso cref="AsyncCommand{TSettings}"/>
|
||||
public abstract class Command<TSettings> : ICommand<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings)
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings);
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Validate(context, (TSettings)settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
Debug.Assert(settings is TSettings, "Command settings is of unexpected type.");
|
||||
return Task.FromResult(Execute(context, (TSettings)settings));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings)
|
||||
{
|
||||
return Task.FromResult(Execute(context, settings));
|
||||
}
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings);
|
||||
|
||||
/// <inheritdoc/>
|
||||
ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Validate(context, (TSettings)settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand.Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
Debug.Assert(settings is TSettings, "Command settings is of unexpected type.");
|
||||
return Task.FromResult(Execute(context, (TSettings)settings));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings)
|
||||
{
|
||||
return Task.FromResult(Execute(context, settings));
|
||||
}
|
||||
}
|
@ -1,38 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a context for <see cref="ICommandParameterInfo"/> related operations.
|
||||
/// </summary>
|
||||
public sealed class CommandParameterContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a context for <see cref="ICommandParameterInfo"/> related operations.
|
||||
/// Gets the parameter.
|
||||
/// </summary>
|
||||
public sealed class CommandParameterContext
|
||||
public ICommandParameterInfo Parameter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type resolver.
|
||||
/// </summary>
|
||||
public ITypeResolver Resolver { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets tje parameter value.
|
||||
/// </summary>
|
||||
public object? Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandParameterContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter.</param>
|
||||
/// <param name="resolver">The type resolver.</param>
|
||||
/// <param name="value">The parameter value.</param>
|
||||
public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the parameter.
|
||||
/// </summary>
|
||||
public ICommandParameterInfo Parameter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type resolver.
|
||||
/// </summary>
|
||||
public ITypeResolver Resolver { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets tje parameter value.
|
||||
/// </summary>
|
||||
public object? Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommandParameterContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The parameter.</param>
|
||||
/// <param name="resolver">The type resolver.</param>
|
||||
/// <param name="value">The parameter value.</param>
|
||||
public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value)
|
||||
{
|
||||
Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter));
|
||||
Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
|
||||
Value = value;
|
||||
}
|
||||
Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter));
|
||||
Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,125 +3,124 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur during parsing.
|
||||
/// </summary>
|
||||
public sealed class CommandParseException : CommandRuntimeException
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occur during parsing.
|
||||
/// </summary>
|
||||
public sealed class CommandParseException : CommandRuntimeException
|
||||
internal CommandParseException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
internal CommandParseException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotCreateSettings(Type settingsType)
|
||||
{
|
||||
return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotCreateCommand(Type? commandType)
|
||||
{
|
||||
if (commandType == null)
|
||||
{
|
||||
return new CommandParseException($"Could not create command. Command type is unknown.");
|
||||
}
|
||||
|
||||
return new CommandParseException($"Could not create command of type '{commandType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected)
|
||||
{
|
||||
return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found)
|
||||
{
|
||||
return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead.");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionHasNoValue(IEnumerable<string> args, CommandTreeToken token, CommandOption option)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnexpectedOption(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?");
|
||||
}
|
||||
|
||||
internal static CommandParseException CannotAssignValueToFlag(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value.");
|
||||
}
|
||||
|
||||
internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option.");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--");
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");
|
||||
var reason = $"Did you mean -{name}?";
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason);
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit.");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character)
|
||||
{
|
||||
var name = character.ToString(CultureInfo.InvariantCulture);
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name);
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value);
|
||||
var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command.";
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text);
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotMatchArgument(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnknownOption(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ValueIsNotInValidFormat(string value)
|
||||
{
|
||||
var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format";
|
||||
return new CommandParseException("Could not parse value", new Markup(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotCreateSettings(Type settingsType)
|
||||
{
|
||||
return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotCreateCommand(Type? commandType)
|
||||
{
|
||||
if (commandType == null)
|
||||
{
|
||||
return new CommandParseException($"Could not create command. Command type is unknown.");
|
||||
}
|
||||
|
||||
return new CommandParseException($"Could not create command of type '{commandType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected)
|
||||
{
|
||||
return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found)
|
||||
{
|
||||
return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead.");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?");
|
||||
}
|
||||
|
||||
internal static CommandParseException OptionHasNoValue(IEnumerable<string> args, CommandTreeToken token, CommandOption option)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnexpectedOption(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?");
|
||||
}
|
||||
|
||||
internal static CommandParseException CannotAssignValueToFlag(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value.");
|
||||
}
|
||||
|
||||
internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option.");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--");
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");
|
||||
var reason = $"Did you mean -{name}?";
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason);
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name)
|
||||
{
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit.");
|
||||
}
|
||||
|
||||
internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character)
|
||||
{
|
||||
var name = character.ToString(CultureInfo.InvariantCulture);
|
||||
var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name);
|
||||
return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value);
|
||||
var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command.";
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text);
|
||||
}
|
||||
|
||||
internal static CommandParseException CouldNotMatchArgument(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument.");
|
||||
}
|
||||
|
||||
internal static CommandParseException UnknownOption(IEnumerable<string> args, CommandTreeToken token)
|
||||
{
|
||||
return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option.");
|
||||
}
|
||||
|
||||
internal static CommandParseException ValueIsNotInValidFormat(string value)
|
||||
{
|
||||
var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format";
|
||||
return new CommandParseException("Could not parse value", new Markup(text));
|
||||
}
|
||||
}
|
@ -1,58 +1,57 @@
|
||||
using System;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur during runtime.
|
||||
/// </summary>
|
||||
public class CommandRuntimeException : CommandAppException
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occur during runtime.
|
||||
/// </summary>
|
||||
public class CommandRuntimeException : CommandAppException
|
||||
internal CommandRuntimeException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
internal CommandRuntimeException(string message, IRenderable? pretty = null)
|
||||
: base(message, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null)
|
||||
{
|
||||
var message = $"Could not resolve type '{type.FullName}'.";
|
||||
if (ex != null)
|
||||
{
|
||||
// TODO: Show internal stuff here.
|
||||
return new CommandRuntimeException(message, ex);
|
||||
}
|
||||
|
||||
return new CommandRuntimeException(message);
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument)
|
||||
{
|
||||
if (node.Command.Name == CliConstants.DefaultCommandName)
|
||||
{
|
||||
return new CommandRuntimeException($"Missing required argument '{argument.Value}'.");
|
||||
}
|
||||
|
||||
return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'.");
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException NoConverterFound(CommandParameter parameter)
|
||||
{
|
||||
return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException ValidationFailed(ValidationResult result)
|
||||
{
|
||||
return new CommandRuntimeException(result.Message ?? "Unknown validation error.");
|
||||
}
|
||||
|
||||
internal static Exception CouldNotGetSettingsType(Type commandType)
|
||||
{
|
||||
return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null)
|
||||
: base(message, ex, pretty)
|
||||
{
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null)
|
||||
{
|
||||
var message = $"Could not resolve type '{type.FullName}'.";
|
||||
if (ex != null)
|
||||
{
|
||||
// TODO: Show internal stuff here.
|
||||
return new CommandRuntimeException(message, ex);
|
||||
}
|
||||
|
||||
return new CommandRuntimeException(message);
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument)
|
||||
{
|
||||
if (node.Command.Name == CliConstants.DefaultCommandName)
|
||||
{
|
||||
return new CommandRuntimeException($"Missing required argument '{argument.Value}'.");
|
||||
}
|
||||
|
||||
return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'.");
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException NoConverterFound(CommandParameter parameter)
|
||||
{
|
||||
return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'.");
|
||||
}
|
||||
|
||||
internal static CommandRuntimeException ValidationFailed(ValidationResult result)
|
||||
{
|
||||
return new CommandRuntimeException(result.Message ?? "Unknown validation error.");
|
||||
}
|
||||
|
||||
internal static Exception CouldNotGetSettingsType(Type commandType)
|
||||
{
|
||||
return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'.");
|
||||
}
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for command settings.
|
||||
/// </summary>
|
||||
public abstract class CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for command settings.
|
||||
/// Performs validation of the settings.
|
||||
/// </summary>
|
||||
public abstract class CommandSettings
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate()
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs validation of the settings.
|
||||
/// </summary>
|
||||
/// <returns>The validation result.</returns>
|
||||
public virtual ValidationResult Validate()
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,160 +1,159 @@
|
||||
using System.Globalization;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors related to parameter templates.
|
||||
/// </summary>
|
||||
public sealed class CommandTemplateException : CommandConfigurationException
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors related to parameter templates.
|
||||
/// Gets the template that contains the error.
|
||||
/// </summary>
|
||||
public sealed class CommandTemplateException : CommandConfigurationException
|
||||
public string Template { get; }
|
||||
|
||||
internal override bool AlwaysPropagateWhenDebugging => true;
|
||||
|
||||
internal CommandTemplateException(string message, string template, IRenderable pretty)
|
||||
: base(message, pretty)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the template that contains the error.
|
||||
/// </summary>
|
||||
public string Template { get; }
|
||||
|
||||
internal override bool AlwaysPropagateWhenDebugging => true;
|
||||
|
||||
internal CommandTemplateException(string message, string template, IRenderable pretty)
|
||||
: base(message, pretty)
|
||||
{
|
||||
Template = template;
|
||||
}
|
||||
|
||||
internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template,
|
||||
new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"),
|
||||
$"Encountered unexpected character '{character}'.",
|
||||
"Unexpected character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template, token,
|
||||
$"Encountered unterminated value name '{token.Value}'.",
|
||||
"Unterminated value name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template, token,
|
||||
"Arguments can not contain options.",
|
||||
"Not permitted.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple values are not supported.",
|
||||
"Too many values.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Values without name are not allowed.",
|
||||
"Missing value name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Options without name are not allowed.",
|
||||
"Missing option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole string.
|
||||
token = new TemplateToken(
|
||||
token.TokenKind,
|
||||
token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2,
|
||||
token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Option names cannot start with a digit.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character)
|
||||
{
|
||||
// Rewrite the token to point to the invalid character instead of the whole value.
|
||||
var position = (token.TokenKind == TemplateToken.Kind.ShortName
|
||||
? token.Position + 1
|
||||
: token.Position + 2) + token.Value.OrdinalIndexOf(character);
|
||||
|
||||
token = new TemplateToken(
|
||||
token.TokenKind, position,
|
||||
token.Value, character.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
$"Encountered invalid character '{character}' in option name.",
|
||||
"Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole option.
|
||||
token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Long option names must consist of more than one character.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple short option names are not supported.",
|
||||
"Too many short options.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole option.
|
||||
token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Short option names can not be longer than one character.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple option values are not supported.",
|
||||
"Too many option values.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character)
|
||||
{
|
||||
// Rewrite the token to point to the invalid character instead of the whole value.
|
||||
token = new TemplateToken(
|
||||
token.TokenKind,
|
||||
token.Position + 1 + token.Value.OrdinalIndexOf(character),
|
||||
token.Value, character.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
$"Encountered invalid character '{character}' in value name.",
|
||||
"Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"No long or short name for option has been specified.",
|
||||
"Missing option. Was this meant to be an argument?");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ArgumentsMustHaveValueName(string template)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, null,
|
||||
"Arguments must have a value name.",
|
||||
"Missing value name.");
|
||||
}
|
||||
Template = template;
|
||||
}
|
||||
}
|
||||
|
||||
internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template,
|
||||
new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"),
|
||||
$"Encountered unexpected character '{character}'.",
|
||||
"Unexpected character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template, token,
|
||||
$"Encountered unterminated value name '{token.Value}'.",
|
||||
"Unterminated value name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(
|
||||
template, token,
|
||||
"Arguments can not contain options.",
|
||||
"Not permitted.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple values are not supported.",
|
||||
"Too many values.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Values without name are not allowed.",
|
||||
"Missing value name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Options without name are not allowed.",
|
||||
"Missing option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole string.
|
||||
token = new TemplateToken(
|
||||
token.TokenKind,
|
||||
token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2,
|
||||
token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Option names cannot start with a digit.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character)
|
||||
{
|
||||
// Rewrite the token to point to the invalid character instead of the whole value.
|
||||
var position = (token.TokenKind == TemplateToken.Kind.ShortName
|
||||
? token.Position + 1
|
||||
: token.Position + 2) + token.Value.OrdinalIndexOf(character);
|
||||
|
||||
token = new TemplateToken(
|
||||
token.TokenKind, position,
|
||||
token.Value, character.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
$"Encountered invalid character '{character}' in option name.",
|
||||
"Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole option.
|
||||
token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Long option names must consist of more than one character.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple short option names are not supported.",
|
||||
"Too many short options.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token)
|
||||
{
|
||||
// Rewrite the token to point to the option name instead of the whole option.
|
||||
token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value);
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Short option names can not be longer than one character.",
|
||||
"Invalid option name.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"Multiple option values are not supported.",
|
||||
"Too many option values.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character)
|
||||
{
|
||||
// Rewrite the token to point to the invalid character instead of the whole value.
|
||||
token = new TemplateToken(
|
||||
token.TokenKind,
|
||||
token.Position + 1 + token.Value.OrdinalIndexOf(character),
|
||||
token.Value, character.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
$"Encountered invalid character '{character}' in value name.",
|
||||
"Invalid character.");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, token,
|
||||
"No long or short name for option has been specified.",
|
||||
"Missing option. Was this meant to be an argument?");
|
||||
}
|
||||
|
||||
internal static CommandTemplateException ArgumentsMustHaveValueName(string template)
|
||||
{
|
||||
return CommandLineTemplateExceptionFactory.Create(template, null,
|
||||
"Arguments must have a value name.",
|
||||
"Missing value name.");
|
||||
}
|
||||
}
|
@ -1,262 +1,261 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Contains extensions for <see cref="IConfigurator"/>
|
||||
/// and <see cref="IConfigurator{TSettings}"/>.
|
||||
/// </summary>
|
||||
public static class ConfiguratorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extensions for <see cref="IConfigurator"/>
|
||||
/// and <see cref="IConfigurator{TSettings}"/>.
|
||||
/// Sets the name of the application.
|
||||
/// </summary>
|
||||
public static class ConfiguratorExtensions
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the application.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetApplicationName(this IConfigurator configurator, string name)
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the name of the application.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the application.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetApplicationName(this IConfigurator configurator, string name)
|
||||
if (configurator == null)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ApplicationName = name;
|
||||
return configurator;
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the auto-detected version of the application.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="version">The version of application.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ApplicationVersion = version;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the console.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.Console = console;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the parsing mode to strict.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator UseStrictParsing(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.StrictParsing = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the command line application to propagate all
|
||||
/// exceptions to the user.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator PropagateExceptions(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.PropagateExceptions = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures case sensitivity.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configuration.</param>
|
||||
/// <param name="sensitivity">The case sensitivity.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.CaseSensitivity = sensitivity;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the command line application to validate all
|
||||
/// examples before running the application.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator ValidateExamples(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ValidateExamples = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the command interceptor to be used.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="interceptor">A <see cref="ICommandInterceptor"/>.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.Interceptor = interceptor;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
public static void AddBranch(
|
||||
this IConfigurator configurator,
|
||||
string name,
|
||||
Action<IConfigurator<CommandSettings>> action)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.AddBranch(name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
public static void AddBranch<TSettings>(
|
||||
this IConfigurator<TSettings> configurator,
|
||||
string name,
|
||||
Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.AddBranch(name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command without settings that executes a delegate.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
public static ICommandConfigurator AddDelegate(
|
||||
this IConfigurator configurator,
|
||||
string name,
|
||||
Func<CommandContext, int> func)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
return configurator.AddDelegate<EmptyCommandSettings>(name, (c, _) => func(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command without settings that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
public static ICommandConfigurator AddDelegate<TSettings>(
|
||||
this IConfigurator<TSettings> configurator,
|
||||
string name,
|
||||
Func<CommandContext, int> func)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
return configurator.AddDelegate<TSettings>(name, (c, _) => func(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// <para>Setting <see cref="ICommandAppSettings.ExceptionHandler"/> this way will use the
|
||||
/// default exit code of -1.</para>
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action<Exception> exceptionHandler)
|
||||
{
|
||||
return configurator.SetExceptionHandler(ex =>
|
||||
{
|
||||
exceptionHandler(ex);
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func<Exception, int>? exceptionHandler)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ExceptionHandler = exceptionHandler;
|
||||
return configurator;
|
||||
}
|
||||
configurator.Settings.ApplicationName = name;
|
||||
return configurator;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the auto-detected version of the application.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="version">The version of application.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ApplicationVersion = version;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the console.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="console">The console.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.Console = console;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the parsing mode to strict.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator UseStrictParsing(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.StrictParsing = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the command line application to propagate all
|
||||
/// exceptions to the user.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator PropagateExceptions(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.PropagateExceptions = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures case sensitivity.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configuration.</param>
|
||||
/// <param name="sensitivity">The case sensitivity.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.CaseSensitivity = sensitivity;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the command line application to validate all
|
||||
/// examples before running the application.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator ValidateExamples(this IConfigurator configurator)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ValidateExamples = true;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the command interceptor to be used.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="interceptor">A <see cref="ICommandInterceptor"/>.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.Interceptor = interceptor;
|
||||
return configurator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
public static void AddBranch(
|
||||
this IConfigurator configurator,
|
||||
string name,
|
||||
Action<IConfigurator<CommandSettings>> action)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.AddBranch(name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
public static void AddBranch<TSettings>(
|
||||
this IConfigurator<TSettings> configurator,
|
||||
string name,
|
||||
Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.AddBranch(name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command without settings that executes a delegate.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
public static ICommandConfigurator AddDelegate(
|
||||
this IConfigurator configurator,
|
||||
string name,
|
||||
Func<CommandContext, int> func)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
return configurator.AddDelegate<EmptyCommandSettings>(name, (c, _) => func(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command without settings that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
public static ICommandConfigurator AddDelegate<TSettings>(
|
||||
this IConfigurator<TSettings> configurator,
|
||||
string name,
|
||||
Func<CommandContext, int> func)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
return configurator.AddDelegate<TSettings>(name, (c, _) => func(c));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// <para>Setting <see cref="ICommandAppSettings.ExceptionHandler"/> this way will use the
|
||||
/// default exit code of -1.</para>
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action<Exception> exceptionHandler)
|
||||
{
|
||||
return configurator.SetExceptionHandler(ex =>
|
||||
{
|
||||
exceptionHandler(ex);
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ExceptionsHandler.
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator.</param>
|
||||
/// <param name="exceptionHandler">The Action that handles the exception.</param>
|
||||
/// <returns>A configurator that can be used to configure the application further.</returns>
|
||||
public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func<Exception, int>? exceptionHandler)
|
||||
{
|
||||
if (configurator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configurator));
|
||||
}
|
||||
|
||||
configurator.Settings.ExceptionHandler = exceptionHandler;
|
||||
return configurator;
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents empty settings.
|
||||
/// </summary>
|
||||
public sealed class EmptyCommandSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents empty settings.
|
||||
/// </summary>
|
||||
public sealed class EmptyCommandSettings : CommandSettings
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +1,58 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a flag with an optional value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The flag's element type.</typeparam>
|
||||
public sealed class FlagValue<T> : IFlagValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a flag with an optional value.
|
||||
/// Gets or sets a value indicating whether or not the flag was set or not.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The flag's element type.</typeparam>
|
||||
public sealed class FlagValue<T> : IFlagValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the flag was set or not.
|
||||
/// </summary>
|
||||
public bool IsSet { get; set; }
|
||||
public bool IsSet { get; set; }
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
|
||||
/// <summary>
|
||||
/// Gets or sets the flag's value.
|
||||
/// </summary>
|
||||
public T Value { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the flag's value.
|
||||
/// </summary>
|
||||
public T Value { get; set; }
|
||||
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
|
||||
|
||||
/// <inheritdoc/>
|
||||
Type IFlagValue.Type => typeof(T);
|
||||
/// <inheritdoc/>
|
||||
Type IFlagValue.Type => typeof(T);
|
||||
|
||||
/// <inheritdoc/>
|
||||
object? IFlagValue.Value
|
||||
/// <inheritdoc/>
|
||||
object? IFlagValue.Value
|
||||
{
|
||||
get => Value;
|
||||
set
|
||||
{
|
||||
get => Value;
|
||||
set
|
||||
{
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
Value = (T)value;
|
||||
Value = (T)value;
|
||||
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
var flag = (IFlagValue)this;
|
||||
if (flag.Value != null)
|
||||
{
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Set={0}, Value={1}",
|
||||
IsSet,
|
||||
flag.Value.ToString());
|
||||
}
|
||||
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Set={0}", IsSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
var flag = (IFlagValue)this;
|
||||
if (flag.Value != null)
|
||||
{
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Set={0}, Value={1}",
|
||||
IsSet,
|
||||
flag.Value.ToString());
|
||||
}
|
||||
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Set={0}", IsSet);
|
||||
}
|
||||
}
|
@ -1,26 +1,25 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command.
|
||||
/// </summary>
|
||||
public interface ICommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command.
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
public interface ICommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the specified settings and remaining arguments.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
ValidationResult Validate(CommandContext context, CommandSettings settings);
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
ValidationResult Validate(CommandContext context, CommandSettings settings);
|
||||
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
Task<int> Execute(CommandContext context, CommandSettings settings);
|
||||
}
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The validation result.</returns>
|
||||
Task<int> Execute(CommandContext context, CommandSettings settings);
|
||||
}
|
@ -2,31 +2,30 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command line application.
|
||||
/// </summary>
|
||||
public interface ICommandApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command line application.
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
public interface ICommandApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the command line application.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
void Configure(Action<IConfigurator> configuration);
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
void Configure(Action<IConfigurator> configuration);
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
int Run(IEnumerable<string> args);
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
int Run(IEnumerable<string> args);
|
||||
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
Task<int> RunAsync(IEnumerable<string> args);
|
||||
}
|
||||
/// <summary>
|
||||
/// Runs the command line application with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The exit code from the executed command.</returns>
|
||||
Task<int> RunAsync(IEnumerable<string> args);
|
||||
}
|
@ -1,64 +1,63 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command line application settings.
|
||||
/// </summary>
|
||||
public interface ICommandAppSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command line application settings.
|
||||
/// Gets or sets the application name.
|
||||
/// </summary>
|
||||
public interface ICommandAppSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the application name.
|
||||
/// </summary>
|
||||
string? ApplicationName { get; set; }
|
||||
string? ApplicationName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the application version (use it to override auto-detected value).
|
||||
/// </summary>
|
||||
string? ApplicationVersion { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the application version (use it to override auto-detected value).
|
||||
/// </summary>
|
||||
string? ApplicationVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
IAnsiConsole? Console { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IAnsiConsole"/>.
|
||||
/// </summary>
|
||||
IAnsiConsole? Console { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ICommandInterceptor"/> used
|
||||
/// to intercept settings before it's being sent to the command.
|
||||
/// </summary>
|
||||
ICommandInterceptor? Interceptor { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ICommandInterceptor"/> used
|
||||
/// to intercept settings before it's being sent to the command.
|
||||
/// </summary>
|
||||
ICommandInterceptor? Interceptor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type registrar.
|
||||
/// </summary>
|
||||
ITypeRegistrarFrontend Registrar { get; }
|
||||
/// <summary>
|
||||
/// Gets the type registrar.
|
||||
/// </summary>
|
||||
ITypeRegistrarFrontend Registrar { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets case sensitivity.
|
||||
/// </summary>
|
||||
CaseSensitivity CaseSensitivity { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets case sensitivity.
|
||||
/// </summary>
|
||||
CaseSensitivity CaseSensitivity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not parsing is strict.
|
||||
/// </summary>
|
||||
bool StrictParsing { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not parsing is strict.
|
||||
/// </summary>
|
||||
bool StrictParsing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not exceptions should be propagated.
|
||||
/// <para>Setting this to <c>true</c> will disable default Exception handling and
|
||||
/// any <see cref="ExceptionHandler"/>, if set.</para>
|
||||
/// </summary>
|
||||
bool PropagateExceptions { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not exceptions should be propagated.
|
||||
/// <para>Setting this to <c>true</c> will disable default Exception handling and
|
||||
/// any <see cref="ExceptionHandler"/>, if set.</para>
|
||||
/// </summary>
|
||||
bool PropagateExceptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not examples should be validated.
|
||||
/// </summary>
|
||||
bool ValidateExamples { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not examples should be validated.
|
||||
/// </summary>
|
||||
bool ValidateExamples { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a handler for Exceptions.
|
||||
/// <para>This handler will not be called, if <see cref="PropagateExceptions"/> is set to <c>true</c>.</para>
|
||||
/// </summary>
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a handler for Exceptions.
|
||||
/// <para>This handler will not be called, if <see cref="PropagateExceptions"/> is set to <c>true</c>.</para>
|
||||
/// </summary>
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
}
|
@ -1,44 +1,43 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command configurator.
|
||||
/// </summary>
|
||||
public interface ICommandConfigurator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command configurator.
|
||||
/// Adds an example of how to use the command.
|
||||
/// </summary>
|
||||
public interface ICommandConfigurator
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an example of how to use the command.
|
||||
/// </summary>
|
||||
/// <param name="args">The example arguments.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithExample(string[] args);
|
||||
/// <param name="args">The example arguments.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithExample(string[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Adds an alias (an alternative name) to the command being configured.
|
||||
/// </summary>
|
||||
/// <param name="name">The alias to add to the command being configured.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithAlias(string name);
|
||||
/// <summary>
|
||||
/// Adds an alias (an alternative name) to the command being configured.
|
||||
/// </summary>
|
||||
/// <param name="name">The alias to add to the command being configured.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithAlias(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the description of the command.
|
||||
/// </summary>
|
||||
/// <param name="description">The command description.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithDescription(string description);
|
||||
/// <summary>
|
||||
/// Sets the description of the command.
|
||||
/// </summary>
|
||||
/// <param name="description">The command description.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithDescription(string description);
|
||||
|
||||
/// <summary>
|
||||
/// Sets data that will be passed to the command via the <see cref="CommandContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to pass to the command.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithData(object data);
|
||||
/// <summary>
|
||||
/// Sets data that will be passed to the command via the <see cref="CommandContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to pass to the command.</param>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator WithData(object data);
|
||||
|
||||
/// <summary>
|
||||
/// Marks the command as hidden.
|
||||
/// Hidden commands do not show up in help documentation or
|
||||
/// generated XML models.
|
||||
/// </summary>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator IsHidden();
|
||||
}
|
||||
/// <summary>
|
||||
/// Marks the command as hidden.
|
||||
/// Hidden commands do not show up in help documentation or
|
||||
/// generated XML models.
|
||||
/// </summary>
|
||||
/// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns>
|
||||
ICommandConfigurator IsHidden();
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command settings interceptor that
|
||||
/// will intercept command settings before it's
|
||||
/// passed to a command.
|
||||
/// </summary>
|
||||
public interface ICommandInterceptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command settings interceptor that
|
||||
/// will intercept command settings before it's
|
||||
/// passed to a command.
|
||||
/// Intercepts command information before it's passed to a command.
|
||||
/// </summary>
|
||||
public interface ICommandInterceptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Intercepts command information before it's passed to a command.
|
||||
/// </summary>
|
||||
/// <param name="context">The intercepted <see cref="CommandContext"/>.</param>
|
||||
/// <param name="settings">The intercepted <see cref="CommandSettings"/>.</param>
|
||||
void Intercept(CommandContext context, CommandSettings settings);
|
||||
}
|
||||
}
|
||||
/// <param name="context">The intercepted <see cref="CommandContext"/>.</param>
|
||||
/// <param name="settings">The intercepted <see cref="CommandSettings"/>.</param>
|
||||
void Intercept(CommandContext context, CommandSettings settings);
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command limiter.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The type of the settings to limit to.</typeparam>
|
||||
/// <seealso cref="ICommand" />
|
||||
public interface ICommandLimiter<out TSettings> : ICommand
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command limiter.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The type of the settings to limit to.</typeparam>
|
||||
/// <seealso cref="ICommand" />
|
||||
public interface ICommandLimiter<out TSettings> : ICommand
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
public interface ICommand<TSettings> : ICommandLimiter<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command.
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The settings type.</typeparam>
|
||||
public interface ICommand<TSettings> : ICommandLimiter<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the command.
|
||||
/// </summary>
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
Task<int> Execute(CommandContext context, TSettings settings);
|
||||
}
|
||||
}
|
||||
/// <param name="context">The command context.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>An integer indicating whether or not the command executed successfully.</returns>
|
||||
Task<int> Execute(CommandContext context, TSettings settings);
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command parameter.
|
||||
/// </summary>
|
||||
public interface ICommandParameterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a command parameter.
|
||||
/// Gets the property name.
|
||||
/// </summary>
|
||||
public interface ICommandParameterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the property name.
|
||||
/// </summary>
|
||||
/// <value>The property name.</value>
|
||||
public string PropertyName { get; }
|
||||
/// <value>The property name.</value>
|
||||
public string PropertyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter type.
|
||||
/// </summary>
|
||||
public Type ParameterType { get; }
|
||||
/// <summary>
|
||||
/// Gets the parameter type.
|
||||
/// </summary>
|
||||
public Type ParameterType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description.
|
||||
/// </summary>
|
||||
/// <value>The description.</value>
|
||||
public string? Description { get; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the description.
|
||||
/// </summary>
|
||||
/// <value>The description.</value>
|
||||
public string? Description { get; }
|
||||
}
|
@ -1,49 +1,48 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a configurator.
|
||||
/// </summary>
|
||||
public interface IConfigurator
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a configurator.
|
||||
/// Gets the command app settings.
|
||||
/// </summary>
|
||||
public interface IConfigurator
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the command app settings.
|
||||
/// </summary>
|
||||
public ICommandAppSettings Settings { get; }
|
||||
public ICommandAppSettings Settings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an example of how to use the application.
|
||||
/// </summary>
|
||||
/// <param name="args">The example arguments.</param>
|
||||
void AddExample(string[] args);
|
||||
/// <summary>
|
||||
/// Adds an example of how to use the application.
|
||||
/// </summary>
|
||||
/// <param name="args">The example arguments.</param>
|
||||
void AddExample(string[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommand;
|
||||
/// <summary>
|
||||
/// Adds a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommand;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func)
|
||||
where TSettings : CommandSettings;
|
||||
/// <summary>
|
||||
/// Adds a command that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func)
|
||||
where TSettings : CommandSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configurator.</param>
|
||||
void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configurator.</param>
|
||||
void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings;
|
||||
}
|
@ -1,59 +1,58 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a configurator for specific settings.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
public interface IConfigurator<in TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a configurator for specific settings.
|
||||
/// Sets the description of the branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSettings">The command setting type.</typeparam>
|
||||
public interface IConfigurator<in TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the description of the branch.
|
||||
/// </summary>
|
||||
/// <param name="description">The description of the branch.</param>
|
||||
void SetDescription(string description);
|
||||
/// <param name="description">The description of the branch.</param>
|
||||
void SetDescription(string description);
|
||||
|
||||
/// <summary>
|
||||
/// Adds an example of how to use the branch.
|
||||
/// </summary>
|
||||
/// <param name="args">The example arguments.</param>
|
||||
void AddExample(string[] args);
|
||||
/// <summary>
|
||||
/// Adds an example of how to use the branch.
|
||||
/// </summary>
|
||||
/// <param name="args">The example arguments.</param>
|
||||
void AddExample(string[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Marks the branch as hidden.
|
||||
/// Hidden branches do not show up in help documentation or
|
||||
/// generated XML models.
|
||||
/// </summary>
|
||||
void HideBranch();
|
||||
/// <summary>
|
||||
/// Marks the branch as hidden.
|
||||
/// Hidden branches do not show up in help documentation or
|
||||
/// generated XML models.
|
||||
/// </summary>
|
||||
void HideBranch();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommandLimiter<TSettings>;
|
||||
/// <summary>
|
||||
/// Adds a command.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCommand">The command type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommandLimiter<TSettings>;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func)
|
||||
where TDerivedSettings : TSettings;
|
||||
/// <summary>
|
||||
/// Adds a command that executes a delegate.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="func">The delegate to execute as part of command execution.</param>
|
||||
/// <returns>A command configurator that can be used to configure the command further.</returns>
|
||||
ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func)
|
||||
where TDerivedSettings : TSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
|
||||
where TDerivedSettings : TSettings;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a command branch.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam>
|
||||
/// <param name="name">The name of the command branch.</param>
|
||||
/// <param name="action">The command branch configuration.</param>
|
||||
void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
|
||||
where TDerivedSettings : TSettings;
|
||||
}
|
@ -1,25 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a flag with an optional value.
|
||||
/// </summary>
|
||||
public interface IFlagValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a flag with an optional value.
|
||||
/// Gets or sets a value indicating whether or not the flag was set or not.
|
||||
/// </summary>
|
||||
public interface IFlagValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not the flag was set or not.
|
||||
/// </summary>
|
||||
bool IsSet { get; set; }
|
||||
bool IsSet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flag's element type.
|
||||
/// </summary>
|
||||
Type Type { get; }
|
||||
/// <summary>
|
||||
/// Gets the flag's element type.
|
||||
/// </summary>
|
||||
Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag's value.
|
||||
/// </summary>
|
||||
object? Value { get; set; }
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the flag's value.
|
||||
/// </summary>
|
||||
object? Value { get; set; }
|
||||
}
|
@ -1,21 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the remaining arguments.
|
||||
/// </summary>
|
||||
public interface IRemainingArguments
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the remaining arguments.
|
||||
/// Gets the parsed remaining arguments.
|
||||
/// </summary>
|
||||
public interface IRemainingArguments
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the parsed remaining arguments.
|
||||
/// </summary>
|
||||
ILookup<string, string?> Parsed { get; }
|
||||
ILookup<string, string?> Parsed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw, non-parsed remaining arguments.
|
||||
/// </summary>
|
||||
IReadOnlyList<string> Raw { get; }
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the raw, non-parsed remaining arguments.
|
||||
/// </summary>
|
||||
IReadOnlyList<string> Raw { get; }
|
||||
}
|
@ -1,38 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a type registrar.
|
||||
/// </summary>
|
||||
public interface ITypeRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a type registrar.
|
||||
/// Registers the specified service.
|
||||
/// </summary>
|
||||
public interface ITypeRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the specified service.
|
||||
/// </summary>
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
void Register(Type service, Type implementation);
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
void Register(Type service, Type implementation);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified instance.
|
||||
/// </summary>
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
void RegisterInstance(Type service, object implementation);
|
||||
/// <summary>
|
||||
/// Registers the specified instance.
|
||||
/// </summary>
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
void RegisterInstance(Type service, object implementation);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified instance lazily.
|
||||
/// </summary>
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="factory">The factory that creates the implementation.</param>
|
||||
void RegisterLazy(Type service, Func<object> factory);
|
||||
/// <summary>
|
||||
/// Registers the specified instance lazily.
|
||||
/// </summary>
|
||||
/// <param name="service">The service.</param>
|
||||
/// <param name="factory">The factory that creates the implementation.</param>
|
||||
void RegisterLazy(Type service, Func<object> factory);
|
||||
|
||||
/// <summary>
|
||||
/// Builds the type resolver representing the registrations
|
||||
/// specified in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>A type resolver.</returns>
|
||||
ITypeResolver Build();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Builds the type resolver representing the registrations
|
||||
/// specified in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>A type resolver.</returns>
|
||||
ITypeResolver Build();
|
||||
}
|
@ -1,32 +1,31 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a user friendly frontend for a <see cref="ITypeRegistrar"/>.
|
||||
/// </summary>
|
||||
public interface ITypeRegistrarFrontend
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user friendly frontend for a <see cref="ITypeRegistrar"/>.
|
||||
/// Registers the type with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
public interface ITypeRegistrarFrontend
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the type with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The exposed service type.</typeparam>
|
||||
/// <typeparam name="TImplementation">The implementing type.</typeparam>
|
||||
void Register<TService, TImplementation>()
|
||||
where TImplementation : TService;
|
||||
/// <typeparam name="TService">The exposed service type.</typeparam>
|
||||
/// <typeparam name="TImplementation">The implementing type.</typeparam>
|
||||
void Register<TService, TImplementation>()
|
||||
where TImplementation : TService;
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified instance with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">The type of the instance.</typeparam>
|
||||
/// <param name="instance">The instance to register.</param>
|
||||
void RegisterInstance<TImplementation>(TImplementation instance);
|
||||
/// <summary>
|
||||
/// Registers the specified instance with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
/// <typeparam name="TImplementation">The type of the instance.</typeparam>
|
||||
/// <param name="instance">The instance to register.</param>
|
||||
void RegisterInstance<TImplementation>(TImplementation instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified instance with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The exposed service type.</typeparam>
|
||||
/// <typeparam name="TImplementation"> implementing type.</typeparam>
|
||||
/// <param name="instance">The instance to register.</param>
|
||||
void RegisterInstance<TService, TImplementation>(TImplementation instance)
|
||||
where TImplementation : TService;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers the specified instance with the type registrar as a singleton.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The exposed service type.</typeparam>
|
||||
/// <typeparam name="TImplementation"> implementing type.</typeparam>
|
||||
/// <param name="instance">The instance to register.</param>
|
||||
void RegisterInstance<TService, TImplementation>(TImplementation instance)
|
||||
where TImplementation : TService;
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a type resolver.
|
||||
/// </summary>
|
||||
public interface ITypeResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a type resolver.
|
||||
/// Resolves an instance of the specified type.
|
||||
/// </summary>
|
||||
public interface ITypeResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves an instance of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to resolve.</param>
|
||||
/// <returns>An instance of the specified type, or <c>null</c> if no registration for the specified type exists.</returns>
|
||||
object? Resolve(Type? type);
|
||||
}
|
||||
}
|
||||
/// <param name="type">The type to resolve.</param>
|
||||
/// <returns>An instance of the specified type, or <c>null</c> if no registration for the specified type exists.</returns>
|
||||
object? Resolve(Type? type);
|
||||
}
|
@ -2,54 +2,53 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandConstructorBinder
|
||||
{
|
||||
internal static class CommandConstructorBinder
|
||||
public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver)
|
||||
{
|
||||
public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver)
|
||||
if (constructor.DeclaringType == null)
|
||||
{
|
||||
if (constructor.DeclaringType == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create settings since constructor have no declaring type.");
|
||||
}
|
||||
|
||||
var parameters = new List<object?>();
|
||||
var mapped = new HashSet<Guid>();
|
||||
foreach (var parameter in constructor.GetParameters())
|
||||
{
|
||||
if (lookup.TryGetParameterWithName(parameter.Name, out var result))
|
||||
{
|
||||
parameters.Add(result.Value);
|
||||
mapped.Add(result.Parameter.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = resolver.Resolve(parameter.ParameterType);
|
||||
if (value == null)
|
||||
{
|
||||
throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType);
|
||||
}
|
||||
|
||||
parameters.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the settings.
|
||||
if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings))
|
||||
{
|
||||
throw new InvalidOperationException("Could not create settings");
|
||||
}
|
||||
|
||||
// Try to do property injection for parameters that wasn't injected.
|
||||
foreach (var (parameter, value) in lookup)
|
||||
{
|
||||
if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null)
|
||||
{
|
||||
parameter.Property.SetValue(settings, value);
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
throw new InvalidOperationException("Cannot create settings since constructor have no declaring type.");
|
||||
}
|
||||
|
||||
var parameters = new List<object?>();
|
||||
var mapped = new HashSet<Guid>();
|
||||
foreach (var parameter in constructor.GetParameters())
|
||||
{
|
||||
if (lookup.TryGetParameterWithName(parameter.Name, out var result))
|
||||
{
|
||||
parameters.Add(result.Value);
|
||||
mapped.Add(result.Parameter.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = resolver.Resolve(parameter.ParameterType);
|
||||
if (value == null)
|
||||
{
|
||||
throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType);
|
||||
}
|
||||
|
||||
parameters.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the settings.
|
||||
if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings))
|
||||
{
|
||||
throw new InvalidOperationException("Could not create settings");
|
||||
}
|
||||
|
||||
// Try to do property injection for parameters that wasn't injected.
|
||||
foreach (var (parameter, value) in lookup)
|
||||
{
|
||||
if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null)
|
||||
{
|
||||
parameter.Property.SetValue(settings, value);
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandPropertyBinder
|
||||
{
|
||||
internal static class CommandPropertyBinder
|
||||
public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver)
|
||||
{
|
||||
public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver)
|
||||
var settings = CreateSettings(resolver, settingsType);
|
||||
|
||||
foreach (var (parameter, value) in lookup)
|
||||
{
|
||||
var settings = CreateSettings(resolver, settingsType);
|
||||
|
||||
foreach (var (parameter, value) in lookup)
|
||||
if (value != default)
|
||||
{
|
||||
if (value != default)
|
||||
{
|
||||
parameter.Property.SetValue(settings, value);
|
||||
}
|
||||
parameter.Property.SetValue(settings, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the settings.
|
||||
var validationResult = settings.Validate();
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
throw CommandRuntimeException.ValidationFailed(validationResult);
|
||||
}
|
||||
// Validate the settings.
|
||||
var validationResult = settings.Validate();
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
throw CommandRuntimeException.ValidationFailed(validationResult);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType)
|
||||
{
|
||||
if (resolver.Resolve(settingsType) is CommandSettings settings)
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType)
|
||||
if (Activator.CreateInstance(settingsType) is CommandSettings instance)
|
||||
{
|
||||
if (resolver.Resolve(settingsType) is CommandSettings settings)
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
|
||||
if (Activator.CreateInstance(settingsType) is CommandSettings instance)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
throw CommandParseException.CouldNotCreateSettings(settingsType);
|
||||
return instance;
|
||||
}
|
||||
|
||||
throw CommandParseException.CouldNotCreateSettings(settingsType);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,118 +1,117 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class CommandValueBinder
|
||||
{
|
||||
internal sealed class CommandValueBinder
|
||||
private readonly CommandValueLookup _lookup;
|
||||
|
||||
public CommandValueBinder(CommandValueLookup lookup)
|
||||
{
|
||||
private readonly CommandValueLookup _lookup;
|
||||
_lookup = lookup;
|
||||
}
|
||||
|
||||
public CommandValueBinder(CommandValueLookup lookup)
|
||||
public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value)
|
||||
{
|
||||
if (parameter.ParameterKind == ParameterKind.Pair)
|
||||
{
|
||||
_lookup = lookup;
|
||||
value = GetLookup(parameter, resolver, value);
|
||||
}
|
||||
else if (parameter.ParameterKind == ParameterKind.Vector)
|
||||
{
|
||||
value = GetArray(parameter, value);
|
||||
}
|
||||
else if (parameter.ParameterKind == ParameterKind.FlagWithValue)
|
||||
{
|
||||
value = GetFlag(parameter, value);
|
||||
}
|
||||
|
||||
public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value)
|
||||
_lookup.SetValue(parameter, value);
|
||||
}
|
||||
|
||||
private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value)
|
||||
{
|
||||
var genericTypes = parameter.Property.PropertyType.GetGenericArguments();
|
||||
|
||||
var multimap = (IMultiMap?)_lookup.GetValue(parameter);
|
||||
if (multimap == null)
|
||||
{
|
||||
if (parameter.ParameterKind == ParameterKind.Pair)
|
||||
{
|
||||
value = GetLookup(parameter, resolver, value);
|
||||
}
|
||||
else if (parameter.ParameterKind == ParameterKind.Vector)
|
||||
{
|
||||
value = GetArray(parameter, value);
|
||||
}
|
||||
else if (parameter.ParameterKind == ParameterKind.FlagWithValue)
|
||||
{
|
||||
value = GetFlag(parameter, value);
|
||||
}
|
||||
|
||||
_lookup.SetValue(parameter, value);
|
||||
}
|
||||
|
||||
private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value)
|
||||
{
|
||||
var genericTypes = parameter.Property.PropertyType.GetGenericArguments();
|
||||
|
||||
var multimap = (IMultiMap?)_lookup.GetValue(parameter);
|
||||
multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap;
|
||||
if (multimap == null)
|
||||
{
|
||||
multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap;
|
||||
if (multimap == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not create multimap");
|
||||
}
|
||||
throw new InvalidOperationException("Could not create multimap");
|
||||
}
|
||||
|
||||
// Create deconstructor.
|
||||
var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor);
|
||||
if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor))
|
||||
{
|
||||
if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor))
|
||||
{
|
||||
throw new InvalidOperationException($"Could not create pair deconstructor.");
|
||||
}
|
||||
|
||||
deconstructor = activatedDeconstructor;
|
||||
}
|
||||
|
||||
// Deconstruct and add to multimap.
|
||||
var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string);
|
||||
if (pair.Key != null)
|
||||
{
|
||||
multimap.Add(pair);
|
||||
}
|
||||
|
||||
return multimap;
|
||||
}
|
||||
|
||||
private object GetArray(CommandParameter parameter, object? value)
|
||||
// Create deconstructor.
|
||||
var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor);
|
||||
if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor))
|
||||
{
|
||||
// Add a new item to the array
|
||||
var array = (Array?)_lookup.GetValue(parameter);
|
||||
Array newArray;
|
||||
|
||||
var elementType = parameter.Property.PropertyType.GetElementType();
|
||||
if (elementType == null)
|
||||
if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor))
|
||||
{
|
||||
throw new InvalidOperationException("Could not get property type.");
|
||||
throw new InvalidOperationException($"Could not create pair deconstructor.");
|
||||
}
|
||||
|
||||
if (array == null)
|
||||
{
|
||||
newArray = Array.CreateInstance(elementType, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
newArray = Array.CreateInstance(elementType, array.Length + 1);
|
||||
array.CopyTo(newArray, 0);
|
||||
}
|
||||
|
||||
newArray.SetValue(value, newArray.Length - 1);
|
||||
return newArray;
|
||||
deconstructor = activatedDeconstructor;
|
||||
}
|
||||
|
||||
private object GetFlag(CommandParameter parameter, object? value)
|
||||
// Deconstruct and add to multimap.
|
||||
var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string);
|
||||
if (pair.Key != null)
|
||||
{
|
||||
var flagValue = (IFlagValue?)_lookup.GetValue(parameter);
|
||||
multimap.Add(pair);
|
||||
}
|
||||
|
||||
return multimap;
|
||||
}
|
||||
|
||||
private object GetArray(CommandParameter parameter, object? value)
|
||||
{
|
||||
// Add a new item to the array
|
||||
var array = (Array?)_lookup.GetValue(parameter);
|
||||
Array newArray;
|
||||
|
||||
var elementType = parameter.Property.PropertyType.GetElementType();
|
||||
if (elementType == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not get property type.");
|
||||
}
|
||||
|
||||
if (array == null)
|
||||
{
|
||||
newArray = Array.CreateInstance(elementType, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
newArray = Array.CreateInstance(elementType, array.Length + 1);
|
||||
array.CopyTo(newArray, 0);
|
||||
}
|
||||
|
||||
newArray.SetValue(value, newArray.Length - 1);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private object GetFlag(CommandParameter parameter, object? value)
|
||||
{
|
||||
var flagValue = (IFlagValue?)_lookup.GetValue(parameter);
|
||||
if (flagValue == null)
|
||||
{
|
||||
flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType);
|
||||
if (flagValue == null)
|
||||
{
|
||||
flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType);
|
||||
if (flagValue == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not create flag value.");
|
||||
}
|
||||
throw new InvalidOperationException("Could not create flag value.");
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Null means set, but not with a valid value.
|
||||
flagValue.Value = value;
|
||||
}
|
||||
|
||||
// If the parameter was mapped, then it's set.
|
||||
flagValue.IsSet = true;
|
||||
|
||||
return flagValue;
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Null means set, but not with a valid value.
|
||||
flagValue.Value = value;
|
||||
}
|
||||
|
||||
// If the parameter was mapped, then it's set.
|
||||
flagValue.IsSet = true;
|
||||
|
||||
return flagValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,61 +3,60 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)>
|
||||
{
|
||||
internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)>
|
||||
private readonly Dictionary<Guid, (CommandParameter Parameter, object? Value)> _lookup;
|
||||
|
||||
public CommandValueLookup()
|
||||
{
|
||||
private readonly Dictionary<Guid, (CommandParameter Parameter, object? Value)> _lookup;
|
||||
_lookup = new Dictionary<Guid, (CommandParameter, object?)>();
|
||||
}
|
||||
|
||||
public CommandValueLookup()
|
||||
public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator()
|
||||
{
|
||||
foreach (var pair in _lookup)
|
||||
{
|
||||
_lookup = new Dictionary<Guid, (CommandParameter, object?)>();
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator()
|
||||
public bool HasParameterWithName(string? name)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
foreach (var pair in _lookup)
|
||||
{
|
||||
yield return pair.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasParameterWithName(string? name)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result)
|
||||
{
|
||||
if (HasParameterWithName(name))
|
||||
{
|
||||
result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public object? GetValue(CommandParameter parameter)
|
||||
{
|
||||
_lookup.TryGetValue(parameter.Id, out var result);
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
public void SetValue(CommandParameter parameter, object? value)
|
||||
{
|
||||
_lookup[parameter.Id] = (parameter, value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result)
|
||||
{
|
||||
if (HasParameterWithName(name))
|
||||
{
|
||||
result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public object? GetValue(CommandParameter parameter)
|
||||
{
|
||||
_lookup.TryGetValue(parameter.Id, out var result);
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
public void SetValue(CommandParameter parameter, object? value)
|
||||
{
|
||||
_lookup[parameter.Id] = (parameter, value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
@ -2,166 +2,165 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandValueResolver
|
||||
{
|
||||
internal static class CommandValueResolver
|
||||
public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver)
|
||||
{
|
||||
public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver)
|
||||
var lookup = new CommandValueLookup();
|
||||
var binder = new CommandValueBinder(lookup);
|
||||
|
||||
CommandValidator.ValidateRequiredParameters(tree);
|
||||
|
||||
while (tree != null)
|
||||
{
|
||||
var lookup = new CommandValueLookup();
|
||||
var binder = new CommandValueBinder(lookup);
|
||||
|
||||
CommandValidator.ValidateRequiredParameters(tree);
|
||||
|
||||
while (tree != null)
|
||||
// Process unmapped parameters.
|
||||
foreach (var parameter in tree.Unmapped)
|
||||
{
|
||||
// Process unmapped parameters.
|
||||
foreach (var parameter in tree.Unmapped)
|
||||
// Got a value provider?
|
||||
if (parameter.ValueProvider != null)
|
||||
{
|
||||
// Got a value provider?
|
||||
if (parameter.ValueProvider != null)
|
||||
var context = new CommandParameterContext(parameter, resolver, null);
|
||||
if (parameter.ValueProvider.TryGetValue(context, out var result))
|
||||
{
|
||||
var context = new CommandParameterContext(parameter, resolver, null);
|
||||
if (parameter.ValueProvider.TryGetValue(context, out var result))
|
||||
{
|
||||
result = ConvertValue(resolver, lookup, binder, parameter, result);
|
||||
result = ConvertValue(resolver, lookup, binder, parameter, result);
|
||||
|
||||
lookup.SetValue(parameter, result);
|
||||
CommandValidator.ValidateParameter(parameter, lookup, resolver);
|
||||
continue;
|
||||
}
|
||||
lookup.SetValue(parameter, result);
|
||||
CommandValidator.ValidateParameter(parameter, lookup, resolver);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parameter.IsFlagValue())
|
||||
{
|
||||
// Set the flag value to an empty, not set instance.
|
||||
var instance = Activator.CreateInstance(parameter.ParameterType);
|
||||
lookup.SetValue(parameter, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is this an option with a default value?
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
var value = parameter.DefaultValue?.Value;
|
||||
value = ConvertValue(resolver, lookup, binder, parameter, value);
|
||||
|
||||
binder.Bind(parameter, resolver, value);
|
||||
CommandValidator.ValidateParameter(parameter, lookup, resolver);
|
||||
}
|
||||
else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null ||
|
||||
!parameter.ParameterType.IsValueType)
|
||||
{
|
||||
lookup.SetValue(parameter, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process mapped parameters.
|
||||
foreach (var mapped in tree.Mapped)
|
||||
{
|
||||
if (mapped.Parameter.WantRawValue)
|
||||
{
|
||||
// Just try to assign the raw value.
|
||||
binder.Bind(mapped.Parameter, resolver, mapped.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mapped.Parameter.IsFlagValue() && mapped.Value == null)
|
||||
{
|
||||
if (mapped.Parameter is CommandOption option && option.DefaultValue != null)
|
||||
{
|
||||
// Set the default value.
|
||||
binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the flag but not the value.
|
||||
binder.Bind(mapped.Parameter, resolver, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var converter = GetConverter(lookup, binder, resolver, mapped.Parameter);
|
||||
if (converter == null)
|
||||
{
|
||||
throw CommandRuntimeException.NoConverterFound(mapped.Parameter);
|
||||
}
|
||||
|
||||
// Assign the value to the parameter.
|
||||
binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Got a value provider?
|
||||
if (mapped.Parameter.ValueProvider != null)
|
||||
{
|
||||
var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value);
|
||||
if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result))
|
||||
{
|
||||
lookup.SetValue(mapped.Parameter, result);
|
||||
}
|
||||
}
|
||||
|
||||
CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver);
|
||||
}
|
||||
|
||||
tree = tree.Next;
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result)
|
||||
{
|
||||
if (result != null && result.GetType() != parameter.ParameterType)
|
||||
{
|
||||
var converter = GetConverter(lookup, binder, resolver, parameter);
|
||||
if (converter != null)
|
||||
{
|
||||
result = converter.ConvertFrom(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")]
|
||||
private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter)
|
||||
{
|
||||
if (parameter.Converter == null)
|
||||
{
|
||||
if (parameter.ParameterType.IsArray)
|
||||
{
|
||||
// Return a converter for each array item (not the whole array)
|
||||
return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType());
|
||||
}
|
||||
|
||||
if (parameter.IsFlagValue())
|
||||
{
|
||||
// Is the optional value instanciated?
|
||||
var value = lookup.GetValue(parameter) as IFlagValue;
|
||||
if (value == null)
|
||||
{
|
||||
// Try to assign it with a null value.
|
||||
// This will create the optional value instance without a value.
|
||||
binder.Bind(parameter, resolver, null);
|
||||
value = lookup.GetValue(parameter) as IFlagValue;
|
||||
if (value == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not intialize optional value.");
|
||||
}
|
||||
}
|
||||
|
||||
// Return a converter for the flag element type.
|
||||
return TypeDescriptor.GetConverter(value.Type);
|
||||
// Set the flag value to an empty, not set instance.
|
||||
var instance = Activator.CreateInstance(parameter.ParameterType);
|
||||
lookup.SetValue(parameter, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is this an option with a default value?
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
var value = parameter.DefaultValue?.Value;
|
||||
value = ConvertValue(resolver, lookup, binder, parameter, value);
|
||||
|
||||
return TypeDescriptor.GetConverter(parameter.ParameterType);
|
||||
binder.Bind(parameter, resolver, value);
|
||||
CommandValidator.ValidateParameter(parameter, lookup, resolver);
|
||||
}
|
||||
else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null ||
|
||||
!parameter.ParameterType.IsValueType)
|
||||
{
|
||||
lookup.SetValue(parameter, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var type = Type.GetType(parameter.Converter.ConverterTypeName);
|
||||
return resolver.Resolve(type) as TypeConverter;
|
||||
// Process mapped parameters.
|
||||
foreach (var mapped in tree.Mapped)
|
||||
{
|
||||
if (mapped.Parameter.WantRawValue)
|
||||
{
|
||||
// Just try to assign the raw value.
|
||||
binder.Bind(mapped.Parameter, resolver, mapped.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mapped.Parameter.IsFlagValue() && mapped.Value == null)
|
||||
{
|
||||
if (mapped.Parameter is CommandOption option && option.DefaultValue != null)
|
||||
{
|
||||
// Set the default value.
|
||||
binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the flag but not the value.
|
||||
binder.Bind(mapped.Parameter, resolver, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var converter = GetConverter(lookup, binder, resolver, mapped.Parameter);
|
||||
if (converter == null)
|
||||
{
|
||||
throw CommandRuntimeException.NoConverterFound(mapped.Parameter);
|
||||
}
|
||||
|
||||
// Assign the value to the parameter.
|
||||
binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value));
|
||||
}
|
||||
}
|
||||
|
||||
// Got a value provider?
|
||||
if (mapped.Parameter.ValueProvider != null)
|
||||
{
|
||||
var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value);
|
||||
if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result))
|
||||
{
|
||||
lookup.SetValue(mapped.Parameter, result);
|
||||
}
|
||||
}
|
||||
|
||||
CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver);
|
||||
}
|
||||
|
||||
tree = tree.Next;
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result)
|
||||
{
|
||||
if (result != null && result.GetType() != parameter.ParameterType)
|
||||
{
|
||||
var converter = GetConverter(lookup, binder, resolver, parameter);
|
||||
if (converter != null)
|
||||
{
|
||||
result = converter.ConvertFrom(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")]
|
||||
private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter)
|
||||
{
|
||||
if (parameter.Converter == null)
|
||||
{
|
||||
if (parameter.ParameterType.IsArray)
|
||||
{
|
||||
// Return a converter for each array item (not the whole array)
|
||||
return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType());
|
||||
}
|
||||
|
||||
if (parameter.IsFlagValue())
|
||||
{
|
||||
// Is the optional value instanciated?
|
||||
var value = lookup.GetValue(parameter) as IFlagValue;
|
||||
if (value == null)
|
||||
{
|
||||
// Try to assign it with a null value.
|
||||
// This will create the optional value instance without a value.
|
||||
binder.Bind(parameter, resolver, null);
|
||||
value = lookup.GetValue(parameter) as IFlagValue;
|
||||
if (value == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not intialize optional value.");
|
||||
}
|
||||
}
|
||||
|
||||
// Return a converter for the flag element type.
|
||||
return TypeDescriptor.GetConverter(value.Type);
|
||||
}
|
||||
|
||||
return TypeDescriptor.GetConverter(parameter.ParameterType);
|
||||
}
|
||||
|
||||
var type = Type.GetType(parameter.Converter.ConverterTypeName);
|
||||
return resolver.Resolve(type) as TypeConverter;
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Representation of a multi map.
|
||||
/// </summary>
|
||||
internal interface IMultiMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Representation of a multi map.
|
||||
/// Adds a key and a value to the multi map.
|
||||
/// </summary>
|
||||
internal interface IMultiMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a key and a value to the multi map.
|
||||
/// </summary>
|
||||
/// <param name="pair">The pair to add.</param>
|
||||
void Add((object? Key, object? Value) pair);
|
||||
}
|
||||
}
|
||||
/// <param name="pair">The pair to add.</param>
|
||||
void Add((object? Key, object? Value) pair);
|
||||
}
|
@ -4,172 +4,171 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class MultiMap<TKey, TValue> : IMultiMap, ILookup<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
|
||||
where TKey : notnull
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class MultiMap<TKey, TValue> : IMultiMap, ILookup<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
|
||||
where TKey : notnull
|
||||
private readonly IDictionary<TKey, MultiMapGrouping> _lookup;
|
||||
private readonly IDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
public int Count => _lookup.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public ICollection<TKey> Keys => _lookup.Keys;
|
||||
|
||||
public ICollection<TValue> Values => _dictionary.Values;
|
||||
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _lookup.Keys;
|
||||
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values;
|
||||
|
||||
TValue IReadOnlyDictionary<TKey, TValue>.this[TKey key] => _dictionary[key];
|
||||
|
||||
TValue IDictionary<TKey, TValue>.this[TKey key]
|
||||
{
|
||||
private readonly IDictionary<TKey, MultiMapGrouping> _lookup;
|
||||
private readonly IDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
public int Count => _lookup.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public ICollection<TKey> Keys => _lookup.Keys;
|
||||
|
||||
public ICollection<TValue> Values => _dictionary.Values;
|
||||
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _lookup.Keys;
|
||||
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values;
|
||||
|
||||
TValue IReadOnlyDictionary<TKey, TValue>.this[TKey key] => _dictionary[key];
|
||||
|
||||
TValue IDictionary<TKey, TValue>.this[TKey key]
|
||||
get
|
||||
{
|
||||
get
|
||||
return _dictionary[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TValue> this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lookup.TryGetValue(key, out var group))
|
||||
{
|
||||
return _dictionary[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
Add(key, value);
|
||||
return group;
|
||||
}
|
||||
|
||||
return Array.Empty<TValue>();
|
||||
}
|
||||
}
|
||||
|
||||
public MultiMap()
|
||||
{
|
||||
_lookup = new Dictionary<TKey, MultiMapGrouping>();
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
private sealed class MultiMapGrouping : IGrouping<TKey, TValue>
|
||||
{
|
||||
private readonly List<TValue> _items;
|
||||
|
||||
public TKey Key { get; }
|
||||
|
||||
public MultiMapGrouping(TKey key, List<TValue> items)
|
||||
{
|
||||
Key = key;
|
||||
_items = items;
|
||||
}
|
||||
|
||||
public IEnumerable<TValue> this[TKey key]
|
||||
public void Add(TValue value)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lookup.TryGetValue(key, out var group))
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
return Array.Empty<TValue>();
|
||||
}
|
||||
_items.Add(value);
|
||||
}
|
||||
|
||||
public MultiMap()
|
||||
public IEnumerator<TValue> GetEnumerator()
|
||||
{
|
||||
_lookup = new Dictionary<TKey, MultiMapGrouping>();
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
private sealed class MultiMapGrouping : IGrouping<TKey, TValue>
|
||||
{
|
||||
private readonly List<TValue> _items;
|
||||
|
||||
public TKey Key { get; }
|
||||
|
||||
public MultiMapGrouping(TKey key, List<TValue> items)
|
||||
{
|
||||
Key = key;
|
||||
_items = items;
|
||||
}
|
||||
|
||||
public void Add(TValue value)
|
||||
{
|
||||
_items.Add(value);
|
||||
}
|
||||
|
||||
public IEnumerator<TValue> GetEnumerator()
|
||||
{
|
||||
return _items.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
return _lookup.ContainsKey(key);
|
||||
}
|
||||
|
||||
public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
foreach (var group in _lookup.Values)
|
||||
{
|
||||
yield return group;
|
||||
}
|
||||
return _items.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
return _lookup.ContainsKey(key);
|
||||
}
|
||||
|
||||
public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
foreach (var group in _lookup.Values)
|
||||
{
|
||||
if (!_lookup.ContainsKey(key))
|
||||
{
|
||||
_lookup[key] = new MultiMapGrouping(key, new List<TValue>());
|
||||
}
|
||||
|
||||
_lookup[key].Add(value);
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return Contains(key);
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
return _lookup.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_lookup.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Contains(item.Key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
_dictionary.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Remove(item.Key);
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
return _dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add((object? Key, object? Value) pair)
|
||||
{
|
||||
if (pair.Key != null)
|
||||
{
|
||||
#pragma warning disable CS8604 // Possible null reference argument of value.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
Add((TKey)pair.Key, (TValue)pair.Value);
|
||||
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning restore CS8604 // Possible null reference argument of value.
|
||||
}
|
||||
yield return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
if (!_lookup.ContainsKey(key))
|
||||
{
|
||||
_lookup[key] = new MultiMapGrouping(key, new List<TValue>());
|
||||
}
|
||||
|
||||
_lookup[key].Add(value);
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return Contains(key);
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
return _lookup.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_lookup.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Contains(item.Key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
_dictionary.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Remove(item.Key);
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
return _dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add((object? Key, object? Value) pair)
|
||||
{
|
||||
if (pair.Key != null)
|
||||
{
|
||||
#pragma warning disable CS8604 // Possible null reference argument of value.
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
Add((TKey)pair.Key, (TValue)pair.Value);
|
||||
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning restore CS8604 // Possible null reference argument of value.
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
internal static class CommandBinder
|
||||
{
|
||||
public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver)
|
||||
{
|
||||
var lookup = CommandValueResolver.GetParameterValues(tree, resolver);
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
// Got a constructor with at least one name corresponding to a settings?
|
||||
foreach (var constructor in settingsType.GetConstructors())
|
||||
internal static class CommandBinder
|
||||
{
|
||||
public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver)
|
||||
{
|
||||
var lookup = CommandValueResolver.GetParameterValues(tree, resolver);
|
||||
|
||||
// Got a constructor with at least one name corresponding to a settings?
|
||||
foreach (var constructor in settingsType.GetConstructors())
|
||||
{
|
||||
var parameters = constructor.GetParameters();
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
var parameters = constructor.GetParameters();
|
||||
if (parameters.Length > 0)
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
if (lookup.HasParameterWithName(parameter?.Name))
|
||||
{
|
||||
if (lookup.HasParameterWithName(parameter?.Name))
|
||||
{
|
||||
// Use constructor injection.
|
||||
return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver);
|
||||
}
|
||||
// Use constructor injection.
|
||||
return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver);
|
||||
}
|
||||
|
||||
return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,115 +4,114 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
internal sealed class CommandExecutor
|
||||
{
|
||||
private readonly ITypeRegistrar _registrar;
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
public CommandExecutor(ITypeRegistrar registrar)
|
||||
internal sealed class CommandExecutor
|
||||
{
|
||||
private readonly ITypeRegistrar _registrar;
|
||||
|
||||
public CommandExecutor(ITypeRegistrar registrar)
|
||||
{
|
||||
_registrar = registrar ?? throw new ArgumentNullException(nameof(registrar));
|
||||
_registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor));
|
||||
}
|
||||
|
||||
public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
_registrar = registrar ?? throw new ArgumentNullException(nameof(registrar));
|
||||
_registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor));
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args)
|
||||
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
||||
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
||||
|
||||
// Create the command model.
|
||||
var model = CommandModelBuilder.Build(configuration);
|
||||
_registrar.RegisterInstance(typeof(CommandModel), model);
|
||||
_registrar.RegisterDependencies(model);
|
||||
|
||||
// No default command?
|
||||
if (model.DefaultCommand == null)
|
||||
{
|
||||
if (configuration == null)
|
||||
// Got at least one argument?
|
||||
var firstArgument = args.FirstOrDefault();
|
||||
if (firstArgument != null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
||||
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
||||
|
||||
// Create the command model.
|
||||
var model = CommandModelBuilder.Build(configuration);
|
||||
_registrar.RegisterInstance(typeof(CommandModel), model);
|
||||
_registrar.RegisterDependencies(model);
|
||||
|
||||
// No default command?
|
||||
if (model.DefaultCommand == null)
|
||||
{
|
||||
// Got at least one argument?
|
||||
var firstArgument = args.FirstOrDefault();
|
||||
if (firstArgument != null)
|
||||
// Asking for version? Kind of a hack, but it's alright.
|
||||
// We should probably make this a bit better in the future.
|
||||
if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) ||
|
||||
firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Asking for version? Kind of a hack, but it's alright.
|
||||
// We should probably make this a bit better in the future.
|
||||
if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) ||
|
||||
firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var console = configuration.Settings.Console.GetConsole();
|
||||
console.WriteLine(ResolveApplicationVersion(configuration));
|
||||
return 0;
|
||||
}
|
||||
var console = configuration.Settings.Console.GetConsole();
|
||||
console.WriteLine(ResolveApplicationVersion(configuration));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse and map the model against the arguments.
|
||||
var parser = new CommandTreeParser(model, configuration.Settings);
|
||||
var parsedResult = parser.Parse(args);
|
||||
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
|
||||
|
||||
// Currently the root?
|
||||
if (parsedResult.Tree == null)
|
||||
{
|
||||
// Display help.
|
||||
configuration.Settings.Console.SafeRender(HelpWriter.Write(model));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the command to execute.
|
||||
var leaf = parsedResult.Tree.GetLeafCommand();
|
||||
if (leaf.Command.IsBranch || leaf.ShowHelp)
|
||||
{
|
||||
// Branches can't be executed. Show help.
|
||||
configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command));
|
||||
return leaf.ShowHelp ? 0 : 1;
|
||||
}
|
||||
|
||||
// Register the arguments with the container.
|
||||
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
|
||||
|
||||
// Create the resolver and the context.
|
||||
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
|
||||
{
|
||||
var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data);
|
||||
|
||||
// Execute the command tree.
|
||||
return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveApplicationVersion(IConfiguration configuration)
|
||||
// Parse and map the model against the arguments.
|
||||
var parser = new CommandTreeParser(model, configuration.Settings);
|
||||
var parsedResult = parser.Parse(args);
|
||||
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
|
||||
|
||||
// Currently the root?
|
||||
if (parsedResult.Tree == null)
|
||||
{
|
||||
return
|
||||
configuration.Settings.ApplicationVersion ?? // potential override
|
||||
VersionHelper.GetVersion(Assembly.GetEntryAssembly());
|
||||
// Display help.
|
||||
configuration.Settings.Console.SafeRender(HelpWriter.Write(model));
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Task<int> Execute(
|
||||
CommandTree leaf,
|
||||
CommandTree tree,
|
||||
CommandContext context,
|
||||
ITypeResolver resolver,
|
||||
IConfiguration configuration)
|
||||
// Get the command to execute.
|
||||
var leaf = parsedResult.Tree.GetLeafCommand();
|
||||
if (leaf.Command.IsBranch || leaf.ShowHelp)
|
||||
{
|
||||
// Bind the command tree against the settings.
|
||||
var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver);
|
||||
configuration.Settings.Interceptor?.Intercept(context, settings);
|
||||
// Branches can't be executed. Show help.
|
||||
configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command));
|
||||
return leaf.ShowHelp ? 0 : 1;
|
||||
}
|
||||
|
||||
// Create and validate the command.
|
||||
var command = leaf.CreateCommand(resolver);
|
||||
var validationResult = command.Validate(context, settings);
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
throw CommandRuntimeException.ValidationFailed(validationResult);
|
||||
}
|
||||
// Register the arguments with the container.
|
||||
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
|
||||
|
||||
// Execute the command.
|
||||
return command.Execute(context, settings);
|
||||
// Create the resolver and the context.
|
||||
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
|
||||
{
|
||||
var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data);
|
||||
|
||||
// Execute the command tree.
|
||||
return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveApplicationVersion(IConfiguration configuration)
|
||||
{
|
||||
return
|
||||
configuration.Settings.ApplicationVersion ?? // potential override
|
||||
VersionHelper.GetVersion(Assembly.GetEntryAssembly());
|
||||
}
|
||||
|
||||
private static Task<int> Execute(
|
||||
CommandTree leaf,
|
||||
CommandTree tree,
|
||||
CommandContext context,
|
||||
ITypeResolver resolver,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
// Bind the command tree against the settings.
|
||||
var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver);
|
||||
configuration.Settings.Interceptor?.Intercept(context, settings);
|
||||
|
||||
// Create and validate the command.
|
||||
var command = leaf.CreateCommand(resolver);
|
||||
var validationResult = command.Validate(context, settings);
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
throw CommandRuntimeException.ValidationFailed(validationResult);
|
||||
}
|
||||
|
||||
// Execute the command.
|
||||
return command.Execute(context, settings);
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal enum CommandPart
|
||||
{
|
||||
internal enum CommandPart
|
||||
{
|
||||
CommandName,
|
||||
LongOption,
|
||||
}
|
||||
}
|
||||
CommandName,
|
||||
LongOption,
|
||||
}
|
@ -1,77 +1,76 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandSuggestor
|
||||
{
|
||||
internal static class CommandSuggestor
|
||||
private const float SmallestDistance = 2f;
|
||||
|
||||
public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name)
|
||||
{
|
||||
private const float SmallestDistance = 2f;
|
||||
var result = (CommandInfo?)null;
|
||||
|
||||
public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name)
|
||||
var container = command ?? (ICommandContainer)model;
|
||||
if (command?.IsDefaultCommand ?? false)
|
||||
{
|
||||
var result = (CommandInfo?)null;
|
||||
|
||||
var container = command ?? (ICommandContainer)model;
|
||||
if (command?.IsDefaultCommand ?? false)
|
||||
{
|
||||
// Default commands have no children,
|
||||
// so use the root commands here.
|
||||
container = model;
|
||||
}
|
||||
|
||||
var score = float.MaxValue;
|
||||
foreach (var child in container.Commands.Where(x => !x.IsHidden))
|
||||
{
|
||||
var temp = Score(child.Name, name);
|
||||
if (temp < score)
|
||||
{
|
||||
score = temp;
|
||||
result = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (score <= SmallestDistance)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
// Default commands have no children,
|
||||
// so use the root commands here.
|
||||
container = model;
|
||||
}
|
||||
|
||||
private static float Score(string source, string target)
|
||||
var score = float.MaxValue;
|
||||
foreach (var child in container.Commands.Where(x => !x.IsHidden))
|
||||
{
|
||||
source = source.ToUpperInvariant();
|
||||
target = target.ToUpperInvariant();
|
||||
|
||||
var n = source.Length;
|
||||
var m = target.Length;
|
||||
|
||||
if (n == 0)
|
||||
var temp = Score(child.Name, name);
|
||||
if (temp < score)
|
||||
{
|
||||
return m;
|
||||
score = temp;
|
||||
result = child;
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
var d = new int[n + 1, m + 1];
|
||||
Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i);
|
||||
Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i);
|
||||
|
||||
for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++)
|
||||
{
|
||||
for (var targetIndex = 1; targetIndex <= m; targetIndex++)
|
||||
{
|
||||
var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1;
|
||||
d[sourceIndex, targetIndex] = Math.Min(
|
||||
Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1),
|
||||
d[sourceIndex - 1, targetIndex - 1] + cost);
|
||||
}
|
||||
}
|
||||
|
||||
return d[n, m];
|
||||
}
|
||||
|
||||
if (score <= SmallestDistance)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static float Score(string source, string target)
|
||||
{
|
||||
source = source.ToUpperInvariant();
|
||||
target = target.ToUpperInvariant();
|
||||
|
||||
var n = source.Length;
|
||||
var m = target.Length;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
var d = new int[n + 1, m + 1];
|
||||
Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i);
|
||||
Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i);
|
||||
|
||||
for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++)
|
||||
{
|
||||
for (var targetIndex = 1; targetIndex <= m; targetIndex++)
|
||||
{
|
||||
var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1;
|
||||
d[sourceIndex, targetIndex] = Math.Min(
|
||||
Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1),
|
||||
d[sourceIndex - 1, targetIndex - 1] + cost);
|
||||
}
|
||||
}
|
||||
|
||||
return d[n, m];
|
||||
}
|
||||
}
|
@ -1,46 +1,45 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandValidator
|
||||
{
|
||||
internal static class CommandValidator
|
||||
public static void ValidateRequiredParameters(CommandTree? tree)
|
||||
{
|
||||
public static void ValidateRequiredParameters(CommandTree? tree)
|
||||
var node = tree?.GetRootCommand();
|
||||
while (node != null)
|
||||
{
|
||||
var node = tree?.GetRootCommand();
|
||||
while (node != null)
|
||||
foreach (var parameter in node.Unmapped)
|
||||
{
|
||||
foreach (var parameter in node.Unmapped)
|
||||
if (parameter.Required)
|
||||
{
|
||||
if (parameter.Required)
|
||||
switch (parameter)
|
||||
{
|
||||
switch (parameter)
|
||||
{
|
||||
case CommandArgument argument:
|
||||
throw CommandRuntimeException.MissingRequiredArgument(node, argument);
|
||||
}
|
||||
case CommandArgument argument:
|
||||
throw CommandRuntimeException.MissingRequiredArgument(node, argument);
|
||||
}
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver)
|
||||
public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver)
|
||||
{
|
||||
var assignedValue = settings.GetValue(parameter);
|
||||
foreach (var validator in parameter.Validators)
|
||||
{
|
||||
var assignedValue = settings.GetValue(parameter);
|
||||
foreach (var validator in parameter.Validators)
|
||||
var context = new CommandParameterContext(parameter, resolver, assignedValue);
|
||||
var validationResult = validator.Validate(context);
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
var context = new CommandParameterContext(parameter, resolver, assignedValue);
|
||||
var validationResult = validator.Validate(context);
|
||||
if (!validationResult.Successful)
|
||||
{
|
||||
// If there is an error message specified in the parameter validator attribute,
|
||||
// then use that one, otherwise use the validation result.
|
||||
var result = string.IsNullOrWhiteSpace(validator.ErrorMessage)
|
||||
? validationResult
|
||||
: ValidationResult.Error(validator.ErrorMessage);
|
||||
// If there is an error message specified in the parameter validator attribute,
|
||||
// then use that one, otherwise use the validation result.
|
||||
var result = string.IsNullOrWhiteSpace(validator.ErrorMessage)
|
||||
? validationResult
|
||||
: ValidationResult.Error(validator.ErrorMessage);
|
||||
|
||||
throw CommandRuntimeException.ValidationFailed(result);
|
||||
}
|
||||
throw CommandRuntimeException.ValidationFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,272 +1,271 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
[Description("Displays diagnostics about CLI configurations")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class ExplainCommand : Command<ExplainCommand.Settings>
|
||||
{
|
||||
[Description("Displays diagnostics about CLI configurations")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class ExplainCommand : Command<ExplainCommand.Settings>
|
||||
private readonly CommandModel _commandModel;
|
||||
private readonly IAnsiConsole _writer;
|
||||
|
||||
public ExplainCommand(IConfiguration configuration, CommandModel commandModel)
|
||||
{
|
||||
private readonly CommandModel _commandModel;
|
||||
private readonly IAnsiConsole _writer;
|
||||
_commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel));
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
}
|
||||
|
||||
public ExplainCommand(IConfiguration configuration, CommandModel commandModel)
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
public Settings(string[]? commands, bool? detailed, bool includeHidden)
|
||||
{
|
||||
_commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel));
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
Commands = commands;
|
||||
Detailed = detailed;
|
||||
IncludeHidden = includeHidden;
|
||||
}
|
||||
|
||||
public sealed class Settings : CommandSettings
|
||||
[CommandArgument(0, "[command]")]
|
||||
public string[]? Commands { get; }
|
||||
|
||||
[Description("Include detailed information about the commands.")]
|
||||
[CommandOption("-d|--detailed")]
|
||||
public bool? Detailed { get; }
|
||||
|
||||
[Description("Include hidden commands and options.")]
|
||||
[CommandOption("--hidden")]
|
||||
public bool IncludeHidden { get; }
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
{
|
||||
var tree = new Tree("CLI Configuration");
|
||||
tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name"));
|
||||
tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString()));
|
||||
|
||||
if (settings.Commands == null || settings.Commands.Length == 0)
|
||||
{
|
||||
public Settings(string[]? commands, bool? detailed, bool includeHidden)
|
||||
{
|
||||
Commands = commands;
|
||||
Detailed = detailed;
|
||||
IncludeHidden = includeHidden;
|
||||
}
|
||||
// If there is a default command we'll want to include it in the list too.
|
||||
var commands = _commandModel.DefaultCommand != null
|
||||
? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands)
|
||||
: _commandModel.Commands;
|
||||
|
||||
[CommandArgument(0, "[command]")]
|
||||
public string[]? Commands { get; }
|
||||
|
||||
[Description("Include detailed information about the commands.")]
|
||||
[CommandOption("-d|--detailed")]
|
||||
public bool? Detailed { get; }
|
||||
|
||||
[Description("Include hidden commands and options.")]
|
||||
[CommandOption("--hidden")]
|
||||
public bool IncludeHidden { get; }
|
||||
AddCommands(
|
||||
tree.AddNode(ParentMarkup("Commands")),
|
||||
commands,
|
||||
settings.Detailed ?? false,
|
||||
settings.IncludeHidden);
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
else
|
||||
{
|
||||
var tree = new Tree("CLI Configuration");
|
||||
tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name"));
|
||||
tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString()));
|
||||
|
||||
if (settings.Commands == null || settings.Commands.Length == 0)
|
||||
var currentCommandTier = _commandModel.Commands;
|
||||
CommandInfo? currentCommand = null;
|
||||
foreach (var command in settings.Commands)
|
||||
{
|
||||
// If there is a default command we'll want to include it in the list too.
|
||||
var commands = _commandModel.DefaultCommand != null
|
||||
? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands)
|
||||
: _commandModel.Commands;
|
||||
|
||||
AddCommands(
|
||||
tree.AddNode(ParentMarkup("Commands")),
|
||||
commands,
|
||||
settings.Detailed ?? false,
|
||||
settings.IncludeHidden);
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentCommandTier = _commandModel.Commands;
|
||||
CommandInfo? currentCommand = null;
|
||||
foreach (var command in settings.Commands)
|
||||
{
|
||||
currentCommand = currentCommandTier
|
||||
.SingleOrDefault(i =>
|
||||
i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) ||
|
||||
i.Aliases
|
||||
.Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase)));
|
||||
|
||||
if (currentCommand == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
currentCommandTier = currentCommand.Children;
|
||||
}
|
||||
currentCommand = currentCommandTier
|
||||
.SingleOrDefault(i =>
|
||||
i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) ||
|
||||
i.Aliases
|
||||
.Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase)));
|
||||
|
||||
if (currentCommand == null)
|
||||
{
|
||||
throw new Exception($"Command {string.Join(" ", settings.Commands)} not found");
|
||||
break;
|
||||
}
|
||||
|
||||
AddCommands(
|
||||
tree.AddNode(ParentMarkup("Commands")),
|
||||
new[] { currentCommand },
|
||||
settings.Detailed ?? true,
|
||||
settings.IncludeHidden);
|
||||
currentCommandTier = currentCommand.Children;
|
||||
}
|
||||
|
||||
_writer.Write(tree);
|
||||
if (currentCommand == null)
|
||||
{
|
||||
throw new Exception($"Command {string.Join(" ", settings.Commands)} not found");
|
||||
}
|
||||
|
||||
return 0;
|
||||
AddCommands(
|
||||
tree.AddNode(ParentMarkup("Commands")),
|
||||
new[] { currentCommand },
|
||||
settings.Detailed ?? true,
|
||||
settings.IncludeHidden);
|
||||
}
|
||||
|
||||
private IRenderable ValueMarkup(string key, string value)
|
||||
_writer.Write(tree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private IRenderable ValueMarkup(string key, string value)
|
||||
{
|
||||
return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]");
|
||||
}
|
||||
|
||||
private IRenderable ValueMarkup(string key, string? value, string noValueText)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]");
|
||||
return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]");
|
||||
}
|
||||
|
||||
private IRenderable ValueMarkup(string key, string? value, string noValueText)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]");
|
||||
}
|
||||
var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value");
|
||||
table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]");
|
||||
return table;
|
||||
}
|
||||
|
||||
var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value");
|
||||
table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]");
|
||||
return table;
|
||||
private string ParentMarkup(string description)
|
||||
{
|
||||
return $"[yellow]{description.EscapeMarkup()}[/]";
|
||||
}
|
||||
|
||||
private void AddStringList(TreeNode node, string description, IList<string>? strings)
|
||||
{
|
||||
if (strings == null || strings.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private string ParentMarkup(string description)
|
||||
var parentNode = node.AddNode(ParentMarkup(description));
|
||||
foreach (var s in strings)
|
||||
{
|
||||
return $"[yellow]{description.EscapeMarkup()}[/]";
|
||||
}
|
||||
|
||||
private void AddStringList(TreeNode node, string description, IList<string>? strings)
|
||||
{
|
||||
if (strings == null || strings.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parentNode = node.AddNode(ParentMarkup(description));
|
||||
foreach (var s in strings)
|
||||
{
|
||||
parentNode.AddNode(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCommands(TreeNode node, IEnumerable<CommandInfo> commands, bool detailed, bool includeHidden)
|
||||
{
|
||||
foreach (var command in commands)
|
||||
{
|
||||
if (!includeHidden && command.IsHidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var commandName = $"[green]{command.Name}[/]";
|
||||
if (command.IsDefaultCommand)
|
||||
{
|
||||
commandName += " (default)";
|
||||
}
|
||||
|
||||
var commandNode = node.AddNode(commandName);
|
||||
commandNode.AddNode(ValueMarkup("Description", command.Description, "no description"));
|
||||
if (command.IsHidden)
|
||||
{
|
||||
commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString()));
|
||||
}
|
||||
|
||||
if (!command.IsBranch)
|
||||
{
|
||||
commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type"));
|
||||
commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString()));
|
||||
}
|
||||
|
||||
if (command.Parameters.Count > 0)
|
||||
{
|
||||
var parametersNode = commandNode.AddNode(ParentMarkup("Parameters"));
|
||||
foreach (var parameter in command.Parameters)
|
||||
{
|
||||
AddParameter(parametersNode, parameter, detailed, includeHidden);
|
||||
}
|
||||
}
|
||||
|
||||
AddStringList(commandNode, "Aliases", command.Aliases.ToList());
|
||||
AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList());
|
||||
|
||||
if (command.Children.Count > 0)
|
||||
{
|
||||
var childNode = commandNode.AddNode(ParentMarkup("Child Commands"));
|
||||
AddCommands(childNode, command.Children, detailed, includeHidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden)
|
||||
{
|
||||
if (!includeHidden && parameter.IsHidden)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!detailed)
|
||||
{
|
||||
parametersNode.AddNode(
|
||||
$"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var parameterNode = parametersNode.AddNode(
|
||||
$"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]");
|
||||
|
||||
parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description"));
|
||||
parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString()));
|
||||
|
||||
if (parameter is CommandOption commandOptionParameter)
|
||||
{
|
||||
if (commandOptionParameter.IsShadowed)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString()));
|
||||
}
|
||||
|
||||
if (commandOptionParameter.LongNames.Count > 0)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Long Names",
|
||||
string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}"))));
|
||||
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Short Names",
|
||||
string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}"))));
|
||||
}
|
||||
}
|
||||
else if (parameter is CommandArgument commandArgumentParameter)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString()));
|
||||
parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value));
|
||||
}
|
||||
|
||||
parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString()));
|
||||
|
||||
if (parameter.Converter != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Converter", $"\"{parameter.Converter.ConverterTypeName}\""));
|
||||
}
|
||||
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Default Value", $"\"{parameter.DefaultValue.Value}\""));
|
||||
}
|
||||
|
||||
if (parameter.PairDeconstructor != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString()));
|
||||
}
|
||||
|
||||
AddStringList(
|
||||
parameterNode,
|
||||
"Validators",
|
||||
parameter.Validators.Select(i => i.GetType().ToString()).ToList());
|
||||
}
|
||||
|
||||
private static string GetShortOptions(CommandParameter parameter)
|
||||
{
|
||||
if (parameter is CommandOption commandOptionParameter)
|
||||
{
|
||||
return string.Join(
|
||||
" | ",
|
||||
commandOptionParameter.LongNames.Select(i => $"--{i}")
|
||||
.Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}")));
|
||||
}
|
||||
|
||||
if (parameter is CommandArgument commandArgumentParameter)
|
||||
{
|
||||
return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
parentNode.AddNode(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCommands(TreeNode node, IEnumerable<CommandInfo> commands, bool detailed, bool includeHidden)
|
||||
{
|
||||
foreach (var command in commands)
|
||||
{
|
||||
if (!includeHidden && command.IsHidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var commandName = $"[green]{command.Name}[/]";
|
||||
if (command.IsDefaultCommand)
|
||||
{
|
||||
commandName += " (default)";
|
||||
}
|
||||
|
||||
var commandNode = node.AddNode(commandName);
|
||||
commandNode.AddNode(ValueMarkup("Description", command.Description, "no description"));
|
||||
if (command.IsHidden)
|
||||
{
|
||||
commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString()));
|
||||
}
|
||||
|
||||
if (!command.IsBranch)
|
||||
{
|
||||
commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type"));
|
||||
commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString()));
|
||||
}
|
||||
|
||||
if (command.Parameters.Count > 0)
|
||||
{
|
||||
var parametersNode = commandNode.AddNode(ParentMarkup("Parameters"));
|
||||
foreach (var parameter in command.Parameters)
|
||||
{
|
||||
AddParameter(parametersNode, parameter, detailed, includeHidden);
|
||||
}
|
||||
}
|
||||
|
||||
AddStringList(commandNode, "Aliases", command.Aliases.ToList());
|
||||
AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList());
|
||||
|
||||
if (command.Children.Count > 0)
|
||||
{
|
||||
var childNode = commandNode.AddNode(ParentMarkup("Child Commands"));
|
||||
AddCommands(childNode, command.Children, detailed, includeHidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden)
|
||||
{
|
||||
if (!includeHidden && parameter.IsHidden)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!detailed)
|
||||
{
|
||||
parametersNode.AddNode(
|
||||
$"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var parameterNode = parametersNode.AddNode(
|
||||
$"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]");
|
||||
|
||||
parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description"));
|
||||
parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString()));
|
||||
|
||||
if (parameter is CommandOption commandOptionParameter)
|
||||
{
|
||||
if (commandOptionParameter.IsShadowed)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString()));
|
||||
}
|
||||
|
||||
if (commandOptionParameter.LongNames.Count > 0)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Long Names",
|
||||
string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}"))));
|
||||
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Short Names",
|
||||
string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}"))));
|
||||
}
|
||||
}
|
||||
else if (parameter is CommandArgument commandArgumentParameter)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString()));
|
||||
parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value));
|
||||
}
|
||||
|
||||
parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString()));
|
||||
|
||||
if (parameter.Converter != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Converter", $"\"{parameter.Converter.ConverterTypeName}\""));
|
||||
}
|
||||
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup(
|
||||
"Default Value", $"\"{parameter.DefaultValue.Value}\""));
|
||||
}
|
||||
|
||||
if (parameter.PairDeconstructor != null)
|
||||
{
|
||||
parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString()));
|
||||
}
|
||||
|
||||
AddStringList(
|
||||
parameterNode,
|
||||
"Validators",
|
||||
parameter.Validators.Select(i => i.GetType().ToString()).ToList());
|
||||
}
|
||||
|
||||
private static string GetShortOptions(CommandParameter parameter)
|
||||
{
|
||||
if (parameter is CommandOption commandOptionParameter)
|
||||
{
|
||||
return string.Join(
|
||||
" | ",
|
||||
commandOptionParameter.LongNames.Select(i => $"--{i}")
|
||||
.Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}")));
|
||||
}
|
||||
|
||||
if (parameter is CommandArgument commandArgumentParameter)
|
||||
{
|
||||
return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
@ -1,34 +1,33 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
[Description("Displays the CLI library version")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class VersionCommand : Command<VersionCommand.Settings>
|
||||
{
|
||||
[Description("Displays the CLI library version")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class VersionCommand : Command<VersionCommand.Settings>
|
||||
private readonly IAnsiConsole _writer;
|
||||
|
||||
public VersionCommand(IConfiguration configuration)
|
||||
{
|
||||
private readonly IAnsiConsole _writer;
|
||||
|
||||
public VersionCommand(IConfiguration configuration)
|
||||
{
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
}
|
||||
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
{
|
||||
_writer.MarkupLine(
|
||||
"[yellow]Spectre.Cli[/] version [aqua]{0}[/]",
|
||||
VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly));
|
||||
|
||||
_writer.MarkupLine(
|
||||
"[yellow]Spectre.Console[/] version [aqua]{0}[/]",
|
||||
VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly));
|
||||
|
||||
return 0;
|
||||
}
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
{
|
||||
_writer.MarkupLine(
|
||||
"[yellow]Spectre.Cli[/] version [aqua]{0}[/]",
|
||||
VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly));
|
||||
|
||||
_writer.MarkupLine(
|
||||
"[yellow]Spectre.Console[/] version [aqua]{0}[/]",
|
||||
VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -7,179 +7,178 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
[Description("Generates an XML representation of the CLI configuration.")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class XmlDocCommand : Command<XmlDocCommand.Settings>
|
||||
{
|
||||
[Description("Generates an XML representation of the CLI configuration.")]
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class XmlDocCommand : Command<XmlDocCommand.Settings>
|
||||
private readonly CommandModel _model;
|
||||
private readonly IAnsiConsole _writer;
|
||||
|
||||
public XmlDocCommand(IConfiguration configuration, CommandModel model)
|
||||
{
|
||||
private readonly CommandModel _model;
|
||||
private readonly IAnsiConsole _writer;
|
||||
_model = model ?? throw new ArgumentNullException(nameof(model));
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
}
|
||||
|
||||
public XmlDocCommand(IConfiguration configuration, CommandModel model)
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
{
|
||||
_writer.Write(Serialize(_model), Style.Plain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string Serialize(CommandModel model)
|
||||
{
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
_model = model ?? throw new ArgumentNullException(nameof(model));
|
||||
_writer = configuration.Settings.Console.GetConsole();
|
||||
}
|
||||
Indent = true,
|
||||
IndentChars = " ",
|
||||
NewLineChars = "\n",
|
||||
OmitXmlDeclaration = false,
|
||||
Encoding = Encoding.UTF8,
|
||||
};
|
||||
|
||||
public sealed class Settings : CommandSettings
|
||||
using (var buffer = new StringWriterWithEncoding(Encoding.UTF8))
|
||||
using (var xmlWriter = XmlWriter.Create(buffer, settings))
|
||||
{
|
||||
}
|
||||
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings)
|
||||
{
|
||||
_writer.Write(Serialize(_model), Style.Plain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string Serialize(CommandModel model)
|
||||
{
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
IndentChars = " ",
|
||||
NewLineChars = "\n",
|
||||
OmitXmlDeclaration = false,
|
||||
Encoding = Encoding.UTF8,
|
||||
};
|
||||
|
||||
using (var buffer = new StringWriterWithEncoding(Encoding.UTF8))
|
||||
using (var xmlWriter = XmlWriter.Create(buffer, settings))
|
||||
{
|
||||
SerializeModel(model).WriteTo(xmlWriter);
|
||||
xmlWriter.Flush();
|
||||
return buffer.GetStringBuilder().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private static XmlDocument SerializeModel(CommandModel model)
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
var root = document.CreateElement("Model");
|
||||
|
||||
if (model.DefaultCommand != null)
|
||||
{
|
||||
root.AppendChild(document.CreateComment("DEFAULT COMMAND"));
|
||||
root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true));
|
||||
}
|
||||
|
||||
foreach (var command in model.Commands.Where(x => !x.IsHidden))
|
||||
{
|
||||
root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant()));
|
||||
root.AppendChild(CreateCommandNode(document, command));
|
||||
}
|
||||
|
||||
document.AppendChild(root);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false)
|
||||
{
|
||||
var node = doc.CreateElement("Command");
|
||||
|
||||
// Attributes
|
||||
node.SetNullableAttribute("Name", command.Name);
|
||||
node.SetBooleanAttribute("IsBranch", command.IsBranch);
|
||||
|
||||
if (isDefaultCommand)
|
||||
{
|
||||
node.SetBooleanAttribute("IsDefault", true);
|
||||
}
|
||||
|
||||
if (command.CommandType != null)
|
||||
{
|
||||
node.SetNullableAttribute("ClrType", command.CommandType?.FullName);
|
||||
}
|
||||
|
||||
node.SetNullableAttribute("Settings", command.SettingsType?.FullName);
|
||||
|
||||
// Parameters
|
||||
if (command.Parameters.Count > 0)
|
||||
{
|
||||
var parameterRootNode = doc.CreateElement("Parameters");
|
||||
foreach (var parameter in CreateParameterNodes(doc, command))
|
||||
{
|
||||
parameterRootNode.AppendChild(parameter);
|
||||
}
|
||||
|
||||
node.AppendChild(parameterRootNode);
|
||||
}
|
||||
|
||||
// Commands
|
||||
foreach (var childCommand in command.Children)
|
||||
{
|
||||
node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant()));
|
||||
node.AppendChild(CreateCommandNode(doc, childCommand));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static IEnumerable<XmlNode> CreateParameterNodes(XmlDocument document, CommandInfo command)
|
||||
{
|
||||
// Arguments
|
||||
foreach (var argument in command.Parameters.OfType<CommandArgument>().OrderBy(x => x.Position))
|
||||
{
|
||||
var node = document.CreateElement("Argument");
|
||||
node.SetNullableAttribute("Name", argument.Value);
|
||||
node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture));
|
||||
node.SetBooleanAttribute("Required", argument.Required);
|
||||
node.SetEnumAttribute("Kind", argument.ParameterKind);
|
||||
node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(argument.Description))
|
||||
{
|
||||
var descriptionNode = document.CreateElement("Description");
|
||||
descriptionNode.InnerText = argument.Description;
|
||||
node.AppendChild(descriptionNode);
|
||||
}
|
||||
|
||||
if (argument.Validators.Count > 0)
|
||||
{
|
||||
var validatorRootNode = document.CreateElement("Validators");
|
||||
foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName))
|
||||
{
|
||||
var validatorNode = document.CreateElement("Validator");
|
||||
validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName);
|
||||
validatorNode.SetNullableAttribute("Message", validator.ErrorMessage);
|
||||
validatorRootNode.AppendChild(validatorNode);
|
||||
}
|
||||
|
||||
node.AppendChild(validatorRootNode);
|
||||
}
|
||||
|
||||
yield return node;
|
||||
}
|
||||
|
||||
// Options
|
||||
foreach (var option in command.Parameters.OfType<CommandOption>()
|
||||
.Where(x => !x.IsHidden)
|
||||
.OrderBy(x => string.Join(",", x.LongNames))
|
||||
.ThenBy(x => string.Join(",", x.ShortNames)))
|
||||
{
|
||||
var node = document.CreateElement("Option");
|
||||
|
||||
if (option.IsShadowed)
|
||||
{
|
||||
node.SetBooleanAttribute("Shadowed", true);
|
||||
}
|
||||
|
||||
node.SetNullableAttribute("Short", option.ShortNames);
|
||||
node.SetNullableAttribute("Long", option.LongNames);
|
||||
node.SetNullableAttribute("Value", option.ValueName);
|
||||
node.SetBooleanAttribute("Required", option.Required);
|
||||
node.SetEnumAttribute("Kind", option.ParameterKind);
|
||||
node.SetNullableAttribute("ClrType", option.ParameterType?.FullName);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(option.Description))
|
||||
{
|
||||
var descriptionNode = document.CreateElement("Description");
|
||||
descriptionNode.InnerText = option.Description;
|
||||
node.AppendChild(descriptionNode);
|
||||
}
|
||||
|
||||
yield return node;
|
||||
}
|
||||
SerializeModel(model).WriteTo(xmlWriter);
|
||||
xmlWriter.Flush();
|
||||
return buffer.GetStringBuilder().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static XmlDocument SerializeModel(CommandModel model)
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
var root = document.CreateElement("Model");
|
||||
|
||||
if (model.DefaultCommand != null)
|
||||
{
|
||||
root.AppendChild(document.CreateComment("DEFAULT COMMAND"));
|
||||
root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true));
|
||||
}
|
||||
|
||||
foreach (var command in model.Commands.Where(x => !x.IsHidden))
|
||||
{
|
||||
root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant()));
|
||||
root.AppendChild(CreateCommandNode(document, command));
|
||||
}
|
||||
|
||||
document.AppendChild(root);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false)
|
||||
{
|
||||
var node = doc.CreateElement("Command");
|
||||
|
||||
// Attributes
|
||||
node.SetNullableAttribute("Name", command.Name);
|
||||
node.SetBooleanAttribute("IsBranch", command.IsBranch);
|
||||
|
||||
if (isDefaultCommand)
|
||||
{
|
||||
node.SetBooleanAttribute("IsDefault", true);
|
||||
}
|
||||
|
||||
if (command.CommandType != null)
|
||||
{
|
||||
node.SetNullableAttribute("ClrType", command.CommandType?.FullName);
|
||||
}
|
||||
|
||||
node.SetNullableAttribute("Settings", command.SettingsType?.FullName);
|
||||
|
||||
// Parameters
|
||||
if (command.Parameters.Count > 0)
|
||||
{
|
||||
var parameterRootNode = doc.CreateElement("Parameters");
|
||||
foreach (var parameter in CreateParameterNodes(doc, command))
|
||||
{
|
||||
parameterRootNode.AppendChild(parameter);
|
||||
}
|
||||
|
||||
node.AppendChild(parameterRootNode);
|
||||
}
|
||||
|
||||
// Commands
|
||||
foreach (var childCommand in command.Children)
|
||||
{
|
||||
node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant()));
|
||||
node.AppendChild(CreateCommandNode(doc, childCommand));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static IEnumerable<XmlNode> CreateParameterNodes(XmlDocument document, CommandInfo command)
|
||||
{
|
||||
// Arguments
|
||||
foreach (var argument in command.Parameters.OfType<CommandArgument>().OrderBy(x => x.Position))
|
||||
{
|
||||
var node = document.CreateElement("Argument");
|
||||
node.SetNullableAttribute("Name", argument.Value);
|
||||
node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture));
|
||||
node.SetBooleanAttribute("Required", argument.Required);
|
||||
node.SetEnumAttribute("Kind", argument.ParameterKind);
|
||||
node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(argument.Description))
|
||||
{
|
||||
var descriptionNode = document.CreateElement("Description");
|
||||
descriptionNode.InnerText = argument.Description;
|
||||
node.AppendChild(descriptionNode);
|
||||
}
|
||||
|
||||
if (argument.Validators.Count > 0)
|
||||
{
|
||||
var validatorRootNode = document.CreateElement("Validators");
|
||||
foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName))
|
||||
{
|
||||
var validatorNode = document.CreateElement("Validator");
|
||||
validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName);
|
||||
validatorNode.SetNullableAttribute("Message", validator.ErrorMessage);
|
||||
validatorRootNode.AppendChild(validatorNode);
|
||||
}
|
||||
|
||||
node.AppendChild(validatorRootNode);
|
||||
}
|
||||
|
||||
yield return node;
|
||||
}
|
||||
|
||||
// Options
|
||||
foreach (var option in command.Parameters.OfType<CommandOption>()
|
||||
.Where(x => !x.IsHidden)
|
||||
.OrderBy(x => string.Join(",", x.LongNames))
|
||||
.ThenBy(x => string.Join(",", x.ShortNames)))
|
||||
{
|
||||
var node = document.CreateElement("Option");
|
||||
|
||||
if (option.IsShadowed)
|
||||
{
|
||||
node.SetBooleanAttribute("Shadowed", true);
|
||||
}
|
||||
|
||||
node.SetNullableAttribute("Short", option.ShortNames);
|
||||
node.SetNullableAttribute("Long", option.LongNames);
|
||||
node.SetNullableAttribute("Value", option.ValueName);
|
||||
node.SetBooleanAttribute("Required", option.Required);
|
||||
node.SetEnumAttribute("Kind", option.ParameterKind);
|
||||
node.SetNullableAttribute("ClrType", option.ParameterType?.FullName);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(option.Description))
|
||||
{
|
||||
var descriptionNode = document.CreateElement("Description");
|
||||
descriptionNode.InnerText = option.Description;
|
||||
node.AppendChild(descriptionNode);
|
||||
}
|
||||
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,104 +3,103 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class Composer : IRenderable
|
||||
{
|
||||
internal sealed class Composer : IRenderable
|
||||
private readonly StringBuilder _content;
|
||||
|
||||
public Composer()
|
||||
{
|
||||
private readonly StringBuilder _content;
|
||||
|
||||
public Composer()
|
||||
{
|
||||
_content = new StringBuilder();
|
||||
}
|
||||
|
||||
public Composer Text(string text)
|
||||
{
|
||||
_content.Append(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(string style, string text)
|
||||
{
|
||||
_content.Append('[').Append(style).Append(']');
|
||||
_content.Append(text.EscapeMarkup());
|
||||
_content.Append("[/]");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(string style, Action<Composer> action)
|
||||
{
|
||||
_content.Append('[').Append(style).Append(']');
|
||||
action(this);
|
||||
_content.Append("[/]");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Space()
|
||||
{
|
||||
return Spaces(1);
|
||||
}
|
||||
|
||||
public Composer Spaces(int count)
|
||||
{
|
||||
return Repeat(' ', count);
|
||||
}
|
||||
|
||||
public Composer Tab()
|
||||
{
|
||||
return Tabs(1);
|
||||
}
|
||||
|
||||
public Composer Tabs(int count)
|
||||
{
|
||||
return Spaces(count * 4);
|
||||
}
|
||||
|
||||
public Composer Repeat(char character, int count)
|
||||
{
|
||||
_content.Append(new string(character, count));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer LineBreak()
|
||||
{
|
||||
return LineBreaks(1);
|
||||
}
|
||||
|
||||
public Composer LineBreaks(int count)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
_content.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Join(string separator, IEnumerable<string> composers)
|
||||
{
|
||||
if (composers != null)
|
||||
{
|
||||
Space();
|
||||
Text(string.Join(separator, composers));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)new Markup(_content.ToString())).Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
public IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)new Markup(_content.ToString())).Render(context, maxWidth);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _content.ToString();
|
||||
}
|
||||
_content = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
public Composer Text(string text)
|
||||
{
|
||||
_content.Append(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(string style, string text)
|
||||
{
|
||||
_content.Append('[').Append(style).Append(']');
|
||||
_content.Append(text.EscapeMarkup());
|
||||
_content.Append("[/]");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Style(string style, Action<Composer> action)
|
||||
{
|
||||
_content.Append('[').Append(style).Append(']');
|
||||
action(this);
|
||||
_content.Append("[/]");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Space()
|
||||
{
|
||||
return Spaces(1);
|
||||
}
|
||||
|
||||
public Composer Spaces(int count)
|
||||
{
|
||||
return Repeat(' ', count);
|
||||
}
|
||||
|
||||
public Composer Tab()
|
||||
{
|
||||
return Tabs(1);
|
||||
}
|
||||
|
||||
public Composer Tabs(int count)
|
||||
{
|
||||
return Spaces(count * 4);
|
||||
}
|
||||
|
||||
public Composer Repeat(char character, int count)
|
||||
{
|
||||
_content.Append(new string(character, count));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer LineBreak()
|
||||
{
|
||||
return LineBreaks(1);
|
||||
}
|
||||
|
||||
public Composer LineBreaks(int count)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
_content.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Composer Join(string separator, IEnumerable<string> composers)
|
||||
{
|
||||
if (composers != null)
|
||||
{
|
||||
Space();
|
||||
Text(string.Join(separator, composers));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)new Markup(_content.ToString())).Measure(context, maxWidth);
|
||||
}
|
||||
|
||||
public IEnumerable<Segment> Render(RenderContext context, int maxWidth)
|
||||
{
|
||||
return ((IRenderable)new Markup(_content.ToString())).Render(context, maxWidth);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _content.ToString();
|
||||
}
|
||||
}
|
@ -2,132 +2,131 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal abstract class ComponentActivator
|
||||
{
|
||||
internal abstract class ComponentActivator
|
||||
{
|
||||
public abstract object Activate(DefaultTypeResolver container);
|
||||
public abstract object Activate(DefaultTypeResolver container);
|
||||
|
||||
public abstract ComponentActivator CreateCopy();
|
||||
public abstract ComponentActivator CreateCopy();
|
||||
}
|
||||
|
||||
internal class CachingActivator : ComponentActivator
|
||||
{
|
||||
private readonly ComponentActivator _activator;
|
||||
private object? _result;
|
||||
|
||||
public CachingActivator(ComponentActivator activator)
|
||||
{
|
||||
_activator = activator ?? throw new ArgumentNullException(nameof(activator));
|
||||
_result = null;
|
||||
}
|
||||
|
||||
internal class CachingActivator : ComponentActivator
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
private readonly ComponentActivator _activator;
|
||||
private object? _result;
|
||||
return _result ??= _activator.Activate(container);
|
||||
}
|
||||
|
||||
public CachingActivator(ComponentActivator activator)
|
||||
{
|
||||
_activator = activator ?? throw new ArgumentNullException(nameof(activator));
|
||||
_result = null;
|
||||
}
|
||||
public override ComponentActivator CreateCopy()
|
||||
{
|
||||
return new CachingActivator(_activator.CreateCopy());
|
||||
}
|
||||
}
|
||||
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
return _result ??= _activator.Activate(container);
|
||||
}
|
||||
internal sealed class InstanceActivator : ComponentActivator
|
||||
{
|
||||
private readonly object _instance;
|
||||
|
||||
public override ComponentActivator CreateCopy()
|
||||
public InstanceActivator(object instance)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public override ComponentActivator CreateCopy()
|
||||
{
|
||||
return new InstanceActivator(_instance);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ReflectionActivator : ComponentActivator
|
||||
{
|
||||
private readonly Type _type;
|
||||
private readonly ConstructorInfo _constructor;
|
||||
private readonly List<ParameterInfo> _parameters;
|
||||
|
||||
public ReflectionActivator(Type type)
|
||||
{
|
||||
_type = type;
|
||||
_constructor = GetGreediestConstructor(type);
|
||||
_parameters = new List<ParameterInfo>();
|
||||
|
||||
foreach (var parameter in _constructor.GetParameters())
|
||||
{
|
||||
return new CachingActivator(_activator.CreateCopy());
|
||||
_parameters.Add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class InstanceActivator : ComponentActivator
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
private readonly object _instance;
|
||||
|
||||
public InstanceActivator(object instance)
|
||||
var parameters = new object?[_parameters.Count];
|
||||
for (var i = 0; i < _parameters.Count; i++)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public override ComponentActivator CreateCopy()
|
||||
{
|
||||
return new InstanceActivator(_instance);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ReflectionActivator : ComponentActivator
|
||||
{
|
||||
private readonly Type _type;
|
||||
private readonly ConstructorInfo _constructor;
|
||||
private readonly List<ParameterInfo> _parameters;
|
||||
|
||||
public ReflectionActivator(Type type)
|
||||
{
|
||||
_type = type;
|
||||
_constructor = GetGreediestConstructor(type);
|
||||
_parameters = new List<ParameterInfo>();
|
||||
|
||||
foreach (var parameter in _constructor.GetParameters())
|
||||
var parameter = _parameters[i];
|
||||
if (parameter.ParameterType == typeof(DefaultTypeResolver))
|
||||
{
|
||||
_parameters.Add(parameter);
|
||||
parameters[i] = container;
|
||||
}
|
||||
}
|
||||
|
||||
public override object Activate(DefaultTypeResolver container)
|
||||
{
|
||||
var parameters = new object?[_parameters.Count];
|
||||
for (var i = 0; i < _parameters.Count; i++)
|
||||
else
|
||||
{
|
||||
var parameter = _parameters[i];
|
||||
if (parameter.ParameterType == typeof(DefaultTypeResolver))
|
||||
var resolved = container.Resolve(parameter.ParameterType);
|
||||
if (resolved == null)
|
||||
{
|
||||
parameters[i] = container;
|
||||
if (!parameter.IsOptional)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find registration for '{parameter.ParameterType.FullName}'.");
|
||||
}
|
||||
|
||||
parameters[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolved = container.Resolve(parameter.ParameterType);
|
||||
if (resolved == null)
|
||||
{
|
||||
if (!parameter.IsOptional)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find registration for '{parameter.ParameterType.FullName}'.");
|
||||
}
|
||||
|
||||
parameters[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters[i] = resolved;
|
||||
}
|
||||
parameters[i] = resolved;
|
||||
}
|
||||
}
|
||||
|
||||
return _constructor.Invoke(parameters);
|
||||
}
|
||||
|
||||
public override ComponentActivator CreateCopy()
|
||||
return _constructor.Invoke(parameters);
|
||||
}
|
||||
|
||||
public override ComponentActivator CreateCopy()
|
||||
{
|
||||
return new ReflectionActivator(_type);
|
||||
}
|
||||
|
||||
private static ConstructorInfo GetGreediestConstructor(Type type)
|
||||
{
|
||||
ConstructorInfo? current = null;
|
||||
var count = -1;
|
||||
foreach (var constructor in type.GetTypeInfo().GetConstructors())
|
||||
{
|
||||
return new ReflectionActivator(_type);
|
||||
var parameters = constructor.GetParameters();
|
||||
if (parameters.Length > count)
|
||||
{
|
||||
count = parameters.Length;
|
||||
current = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
private static ConstructorInfo GetGreediestConstructor(Type type)
|
||||
if (current == null)
|
||||
{
|
||||
ConstructorInfo? current = null;
|
||||
var count = -1;
|
||||
foreach (var constructor in type.GetTypeInfo().GetConstructors())
|
||||
{
|
||||
var parameters = constructor.GetParameters();
|
||||
if (parameters.Length > count)
|
||||
{
|
||||
count = parameters.Length;
|
||||
current = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
if (current == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a constructor for '{type.FullName}'.");
|
||||
}
|
||||
|
||||
return current;
|
||||
throw new InvalidOperationException($"Could not find a constructor for '{type.FullName}'.");
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
}
|
@ -1,31 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class ComponentRegistration
|
||||
{
|
||||
internal sealed class ComponentRegistration
|
||||
public Type ImplementationType { get; }
|
||||
public ComponentActivator Activator { get; }
|
||||
public IReadOnlyList<Type> RegistrationTypes { get; }
|
||||
|
||||
public ComponentRegistration(Type type, ComponentActivator activator, IEnumerable<Type>? registrationTypes = null)
|
||||
{
|
||||
public Type ImplementationType { get; }
|
||||
public ComponentActivator Activator { get; }
|
||||
public IReadOnlyList<Type> RegistrationTypes { get; }
|
||||
|
||||
public ComponentRegistration(Type type, ComponentActivator activator, IEnumerable<Type>? registrationTypes = null)
|
||||
var registrations = new List<Type>(registrationTypes ?? Array.Empty<Type>());
|
||||
if (registrations.Count == 0)
|
||||
{
|
||||
var registrations = new List<Type>(registrationTypes ?? Array.Empty<Type>());
|
||||
if (registrations.Count == 0)
|
||||
{
|
||||
// Every registration needs at least one registration type.
|
||||
registrations.Add(type);
|
||||
}
|
||||
|
||||
ImplementationType = type;
|
||||
RegistrationTypes = registrations;
|
||||
Activator = activator ?? throw new ArgumentNullException(nameof(activator));
|
||||
// Every registration needs at least one registration type.
|
||||
registrations.Add(type);
|
||||
}
|
||||
|
||||
public ComponentRegistration CreateCopy()
|
||||
{
|
||||
return new ComponentRegistration(ImplementationType, Activator.CreateCopy(), RegistrationTypes);
|
||||
}
|
||||
ImplementationType = type;
|
||||
RegistrationTypes = registrations;
|
||||
Activator = activator ?? throw new ArgumentNullException(nameof(activator));
|
||||
}
|
||||
|
||||
public ComponentRegistration CreateCopy()
|
||||
{
|
||||
return new ComponentRegistration(ImplementationType, Activator.CreateCopy(), RegistrationTypes);
|
||||
}
|
||||
}
|
@ -2,59 +2,58 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class ComponentRegistry : IDisposable
|
||||
{
|
||||
internal sealed class ComponentRegistry : IDisposable
|
||||
private readonly Dictionary<Type, HashSet<ComponentRegistration>> _registrations;
|
||||
|
||||
public ComponentRegistry()
|
||||
{
|
||||
private readonly Dictionary<Type, HashSet<ComponentRegistration>> _registrations;
|
||||
_registrations = new Dictionary<Type, HashSet<ComponentRegistration>>();
|
||||
}
|
||||
|
||||
public ComponentRegistry()
|
||||
public ComponentRegistry CreateCopy()
|
||||
{
|
||||
var registry = new ComponentRegistry();
|
||||
foreach (var registration in _registrations.SelectMany(p => p.Value))
|
||||
{
|
||||
_registrations = new Dictionary<Type, HashSet<ComponentRegistration>>();
|
||||
registry.Register(registration.CreateCopy());
|
||||
}
|
||||
|
||||
public ComponentRegistry CreateCopy()
|
||||
{
|
||||
var registry = new ComponentRegistry();
|
||||
foreach (var registration in _registrations.SelectMany(p => p.Value))
|
||||
{
|
||||
registry.Register(registration.CreateCopy());
|
||||
}
|
||||
return registry;
|
||||
}
|
||||
|
||||
return registry;
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var registration in _registrations)
|
||||
{
|
||||
registration.Value.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
_registrations.Clear();
|
||||
}
|
||||
|
||||
public void Register(ComponentRegistration registration)
|
||||
{
|
||||
foreach (var type in new HashSet<Type>(registration.RegistrationTypes))
|
||||
{
|
||||
foreach (var registration in _registrations)
|
||||
if (!_registrations.ContainsKey(type))
|
||||
{
|
||||
registration.Value.Clear();
|
||||
_registrations.Add(type, new HashSet<ComponentRegistration>());
|
||||
}
|
||||
|
||||
_registrations.Clear();
|
||||
}
|
||||
|
||||
public void Register(ComponentRegistration registration)
|
||||
{
|
||||
foreach (var type in new HashSet<Type>(registration.RegistrationTypes))
|
||||
{
|
||||
if (!_registrations.ContainsKey(type))
|
||||
{
|
||||
_registrations.Add(type, new HashSet<ComponentRegistration>());
|
||||
}
|
||||
|
||||
_registrations[type].Add(registration);
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<ComponentRegistration> GetRegistrations(Type type)
|
||||
{
|
||||
if (_registrations.ContainsKey(type))
|
||||
{
|
||||
return _registrations[type];
|
||||
}
|
||||
|
||||
return new List<ComponentRegistration>();
|
||||
_registrations[type].Add(registration);
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<ComponentRegistration> GetRegistrations(Type type)
|
||||
{
|
||||
if (_registrations.ContainsKey(type))
|
||||
{
|
||||
return _registrations[type];
|
||||
}
|
||||
|
||||
return new List<ComponentRegistration>();
|
||||
}
|
||||
}
|
@ -1,55 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class DefaultTypeRegistrar : ITypeRegistrar
|
||||
{
|
||||
internal sealed class DefaultTypeRegistrar : ITypeRegistrar
|
||||
private readonly Queue<Action<ComponentRegistry>> _registry;
|
||||
|
||||
public DefaultTypeRegistrar()
|
||||
{
|
||||
private readonly Queue<Action<ComponentRegistry>> _registry;
|
||||
|
||||
public DefaultTypeRegistrar()
|
||||
{
|
||||
_registry = new Queue<Action<ComponentRegistry>>();
|
||||
}
|
||||
|
||||
public ITypeResolver Build()
|
||||
{
|
||||
var container = new DefaultTypeResolver();
|
||||
while (_registry.Count > 0)
|
||||
{
|
||||
var action = _registry.Dequeue();
|
||||
action(container.Registry);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public void Register(Type service, Type implementation)
|
||||
{
|
||||
var registration = new ComponentRegistration(implementation, new ReflectionActivator(implementation), new[] { service });
|
||||
_registry.Enqueue(registry => registry.Register(registration));
|
||||
}
|
||||
|
||||
public void RegisterInstance(Type service, object implementation)
|
||||
{
|
||||
var registration = new ComponentRegistration(service, new CachingActivator(new InstanceActivator(implementation)));
|
||||
_registry.Enqueue(registry => registry.Register(registration));
|
||||
}
|
||||
|
||||
public void RegisterLazy(Type service, Func<object> factory)
|
||||
{
|
||||
if (factory is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
_registry.Enqueue(registry =>
|
||||
{
|
||||
var activator = new CachingActivator(new InstanceActivator(factory()));
|
||||
var registration = new ComponentRegistration(service, activator);
|
||||
|
||||
registry.Register(registration);
|
||||
});
|
||||
}
|
||||
_registry = new Queue<Action<ComponentRegistry>>();
|
||||
}
|
||||
}
|
||||
|
||||
public ITypeResolver Build()
|
||||
{
|
||||
var container = new DefaultTypeResolver();
|
||||
while (_registry.Count > 0)
|
||||
{
|
||||
var action = _registry.Dequeue();
|
||||
action(container.Registry);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public void Register(Type service, Type implementation)
|
||||
{
|
||||
var registration = new ComponentRegistration(implementation, new ReflectionActivator(implementation), new[] { service });
|
||||
_registry.Enqueue(registry => registry.Register(registration));
|
||||
}
|
||||
|
||||
public void RegisterInstance(Type service, object implementation)
|
||||
{
|
||||
var registration = new ComponentRegistration(service, new CachingActivator(new InstanceActivator(implementation)));
|
||||
_registry.Enqueue(registry => registry.Register(registration));
|
||||
}
|
||||
|
||||
public void RegisterLazy(Type service, Func<object> factory)
|
||||
{
|
||||
if (factory is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
_registry.Enqueue(registry =>
|
||||
{
|
||||
var activator = new CachingActivator(new InstanceActivator(factory()));
|
||||
var registration = new ComponentRegistration(service, activator);
|
||||
|
||||
registry.Register(registration);
|
||||
});
|
||||
}
|
||||
}
|
@ -2,66 +2,65 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class DefaultTypeResolver : IDisposable, ITypeResolver
|
||||
{
|
||||
internal sealed class DefaultTypeResolver : IDisposable, ITypeResolver
|
||||
public ComponentRegistry Registry { get; }
|
||||
|
||||
public DefaultTypeResolver()
|
||||
: this(null)
|
||||
{
|
||||
public ComponentRegistry Registry { get; }
|
||||
}
|
||||
|
||||
public DefaultTypeResolver()
|
||||
: this(null)
|
||||
public DefaultTypeResolver(ComponentRegistry? registry)
|
||||
{
|
||||
Registry = registry ?? new ComponentRegistry();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Registry.Dispose();
|
||||
}
|
||||
|
||||
public object? Resolve(Type? type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public DefaultTypeResolver(ComponentRegistry? registry)
|
||||
var isEnumerable = false;
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
Registry = registry ?? new ComponentRegistry();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Registry.Dispose();
|
||||
}
|
||||
|
||||
public object? Resolve(Type? type)
|
||||
{
|
||||
if (type == null)
|
||||
if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
{
|
||||
return null;
|
||||
isEnumerable = true;
|
||||
type = type.GenericTypeArguments[0];
|
||||
}
|
||||
}
|
||||
|
||||
var isEnumerable = false;
|
||||
if (type.IsGenericType)
|
||||
var registrations = Registry.GetRegistrations(type);
|
||||
if (registrations != null)
|
||||
{
|
||||
if (isEnumerable)
|
||||
{
|
||||
if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
||||
var result = Array.CreateInstance(type, registrations.Count);
|
||||
for (var index = 0; index < registrations.Count; index++)
|
||||
{
|
||||
isEnumerable = true;
|
||||
type = type.GenericTypeArguments[0];
|
||||
var registration = registrations.ElementAt(index);
|
||||
result.SetValue(Resolve(registration), index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var registrations = Registry.GetRegistrations(type);
|
||||
if (registrations != null)
|
||||
{
|
||||
if (isEnumerable)
|
||||
{
|
||||
var result = Array.CreateInstance(type, registrations.Count);
|
||||
for (var index = 0; index < registrations.Count; index++)
|
||||
{
|
||||
var registration = registrations.ElementAt(index);
|
||||
result.SetValue(Resolve(registration), index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Resolve(registrations?.LastOrDefault());
|
||||
}
|
||||
|
||||
public object? Resolve(ComponentRegistration? registration)
|
||||
{
|
||||
return registration?.Activator?.Activate(this);
|
||||
}
|
||||
return Resolve(registrations?.LastOrDefault());
|
||||
}
|
||||
|
||||
public object? Resolve(ComponentRegistration? registration)
|
||||
{
|
||||
return registration?.Activator?.Activate(this);
|
||||
}
|
||||
}
|
@ -1,47 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class CommandAppSettings : ICommandAppSettings
|
||||
{
|
||||
internal sealed class CommandAppSettings : ICommandAppSettings
|
||||
public string? ApplicationName { get; set; }
|
||||
public string? ApplicationVersion { get; set; }
|
||||
public IAnsiConsole? Console { get; set; }
|
||||
public ICommandInterceptor? Interceptor { get; set; }
|
||||
public ITypeRegistrarFrontend Registrar { get; set; }
|
||||
public CaseSensitivity CaseSensitivity { get; set; }
|
||||
public bool PropagateExceptions { get; set; }
|
||||
public bool ValidateExamples { get; set; }
|
||||
public bool StrictParsing { get; set; }
|
||||
|
||||
public ParsingMode ParsingMode =>
|
||||
StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed;
|
||||
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
|
||||
public CommandAppSettings(ITypeRegistrar registrar)
|
||||
{
|
||||
public string? ApplicationName { get; set; }
|
||||
public string? ApplicationVersion { get; set; }
|
||||
public IAnsiConsole? Console { get; set; }
|
||||
public ICommandInterceptor? Interceptor { get; set; }
|
||||
public ITypeRegistrarFrontend Registrar { get; set; }
|
||||
public CaseSensitivity CaseSensitivity { get; set; }
|
||||
public bool PropagateExceptions { get; set; }
|
||||
public bool ValidateExamples { get; set; }
|
||||
public bool StrictParsing { get; set; }
|
||||
Registrar = new TypeRegistrar(registrar);
|
||||
CaseSensitivity = CaseSensitivity.All;
|
||||
}
|
||||
|
||||
public ParsingMode ParsingMode =>
|
||||
StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed;
|
||||
|
||||
public Func<Exception, int>? ExceptionHandler { get; set; }
|
||||
|
||||
public CommandAppSettings(ITypeRegistrar registrar)
|
||||
public bool IsTrue(Func<CommandAppSettings, bool> func, string environmentVariableName)
|
||||
{
|
||||
if (func(this))
|
||||
{
|
||||
Registrar = new TypeRegistrar(registrar);
|
||||
CaseSensitivity = CaseSensitivity.All;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsTrue(Func<CommandAppSettings, bool> func, string environmentVariableName)
|
||||
var environmentVariable = Environment.GetEnvironmentVariable(environmentVariableName);
|
||||
if (!string.IsNullOrWhiteSpace(environmentVariable))
|
||||
{
|
||||
if (func(this))
|
||||
if (environmentVariable.Equals("True", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var environmentVariable = Environment.GetEnvironmentVariable(environmentVariableName);
|
||||
if (!string.IsNullOrWhiteSpace(environmentVariable))
|
||||
{
|
||||
if (environmentVariable.Equals("True", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,42 +1,41 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class CommandConfigurator : ICommandConfigurator
|
||||
{
|
||||
internal sealed class CommandConfigurator : ICommandConfigurator
|
||||
public ConfiguredCommand Command { get; }
|
||||
|
||||
public CommandConfigurator(ConfiguredCommand command)
|
||||
{
|
||||
public ConfiguredCommand Command { get; }
|
||||
|
||||
public CommandConfigurator(ConfiguredCommand command)
|
||||
{
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithExample(string[] args)
|
||||
{
|
||||
Command.Examples.Add(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithAlias(string alias)
|
||||
{
|
||||
Command.Aliases.Add(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithDescription(string description)
|
||||
{
|
||||
Command.Description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithData(object data)
|
||||
{
|
||||
Command.Data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator IsHidden()
|
||||
{
|
||||
Command.IsHidden = true;
|
||||
return this;
|
||||
}
|
||||
Command = command;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithExample(string[] args)
|
||||
{
|
||||
Command.Examples.Add(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithAlias(string alias)
|
||||
{
|
||||
Command.Aliases.Add(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithDescription(string description)
|
||||
{
|
||||
Command.Description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator WithData(object data)
|
||||
{
|
||||
Command.Data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ICommandConfigurator IsHidden()
|
||||
{
|
||||
Command.IsHidden = true;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -2,42 +2,41 @@ using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
internal static class ConfigurationHelper
|
||||
{
|
||||
public static Type? GetSettingsType(Type commandType)
|
||||
{
|
||||
if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(commandType) &&
|
||||
GetGenericTypeArguments(commandType, typeof(ICommand<>), out var result))
|
||||
{
|
||||
return result[0];
|
||||
}
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
return null;
|
||||
internal static class ConfigurationHelper
|
||||
{
|
||||
public static Type? GetSettingsType(Type commandType)
|
||||
{
|
||||
if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(commandType) &&
|
||||
GetGenericTypeArguments(commandType, typeof(ICommand<>), out var result))
|
||||
{
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private static bool GetGenericTypeArguments(Type? type, Type genericType,
|
||||
[NotNullWhen(true)] out Type[]? genericTypeArguments)
|
||||
{
|
||||
while (type != null)
|
||||
{
|
||||
foreach (var @interface in type.GetTypeInfo().GetInterfaces())
|
||||
{
|
||||
if (!@interface.GetTypeInfo().IsGenericType || @interface.GetGenericTypeDefinition() != genericType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
genericTypeArguments = @interface.GenericTypeArguments;
|
||||
return true;
|
||||
private static bool GetGenericTypeArguments(Type? type, Type genericType,
|
||||
[NotNullWhen(true)] out Type[]? genericTypeArguments)
|
||||
{
|
||||
while (type != null)
|
||||
{
|
||||
foreach (var @interface in type.GetTypeInfo().GetInterfaces())
|
||||
{
|
||||
if (!@interface.GetTypeInfo().IsGenericType || @interface.GetGenericTypeDefinition() != genericType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
type = type.GetTypeInfo().BaseType;
|
||||
genericTypeArguments = @interface.GenericTypeArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
genericTypeArguments = null;
|
||||
return false;
|
||||
type = type.GetTypeInfo().BaseType;
|
||||
}
|
||||
|
||||
genericTypeArguments = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,94 +2,93 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Cli.Unsafe;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfiguration
|
||||
{
|
||||
internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfiguration
|
||||
private readonly ITypeRegistrar _registrar;
|
||||
|
||||
public IList<ConfiguredCommand> Commands { get; }
|
||||
public CommandAppSettings Settings { get; }
|
||||
public ConfiguredCommand? DefaultCommand { get; private set; }
|
||||
public IList<string[]> Examples { get; }
|
||||
|
||||
ICommandAppSettings IConfigurator.Settings => Settings;
|
||||
|
||||
public Configurator(ITypeRegistrar registrar)
|
||||
{
|
||||
private readonly ITypeRegistrar _registrar;
|
||||
_registrar = registrar;
|
||||
|
||||
public IList<ConfiguredCommand> Commands { get; }
|
||||
public CommandAppSettings Settings { get; }
|
||||
public ConfiguredCommand? DefaultCommand { get; private set; }
|
||||
public IList<string[]> Examples { get; }
|
||||
|
||||
ICommandAppSettings IConfigurator.Settings => Settings;
|
||||
|
||||
public Configurator(ITypeRegistrar registrar)
|
||||
{
|
||||
_registrar = registrar;
|
||||
|
||||
Commands = new List<ConfiguredCommand>();
|
||||
Settings = new CommandAppSettings(registrar);
|
||||
Examples = new List<string[]>();
|
||||
}
|
||||
|
||||
public void AddExample(string[] args)
|
||||
{
|
||||
Examples.Add(args);
|
||||
}
|
||||
|
||||
public void SetDefaultCommand<TDefaultCommand>()
|
||||
where TDefaultCommand : class, ICommand
|
||||
{
|
||||
DefaultCommand = ConfiguredCommand.FromType<TDefaultCommand>(
|
||||
CliConstants.DefaultCommandName, isDefaultCommand: true);
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommand
|
||||
{
|
||||
var command = Commands.AddAndReturn(ConfiguredCommand.FromType<TCommand>(name, false));
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
var command = Commands.AddAndReturn(ConfiguredCommand.FromDelegate<TSettings>(
|
||||
name, (context, settings) => func(context, (TSettings)settings)));
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch<TSettings>(name);
|
||||
action(new Configurator<TSettings>(command, _registrar));
|
||||
Commands.Add(command);
|
||||
}
|
||||
|
||||
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
|
||||
{
|
||||
var method = GetType().GetMethod("AddCommand");
|
||||
if (method == null)
|
||||
{
|
||||
throw new CommandConfigurationException("Could not find AddCommand by reflection.");
|
||||
}
|
||||
|
||||
method = method.MakeGenericMethod(command);
|
||||
|
||||
if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result))
|
||||
{
|
||||
throw new CommandConfigurationException("Invoking AddCommand returned null.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch(settings, name);
|
||||
|
||||
// Create the configurator.
|
||||
var configuratorType = typeof(Configurator<>).MakeGenericType(settings);
|
||||
if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator))
|
||||
{
|
||||
throw new CommandConfigurationException("Could not create configurator by reflection.");
|
||||
}
|
||||
|
||||
action(configurator);
|
||||
Commands.Add(command);
|
||||
}
|
||||
Commands = new List<ConfiguredCommand>();
|
||||
Settings = new CommandAppSettings(registrar);
|
||||
Examples = new List<string[]>();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddExample(string[] args)
|
||||
{
|
||||
Examples.Add(args);
|
||||
}
|
||||
|
||||
public void SetDefaultCommand<TDefaultCommand>()
|
||||
where TDefaultCommand : class, ICommand
|
||||
{
|
||||
DefaultCommand = ConfiguredCommand.FromType<TDefaultCommand>(
|
||||
CliConstants.DefaultCommandName, isDefaultCommand: true);
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommand
|
||||
{
|
||||
var command = Commands.AddAndReturn(ConfiguredCommand.FromType<TCommand>(name, false));
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
var command = Commands.AddAndReturn(ConfiguredCommand.FromDelegate<TSettings>(
|
||||
name, (context, settings) => func(context, (TSettings)settings)));
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch<TSettings>(name);
|
||||
action(new Configurator<TSettings>(command, _registrar));
|
||||
Commands.Add(command);
|
||||
}
|
||||
|
||||
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
|
||||
{
|
||||
var method = GetType().GetMethod("AddCommand");
|
||||
if (method == null)
|
||||
{
|
||||
throw new CommandConfigurationException("Could not find AddCommand by reflection.");
|
||||
}
|
||||
|
||||
method = method.MakeGenericMethod(command);
|
||||
|
||||
if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result))
|
||||
{
|
||||
throw new CommandConfigurationException("Invoking AddCommand returned null.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch(settings, name);
|
||||
|
||||
// Create the configurator.
|
||||
var configuratorType = typeof(Configurator<>).MakeGenericType(settings);
|
||||
if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator))
|
||||
{
|
||||
throw new CommandConfigurationException("Could not create configurator by reflection.");
|
||||
}
|
||||
|
||||
action(configurator);
|
||||
Commands.Add(command);
|
||||
}
|
||||
}
|
@ -1,94 +1,93 @@
|
||||
using System;
|
||||
using Spectre.Console.Cli.Unsafe;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class Configurator<TSettings> : IUnsafeBranchConfigurator, IConfigurator<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
internal sealed class Configurator<TSettings> : IUnsafeBranchConfigurator, IConfigurator<TSettings>
|
||||
where TSettings : CommandSettings
|
||||
private readonly ConfiguredCommand _command;
|
||||
private readonly ITypeRegistrar? _registrar;
|
||||
|
||||
public Configurator(ConfiguredCommand command, ITypeRegistrar? registrar)
|
||||
{
|
||||
private readonly ConfiguredCommand _command;
|
||||
private readonly ITypeRegistrar? _registrar;
|
||||
|
||||
public Configurator(ConfiguredCommand command, ITypeRegistrar? registrar)
|
||||
{
|
||||
_command = command;
|
||||
_registrar = registrar;
|
||||
}
|
||||
|
||||
public void SetDescription(string description)
|
||||
{
|
||||
_command.Description = description;
|
||||
}
|
||||
|
||||
public void AddExample(string[] args)
|
||||
{
|
||||
_command.Examples.Add(args);
|
||||
}
|
||||
|
||||
public void HideBranch()
|
||||
{
|
||||
_command.IsHidden = true;
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommandLimiter<TSettings>
|
||||
{
|
||||
var command = ConfiguredCommand.FromType<TCommand>(name);
|
||||
var configurator = new CommandConfigurator(command);
|
||||
|
||||
_command.Children.Add(command);
|
||||
return configurator;
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func)
|
||||
where TDerivedSettings : TSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromDelegate<TDerivedSettings>(
|
||||
name, (context, settings) => func(context, (TDerivedSettings)settings));
|
||||
|
||||
_command.Children.Add(command);
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
|
||||
where TDerivedSettings : TSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch<TDerivedSettings>(name);
|
||||
action(new Configurator<TDerivedSettings>(command, _registrar));
|
||||
_command.Children.Add(command);
|
||||
}
|
||||
|
||||
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
|
||||
{
|
||||
var method = GetType().GetMethod("AddCommand");
|
||||
if (method == null)
|
||||
{
|
||||
throw new CommandConfigurationException("Could not find AddCommand by reflection.");
|
||||
}
|
||||
|
||||
method = method.MakeGenericMethod(command);
|
||||
|
||||
if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result))
|
||||
{
|
||||
throw new CommandConfigurationException("Invoking AddCommand returned null.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch(settings, name);
|
||||
|
||||
// Create the configurator.
|
||||
var configuratorType = typeof(Configurator<>).MakeGenericType(settings);
|
||||
if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator))
|
||||
{
|
||||
throw new CommandConfigurationException("Could not create configurator by reflection.");
|
||||
}
|
||||
|
||||
action(configurator);
|
||||
_command.Children.Add(command);
|
||||
}
|
||||
_command = command;
|
||||
_registrar = registrar;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDescription(string description)
|
||||
{
|
||||
_command.Description = description;
|
||||
}
|
||||
|
||||
public void AddExample(string[] args)
|
||||
{
|
||||
_command.Examples.Add(args);
|
||||
}
|
||||
|
||||
public void HideBranch()
|
||||
{
|
||||
_command.IsHidden = true;
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddCommand<TCommand>(string name)
|
||||
where TCommand : class, ICommandLimiter<TSettings>
|
||||
{
|
||||
var command = ConfiguredCommand.FromType<TCommand>(name);
|
||||
var configurator = new CommandConfigurator(command);
|
||||
|
||||
_command.Children.Add(command);
|
||||
return configurator;
|
||||
}
|
||||
|
||||
public ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func)
|
||||
where TDerivedSettings : TSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromDelegate<TDerivedSettings>(
|
||||
name, (context, settings) => func(context, (TDerivedSettings)settings));
|
||||
|
||||
_command.Children.Add(command);
|
||||
return new CommandConfigurator(command);
|
||||
}
|
||||
|
||||
public void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action)
|
||||
where TDerivedSettings : TSettings
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch<TDerivedSettings>(name);
|
||||
action(new Configurator<TDerivedSettings>(command, _registrar));
|
||||
_command.Children.Add(command);
|
||||
}
|
||||
|
||||
ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command)
|
||||
{
|
||||
var method = GetType().GetMethod("AddCommand");
|
||||
if (method == null)
|
||||
{
|
||||
throw new CommandConfigurationException("Could not find AddCommand by reflection.");
|
||||
}
|
||||
|
||||
method = method.MakeGenericMethod(command);
|
||||
|
||||
if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result))
|
||||
{
|
||||
throw new CommandConfigurationException("Invoking AddCommand returned null.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IUnsafeConfigurator.AddBranch(string name, Type settings, Action<IUnsafeBranchConfigurator> action)
|
||||
{
|
||||
var command = ConfiguredCommand.FromBranch(settings, name);
|
||||
|
||||
// Create the configurator.
|
||||
var configuratorType = typeof(Configurator<>).MakeGenericType(settings);
|
||||
if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator))
|
||||
{
|
||||
throw new CommandConfigurationException("Could not create configurator by reflection.");
|
||||
}
|
||||
|
||||
action(configurator);
|
||||
_command.Children.Add(command);
|
||||
}
|
||||
}
|
@ -1,69 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class ConfiguredCommand
|
||||
{
|
||||
internal sealed class ConfiguredCommand
|
||||
public string Name { get; }
|
||||
public HashSet<string> Aliases { get; }
|
||||
public string? Description { get; set; }
|
||||
public object? Data { get; set; }
|
||||
public Type? CommandType { get; }
|
||||
public Type SettingsType { get; }
|
||||
public Func<CommandContext, CommandSettings, int>? Delegate { get; }
|
||||
public bool IsDefaultCommand { get; }
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
public IList<ConfiguredCommand> Children { get; }
|
||||
public IList<string[]> Examples { get; }
|
||||
|
||||
private ConfiguredCommand(
|
||||
string name,
|
||||
Type? commandType,
|
||||
Type settingsType,
|
||||
Func<CommandContext, CommandSettings, int>? @delegate,
|
||||
bool isDefaultCommand)
|
||||
{
|
||||
public string Name { get; }
|
||||
public HashSet<string> Aliases { get; }
|
||||
public string? Description { get; set; }
|
||||
public object? Data { get; set; }
|
||||
public Type? CommandType { get; }
|
||||
public Type SettingsType { get; }
|
||||
public Func<CommandContext, CommandSettings, int>? Delegate { get; }
|
||||
public bool IsDefaultCommand { get; }
|
||||
public bool IsHidden { get; set; }
|
||||
Name = name;
|
||||
Aliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
CommandType = commandType;
|
||||
SettingsType = settingsType;
|
||||
Delegate = @delegate;
|
||||
IsDefaultCommand = isDefaultCommand;
|
||||
|
||||
public IList<ConfiguredCommand> Children { get; }
|
||||
public IList<string[]> Examples { get; }
|
||||
|
||||
private ConfiguredCommand(
|
||||
string name,
|
||||
Type? commandType,
|
||||
Type settingsType,
|
||||
Func<CommandContext, CommandSettings, int>? @delegate,
|
||||
bool isDefaultCommand)
|
||||
{
|
||||
Name = name;
|
||||
Aliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
CommandType = commandType;
|
||||
SettingsType = settingsType;
|
||||
Delegate = @delegate;
|
||||
IsDefaultCommand = isDefaultCommand;
|
||||
|
||||
Children = new List<ConfiguredCommand>();
|
||||
Examples = new List<string[]>();
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromBranch(Type settings, string name)
|
||||
{
|
||||
return new ConfiguredCommand(name, null, settings, null, false);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromBranch<TSettings>(string name)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
return new ConfiguredCommand(name, null, typeof(TSettings), null, false);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromType<TCommand>(string name, bool isDefaultCommand = false)
|
||||
where TCommand : class, ICommand
|
||||
{
|
||||
var settingsType = ConfigurationHelper.GetSettingsType(typeof(TCommand));
|
||||
if (settingsType == null)
|
||||
{
|
||||
throw CommandRuntimeException.CouldNotGetSettingsType(typeof(TCommand));
|
||||
}
|
||||
|
||||
return new ConfiguredCommand(name, typeof(TCommand), settingsType, null, isDefaultCommand);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromDelegate<TSettings>(
|
||||
string name, Func<CommandContext, CommandSettings, int>? @delegate = null)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
return new ConfiguredCommand(name, null, typeof(TSettings), @delegate, false);
|
||||
}
|
||||
Children = new List<ConfiguredCommand>();
|
||||
Examples = new List<string[]>();
|
||||
}
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromBranch(Type settings, string name)
|
||||
{
|
||||
return new ConfiguredCommand(name, null, settings, null, false);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromBranch<TSettings>(string name)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
return new ConfiguredCommand(name, null, typeof(TSettings), null, false);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromType<TCommand>(string name, bool isDefaultCommand = false)
|
||||
where TCommand : class, ICommand
|
||||
{
|
||||
var settingsType = ConfigurationHelper.GetSettingsType(typeof(TCommand));
|
||||
if (settingsType == null)
|
||||
{
|
||||
throw CommandRuntimeException.CouldNotGetSettingsType(typeof(TCommand));
|
||||
}
|
||||
|
||||
return new ConfiguredCommand(name, typeof(TCommand), settingsType, null, isDefaultCommand);
|
||||
}
|
||||
|
||||
public static ConfiguredCommand FromDelegate<TSettings>(
|
||||
string name, Func<CommandContext, CommandSettings, int>? @delegate = null)
|
||||
where TSettings : CommandSettings
|
||||
{
|
||||
return new ConfiguredCommand(name, null, typeof(TSettings), @delegate, false);
|
||||
}
|
||||
}
|
@ -1,30 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a configuration.
|
||||
/// </summary>
|
||||
internal interface IConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a configuration.
|
||||
/// Gets the configured commands.
|
||||
/// </summary>
|
||||
internal interface IConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the configured commands.
|
||||
/// </summary>
|
||||
IList<ConfiguredCommand> Commands { get; }
|
||||
IList<ConfiguredCommand> Commands { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings for the configuration.
|
||||
/// </summary>
|
||||
CommandAppSettings Settings { get; }
|
||||
/// <summary>
|
||||
/// Gets the settings for the configuration.
|
||||
/// </summary>
|
||||
CommandAppSettings Settings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default command for the configuration.
|
||||
/// </summary>
|
||||
ConfiguredCommand? DefaultCommand { get; }
|
||||
/// <summary>
|
||||
/// Gets the default command for the configuration.
|
||||
/// </summary>
|
||||
ConfiguredCommand? DefaultCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets all examples for the configuration.
|
||||
/// </summary>
|
||||
IList<string[]> Examples { get; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets all examples for the configuration.
|
||||
/// </summary>
|
||||
IList<string[]> Examples { get; }
|
||||
}
|
@ -1,149 +1,148 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class TemplateParser
|
||||
{
|
||||
internal static class TemplateParser
|
||||
public sealed class ArgumentResult
|
||||
{
|
||||
public sealed class ArgumentResult
|
||||
public string Value { get; set; }
|
||||
public bool Required { get; set; }
|
||||
|
||||
public ArgumentResult(string value, bool required)
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public bool Required { get; set; }
|
||||
|
||||
public ArgumentResult(string value, bool required)
|
||||
{
|
||||
Value = value;
|
||||
Required = required;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class OptionResult
|
||||
{
|
||||
public List<string> LongNames { get; set; }
|
||||
public List<string> ShortNames { get; set; }
|
||||
public string? Value { get; set; }
|
||||
public bool ValueIsOptional { get; set; }
|
||||
|
||||
public OptionResult()
|
||||
{
|
||||
ShortNames = new List<string>();
|
||||
LongNames = new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public static ArgumentResult ParseArgumentTemplate(string template)
|
||||
{
|
||||
var valueName = default(string);
|
||||
var required = false;
|
||||
foreach (var token in TemplateTokenizer.Tokenize(template))
|
||||
{
|
||||
if (token.TokenKind == TemplateToken.Kind.ShortName ||
|
||||
token.TokenKind == TemplateToken.Kind.LongName)
|
||||
{
|
||||
throw CommandTemplateException.ArgumentCannotContainOptions(template, token);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.OptionalValue ||
|
||||
token.TokenKind == TemplateToken.Kind.RequiredValue)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(valueName))
|
||||
{
|
||||
throw CommandTemplateException.MultipleValuesAreNotSupported(template, token);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token.Value))
|
||||
{
|
||||
throw CommandTemplateException.ValuesMustHaveName(template, token);
|
||||
}
|
||||
|
||||
valueName = token.Value;
|
||||
required = token.TokenKind == TemplateToken.Kind.RequiredValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (valueName == null)
|
||||
{
|
||||
throw CommandTemplateException.ArgumentsMustHaveValueName(template);
|
||||
}
|
||||
|
||||
return new ArgumentResult(valueName, required);
|
||||
}
|
||||
|
||||
public static OptionResult ParseOptionTemplate(string template)
|
||||
{
|
||||
var result = new OptionResult();
|
||||
|
||||
foreach (var token in TemplateTokenizer.Tokenize(template))
|
||||
{
|
||||
if (token.TokenKind == TemplateToken.Kind.LongName || token.TokenKind == TemplateToken.Kind.ShortName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(token.Value))
|
||||
{
|
||||
throw CommandTemplateException.OptionsMustHaveName(template, token);
|
||||
}
|
||||
|
||||
if (char.IsDigit(token.Value[0]))
|
||||
{
|
||||
throw CommandTemplateException.OptionNamesCannotStartWithDigit(template, token);
|
||||
}
|
||||
|
||||
foreach (var character in token.Value)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(character) && character != '-' && character != '_')
|
||||
{
|
||||
throw CommandTemplateException.InvalidCharacterInOptionName(template, token, character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.LongName)
|
||||
{
|
||||
if (token.Value.Length == 1)
|
||||
{
|
||||
throw CommandTemplateException.LongOptionMustHaveMoreThanOneCharacter(template, token);
|
||||
}
|
||||
|
||||
result.LongNames.Add(token.Value);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.ShortName)
|
||||
{
|
||||
if (token.Value.Length > 1)
|
||||
{
|
||||
throw CommandTemplateException.ShortOptionMustOnlyBeOneCharacter(template, token);
|
||||
}
|
||||
|
||||
result.ShortNames.Add(token.Value);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.RequiredValue ||
|
||||
token.TokenKind == TemplateToken.Kind.OptionalValue)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(result.Value))
|
||||
{
|
||||
throw CommandTemplateException.MultipleOptionValuesAreNotSupported(template, token);
|
||||
}
|
||||
|
||||
foreach (var character in token.Value)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(character) &&
|
||||
character != '=' && character != '-' && character != '_')
|
||||
{
|
||||
throw CommandTemplateException.InvalidCharacterInValueName(template, token, character);
|
||||
}
|
||||
}
|
||||
|
||||
result.Value = token.Value.ToUpperInvariant();
|
||||
result.ValueIsOptional = token.TokenKind == TemplateToken.Kind.OptionalValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.LongNames.Count == 0 &&
|
||||
result.ShortNames.Count == 0)
|
||||
{
|
||||
throw CommandTemplateException.MissingLongAndShortName(template, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
Value = value;
|
||||
Required = required;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class OptionResult
|
||||
{
|
||||
public List<string> LongNames { get; set; }
|
||||
public List<string> ShortNames { get; set; }
|
||||
public string? Value { get; set; }
|
||||
public bool ValueIsOptional { get; set; }
|
||||
|
||||
public OptionResult()
|
||||
{
|
||||
ShortNames = new List<string>();
|
||||
LongNames = new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
public static ArgumentResult ParseArgumentTemplate(string template)
|
||||
{
|
||||
var valueName = default(string);
|
||||
var required = false;
|
||||
foreach (var token in TemplateTokenizer.Tokenize(template))
|
||||
{
|
||||
if (token.TokenKind == TemplateToken.Kind.ShortName ||
|
||||
token.TokenKind == TemplateToken.Kind.LongName)
|
||||
{
|
||||
throw CommandTemplateException.ArgumentCannotContainOptions(template, token);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.OptionalValue ||
|
||||
token.TokenKind == TemplateToken.Kind.RequiredValue)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(valueName))
|
||||
{
|
||||
throw CommandTemplateException.MultipleValuesAreNotSupported(template, token);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(token.Value))
|
||||
{
|
||||
throw CommandTemplateException.ValuesMustHaveName(template, token);
|
||||
}
|
||||
|
||||
valueName = token.Value;
|
||||
required = token.TokenKind == TemplateToken.Kind.RequiredValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (valueName == null)
|
||||
{
|
||||
throw CommandTemplateException.ArgumentsMustHaveValueName(template);
|
||||
}
|
||||
|
||||
return new ArgumentResult(valueName, required);
|
||||
}
|
||||
|
||||
public static OptionResult ParseOptionTemplate(string template)
|
||||
{
|
||||
var result = new OptionResult();
|
||||
|
||||
foreach (var token in TemplateTokenizer.Tokenize(template))
|
||||
{
|
||||
if (token.TokenKind == TemplateToken.Kind.LongName || token.TokenKind == TemplateToken.Kind.ShortName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(token.Value))
|
||||
{
|
||||
throw CommandTemplateException.OptionsMustHaveName(template, token);
|
||||
}
|
||||
|
||||
if (char.IsDigit(token.Value[0]))
|
||||
{
|
||||
throw CommandTemplateException.OptionNamesCannotStartWithDigit(template, token);
|
||||
}
|
||||
|
||||
foreach (var character in token.Value)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(character) && character != '-' && character != '_')
|
||||
{
|
||||
throw CommandTemplateException.InvalidCharacterInOptionName(template, token, character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.LongName)
|
||||
{
|
||||
if (token.Value.Length == 1)
|
||||
{
|
||||
throw CommandTemplateException.LongOptionMustHaveMoreThanOneCharacter(template, token);
|
||||
}
|
||||
|
||||
result.LongNames.Add(token.Value);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.ShortName)
|
||||
{
|
||||
if (token.Value.Length > 1)
|
||||
{
|
||||
throw CommandTemplateException.ShortOptionMustOnlyBeOneCharacter(template, token);
|
||||
}
|
||||
|
||||
result.ShortNames.Add(token.Value);
|
||||
}
|
||||
|
||||
if (token.TokenKind == TemplateToken.Kind.RequiredValue ||
|
||||
token.TokenKind == TemplateToken.Kind.OptionalValue)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(result.Value))
|
||||
{
|
||||
throw CommandTemplateException.MultipleOptionValuesAreNotSupported(template, token);
|
||||
}
|
||||
|
||||
foreach (var character in token.Value)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(character) &&
|
||||
character != '=' && character != '-' && character != '_')
|
||||
{
|
||||
throw CommandTemplateException.InvalidCharacterInValueName(template, token, character);
|
||||
}
|
||||
}
|
||||
|
||||
result.Value = token.Value.ToUpperInvariant();
|
||||
result.ValueIsOptional = token.TokenKind == TemplateToken.Kind.OptionalValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.LongNames.Count == 0 &&
|
||||
result.ShortNames.Count == 0)
|
||||
{
|
||||
throw CommandTemplateException.MissingLongAndShortName(template, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class TemplateToken
|
||||
{
|
||||
internal sealed class TemplateToken
|
||||
public Kind TokenKind { get; }
|
||||
public int Position { get; }
|
||||
public string Value { get; }
|
||||
public string Representation { get; }
|
||||
|
||||
public TemplateToken(Kind kind, int position, string value, string representation)
|
||||
{
|
||||
public Kind TokenKind { get; }
|
||||
public int Position { get; }
|
||||
public string Value { get; }
|
||||
public string Representation { get; }
|
||||
TokenKind = kind;
|
||||
Position = position;
|
||||
Value = value;
|
||||
Representation = representation;
|
||||
}
|
||||
|
||||
public TemplateToken(Kind kind, int position, string value, string representation)
|
||||
{
|
||||
TokenKind = kind;
|
||||
Position = position;
|
||||
Value = value;
|
||||
Representation = representation;
|
||||
}
|
||||
|
||||
public enum Kind
|
||||
{
|
||||
Unknown = 0,
|
||||
LongName,
|
||||
ShortName,
|
||||
RequiredValue,
|
||||
OptionalValue,
|
||||
}
|
||||
public enum Kind
|
||||
{
|
||||
Unknown = 0,
|
||||
LongName,
|
||||
ShortName,
|
||||
RequiredValue,
|
||||
OptionalValue,
|
||||
}
|
||||
}
|
@ -1,135 +1,134 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class TemplateTokenizer
|
||||
{
|
||||
internal static class TemplateTokenizer
|
||||
public static IReadOnlyList<TemplateToken> Tokenize(string template)
|
||||
{
|
||||
public static IReadOnlyList<TemplateToken> Tokenize(string template)
|
||||
using var buffer = new TextBuffer(template);
|
||||
var result = new List<TemplateToken>();
|
||||
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
using var buffer = new TextBuffer(template);
|
||||
var result = new List<TemplateToken>();
|
||||
EatWhitespace(buffer);
|
||||
|
||||
while (!buffer.ReachedEnd)
|
||||
if (!buffer.TryPeek(out var character))
|
||||
{
|
||||
EatWhitespace(buffer);
|
||||
|
||||
if (!buffer.TryPeek(out var character))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (character == '-')
|
||||
{
|
||||
result.Add(ReadOption(buffer));
|
||||
}
|
||||
else if (character == '|')
|
||||
{
|
||||
buffer.Consume('|');
|
||||
}
|
||||
else if (character == '<')
|
||||
{
|
||||
result.Add(ReadValue(buffer, true));
|
||||
}
|
||||
else if (character == '[')
|
||||
{
|
||||
result.Add(ReadValue(buffer, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CommandTemplateException.UnexpectedCharacter(buffer.Original, buffer.Position, character);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void EatWhitespace(TextBuffer buffer)
|
||||
{
|
||||
while (!buffer.ReachedEnd)
|
||||
if (character == '-')
|
||||
{
|
||||
var character = buffer.Peek();
|
||||
if (!char.IsWhiteSpace(character))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.Read();
|
||||
result.Add(ReadOption(buffer));
|
||||
}
|
||||
else if (character == '|')
|
||||
{
|
||||
buffer.Consume('|');
|
||||
}
|
||||
else if (character == '<')
|
||||
{
|
||||
result.Add(ReadValue(buffer, true));
|
||||
}
|
||||
else if (character == '[')
|
||||
{
|
||||
result.Add(ReadValue(buffer, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CommandTemplateException.UnexpectedCharacter(buffer.Original, buffer.Position, character);
|
||||
}
|
||||
}
|
||||
|
||||
private static TemplateToken ReadOption(TextBuffer buffer)
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void EatWhitespace(TextBuffer buffer)
|
||||
{
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
var position = buffer.Position;
|
||||
|
||||
buffer.Consume('-');
|
||||
if (buffer.IsNext('-'))
|
||||
var character = buffer.Peek();
|
||||
if (!char.IsWhiteSpace(character))
|
||||
{
|
||||
buffer.Consume('-');
|
||||
var longValue = ReadOptionName(buffer);
|
||||
return new TemplateToken(TemplateToken.Kind.LongName, position, longValue, $"--{longValue}");
|
||||
break;
|
||||
}
|
||||
|
||||
var shortValue = ReadOptionName(buffer);
|
||||
return new TemplateToken(TemplateToken.Kind.ShortName, position, shortValue, $"-{shortValue}");
|
||||
}
|
||||
|
||||
private static string ReadOptionName(TextBuffer buffer)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
var character = buffer.Peek();
|
||||
if (char.IsWhiteSpace(character) || character == '|')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Append(buffer.Read());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static TemplateToken ReadValue(TextBuffer buffer, bool required)
|
||||
{
|
||||
var start = required ? '<' : '[';
|
||||
var end = required ? '>' : ']';
|
||||
|
||||
var position = buffer.Position;
|
||||
var kind = required ? TemplateToken.Kind.RequiredValue : TemplateToken.Kind.OptionalValue;
|
||||
|
||||
// Consume start of value character (< or [).
|
||||
buffer.Consume(start);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
var character = buffer.Peek();
|
||||
if (character == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.Read();
|
||||
builder.Append(character);
|
||||
}
|
||||
|
||||
if (buffer.ReachedEnd)
|
||||
{
|
||||
var name = builder.ToString();
|
||||
var token = new TemplateToken(kind, position, name, $"{start}{name}");
|
||||
throw CommandTemplateException.UnterminatedValueName(buffer.Original, token);
|
||||
}
|
||||
|
||||
// Consume end of value character (> or ]).
|
||||
buffer.Consume(end);
|
||||
|
||||
// Get the value (the text within the brackets).
|
||||
var value = builder.ToString();
|
||||
|
||||
// Create a token and return it.
|
||||
return new TemplateToken(kind, position, value, required ? $"<{value}>" : $"[{value}]");
|
||||
buffer.Read();
|
||||
}
|
||||
}
|
||||
|
||||
private static TemplateToken ReadOption(TextBuffer buffer)
|
||||
{
|
||||
var position = buffer.Position;
|
||||
|
||||
buffer.Consume('-');
|
||||
if (buffer.IsNext('-'))
|
||||
{
|
||||
buffer.Consume('-');
|
||||
var longValue = ReadOptionName(buffer);
|
||||
return new TemplateToken(TemplateToken.Kind.LongName, position, longValue, $"--{longValue}");
|
||||
}
|
||||
|
||||
var shortValue = ReadOptionName(buffer);
|
||||
return new TemplateToken(TemplateToken.Kind.ShortName, position, shortValue, $"-{shortValue}");
|
||||
}
|
||||
|
||||
private static string ReadOptionName(TextBuffer buffer)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
var character = buffer.Peek();
|
||||
if (char.IsWhiteSpace(character) || character == '|')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Append(buffer.Read());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static TemplateToken ReadValue(TextBuffer buffer, bool required)
|
||||
{
|
||||
var start = required ? '<' : '[';
|
||||
var end = required ? '>' : ']';
|
||||
|
||||
var position = buffer.Position;
|
||||
var kind = required ? TemplateToken.Kind.RequiredValue : TemplateToken.Kind.OptionalValue;
|
||||
|
||||
// Consume start of value character (< or [).
|
||||
buffer.Consume(start);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
while (!buffer.ReachedEnd)
|
||||
{
|
||||
var character = buffer.Peek();
|
||||
if (character == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.Read();
|
||||
builder.Append(character);
|
||||
}
|
||||
|
||||
if (buffer.ReachedEnd)
|
||||
{
|
||||
var name = builder.ToString();
|
||||
var token = new TemplateToken(kind, position, name, $"{start}{name}");
|
||||
throw CommandTemplateException.UnterminatedValueName(buffer.Original, token);
|
||||
}
|
||||
|
||||
// Consume end of value character (> or ]).
|
||||
buffer.Consume(end);
|
||||
|
||||
// Get the value (the text within the brackets).
|
||||
var value = builder.ToString();
|
||||
|
||||
// Create a token and return it.
|
||||
return new TemplateToken(kind, position, value, required ? $"<{value}>" : $"[{value}]");
|
||||
}
|
||||
}
|
@ -1,23 +1,22 @@
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
internal static class CliConstants
|
||||
{
|
||||
public const string DefaultCommandName = "__default_command";
|
||||
public const string True = "true";
|
||||
public const string False = "false";
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
public static string[] AcceptedBooleanValues { get; } = new string[]
|
||||
{
|
||||
internal static class CliConstants
|
||||
{
|
||||
public const string DefaultCommandName = "__default_command";
|
||||
public const string True = "true";
|
||||
public const string False = "false";
|
||||
|
||||
public static string[] AcceptedBooleanValues { get; } = new string[]
|
||||
{
|
||||
True,
|
||||
False,
|
||||
};
|
||||
};
|
||||
|
||||
public static class Commands
|
||||
{
|
||||
public const string Branch = "cli";
|
||||
public const string Version = "version";
|
||||
public const string XmlDoc = "xmldoc";
|
||||
public const string Explain = "explain";
|
||||
}
|
||||
public static class Commands
|
||||
{
|
||||
public const string Branch = "cli";
|
||||
public const string Version = "version";
|
||||
public const string XmlDoc = "xmldoc";
|
||||
public const string Explain = "explain";
|
||||
}
|
||||
}
|
||||
}
|
@ -2,75 +2,74 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class DefaultPairDeconstructor : IPairDeconstructor
|
||||
{
|
||||
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
|
||||
internal sealed class DefaultPairDeconstructor : IPairDeconstructor
|
||||
/// <inheritdoc/>
|
||||
(object? Key, object? Value) IPairDeconstructor.Deconstruct(
|
||||
ITypeResolver resolver,
|
||||
Type keyType,
|
||||
Type valueType,
|
||||
string? value)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
(object? Key, object? Value) IPairDeconstructor.Deconstruct(
|
||||
ITypeResolver resolver,
|
||||
Type keyType,
|
||||
Type valueType,
|
||||
string? value)
|
||||
if (value == null)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
var parts = value.Split(new[] { '=' }, StringSplitOptions.None);
|
||||
if (parts.Length < 1 || parts.Length > 2)
|
||||
{
|
||||
throw CommandParseException.ValueIsNotInValidFormat(value);
|
||||
}
|
||||
|
||||
var stringkey = parts[0];
|
||||
var stringValue = parts.Length == 2 ? parts[1] : null;
|
||||
if (stringValue == null)
|
||||
{
|
||||
// Got a default constructor?
|
||||
if (valueType.IsValueType)
|
||||
{
|
||||
// Get the string variant of a default instance.
|
||||
// Should not get null here, but compiler doesn't know that.
|
||||
stringValue = Activator.CreateInstance(valueType)?.ToString() ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try with an empty string.
|
||||
// Hopefully, the type converter knows how to convert it.
|
||||
stringValue = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return (Parse(stringkey, keyType),
|
||||
Parse(stringValue, valueType));
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
private static object? Parse(string value, Type targetType)
|
||||
var parts = value.Split(new[] { '=' }, StringSplitOptions.None);
|
||||
if (parts.Length < 1 || parts.Length > 2)
|
||||
{
|
||||
try
|
||||
throw CommandParseException.ValueIsNotInValidFormat(value);
|
||||
}
|
||||
|
||||
var stringkey = parts[0];
|
||||
var stringValue = parts.Length == 2 ? parts[1] : null;
|
||||
if (stringValue == null)
|
||||
{
|
||||
// Got a default constructor?
|
||||
if (valueType.IsValueType)
|
||||
{
|
||||
var converter = GetConverter(targetType);
|
||||
return converter.ConvertFrom(value);
|
||||
// Get the string variant of a default instance.
|
||||
// Should not get null here, but compiler doesn't know that.
|
||||
stringValue = Activator.CreateInstance(valueType)?.ToString() ?? string.Empty;
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
// Can't convert something. Just give up and tell the user.
|
||||
throw CommandParseException.ValueIsNotInValidFormat(value);
|
||||
// Try with an empty string.
|
||||
// Hopefully, the type converter knows how to convert it.
|
||||
stringValue = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeConverter GetConverter(Type type)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(type);
|
||||
if (converter != null)
|
||||
{
|
||||
return converter;
|
||||
}
|
||||
return (Parse(stringkey, keyType),
|
||||
Parse(stringValue, valueType));
|
||||
}
|
||||
|
||||
throw new CommandConfigurationException($"Could find a type converter for '{type.FullName}'.");
|
||||
private static object? Parse(string value, Type targetType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var converter = GetConverter(targetType);
|
||||
return converter.ConvertFrom(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Can't convert something. Just give up and tell the user.
|
||||
throw CommandParseException.ValueIsNotInValidFormat(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeConverter GetConverter(Type type)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(type);
|
||||
if (converter != null)
|
||||
{
|
||||
return converter;
|
||||
}
|
||||
|
||||
throw new CommandConfigurationException($"Could find a type converter for '{type.FullName}'.");
|
||||
}
|
||||
}
|
@ -1,25 +1,24 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal sealed class DelegateCommand : ICommand
|
||||
{
|
||||
internal sealed class DelegateCommand : ICommand
|
||||
private readonly Func<CommandContext, CommandSettings, int> _func;
|
||||
|
||||
public DelegateCommand(Func<CommandContext, CommandSettings, int> func)
|
||||
{
|
||||
private readonly Func<CommandContext, CommandSettings, int> _func;
|
||||
|
||||
public DelegateCommand(Func<CommandContext, CommandSettings, int> func)
|
||||
{
|
||||
_func = func;
|
||||
}
|
||||
|
||||
public Task<int> Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Task.FromResult(_func(context, settings));
|
||||
}
|
||||
|
||||
public ValidationResult Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
_func = func;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<int> Execute(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return Task.FromResult(_func(context, settings));
|
||||
}
|
||||
|
||||
public ValidationResult Validate(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
@ -1,52 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandLineParseExceptionFactory
|
||||
{
|
||||
internal static class CommandLineParseExceptionFactory
|
||||
internal static CommandParseException Create(string arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
internal static CommandParseException Create(string arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
return new CommandParseException(message, CreatePrettyMessage(arguments, token, message, details));
|
||||
}
|
||||
|
||||
internal static CommandParseException Create(IEnumerable<string> arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
return new CommandParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details));
|
||||
}
|
||||
|
||||
private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
var composer = new Composer();
|
||||
|
||||
var position = token?.Position ?? 0;
|
||||
var value = token?.Representation ?? arguments;
|
||||
|
||||
// Header
|
||||
composer.LineBreak();
|
||||
composer.Style("red", "Error:");
|
||||
composer.Space().Text(message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
|
||||
// Template
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Text(arguments.EscapeMarkup());
|
||||
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Spaces(position);
|
||||
|
||||
composer.Style("red", error =>
|
||||
{
|
||||
error.Repeat('^', value.Length);
|
||||
error.Space();
|
||||
error.Text(details.TrimEnd('.').EscapeMarkup());
|
||||
error.LineBreak();
|
||||
});
|
||||
|
||||
composer.LineBreak();
|
||||
|
||||
return composer;
|
||||
}
|
||||
return new CommandParseException(message, CreatePrettyMessage(arguments, token, message, details));
|
||||
}
|
||||
}
|
||||
|
||||
internal static CommandParseException Create(IEnumerable<string> arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
return new CommandParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details));
|
||||
}
|
||||
|
||||
private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details)
|
||||
{
|
||||
var composer = new Composer();
|
||||
|
||||
var position = token?.Position ?? 0;
|
||||
var value = token?.Representation ?? arguments;
|
||||
|
||||
// Header
|
||||
composer.LineBreak();
|
||||
composer.Style("red", "Error:");
|
||||
composer.Space().Text(message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
|
||||
// Template
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Text(arguments.EscapeMarkup());
|
||||
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Spaces(position);
|
||||
|
||||
composer.Style("red", error =>
|
||||
{
|
||||
error.Repeat('^', value.Length);
|
||||
error.Space();
|
||||
error.Text(details.TrimEnd('.').EscapeMarkup());
|
||||
error.LineBreak();
|
||||
});
|
||||
|
||||
composer.LineBreak();
|
||||
|
||||
return composer;
|
||||
}
|
||||
}
|
@ -1,57 +1,56 @@
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CommandLineTemplateExceptionFactory
|
||||
{
|
||||
internal static class CommandLineTemplateExceptionFactory
|
||||
internal static CommandTemplateException Create(string template, TemplateToken? token, string message, string details)
|
||||
{
|
||||
internal static CommandTemplateException Create(string template, TemplateToken? token, string message, string details)
|
||||
{
|
||||
return new CommandTemplateException(message, template, CreatePrettyMessage(template, token, message, details));
|
||||
}
|
||||
|
||||
private static IRenderable CreatePrettyMessage(string template, TemplateToken? token, string message, string details)
|
||||
{
|
||||
var composer = new Composer();
|
||||
|
||||
var position = token?.Position ?? 0;
|
||||
var value = token?.Representation ?? template;
|
||||
|
||||
// Header
|
||||
composer.LineBreak();
|
||||
composer.Style("red", "Error:");
|
||||
composer.Space().Text("An error occured when parsing template.");
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Style("yellow", message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
{
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Style("red", message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Template
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Text(template.EscapeMarkup());
|
||||
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Spaces(position);
|
||||
composer.Style("red", error =>
|
||||
{
|
||||
error.Repeat('^', value.Length);
|
||||
error.Space();
|
||||
error.Text(details.TrimEnd('.').EscapeMarkup());
|
||||
error.LineBreak();
|
||||
});
|
||||
}
|
||||
|
||||
composer.LineBreak();
|
||||
|
||||
return composer;
|
||||
}
|
||||
return new CommandTemplateException(message, template, CreatePrettyMessage(template, token, message, details));
|
||||
}
|
||||
}
|
||||
|
||||
private static IRenderable CreatePrettyMessage(string template, TemplateToken? token, string message, string details)
|
||||
{
|
||||
var composer = new Composer();
|
||||
|
||||
var position = token?.Position ?? 0;
|
||||
var value = token?.Representation ?? template;
|
||||
|
||||
// Header
|
||||
composer.LineBreak();
|
||||
composer.Style("red", "Error:");
|
||||
composer.Space().Text("An error occured when parsing template.");
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Style("yellow", message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
{
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Style("red", message.EscapeMarkup());
|
||||
composer.LineBreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Template
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Text(template.EscapeMarkup());
|
||||
|
||||
// Error
|
||||
composer.LineBreak();
|
||||
composer.Spaces(7).Spaces(position);
|
||||
composer.Style("red", error =>
|
||||
{
|
||||
error.Repeat('^', value.Length);
|
||||
error.Space();
|
||||
error.Text(details.TrimEnd('.').EscapeMarkup());
|
||||
error.LineBreak();
|
||||
});
|
||||
}
|
||||
|
||||
composer.LineBreak();
|
||||
|
||||
return composer;
|
||||
}
|
||||
}
|
@ -2,41 +2,40 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class AnsiConsoleExtensions
|
||||
{
|
||||
internal static class AnsiConsoleExtensions
|
||||
private static readonly Lazy<IAnsiConsole> _console;
|
||||
|
||||
static AnsiConsoleExtensions()
|
||||
{
|
||||
private static readonly Lazy<IAnsiConsole> _console;
|
||||
_console = new Lazy<IAnsiConsole>(() => AnsiConsole.Console);
|
||||
}
|
||||
|
||||
static AnsiConsoleExtensions()
|
||||
public static IAnsiConsole GetConsole(this IAnsiConsole? console)
|
||||
{
|
||||
return console ?? _console.Value;
|
||||
}
|
||||
|
||||
public static void SafeRender(this IAnsiConsole? console, IRenderable? renderable)
|
||||
{
|
||||
if (renderable != null)
|
||||
{
|
||||
_console = new Lazy<IAnsiConsole>(() => AnsiConsole.Console);
|
||||
console ??= _console.Value;
|
||||
console.Write(renderable);
|
||||
}
|
||||
}
|
||||
|
||||
public static IAnsiConsole GetConsole(this IAnsiConsole? console)
|
||||
{
|
||||
return console ?? _console.Value;
|
||||
}
|
||||
|
||||
public static void SafeRender(this IAnsiConsole? console, IRenderable? renderable)
|
||||
public static void SafeRender(this IAnsiConsole? console, IEnumerable<IRenderable?> renderables)
|
||||
{
|
||||
console ??= _console.Value;
|
||||
foreach (var renderable in renderables)
|
||||
{
|
||||
if (renderable != null)
|
||||
{
|
||||
console ??= _console.Value;
|
||||
console.Write(renderable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeRender(this IAnsiConsole? console, IEnumerable<IRenderable?> renderables)
|
||||
{
|
||||
console ??= _console.Value;
|
||||
foreach (var renderable in renderables)
|
||||
{
|
||||
if (renderable != null)
|
||||
{
|
||||
console.Write(renderable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class CaseSensitivityExtensions
|
||||
{
|
||||
internal static class CaseSensitivityExtensions
|
||||
public static StringComparison GetStringComparison(this CaseSensitivity caseSensitivity, CommandPart part)
|
||||
{
|
||||
public static StringComparison GetStringComparison(this CaseSensitivity caseSensitivity, CommandPart part)
|
||||
if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0)
|
||||
{
|
||||
if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0)
|
||||
{
|
||||
return StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0)
|
||||
{
|
||||
return StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
return StringComparison.Ordinal;
|
||||
return StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0)
|
||||
{
|
||||
return StringComparison.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
public static StringComparer GetStringComparer(this CaseSensitivity caseSensitivity, CommandPart part)
|
||||
{
|
||||
if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
return StringComparer.Ordinal;
|
||||
}
|
||||
return StringComparison.Ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
public static StringComparer GetStringComparer(this CaseSensitivity caseSensitivity, CommandPart part)
|
||||
{
|
||||
if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
|
||||
return StringComparer.Ordinal;
|
||||
}
|
||||
}
|
@ -1,55 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class ListExtensions
|
||||
{
|
||||
internal static class ListExtensions
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
if (source != null && action != null)
|
||||
{
|
||||
if (source != null && action != null)
|
||||
foreach (var item in source)
|
||||
{
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static T AddAndReturn<T>(this IList<T> source, T item)
|
||||
where T : class
|
||||
public static T AddAndReturn<T>(this IList<T> source, T item)
|
||||
where T : class
|
||||
{
|
||||
source.Add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public static void AddIfNotNull<T>(this IList<T> source, T? item)
|
||||
where T : class
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
source.Add(item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddIfNotNull<T>(this IList<T> source, T? item)
|
||||
where T : class
|
||||
public static void AddRangeIfNotNull<T>(this IList<T> source, IEnumerable<T?> items)
|
||||
where T : class
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
source.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRangeIfNotNull<T>(this IList<T> source, IEnumerable<T?> items)
|
||||
where T : class
|
||||
public static void AddRange<T>(this IList<T> source, IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
source.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange<T>(this IList<T> source, IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
source.Add(item);
|
||||
}
|
||||
source.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class StringExtensions
|
||||
{
|
||||
internal static class StringExtensions
|
||||
internal static int OrdinalIndexOf(this string text, char token)
|
||||
{
|
||||
internal static int OrdinalIndexOf(this string text, char token)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
return text.IndexOf(token);
|
||||
return text.IndexOf(token);
|
||||
#else
|
||||
return text.IndexOf(token, System.StringComparison.Ordinal);
|
||||
return text.IndexOf(token, System.StringComparison.Ordinal);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,23 +2,22 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
{
|
||||
internal static class TypeExtensions
|
||||
{
|
||||
public static bool IsPairDeconstructable(this Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
if (type.GetGenericTypeDefinition() == typeof(ILookup<,>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IDictionary<,>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
return false;
|
||||
internal static class TypeExtensions
|
||||
{
|
||||
public static bool IsPairDeconstructable(this Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
if (type.GetGenericTypeDefinition() == typeof(ILookup<,>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IDictionary<,>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,56 +2,55 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class TypeRegistrarExtensions
|
||||
{
|
||||
internal static class TypeRegistrarExtensions
|
||||
public static void RegisterDependencies(this ITypeRegistrar registrar, CommandModel model)
|
||||
{
|
||||
public static void RegisterDependencies(this ITypeRegistrar registrar, CommandModel model)
|
||||
var stack = new Stack<CommandInfo>();
|
||||
model.Commands.ForEach(c => stack.Push(c));
|
||||
if (model.DefaultCommand != null)
|
||||
{
|
||||
var stack = new Stack<CommandInfo>();
|
||||
model.Commands.ForEach(c => stack.Push(c));
|
||||
if (model.DefaultCommand != null)
|
||||
stack.Push(model.DefaultCommand);
|
||||
}
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var command = stack.Pop();
|
||||
|
||||
if (command.SettingsType == null)
|
||||
{
|
||||
stack.Push(model.DefaultCommand);
|
||||
// TODO: Error message
|
||||
throw new InvalidOperationException("Command setting type cannot be null.");
|
||||
}
|
||||
|
||||
while (stack.Count > 0)
|
||||
if (command.CommandType != null)
|
||||
{
|
||||
var command = stack.Pop();
|
||||
registrar?.Register(command.CommandType, command.CommandType);
|
||||
}
|
||||
|
||||
if (command.SettingsType == null)
|
||||
foreach (var parameter in command.Parameters)
|
||||
{
|
||||
var pairDeconstructor = parameter?.PairDeconstructor?.Type;
|
||||
if (pairDeconstructor != null)
|
||||
{
|
||||
// TODO: Error message
|
||||
throw new InvalidOperationException("Command setting type cannot be null.");
|
||||
registrar?.Register(pairDeconstructor, pairDeconstructor);
|
||||
}
|
||||
|
||||
if (command.CommandType != null)
|
||||
var typeConverterTypeName = parameter?.Converter?.ConverterTypeName;
|
||||
if (!string.IsNullOrWhiteSpace(typeConverterTypeName))
|
||||
{
|
||||
registrar?.Register(command.CommandType, command.CommandType);
|
||||
var typeConverterType = Type.GetType(typeConverterTypeName);
|
||||
Debug.Assert(typeConverterType != null, "Could not create type");
|
||||
registrar?.Register(typeConverterType, typeConverterType);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var parameter in command.Parameters)
|
||||
{
|
||||
var pairDeconstructor = parameter?.PairDeconstructor?.Type;
|
||||
if (pairDeconstructor != null)
|
||||
{
|
||||
registrar?.Register(pairDeconstructor, pairDeconstructor);
|
||||
}
|
||||
|
||||
var typeConverterTypeName = parameter?.Converter?.ConverterTypeName;
|
||||
if (!string.IsNullOrWhiteSpace(typeConverterTypeName))
|
||||
{
|
||||
var typeConverterType = Type.GetType(typeConverterTypeName);
|
||||
Debug.Assert(typeConverterType != null, "Could not create type");
|
||||
registrar?.Register(typeConverterType, typeConverterType);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var child in command.Children)
|
||||
{
|
||||
stack.Push(child);
|
||||
}
|
||||
foreach (var child in command.Children)
|
||||
{
|
||||
stack.Push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,43 +5,42 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
|
||||
namespace Spectre.Console.Cli
|
||||
namespace Spectre.Console.Cli;
|
||||
|
||||
internal static class XmlElementExtensions
|
||||
{
|
||||
internal static class XmlElementExtensions
|
||||
public static void SetNullableAttribute(this XmlElement element, string name, string? value)
|
||||
{
|
||||
public static void SetNullableAttribute(this XmlElement element, string name, string? value)
|
||||
element.SetAttribute(name, value ?? "NULL");
|
||||
}
|
||||
|
||||
public static void SetNullableAttribute(this XmlElement element, string name, IEnumerable<string>? values)
|
||||
{
|
||||
if (values?.Any() != true)
|
||||
{
|
||||
element.SetAttribute(name, value ?? "NULL");
|
||||
element.SetAttribute(name, "NULL");
|
||||
}
|
||||
|
||||
public static void SetNullableAttribute(this XmlElement element, string name, IEnumerable<string>? values)
|
||||
element.SetAttribute(name, string.Join(",", values ?? Enumerable.Empty<string>()));
|
||||
}
|
||||
|
||||
public static void SetBooleanAttribute(this XmlElement element, string name, bool value)
|
||||
{
|
||||
element.SetAttribute(name, value ? "true" : "false");
|
||||
}
|
||||
|
||||
public static void SetEnumAttribute(this XmlElement element, string name, Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
if (field != null)
|
||||
{
|
||||
if (values?.Any() != true)
|
||||
var attribute = field.GetCustomAttribute<DescriptionAttribute>(false);
|
||||
if (attribute == null)
|
||||
{
|
||||
element.SetAttribute(name, "NULL");
|
||||
throw new InvalidOperationException("Enum is missing description.");
|
||||
}
|
||||
|
||||
element.SetAttribute(name, string.Join(",", values ?? Enumerable.Empty<string>()));
|
||||
}
|
||||
|
||||
public static void SetBooleanAttribute(this XmlElement element, string name, bool value)
|
||||
{
|
||||
element.SetAttribute(name, value ? "true" : "false");
|
||||
}
|
||||
|
||||
public static void SetEnumAttribute(this XmlElement element, string name, Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
if (field != null)
|
||||
{
|
||||
var attribute = field.GetCustomAttribute<DescriptionAttribute>(false);
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new InvalidOperationException("Enum is missing description.");
|
||||
}
|
||||
|
||||
element.SetAttribute(name, attribute.Description);
|
||||
}
|
||||
element.SetAttribute(name, attribute.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user