mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-04 10:35:27 +08:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/main' into blz/issues/1390
# Conflicts: # src/Tests/Spectre.Console.Tests/Expectations/Widgets/Layout/Render_Layout_With_Three_And_One_Columns.Output.verified.txt
This commit is contained in:
		@@ -98,4 +98,7 @@ dotnet_diagnostic.IDE0044.severity = warning
 | 
			
		||||
dotnet_diagnostic.RCS1047.severity = none
 | 
			
		||||
 | 
			
		||||
# RCS1090: Call 'ConfigureAwait(false)'.
 | 
			
		||||
dotnet_diagnostic.RCS1090.severity = warning
 | 
			
		||||
dotnet_diagnostic.RCS1090.severity = warning
 | 
			
		||||
 | 
			
		||||
# The file header is missing or not located at the top of the file
 | 
			
		||||
dotnet_diagnostic.SA1633.severity = none
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
<Project>
 | 
			
		||||
<Project>
 | 
			
		||||
  <PropertyGroup Label="Settings">
 | 
			
		||||
    <Deterministic>true</Deterministic>
 | 
			
		||||
    <LangVersion>12</LangVersion>
 | 
			
		||||
@@ -7,19 +7,38 @@
 | 
			
		||||
    <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip>
 | 
			
		||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
			
		||||
    <IsPackable>false</IsPackable>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <NoWarn>$(NoWarn);SA1633</NoWarn>
 | 
			
		||||
    <SignAssembly>true</SignAssembly>
 | 
			
		||||
    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\..\resources\spectre.snk</AssemblyOriginatorKeyFile>
 | 
			
		||||
    <PublicKey>00240000048000009400000006020000002400005253413100040000010001006146d3789d31477cf4a3b508dcf772ff9ccad8613f6bd6b17b9c4a960a7a7b551ecd22e4f4119ced70ee8bbdf3ca0a117c99fd6248c16255ea9033110c2233d42e74e81bf4f3f7eb09bfe8b53ad399d957514f427171a86f5fe9fe0014be121d571c80c4a0cfc3531bdbf5a2900d936d93f2c94171b9134f7644a1ac3612a0d0</PublicKey>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup Label="Deterministic Build" Condition="'$(GITHUB_ACTIONS)' == 'true'">
 | 
			
		||||
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Condition="$(IsPackable)">
 | 
			
		||||
    <None Include="$(MSBuildThisFileDirectory)../resources/nuget/logo.png">
 | 
			
		||||
      <Pack>true</Pack>
 | 
			
		||||
      <PackagePath>\</PackagePath>
 | 
			
		||||
      <Link>Properties/Package/Logo.png</Link>
 | 
			
		||||
    </None>
 | 
			
		||||
    <None Include="$(MSBuildThisFileDirectory)../resources/nuget/$(AssemblyName).md">
 | 
			
		||||
      <Pack>true</Pack>
 | 
			
		||||
      <PackagePath>\README.md</PackagePath>
 | 
			
		||||
      <Link>Properties/Package/README.md</Link>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup Label="Package Information">
 | 
			
		||||
    <Description>A library that makes it easier to create beautiful console applications.</Description>
 | 
			
		||||
    <Copyright>Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray</Copyright>
 | 
			
		||||
    <Authors>Patrik Svensson, Phil Scott, Nils Andresen, Cédric Luthi, Frank Ray</Authors>
 | 
			
		||||
    <RepositoryType>git</RepositoryType>
 | 
			
		||||
    <RepositoryUrl>https://github.com/spectreconsole/spectre.console</RepositoryUrl>
 | 
			
		||||
    <PackageIcon>small-logo.png</PackageIcon>
 | 
			
		||||
    <PackageIcon>logo.png</PackageIcon>
 | 
			
		||||
    <PackageReadmeFile>README.md</PackageReadmeFile>
 | 
			
		||||
    <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
 | 
			
		||||
    <PackageProjectUrl>https://github.com/spectreconsole/spectre.console</PackageProjectUrl>
 | 
			
		||||
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
 | 
			
		||||
@@ -31,14 +50,18 @@
 | 
			
		||||
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="$(MSBuildThisFileDirectory)/stylecop.json" Link="Properties/stylecop.json"/>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <!-- Allow folks to build with minimal dependencies (though they will need to provide their own Version data) -->
 | 
			
		||||
  <ItemGroup Label="Build Tools Package References" Condition="'$(UseBuildTimeTools)' != 'false'">
 | 
			
		||||
    <PackageReference Include="MinVer" PrivateAssets="All" Version="4.3.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="8.0.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
 | 
			
		||||
    <PackageReference Include="MinVer" PrivateAssets="All" />
 | 
			
		||||
    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers">
 | 
			
		||||
      <PrivateAssets>All</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="Roslynator.Analyzers" Version="4.11.0">
 | 
			
		||||
    <PackageReference Include="Roslynator.Analyzers">
 | 
			
		||||
      <PrivateAssets>All</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								src/Directory.Packages.props
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Directory.Packages.props
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
<Project>
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Label="Dependencies">
 | 
			
		||||
    <PackageVersion Include="MinVer" PrivateAssets="All" Version="6.0.0"/>
 | 
			
		||||
    <PackageVersion Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" Version="8.0.0"/>
 | 
			
		||||
    <PackageVersion Include="Wcwidth.Sources" Version="2.0.0"/>
 | 
			
		||||
    <PackageVersion Include="IsExternalInit" Version="1.0.3"/>
 | 
			
		||||
    <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
 | 
			
		||||
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
 | 
			
		||||
    <PackageVersion Include="Shouldly" Version="4.2.1"/>
 | 
			
		||||
    <PackageVersion Include="Spectre.Verify.Extensions" Version="22.3.2-preview.0.1"/>
 | 
			
		||||
    <PackageVersion Include="Verify.Xunit" Version="26.4.5"/>
 | 
			
		||||
    <PackageVersion Include="xunit" Version="2.9.0"/>
 | 
			
		||||
    <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2"/>
 | 
			
		||||
    <PackageVersion Include="System.Memory" Version="4.5.5" />
 | 
			
		||||
    <PackageVersion Include="SixLabors.ImageSharp" Version="3.1.5" />
 | 
			
		||||
 | 
			
		||||
    <PackageVersion Include="Nullable" Version="1.3.1"/>
 | 
			
		||||
    <PackageVersion Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="1.0.0-alpha.160" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Label="Static Analysis">
 | 
			
		||||
    <PackageVersion Include="StyleCop.Analyzers" PrivateAssets="All" Version="1.2.0-beta.556"/>
 | 
			
		||||
    <PackageVersion Include="Roslynator.Analyzers" PrivateAssets="All" Version="4.12.5"/>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <Description>A library that extends Spectre.Console with ImageSharp superpowers.</Description>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="SixLabors.ImageSharp" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.0</TargetFrameworks> 
 | 
			
		||||
    <ImplicitUsings>true</ImplicitUsings>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <Description>A library that extends Spectre.Console with JSON superpowers.</Description>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="..\..\Spectre.Console\Internal\Extensions\CharExtensions.cs" Link="Internal\CharExtensions.cs" />
 | 
			
		||||
    <Compile Include="..\..\Spectre.Console\Internal\Extensions\EnumerableExtensions.cs" Link="Internal\EnumerableExtensions.cs" />
 | 
			
		||||
    <Compile Include="..\..\Spectre.Console\Internal\Text\StringBuffer.cs" Link="Internal\StringBuffer.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer.Sandbox;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Sample sandbox for testing out analyzers.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Program
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The program's entry point.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static void Main()
 | 
			
		||||
    {
 | 
			
		||||
        AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <TargetFramework>net8.0</TargetFramework>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console.Analyzer\Spectre.Console.Analyzer.csproj" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,79 +0,0 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 16
 | 
			
		||||
VisualStudioVersion = 16.0.30114.105
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Analyzer", "Spectre.Console.Analyzer\Spectre.Console.Analyzer.csproj", "{18178142-A80D-424F-882D-DB0F787210BD}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Analyzer.Sandbox", "Spectre.Console.Analyzer.Sandbox\Spectre.Console.Analyzer.Sandbox.csproj", "{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Analyzer.Tests", "..\test\Spectre.Console.Analyzer.Tests\Spectre.Console.Analyzer.Tests.csproj", "{609D5D1B-D904-4A31-B237-A04B49910166}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console", "Spectre.Console\Spectre.Console.csproj", "{6BFF310F-9601-4E5D-BC80-118AC708D72A}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Debug|x64 = Debug|x64
 | 
			
		||||
		Debug|x86 = Debug|x86
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
		Release|x64 = Release|x64
 | 
			
		||||
		Release|x86 = Release|x86
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{18178142-A80D-424F-882D-DB0F787210BD}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{44D2E280-8FCD-4FC1-9133-F61E344FD6A6}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{609D5D1B-D904-4A31-B237-A04B49910166}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|x64.Build.0 = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Debug|x86.Build.0 = Debug|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|x64.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|x64.Build.0 = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|x86.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{6BFF310F-9601-4E5D-BC80-118AC708D72A}.Release|x86.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {3BABBA82-B60D-45CE-9C56-8B833474DD3C}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
<SolutionConfiguration>
 | 
			
		||||
  <Settings>
 | 
			
		||||
    <AllowParallelTestExecution>True</AllowParallelTestExecution>
 | 
			
		||||
    <SolutionConfigured>True</SolutionConfigured>
 | 
			
		||||
  </Settings>
 | 
			
		||||
</SolutionConfiguration>
 | 
			
		||||
@@ -1,90 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Analyzer to suggest using available instances of AnsiConsole over the static methods.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
 | 
			
		||||
public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer
 | 
			
		||||
{
 | 
			
		||||
    private static readonly DiagnosticDescriptor _diagnosticDescriptor =
 | 
			
		||||
        Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 | 
			
		||||
        ImmutableArray.Create(_diagnosticDescriptor);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext)
 | 
			
		||||
    {
 | 
			
		||||
        var ansiConsoleType = compilationStartContext.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
 | 
			
		||||
        if (ansiConsoleType == null)
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compilationStartContext.RegisterOperationAction(
 | 
			
		||||
            context =>
 | 
			
		||||
            {
 | 
			
		||||
                // if this operation isn't an invocation against one of the System.Console methods
 | 
			
		||||
                // defined in _methods then we can safely stop analyzing and return;
 | 
			
		||||
                var invocationOperation = (IInvocationOperation)context.Operation;
 | 
			
		||||
                if (!SymbolEqualityComparer.Default.Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // if we aren't in a method then it might be too complex for us to handle.
 | 
			
		||||
                if (!invocationOperation.Syntax.Ancestors().OfType<MethodDeclarationSyntax>().Any())
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!HasFieldAnsiConsole(invocationOperation.Syntax) &&
 | 
			
		||||
                    !HasParameterAnsiConsole(invocationOperation.Syntax))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var methodSymbol = invocationOperation.TargetMethod;
 | 
			
		||||
 | 
			
		||||
                var displayString = SymbolDisplay.ToDisplayString(
 | 
			
		||||
                    methodSymbol,
 | 
			
		||||
                    SymbolDisplayFormat.CSharpShortErrorMessageFormat
 | 
			
		||||
                        .WithParameterOptions(SymbolDisplayParameterOptions.None)
 | 
			
		||||
                        .WithGenericsOptions(SymbolDisplayGenericsOptions.None));
 | 
			
		||||
 | 
			
		||||
                context.ReportDiagnostic(
 | 
			
		||||
                    Diagnostic.Create(
 | 
			
		||||
                        _diagnosticDescriptor,
 | 
			
		||||
                        invocationOperation.Syntax.GetLocation(),
 | 
			
		||||
                        displayString));
 | 
			
		||||
            }, OperationKind.Invocation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode)
 | 
			
		||||
    {
 | 
			
		||||
        return syntaxNode
 | 
			
		||||
            .Ancestors().OfType<MethodDeclarationSyntax>()
 | 
			
		||||
            .First()
 | 
			
		||||
            .ParameterList.Parameters
 | 
			
		||||
            .Any(i => i.Type?.NormalizeWhitespace()?.ToString() == "IAnsiConsole");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static bool HasFieldAnsiConsole(SyntaxNode syntaxNode)
 | 
			
		||||
    {
 | 
			
		||||
        var isStatic = syntaxNode
 | 
			
		||||
            .Ancestors()
 | 
			
		||||
            .OfType<MethodDeclarationSyntax>()
 | 
			
		||||
            .First()
 | 
			
		||||
            .Modifiers.Any(i => i.IsKind(SyntaxKind.StaticKeyword));
 | 
			
		||||
 | 
			
		||||
        return syntaxNode
 | 
			
		||||
            .Ancestors().OfType<ClassDeclarationSyntax>()
 | 
			
		||||
            .First()
 | 
			
		||||
            .Members
 | 
			
		||||
            .OfType<FieldDeclarationSyntax>()
 | 
			
		||||
            .Any(i =>
 | 
			
		||||
                i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" &&
 | 
			
		||||
                (!isStatic ^ i.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.StaticKeyword))));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Analyzer to detect calls to live renderables within a live renderable context.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
 | 
			
		||||
[Shared]
 | 
			
		||||
public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer
 | 
			
		||||
{
 | 
			
		||||
    private static readonly DiagnosticDescriptor _diagnosticDescriptor =
 | 
			
		||||
        Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 | 
			
		||||
        ImmutableArray.Create(_diagnosticDescriptor);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext)
 | 
			
		||||
    {
 | 
			
		||||
        var liveTypes = Constants.LiveRenderables
 | 
			
		||||
            .Select(i => compilationStartContext.Compilation.GetTypeByMetadataName(i))
 | 
			
		||||
            .Where(i => i != null)
 | 
			
		||||
            .ToImmutableArray();
 | 
			
		||||
 | 
			
		||||
        if (liveTypes.Length == 0)
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compilationStartContext.RegisterOperationAction(
 | 
			
		||||
            context =>
 | 
			
		||||
            {
 | 
			
		||||
                var invocationOperation = (IInvocationOperation)context.Operation;
 | 
			
		||||
                var methodSymbol = invocationOperation.TargetMethod;
 | 
			
		||||
 | 
			
		||||
                const string StartMethod = "Start";
 | 
			
		||||
                if (methodSymbol.Name != StartMethod)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (liveTypes.All(i => !SymbolEqualityComparer.Default.Equals(i, methodSymbol.ContainingType)))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var model = context.Operation.SemanticModel!;
 | 
			
		||||
                var parentInvocations = invocationOperation
 | 
			
		||||
                    .Syntax.Ancestors()
 | 
			
		||||
                    .OfType<InvocationExpressionSyntax>()
 | 
			
		||||
                    .Select(i => model.GetOperation(i, context.CancellationToken))
 | 
			
		||||
                    .OfType<IInvocationOperation>()
 | 
			
		||||
                    .ToList();
 | 
			
		||||
 | 
			
		||||
                if (parentInvocations.All(parent =>
 | 
			
		||||
                    parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType, SymbolEqualityComparer.Default)))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var displayString = SymbolDisplay.ToDisplayString(
 | 
			
		||||
                    methodSymbol,
 | 
			
		||||
                    SymbolDisplayFormat.CSharpShortErrorMessageFormat
 | 
			
		||||
                        .WithParameterOptions(SymbolDisplayParameterOptions.None)
 | 
			
		||||
                        .WithGenericsOptions(SymbolDisplayGenericsOptions.None));
 | 
			
		||||
 | 
			
		||||
                context.ReportDiagnostic(
 | 
			
		||||
                    Diagnostic.Create(
 | 
			
		||||
                        _diagnosticDescriptor,
 | 
			
		||||
                        invocationOperation.Syntax.GetLocation(),
 | 
			
		||||
                        displayString));
 | 
			
		||||
            }, OperationKind.Invocation);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Analyzer to detect calls to live renderables within a live renderable context.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
 | 
			
		||||
[Shared]
 | 
			
		||||
public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer
 | 
			
		||||
{
 | 
			
		||||
    private static readonly DiagnosticDescriptor _diagnosticDescriptor =
 | 
			
		||||
        Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 | 
			
		||||
        ImmutableArray.Create(_diagnosticDescriptor);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext)
 | 
			
		||||
    {
 | 
			
		||||
        var ansiConsoleType = compilationStartContext.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
 | 
			
		||||
        var ansiConsoleExtensionsType = compilationStartContext.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions");
 | 
			
		||||
 | 
			
		||||
        if (ansiConsoleType is null && ansiConsoleExtensionsType is null)
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compilationStartContext.RegisterOperationAction(
 | 
			
		||||
            context =>
 | 
			
		||||
            {
 | 
			
		||||
                // if this operation isn't an invocation against one of the System.Console methods
 | 
			
		||||
                // defined in _methods then we can safely stop analyzing and return;
 | 
			
		||||
                var invocationOperation = (IInvocationOperation)context.Operation;
 | 
			
		||||
                var methodSymbol = invocationOperation.TargetMethod;
 | 
			
		||||
 | 
			
		||||
                var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt");
 | 
			
		||||
                if (!promptMethods.Contains(methodSymbol.Name))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingType, ansiConsoleType) &&
 | 
			
		||||
                    !SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var model = context.Operation.SemanticModel!;
 | 
			
		||||
                var parentInvocations = invocationOperation
 | 
			
		||||
                    .Syntax.Ancestors()
 | 
			
		||||
                    .OfType<InvocationExpressionSyntax>()
 | 
			
		||||
                    .Select(i => model.GetOperation(i, context.CancellationToken))
 | 
			
		||||
                    .OfType<IInvocationOperation>()
 | 
			
		||||
                    .ToList();
 | 
			
		||||
 | 
			
		||||
                var liveTypes = Constants.LiveRenderables
 | 
			
		||||
                    .Select(i => context.Compilation.GetTypeByMetadataName(i))
 | 
			
		||||
                    .ToImmutableArray();
 | 
			
		||||
 | 
			
		||||
                if (parentInvocations.All(parent =>
 | 
			
		||||
                    parent.TargetMethod.Name != "Start" ||
 | 
			
		||||
                    !liveTypes.Contains(parent.TargetMethod.ContainingType, SymbolEqualityComparer.Default)))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var displayString = SymbolDisplay.ToDisplayString(
 | 
			
		||||
                    methodSymbol,
 | 
			
		||||
                    SymbolDisplayFormat.CSharpShortErrorMessageFormat
 | 
			
		||||
                        .WithParameterOptions(SymbolDisplayParameterOptions.None)
 | 
			
		||||
                        .WithGenericsOptions(SymbolDisplayGenericsOptions.None));
 | 
			
		||||
 | 
			
		||||
                context.ReportDiagnostic(
 | 
			
		||||
                    Diagnostic.Create(
 | 
			
		||||
                        _diagnosticDescriptor,
 | 
			
		||||
                        invocationOperation.Syntax.GetLocation(),
 | 
			
		||||
                        displayString));
 | 
			
		||||
            }, OperationKind.Invocation);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Base class for Spectre analyzers.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public abstract class SpectreAnalyzer : DiagnosticAnalyzer
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override void Initialize(AnalysisContext context)
 | 
			
		||||
    {
 | 
			
		||||
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
 | 
			
		||||
        context.EnableConcurrentExecution();
 | 
			
		||||
 | 
			
		||||
        context.RegisterCompilationStartAction(AnalyzeCompilation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Analyze compilation.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="compilationStartContext">Compilation Start Analysis Context.</param>
 | 
			
		||||
    protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,61 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Analyzer to enforce the use of AnsiConsole over System.Console for known methods.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
 | 
			
		||||
public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer
 | 
			
		||||
{
 | 
			
		||||
    private static readonly DiagnosticDescriptor _diagnosticDescriptor =
 | 
			
		||||
        Descriptors.S1000_UseAnsiConsoleOverSystemConsole;
 | 
			
		||||
 | 
			
		||||
    private static readonly string[] _methods = { "WriteLine", "Write" };
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 | 
			
		||||
        ImmutableArray.Create(_diagnosticDescriptor);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext)
 | 
			
		||||
    {
 | 
			
		||||
        var systemConsoleType = compilationStartContext.Compilation.GetTypeByMetadataName("System.Console");
 | 
			
		||||
        var spectreConsoleType = compilationStartContext.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
 | 
			
		||||
        if (systemConsoleType == null || spectreConsoleType == null)
 | 
			
		||||
        {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compilationStartContext.RegisterOperationAction(
 | 
			
		||||
            context =>
 | 
			
		||||
            {
 | 
			
		||||
                // if this operation isn't an invocation against one of the System.Console methods
 | 
			
		||||
                // defined in _methods then we can safely stop analyzing and return;
 | 
			
		||||
                var invocationOperation = (IInvocationOperation)context.Operation;
 | 
			
		||||
 | 
			
		||||
                var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name));
 | 
			
		||||
                if (methodName == null)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!SymbolEqualityComparer.Default.Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType))
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var methodSymbol = invocationOperation.TargetMethod;
 | 
			
		||||
 | 
			
		||||
                var displayString = SymbolDisplay.ToDisplayString(
 | 
			
		||||
                    methodSymbol,
 | 
			
		||||
                    SymbolDisplayFormat.CSharpShortErrorMessageFormat
 | 
			
		||||
                        .WithParameterOptions(SymbolDisplayParameterOptions.None)
 | 
			
		||||
                        .WithGenericsOptions(SymbolDisplayGenericsOptions.None));
 | 
			
		||||
 | 
			
		||||
                context.ReportDiagnostic(
 | 
			
		||||
                    Diagnostic.Create(
 | 
			
		||||
                        _diagnosticDescriptor,
 | 
			
		||||
                        invocationOperation.Syntax.GetLocation(),
 | 
			
		||||
                        displayString));
 | 
			
		||||
            }, OperationKind.Invocation);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
internal static class Constants
 | 
			
		||||
{
 | 
			
		||||
    internal const string StaticInstance = "AnsiConsole";
 | 
			
		||||
    internal const string SpectreConsole = "Spectre.Console";
 | 
			
		||||
 | 
			
		||||
    internal static readonly string[] LiveRenderables =
 | 
			
		||||
    {
 | 
			
		||||
        "Spectre.Console.LiveDisplay",
 | 
			
		||||
        "Spectre.Console.Progress",
 | 
			
		||||
        "Spectre.Console.Status",
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,76 +0,0 @@
 | 
			
		||||
using static Microsoft.CodeAnalysis.DiagnosticSeverity;
 | 
			
		||||
using static Spectre.Console.Analyzer.Descriptors.Category;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Code analysis descriptors.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Descriptors
 | 
			
		||||
{
 | 
			
		||||
    internal enum Category
 | 
			
		||||
    {
 | 
			
		||||
        Usage, // 1xxx
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static readonly ConcurrentDictionary<Category, string> _categoryMapping = new();
 | 
			
		||||
 | 
			
		||||
    private static DiagnosticDescriptor Rule(string id, string title, Category category, DiagnosticSeverity defaultSeverity, string messageFormat, string? description = null)
 | 
			
		||||
    {
 | 
			
		||||
        var helpLink = $"https://spectreconsole.net/analyzer/rules/{id.ToLowerInvariant()}";
 | 
			
		||||
        const bool IsEnabledByDefault = true;
 | 
			
		||||
        return new DiagnosticDescriptor(
 | 
			
		||||
            id,
 | 
			
		||||
            title,
 | 
			
		||||
            messageFormat,
 | 
			
		||||
            _categoryMapping.GetOrAdd(category, c => c.ToString()),
 | 
			
		||||
            defaultSeverity,
 | 
			
		||||
            IsEnabledByDefault,
 | 
			
		||||
            description,
 | 
			
		||||
            helpLink);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets definitions of diagnostics Spectre1000.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static DiagnosticDescriptor S1000_UseAnsiConsoleOverSystemConsole { get; } =
 | 
			
		||||
        Rule(
 | 
			
		||||
            "Spectre1000",
 | 
			
		||||
            "Use AnsiConsole instead of System.Console",
 | 
			
		||||
            Usage,
 | 
			
		||||
            Warning,
 | 
			
		||||
            "Use AnsiConsole instead of System.Console");
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets definitions of diagnostics Spectre1010.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static DiagnosticDescriptor S1010_FavorInstanceAnsiConsoleOverStatic { get; } =
 | 
			
		||||
        Rule(
 | 
			
		||||
            "Spectre1010",
 | 
			
		||||
            "Favor the use of the instance of AnsiConsole over the static helper.",
 | 
			
		||||
            Usage,
 | 
			
		||||
            Info,
 | 
			
		||||
            "Favor the use of the instance of AnsiConsole over the static helper.");
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets definitions of diagnostics Spectre1020.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static DiagnosticDescriptor S1020_AvoidConcurrentCallsToMultipleLiveRenderables { get; } =
 | 
			
		||||
        Rule(
 | 
			
		||||
            "Spectre1020",
 | 
			
		||||
            "Avoid calling other live renderables while a current renderable is running.",
 | 
			
		||||
            Usage,
 | 
			
		||||
            Warning,
 | 
			
		||||
            "Avoid calling other live renderables while a current renderable is running.");
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets definitions of diagnostics Spectre1020.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public static DiagnosticDescriptor S1021_AvoidPromptCallsDuringLiveRenderables { get; } =
 | 
			
		||||
        Rule(
 | 
			
		||||
            "Spectre1021",
 | 
			
		||||
            "Avoid prompting for input while a current renderable is running.",
 | 
			
		||||
            Usage,
 | 
			
		||||
            Warning,
 | 
			
		||||
            "Avoid prompting for input while a current renderable is running.");
 | 
			
		||||
}
 | 
			
		||||
@@ -1,202 +0,0 @@
 | 
			
		||||
using Microsoft.CodeAnalysis.Editing;
 | 
			
		||||
using Microsoft.CodeAnalysis.Simplification;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Analyzer.CodeActions;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Code action to change calls to System.Console to AnsiConsole.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class SwitchToAnsiConsoleAction : CodeAction
 | 
			
		||||
{
 | 
			
		||||
    private readonly Document _document;
 | 
			
		||||
    private readonly InvocationExpressionSyntax _originalInvocation;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="SwitchToAnsiConsoleAction"/> class.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="document">Document to change.</param>
 | 
			
		||||
    /// <param name="originalInvocation">The method to change.</param>
 | 
			
		||||
    /// <param name="title">Title of the fix.</param>
 | 
			
		||||
    public SwitchToAnsiConsoleAction(Document document, InvocationExpressionSyntax originalInvocation, string title)
 | 
			
		||||
    {
 | 
			
		||||
        _document = document;
 | 
			
		||||
        _originalInvocation = originalInvocation;
 | 
			
		||||
        Title = title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override string Title { get; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override string EquivalenceKey => Title;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        var editor = await DocumentEditor.CreateAsync(_document, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
        var compilation = editor.SemanticModel.Compilation;
 | 
			
		||||
 | 
			
		||||
        var operation = editor.SemanticModel.GetOperation(_originalInvocation, cancellationToken) as IInvocationOperation;
 | 
			
		||||
        if (operation == null)
 | 
			
		||||
        {
 | 
			
		||||
            return _document;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If there is an IAnsiConsole passed into the method then we'll use it.
 | 
			
		||||
        // otherwise we'll check for a field level instance.
 | 
			
		||||
        // if neither of those exist we'll fall back to the static param.
 | 
			
		||||
        var spectreConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole");
 | 
			
		||||
        var iansiConsoleSymbol = compilation.GetTypeByMetadataName("Spectre.Console.IAnsiConsole");
 | 
			
		||||
 | 
			
		||||
        ISymbol? accessibleConsoleSymbol = spectreConsoleSymbol;
 | 
			
		||||
        if (iansiConsoleSymbol != null)
 | 
			
		||||
        {
 | 
			
		||||
            var isInStaticContext = IsInStaticContext(operation, cancellationToken, out var parentStaticMemberStartPosition);
 | 
			
		||||
 | 
			
		||||
            foreach (var symbol in editor.SemanticModel.LookupSymbols(operation.Syntax.GetLocation().SourceSpan.Start))
 | 
			
		||||
            {
 | 
			
		||||
                // LookupSymbols check the accessibility of the symbol, but it can
 | 
			
		||||
                // suggest instance members when the current context is static.
 | 
			
		||||
                var symbolType = symbol switch
 | 
			
		||||
                {
 | 
			
		||||
                    IParameterSymbol parameter => parameter.Type,
 | 
			
		||||
                    IFieldSymbol field when !isInStaticContext || field.IsStatic => field.Type,
 | 
			
		||||
                    IPropertySymbol { GetMethod: not null } property when !isInStaticContext || property.IsStatic => property.Type,
 | 
			
		||||
                    ILocalSymbol local => local.Type,
 | 
			
		||||
                    _ => null,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // Locals can be returned even if there are not valid in the current context. For instance,
 | 
			
		||||
                // it can return locals declared after the current location. Or it can return locals that
 | 
			
		||||
                // should not be accessible in a static local function.
 | 
			
		||||
                //
 | 
			
		||||
                // void Sample()
 | 
			
		||||
                // {
 | 
			
		||||
                //    int local = 0;
 | 
			
		||||
                //    static void LocalFunction() => local; <-- local is invalid here but LookupSymbols suggests it
 | 
			
		||||
                // }
 | 
			
		||||
                //
 | 
			
		||||
                // Parameters from the ancestor methods or local functions are also returned even if the operation is in a static local function.
 | 
			
		||||
                if (symbol.Kind is SymbolKind.Local or SymbolKind.Parameter)
 | 
			
		||||
                {
 | 
			
		||||
                    var localPosition = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(cancellationToken).GetLocation().SourceSpan.Start;
 | 
			
		||||
 | 
			
		||||
                    // The local is not part of the source tree
 | 
			
		||||
                    if (localPosition == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // The local is declared after the current expression
 | 
			
		||||
                    if (localPosition > _originalInvocation.Span.Start)
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // The local is declared outside the static local function
 | 
			
		||||
                    if (isInStaticContext && localPosition < parentStaticMemberStartPosition)
 | 
			
		||||
                    {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (IsOrImplementSymbol(symbolType, iansiConsoleSymbol))
 | 
			
		||||
                {
 | 
			
		||||
                    accessibleConsoleSymbol = symbol;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (accessibleConsoleSymbol == null)
 | 
			
		||||
        {
 | 
			
		||||
            return _document;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Replace the original invocation
 | 
			
		||||
        var generator = editor.Generator;
 | 
			
		||||
        var consoleExpression = accessibleConsoleSymbol switch
 | 
			
		||||
        {
 | 
			
		||||
            ITypeSymbol typeSymbol => generator.TypeExpression(typeSymbol, addImport: true).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation),
 | 
			
		||||
            _ => generator.IdentifierName(accessibleConsoleSymbol.Name),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var newExpression = generator.InvocationExpression(generator.MemberAccessExpression(consoleExpression, operation.TargetMethod.Name), _originalInvocation.ArgumentList.Arguments)
 | 
			
		||||
                .WithLeadingTrivia(_originalInvocation.GetLeadingTrivia())
 | 
			
		||||
                .WithTrailingTrivia(_originalInvocation.GetTrailingTrivia());
 | 
			
		||||
 | 
			
		||||
        editor.ReplaceNode(_originalInvocation, newExpression);
 | 
			
		||||
 | 
			
		||||
        return editor.GetChangedDocument();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static bool IsOrImplementSymbol(ITypeSymbol? symbol, ITypeSymbol interfaceSymbol)
 | 
			
		||||
    {
 | 
			
		||||
        if (symbol == null)
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (SymbolEqualityComparer.Default.Equals(symbol, interfaceSymbol))
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (var iface in symbol.AllInterfaces)
 | 
			
		||||
        {
 | 
			
		||||
            if (SymbolEqualityComparer.Default.Equals(iface, interfaceSymbol))
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static bool IsInStaticContext(IOperation operation, CancellationToken cancellationToken, out int parentStaticMemberStartPosition)
 | 
			
		||||
    {
 | 
			
		||||
        // Local functions can be nested, and an instance local function can be declared
 | 
			
		||||
        // in a static local function. So, you need to continue to check ancestors when a
 | 
			
		||||
        // local function is not static.
 | 
			
		||||
        foreach (var member in operation.Syntax.Ancestors())
 | 
			
		||||
        {
 | 
			
		||||
            if (member is LocalFunctionStatementSyntax localFunction)
 | 
			
		||||
            {
 | 
			
		||||
                var symbol = operation.SemanticModel!.GetDeclaredSymbol(localFunction, cancellationToken);
 | 
			
		||||
                if (symbol != null && symbol.IsStatic)
 | 
			
		||||
                {
 | 
			
		||||
                    parentStaticMemberStartPosition = localFunction.GetLocation().SourceSpan.Start;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (member is LambdaExpressionSyntax lambdaExpression)
 | 
			
		||||
            {
 | 
			
		||||
                var symbol = operation.SemanticModel!.GetSymbolInfo(lambdaExpression, cancellationToken).Symbol;
 | 
			
		||||
                if (symbol != null && symbol.IsStatic)
 | 
			
		||||
                {
 | 
			
		||||
                    parentStaticMemberStartPosition = lambdaExpression.GetLocation().SourceSpan.Start;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (member is AnonymousMethodExpressionSyntax anonymousMethod)
 | 
			
		||||
            {
 | 
			
		||||
                var symbol = operation.SemanticModel!.GetSymbolInfo(anonymousMethod, cancellationToken).Symbol;
 | 
			
		||||
                if (symbol != null && symbol.IsStatic)
 | 
			
		||||
                {
 | 
			
		||||
                    parentStaticMemberStartPosition = anonymousMethod.GetLocation().SourceSpan.Start;
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (member is MethodDeclarationSyntax methodDeclaration)
 | 
			
		||||
            {
 | 
			
		||||
                parentStaticMemberStartPosition = methodDeclaration.GetLocation().SourceSpan.Start;
 | 
			
		||||
 | 
			
		||||
                var symbol = operation.SemanticModel!.GetDeclaredSymbol(methodDeclaration, cancellationToken);
 | 
			
		||||
                return symbol != null && symbol.IsStatic;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        parentStaticMemberStartPosition = -1;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer.FixProviders;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Fix provider to change System.Console calls to AnsiConsole calls.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[ExportCodeFixProvider(LanguageNames.CSharp)]
 | 
			
		||||
[Shared]
 | 
			
		||||
public class StaticAnsiConsoleToInstanceFix : CodeFixProvider
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
 | 
			
		||||
        Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override async Task RegisterCodeFixesAsync(CodeFixContext context)
 | 
			
		||||
    {
 | 
			
		||||
        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
 | 
			
		||||
        if (root != null)
 | 
			
		||||
        {
 | 
			
		||||
            var methodDeclaration = root.FindNode(context.Span, getInnermostNodeForTie: true).FirstAncestorOrSelf<InvocationExpressionSyntax>();
 | 
			
		||||
            if (methodDeclaration != null)
 | 
			
		||||
            {
 | 
			
		||||
                context.RegisterCodeFix(
 | 
			
		||||
                    new SwitchToAnsiConsoleAction(
 | 
			
		||||
                        context.Document,
 | 
			
		||||
                        methodDeclaration,
 | 
			
		||||
                        "Convert static AnsiConsole calls to local instance."),
 | 
			
		||||
                    context.Diagnostics);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
namespace Spectre.Console.Analyzer.FixProviders;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Fix provider to change System.Console calls to AnsiConsole calls.
 | 
			
		||||
/// </summary>
 | 
			
		||||
[ExportCodeFixProvider(LanguageNames.CSharp)]
 | 
			
		||||
[Shared]
 | 
			
		||||
public class SystemConsoleToAnsiConsoleFix : CodeFixProvider
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
 | 
			
		||||
        Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id);
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc />
 | 
			
		||||
    public override async Task RegisterCodeFixesAsync(CodeFixContext context)
 | 
			
		||||
    {
 | 
			
		||||
        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
 | 
			
		||||
        if (root != null)
 | 
			
		||||
        {
 | 
			
		||||
            var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>();
 | 
			
		||||
            if (methodDeclaration != null)
 | 
			
		||||
            {
 | 
			
		||||
                context.RegisterCodeFix(
 | 
			
		||||
                    new SwitchToAnsiConsoleAction(
 | 
			
		||||
                        context.Document,
 | 
			
		||||
                        methodDeclaration,
 | 
			
		||||
                        "Convert static call to AnsiConsole to Spectre.Console.AnsiConsole"),
 | 
			
		||||
                    context.Diagnostics);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Analyzer;
 | 
			
		||||
 | 
			
		||||
internal static class Syntax
 | 
			
		||||
{
 | 
			
		||||
    public static readonly UsingDirectiveSyntax SpectreUsing = UsingDirective(QualifiedName(IdentifierName("Spectre"), IdentifierName("Console")));
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
global using System.Collections.Concurrent;
 | 
			
		||||
global using System.Collections.Immutable;
 | 
			
		||||
global using System.Composition;
 | 
			
		||||
global using System.Linq;
 | 
			
		||||
global using System.Threading;
 | 
			
		||||
global using System.Threading.Tasks;
 | 
			
		||||
global using Microsoft.CodeAnalysis;
 | 
			
		||||
global using Microsoft.CodeAnalysis.CodeActions;
 | 
			
		||||
global using Microsoft.CodeAnalysis.CodeFixes;
 | 
			
		||||
global using Microsoft.CodeAnalysis.CSharp;
 | 
			
		||||
global using Microsoft.CodeAnalysis.CSharp.Syntax;
 | 
			
		||||
global using Microsoft.CodeAnalysis.Diagnostics;
 | 
			
		||||
global using Microsoft.CodeAnalysis.Operations;
 | 
			
		||||
global using Spectre.Console.Analyzer.CodeActions;
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
    <PropertyGroup>
 | 
			
		||||
        <Description>Best practice analyzers for Spectre.Console.</Description>
 | 
			
		||||
        <TargetFramework>netstandard2.0</TargetFramework>
 | 
			
		||||
        <IsPackable>true</IsPackable>
 | 
			
		||||
        <DevelopmentDependency>true</DevelopmentDependency>
 | 
			
		||||
        <IncludeBuildOutput>false</IncludeBuildOutput>
 | 
			
		||||
        <Nullable>enable</Nullable>
 | 
			
		||||
        <NoPackageAnalysis>true</NoPackageAnalysis>
 | 
			
		||||
        <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
 | 
			
		||||
    </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
        <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
        <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
 | 
			
		||||
        <PackageReference Include="Microsoft.CodeAnalysis" Version="4.8.0" PrivateAssets="all" />
 | 
			
		||||
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
 | 
			
		||||
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" PrivateAssets="all" />
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
      <None Remove="bin\Debug\netstandard2.0\\Spectre.Console.Analyzer.dll" />
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
        <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -13,6 +13,11 @@ public sealed class CommandContext
 | 
			
		||||
    /// </value>
 | 
			
		||||
    public IRemainingArguments Remaining { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets all the arguments that were passed to the applicaton.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public IReadOnlyList<string> Arguments { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the name of the command.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -32,11 +37,17 @@ public sealed class CommandContext
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="CommandContext"/> class.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="arguments">All arguments that were passed to the application.</param>
 | 
			
		||||
    /// <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)
 | 
			
		||||
    public CommandContext(
 | 
			
		||||
        IEnumerable<string> arguments,
 | 
			
		||||
        IRemainingArguments remaining,
 | 
			
		||||
        string name,
 | 
			
		||||
        object? data)
 | 
			
		||||
    {
 | 
			
		||||
        Arguments = arguments.ToSafeReadOnlyList();
 | 
			
		||||
        Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining));
 | 
			
		||||
        Name = name ?? throw new System.ArgumentNullException(nameof(name));
 | 
			
		||||
        Data = data;
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ public static class ConfiguratorExtensions
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Overrides the auto-detected version of the application.
 | 
			
		||||
    /// Sets the version of the application.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="configurator">The configurator.</param>
 | 
			
		||||
    /// <param name="version">The version of application.</param>
 | 
			
		||||
@@ -98,6 +98,25 @@ public static class ConfiguratorExtensions
 | 
			
		||||
        return configurator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Uses the version retrieved from the <see cref="AssemblyInformationalVersionAttribute"/>
 | 
			
		||||
    /// as the application's version.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="configurator">The configurator.</param>
 | 
			
		||||
    /// <returns>A configurator that can be used to configure the application further.</returns>
 | 
			
		||||
    public static IConfigurator UseAssemblyInformationalVersion(this IConfigurator configurator)
 | 
			
		||||
    {
 | 
			
		||||
        if (configurator == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(configurator));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configurator.Settings.ApplicationVersion =
 | 
			
		||||
            VersionHelper.GetVersion(Assembly.GetEntryAssembly());
 | 
			
		||||
 | 
			
		||||
        return configurator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Hides the <c>DEFAULT</c> column that lists default values coming from the
 | 
			
		||||
    /// <see cref="DefaultValueAttribute"/> in the options help text.
 | 
			
		||||
@@ -324,11 +343,16 @@ public static class ConfiguratorExtensions
 | 
			
		||||
    /// <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,
 | 
			
		||||
        this IConfigurator<TSettings>? configurator,
 | 
			
		||||
        string name,
 | 
			
		||||
        Func<CommandContext, int> func)
 | 
			
		||||
            where TSettings : CommandSettings
 | 
			
		||||
        where TSettings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        if (typeof(TSettings).IsAbstract)
 | 
			
		||||
        {
 | 
			
		||||
            AddDelegate(configurator as IConfigurator<EmptyCommandSettings>, name, func);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (configurator == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(configurator));
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
        public bool Required { get; }
 | 
			
		||||
        public string? Description { get; }
 | 
			
		||||
 | 
			
		||||
        public HelpArgument(string name, int position, bool required, string? description)
 | 
			
		||||
        private HelpArgument(string name, int position, bool required, string? description)
 | 
			
		||||
        {
 | 
			
		||||
            Name = name;
 | 
			
		||||
            Position = position;
 | 
			
		||||
@@ -68,7 +68,7 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
        public string? Description { get; }
 | 
			
		||||
        public object? DefaultValue { get; }
 | 
			
		||||
 | 
			
		||||
        public HelpOption(string? @short, string? @long, string? @value, bool? valueIsOptional, string? description, object? defaultValue)
 | 
			
		||||
        private HelpOption(string? @short, string? @long, string? @value, bool? valueIsOptional, string? description, object? defaultValue)
 | 
			
		||||
        {
 | 
			
		||||
            Short = @short;
 | 
			
		||||
            Long = @long;
 | 
			
		||||
@@ -78,17 +78,27 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
            DefaultValue = defaultValue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IReadOnlyList<HelpOption> Get(ICommandInfo? command, HelpProviderResources resources)
 | 
			
		||||
        public static IReadOnlyList<HelpOption> Get(
 | 
			
		||||
            ICommandModel model,
 | 
			
		||||
            ICommandInfo? command,
 | 
			
		||||
            HelpProviderResources resources)
 | 
			
		||||
        {
 | 
			
		||||
            var parameters = new List<HelpOption>();
 | 
			
		||||
            parameters.Add(new HelpOption("h", "help", null, null, resources.PrintHelpDescription, null));
 | 
			
		||||
            var parameters = new List<HelpOption>
 | 
			
		||||
            {
 | 
			
		||||
                new HelpOption("h", "help", null, null, resources.PrintHelpDescription, null),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Version information applies to the entire application
 | 
			
		||||
            // Include the "-v" option in the help when at the root of the command line application
 | 
			
		||||
            // Don't allow the "-v" option if users have specified one or more sub-commands
 | 
			
		||||
            if ((command == null || command?.Parent == null) && !(command?.IsBranch ?? false))
 | 
			
		||||
            if ((command?.Parent == null) && !(command?.IsBranch ?? false))
 | 
			
		||||
            {
 | 
			
		||||
                parameters.Add(new HelpOption("v", "version", null, null, resources.PrintVersionDescription, null));
 | 
			
		||||
                // Only show the version command if there is an
 | 
			
		||||
                // application version set.
 | 
			
		||||
                if (model.ApplicationVersion != null)
 | 
			
		||||
                {
 | 
			
		||||
                    parameters.Add(new HelpOption("v", "version", null, null, resources.PrintVersionDescription, null));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            parameters.AddRange(command?.Parameters.OfType<ICommandOption>().Where(o => !o.IsHidden).Select(o =>
 | 
			
		||||
@@ -101,11 +111,6 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal Composer NewComposer()
 | 
			
		||||
    {
 | 
			
		||||
        return new Composer(RenderMarkupInline);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="HelpProvider"/> class.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -383,7 +388,7 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
    public virtual IEnumerable<IRenderable> GetOptions(ICommandModel model, ICommandInfo? command)
 | 
			
		||||
    {
 | 
			
		||||
        // Collect all options into a single structure.
 | 
			
		||||
        var parameters = HelpOption.Get(command, resources);
 | 
			
		||||
        var parameters = HelpOption.Get(model, command, resources);
 | 
			
		||||
        if (parameters.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            return Array.Empty<IRenderable>();
 | 
			
		||||
@@ -420,7 +425,7 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
 | 
			
		||||
            if (defaultValueColumn)
 | 
			
		||||
            {
 | 
			
		||||
                columns.Add(GetOptionDefaultValue(option.DefaultValue));
 | 
			
		||||
                columns.Add(GetDefaultValueForOption(option.DefaultValue));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            columns.Add(NewComposer().Text(option.Description?.TrimEnd('.') ?? " "));
 | 
			
		||||
@@ -433,60 +438,6 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IRenderable GetOptionParts(HelpOption option)
 | 
			
		||||
    {
 | 
			
		||||
        var composer = NewComposer();
 | 
			
		||||
 | 
			
		||||
        if (option.Short != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("-").Text(option.Short);
 | 
			
		||||
            if (option.Long != null)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Text(", ");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("  ");
 | 
			
		||||
            if (option.Long != null)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Text("  ");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (option.Long != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("--").Text(option.Long);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (option.Value != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text(" ");
 | 
			
		||||
            if (option.ValueIsOptional ?? false)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Style(helpStyles?.Options?.OptionalOption ?? Style.Plain, $"[{option.Value}]");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                composer.Style(helpStyles?.Options?.RequiredOption ?? Style.Plain, $"<{option.Value}>");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IRenderable GetOptionDefaultValue(object? defaultValue)
 | 
			
		||||
    {
 | 
			
		||||
        return defaultValue switch
 | 
			
		||||
        {
 | 
			
		||||
            null => NewComposer().Text(" "),
 | 
			
		||||
            "" => NewComposer().Text(" "),
 | 
			
		||||
            Array { Length: 0 } => NewComposer().Text(" "),
 | 
			
		||||
            Array array => NewComposer().Join(", ", array.Cast<object>().Select(o => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, o.ToString() ?? string.Empty))),
 | 
			
		||||
            _ => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, defaultValue?.ToString() ?? string.Empty),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the commands section of the help information.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -556,4 +507,63 @@ public class HelpProvider : IHelpProvider
 | 
			
		||||
    {
 | 
			
		||||
        yield break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Composer NewComposer()
 | 
			
		||||
    {
 | 
			
		||||
        return new Composer(RenderMarkupInline);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private IRenderable GetOptionParts(HelpOption option)
 | 
			
		||||
    {
 | 
			
		||||
        var composer = NewComposer();
 | 
			
		||||
 | 
			
		||||
        if (option.Short != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("-").Text(option.Short);
 | 
			
		||||
            if (option.Long != null)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Text(", ");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("  ");
 | 
			
		||||
            if (option.Long != null)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Text("  ");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (option.Long != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text("--").Text(option.Long);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (option.Value != null)
 | 
			
		||||
        {
 | 
			
		||||
            composer.Text(" ");
 | 
			
		||||
            if (option.ValueIsOptional ?? false)
 | 
			
		||||
            {
 | 
			
		||||
                composer.Style(helpStyles?.Options?.OptionalOption ?? Style.Plain, $"[{option.Value}]");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                composer.Style(helpStyles?.Options?.RequiredOption ?? Style.Plain, $"<{option.Value}>");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return composer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Composer GetDefaultValueForOption(object? defaultValue)
 | 
			
		||||
    {
 | 
			
		||||
        return defaultValue switch
 | 
			
		||||
        {
 | 
			
		||||
            null => NewComposer().Text(" "),
 | 
			
		||||
            "" => NewComposer().Text(" "),
 | 
			
		||||
            Array { Length: 0 } => NewComposer().Text(" "),
 | 
			
		||||
            Array array => NewComposer().Join(", ", array.Cast<object>().Select(o => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, o.ToString() ?? string.Empty))),
 | 
			
		||||
            _ => NewComposer().Style(helpStyles?.Options?.DefaultValue ?? Style.Plain, defaultValue?.ToString() ?? string.Empty),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,4 +9,9 @@ public interface ICommandModel : ICommandContainer
 | 
			
		||||
    /// Gets the name of the application.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    string ApplicationName { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the version of the application.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    string? ApplicationVersion { get; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ public interface IRemainingArguments
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the raw, non-parsed remaining arguments.
 | 
			
		||||
    /// This is normally everything after the `--` delimiter.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    IReadOnlyList<string> Raw { get; }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,7 @@ internal sealed class CommandExecutor
 | 
			
		||||
            throw new ArgumentNullException(nameof(configuration));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        args ??= new List<string>();
 | 
			
		||||
        var arguments = args.ToSafeReadOnlyList();
 | 
			
		||||
 | 
			
		||||
        _registrar.RegisterInstance(typeof(IConfiguration), configuration);
 | 
			
		||||
        _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
 | 
			
		||||
@@ -31,7 +31,7 @@ internal sealed class CommandExecutor
 | 
			
		||||
        if (model.DefaultCommand == null)
 | 
			
		||||
        {
 | 
			
		||||
            // Got at least one argument?
 | 
			
		||||
            var firstArgument = args.FirstOrDefault();
 | 
			
		||||
            var firstArgument = arguments.FirstOrDefault();
 | 
			
		||||
            if (firstArgument != null)
 | 
			
		||||
            {
 | 
			
		||||
                // Asking for version? Kind of a hack, but it's alright.
 | 
			
		||||
@@ -39,15 +39,18 @@ internal sealed class CommandExecutor
 | 
			
		||||
                if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) ||
 | 
			
		||||
                    firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    var console = configuration.Settings.Console.GetConsole();
 | 
			
		||||
                    console.WriteLine(ResolveApplicationVersion(configuration));
 | 
			
		||||
                    return 0;
 | 
			
		||||
                    if (configuration.Settings.ApplicationVersion != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        var console = configuration.Settings.Console.GetConsole();
 | 
			
		||||
                        console.MarkupLine(configuration.Settings.ApplicationVersion);
 | 
			
		||||
                        return 0;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Parse and map the model against the arguments.
 | 
			
		||||
        var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args);
 | 
			
		||||
        var parsedResult = ParseCommandLineArguments(model, configuration.Settings, arguments);
 | 
			
		||||
 | 
			
		||||
        // Register the arguments with the container.
 | 
			
		||||
        _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
 | 
			
		||||
@@ -79,7 +82,7 @@ internal sealed class CommandExecutor
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Is this the default and is it called without arguments when there are required arguments?
 | 
			
		||||
            if (leaf.Command.IsDefaultCommand && args.Count() == 0 && leaf.Command.Parameters.Any(p => p.Required))
 | 
			
		||||
            if (leaf.Command.IsDefaultCommand && arguments.Count == 0 && leaf.Command.Parameters.Any(p => p.Required))
 | 
			
		||||
            {
 | 
			
		||||
                // Display help for default command.
 | 
			
		||||
                configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
 | 
			
		||||
@@ -87,15 +90,18 @@ internal sealed class CommandExecutor
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create the content.
 | 
			
		||||
            var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data);
 | 
			
		||||
            var context = new CommandContext(
 | 
			
		||||
                arguments,
 | 
			
		||||
                parsedResult.Remaining,
 | 
			
		||||
                leaf.Command.Name,
 | 
			
		||||
                leaf.Command.Data);
 | 
			
		||||
 | 
			
		||||
            // Execute the command tree.
 | 
			
		||||
            return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#pragma warning disable CS8603 // Possible null reference return.
 | 
			
		||||
    private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
 | 
			
		||||
    private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IReadOnlyList<string> args)
 | 
			
		||||
    {
 | 
			
		||||
        var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
 | 
			
		||||
 | 
			
		||||
@@ -103,7 +109,7 @@ internal sealed class CommandExecutor
 | 
			
		||||
        var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
 | 
			
		||||
        var parsedResult = parser.Parse(parserContext, tokenizerResult);
 | 
			
		||||
 | 
			
		||||
        var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
 | 
			
		||||
        var lastParsedLeaf = parsedResult.Tree?.GetLeafCommand();
 | 
			
		||||
        var lastParsedCommand = lastParsedLeaf?.Command;
 | 
			
		||||
        if (lastParsedLeaf != null && lastParsedCommand != null &&
 | 
			
		||||
            lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
 | 
			
		||||
@@ -122,14 +128,6 @@ internal sealed class CommandExecutor
 | 
			
		||||
 | 
			
		||||
        return parsedResult;
 | 
			
		||||
    }
 | 
			
		||||
#pragma warning restore CS8603 // Possible null reference return.
 | 
			
		||||
 | 
			
		||||
    private static string ResolveApplicationVersion(IConfiguration configuration)
 | 
			
		||||
    {
 | 
			
		||||
        return
 | 
			
		||||
            configuration.Settings.ApplicationVersion ?? // potential override
 | 
			
		||||
            VersionHelper.GetVersion(Assembly.GetEntryAssembly());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static async Task<int> Execute(
 | 
			
		||||
        CommandTree leaf,
 | 
			
		||||
 
 | 
			
		||||
@@ -15,23 +15,16 @@ internal sealed class ExplainCommand : Command<ExplainCommand.Settings>
 | 
			
		||||
 | 
			
		||||
    public sealed class Settings : CommandSettings
 | 
			
		||||
    {
 | 
			
		||||
        public Settings(string[]? commands, bool? detailed, bool includeHidden)
 | 
			
		||||
        {
 | 
			
		||||
            Commands = commands;
 | 
			
		||||
            Detailed = detailed;
 | 
			
		||||
            IncludeHidden = includeHidden;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [CommandArgument(0, "[command]")]
 | 
			
		||||
        public string[]? Commands { get; }
 | 
			
		||||
        public string[]? Commands { get; set; }
 | 
			
		||||
 | 
			
		||||
        [Description("Include detailed information about the commands.")]
 | 
			
		||||
        [CommandOption("-d|--detailed")]
 | 
			
		||||
        public bool? Detailed { get; }
 | 
			
		||||
        public bool? Detailed { get; set; }
 | 
			
		||||
 | 
			
		||||
        [Description("Include hidden commands and options.")]
 | 
			
		||||
        [CommandOption("--hidden")]
 | 
			
		||||
        public bool IncludeHidden { get; }
 | 
			
		||||
        public bool IncludeHidden { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, Settings settings)
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ internal static class TemplateParser
 | 
			
		||||
 | 
			
		||||
                foreach (var character in token.Value)
 | 
			
		||||
                {
 | 
			
		||||
                    if (!char.IsLetterOrDigit(character) && character != '-' && character != '_')
 | 
			
		||||
                    if (!char.IsLetterOrDigit(character) && character != '-' && character != '_' && character != '?')
 | 
			
		||||
                    {
 | 
			
		||||
                        throw CommandTemplateException.InvalidCharacterInOptionName(template, token, character);
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
namespace Spectre.Console.Cli;
 | 
			
		||||
 | 
			
		||||
internal static class EnumerableExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static IReadOnlyList<T> ToSafeReadOnlyList<T>(this IEnumerable<T> source)
 | 
			
		||||
    {
 | 
			
		||||
        return source switch
 | 
			
		||||
        {
 | 
			
		||||
            null => new List<T>(),
 | 
			
		||||
            IReadOnlyList<T> list => list,
 | 
			
		||||
            _ => source.ToList(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,7 @@ namespace Spectre.Console.Cli;
 | 
			
		||||
internal sealed class CommandModel : ICommandContainer, ICommandModel
 | 
			
		||||
{
 | 
			
		||||
    public string? ApplicationName { get; }
 | 
			
		||||
    public string? ApplicationVersion { get; }
 | 
			
		||||
    public ParsingMode ParsingMode { get; }
 | 
			
		||||
    public IList<CommandInfo> Commands { get; }
 | 
			
		||||
    public IList<string[]> Examples { get; }
 | 
			
		||||
@@ -20,9 +21,10 @@ internal sealed class CommandModel : ICommandContainer, ICommandModel
 | 
			
		||||
        IEnumerable<string[]> examples)
 | 
			
		||||
    {
 | 
			
		||||
        ApplicationName = settings.ApplicationName;
 | 
			
		||||
        ApplicationVersion = settings.ApplicationVersion;
 | 
			
		||||
        ParsingMode = settings.ParsingMode;
 | 
			
		||||
        Commands = new List<CommandInfo>(commands ?? Array.Empty<CommandInfo>());
 | 
			
		||||
        Examples = new List<string[]>(examples ?? Array.Empty<string[]>());
 | 
			
		||||
        Commands = new List<CommandInfo>(commands);
 | 
			
		||||
        Examples = new List<string[]>(examples);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ internal class CommandTreeParser
 | 
			
		||||
    {
 | 
			
		||||
        _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
 | 
			
		||||
        _parsingMode = parsingMode ?? _configuration.ParsingMode;
 | 
			
		||||
        _help = new CommandOptionAttribute("-h|--help");
 | 
			
		||||
        _help = new CommandOptionAttribute("-?|-h|--help");
 | 
			
		||||
        _convertFlagsToRemainingArguments = convertFlagsToRemainingArguments ?? false;
 | 
			
		||||
 | 
			
		||||
        CaseSensitivity = caseSensitivity;
 | 
			
		||||
@@ -302,11 +302,7 @@ internal class CommandTreeParser
 | 
			
		||||
        var valueToken = stream.Peek();
 | 
			
		||||
        if (valueToken?.TokenKind == CommandTreeToken.Kind.String)
 | 
			
		||||
        {
 | 
			
		||||
            var parseValue = true;
 | 
			
		||||
            if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped)
 | 
			
		||||
            {
 | 
			
		||||
                parseValue = false;
 | 
			
		||||
            }
 | 
			
		||||
            bool parseValue = token is not { TokenKind: CommandTreeToken.Kind.ShortOption, IsGrouped: true };
 | 
			
		||||
 | 
			
		||||
            if (context.State == State.Normal && parseValue)
 | 
			
		||||
            {
 | 
			
		||||
@@ -333,7 +329,7 @@ internal class CommandTreeParser
 | 
			
		||||
                                    {
 | 
			
		||||
                                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
 | 
			
		||||
 | 
			
		||||
                                        context.AddRemainingArgument(token.Value, value);
 | 
			
		||||
                                        context.AddRemainingArgument(token.Representation, value);
 | 
			
		||||
 | 
			
		||||
                                        // Prevent the option and it's non-boolean value from being added to
 | 
			
		||||
                                        // mapped parameters (otherwise an exception will be thrown later
 | 
			
		||||
@@ -364,14 +360,14 @@ internal class CommandTreeParser
 | 
			
		||||
                        // In relaxed parsing mode?
 | 
			
		||||
                        if (context.ParsingMode == ParsingMode.Relaxed)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.AddRemainingArgument(token.Value, value);
 | 
			
		||||
                            context.AddRemainingArgument(token.Representation, value);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
 | 
			
		||||
                context.AddRemainingArgument(token.Representation, parseValue ? valueToken.Value : null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
@@ -379,7 +375,7 @@ internal class CommandTreeParser
 | 
			
		||||
            if (parameter == null && // Only add tokens which have not been matched to a command parameter
 | 
			
		||||
                (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed))
 | 
			
		||||
            {
 | 
			
		||||
                context.AddRemainingArgument(token.Value, null);
 | 
			
		||||
                context.AddRemainingArgument(token.Representation, null);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -171,12 +171,12 @@ internal static class CommandTreeTokenizer
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Encountered a separator?
 | 
			
		||||
            if (current == '=' || current == ':')
 | 
			
		||||
            if (current is '=' or ':')
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (char.IsLetter(current))
 | 
			
		||||
            if (char.IsLetter(current) || current is '?')
 | 
			
		||||
            {
 | 
			
		||||
                context.AddRemaining(current);
 | 
			
		||||
                reader.Read(); // Consume
 | 
			
		||||
@@ -184,7 +184,7 @@ internal static class CommandTreeTokenizer
 | 
			
		||||
                var value = current.ToString(CultureInfo.InvariantCulture);
 | 
			
		||||
                result.Add(result.Count == 0
 | 
			
		||||
                    ? new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, value, $"-{value}")
 | 
			
		||||
                    : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, value));
 | 
			
		||||
                    : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, $"-{value}"));
 | 
			
		||||
            }
 | 
			
		||||
            else if (result.Count == 0 && char.IsDigit(current))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										150
									
								
								src/Spectre.Console.Cli/Resources/HelpProvider.es.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/Spectre.Console.Cli/Resources/HelpProvider.es.resx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<root>
 | 
			
		||||
  <!-- 
 | 
			
		||||
    Microsoft ResX Schema 
 | 
			
		||||
    
 | 
			
		||||
    Version 2.0
 | 
			
		||||
    
 | 
			
		||||
    The primary goals of this format is to allow a simple XML format 
 | 
			
		||||
    that is mostly human readable. The generation and parsing of the 
 | 
			
		||||
    various data types are done through the TypeConverter classes 
 | 
			
		||||
    associated with the data types.
 | 
			
		||||
    
 | 
			
		||||
    Example:
 | 
			
		||||
    
 | 
			
		||||
    ... ado.net/XML headers & schema ...
 | 
			
		||||
    <resheader name="resmimetype">text/microsoft-resx</resheader>
 | 
			
		||||
    <resheader name="version">2.0</resheader>
 | 
			
		||||
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
 | 
			
		||||
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
 | 
			
		||||
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
 | 
			
		||||
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
 | 
			
		||||
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
 | 
			
		||||
        <value>[base64 mime encoded serialized .NET Framework object]</value>
 | 
			
		||||
    </data>
 | 
			
		||||
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
 | 
			
		||||
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
 | 
			
		||||
        <comment>This is a comment</comment>
 | 
			
		||||
    </data>
 | 
			
		||||
                
 | 
			
		||||
    There are any number of "resheader" rows that contain simple 
 | 
			
		||||
    name/value pairs.
 | 
			
		||||
    
 | 
			
		||||
    Each data row contains a name, and value. The row also contains a 
 | 
			
		||||
    type or mimetype. Type corresponds to a .NET class that support 
 | 
			
		||||
    text/value conversion through the TypeConverter architecture. 
 | 
			
		||||
    Classes that don't support this are serialized and stored with the 
 | 
			
		||||
    mimetype set.
 | 
			
		||||
    
 | 
			
		||||
    The mimetype is used for serialized objects, and tells the 
 | 
			
		||||
    ResXResourceReader how to depersist the object. This is currently not 
 | 
			
		||||
    extensible. For a given mimetype the value must be set accordingly:
 | 
			
		||||
    
 | 
			
		||||
    Note - application/x-microsoft.net.object.binary.base64 is the format 
 | 
			
		||||
    that the ResXResourceWriter will generate, however the reader can 
 | 
			
		||||
    read any of the formats listed below.
 | 
			
		||||
    
 | 
			
		||||
    mimetype: application/x-microsoft.net.object.binary.base64
 | 
			
		||||
    value   : The object must be serialized with 
 | 
			
		||||
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
 | 
			
		||||
            : and then encoded with base64 encoding.
 | 
			
		||||
    
 | 
			
		||||
    mimetype: application/x-microsoft.net.object.soap.base64
 | 
			
		||||
    value   : The object must be serialized with 
 | 
			
		||||
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
 | 
			
		||||
            : and then encoded with base64 encoding.
 | 
			
		||||
 | 
			
		||||
    mimetype: application/x-microsoft.net.object.bytearray.base64
 | 
			
		||||
    value   : The object must be serialized into a byte array 
 | 
			
		||||
            : using a System.ComponentModel.TypeConverter
 | 
			
		||||
            : and then encoded with base64 encoding.
 | 
			
		||||
    -->
 | 
			
		||||
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
 | 
			
		||||
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
 | 
			
		||||
    <xsd:element name="root" msdata:IsDataSet="true">
 | 
			
		||||
      <xsd:complexType>
 | 
			
		||||
        <xsd:choice maxOccurs="unbounded">
 | 
			
		||||
          <xsd:element name="metadata">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" use="required" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="assembly">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:attribute name="alias" type="xsd:string" />
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="data">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
 | 
			
		||||
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
 | 
			
		||||
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
 | 
			
		||||
              <xsd:attribute ref="xml:space" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
          <xsd:element name="resheader">
 | 
			
		||||
            <xsd:complexType>
 | 
			
		||||
              <xsd:sequence>
 | 
			
		||||
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
 | 
			
		||||
              </xsd:sequence>
 | 
			
		||||
              <xsd:attribute name="name" type="xsd:string" use="required" />
 | 
			
		||||
            </xsd:complexType>
 | 
			
		||||
          </xsd:element>
 | 
			
		||||
        </xsd:choice>
 | 
			
		||||
      </xsd:complexType>
 | 
			
		||||
    </xsd:element>
 | 
			
		||||
  </xsd:schema>
 | 
			
		||||
  <resheader name="resmimetype">
 | 
			
		||||
    <value>text/microsoft-resx</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="version">
 | 
			
		||||
    <value>2.0</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="reader">
 | 
			
		||||
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <resheader name="writer">
 | 
			
		||||
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
 | 
			
		||||
  </resheader>
 | 
			
		||||
  <data name="Arguments" xml:space="preserve">
 | 
			
		||||
    <value>ARGUMENTOS</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Command" xml:space="preserve">
 | 
			
		||||
    <value>COMANDO</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Commands" xml:space="preserve">
 | 
			
		||||
    <value>COMMANDOS</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Default" xml:space="preserve">
 | 
			
		||||
    <value>POR DEFECTO</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Description" xml:space="preserve">
 | 
			
		||||
    <value>DESCRIPCION</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Examples" xml:space="preserve">
 | 
			
		||||
    <value>EJEMPLOS</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Options" xml:space="preserve">
 | 
			
		||||
    <value>OPCIONES</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="PrintHelpDescription" xml:space="preserve">
 | 
			
		||||
    <value>Imprime información de ayuda</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="PrintVersionDescription" xml:space="preserve">
 | 
			
		||||
    <value>Imprime información de versión</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="Usage" xml:space="preserve">
 | 
			
		||||
    <value>USO</value>
 | 
			
		||||
  </data>
 | 
			
		||||
</root>
 | 
			
		||||
@@ -2,19 +2,15 @@
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.0</TargetFrameworks>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <NoWarn>SA1633</NoWarn>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  <ItemGroup Label="REMOVE THIS">
 | 
			
		||||
    <InternalsVisibleTo Include="Spectre.Console.Cli.Tests" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
    <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
    <InternalsVisibleTo Include="Spectre.Console.Cli.Tests" />
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
 | 
			
		||||
@@ -23,9 +19,9 @@
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
 | 
			
		||||
    <PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="1.0.0-alpha.160" PrivateAssets="all" />
 | 
			
		||||
    <PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" PrivateAssets="all" />
 | 
			
		||||
    <PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]" />
 | 
			
		||||
    <PackageReference Include="Nullable" Version="1.3.1">
 | 
			
		||||
    <PackageReference Include="Nullable">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <Description>A library that extends Spectre.Console with ImageSharp superpowers.</Description>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
    <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.0</TargetFrameworks>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <ImplicitUsings>true</ImplicitUsings>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <Description>A library that extends Spectre.Console with JSON superpowers.</Description>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="..\Spectre.Console\Internal\Extensions\CharExtensions.cs" Link="Internal\CharExtensions.cs" />
 | 
			
		||||
    <Compile Include="..\Spectre.Console\Internal\Extensions\EnumerableExtensions.cs" Link="Internal\EnumerableExtensions.cs" />
 | 
			
		||||
    <Compile Include="..\Spectre.Console\Internal\Text\StringBuffer.cs" Link="Internal\StringBuffer.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
    <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -3,21 +3,15 @@
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
 | 
			
		||||
    <IsTestProject>false</IsTestProject>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <Description>Contains testing utilities for Spectre.Console.</Description>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
  <ItemGroup Label="REMOVE THIS">
 | 
			
		||||
    <InternalsVisibleTo Include="Spectre.Console.Tests" />
 | 
			
		||||
    <InternalsVisibleTo Include="Spectre.Console.Cli.Tests" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
    <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Label="Project References">
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console.Cli\Spectre.Console.Cli.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\Spectre.Console\Spectre.Console.csproj" />
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ VisualStudioVersion = 17.1.32414.318
 | 
			
		||||
MinimumVisualStudioVersion = 15.0.26124.0
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console", "Spectre.Console\Spectre.Console.csproj", "{80DCBEF3-99D6-46C0-9C5B-42B4534D9113}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{20595AD4-8D75-4AF8-B6BC-9C38C160423F}"
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{20595AD4-8D75-4AF8-B6BC-9C38C160423F}"
 | 
			
		||||
	ProjectSection(SolutionItems) = preProject
 | 
			
		||||
		.editorconfig = .editorconfig
 | 
			
		||||
		Directory.Build.props = Directory.Build.props
 | 
			
		||||
@@ -13,28 +13,34 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{20595AD4-8
 | 
			
		||||
		..\dotnet-tools.json = ..\dotnet-tools.json
 | 
			
		||||
		..\global.json = ..\global.json
 | 
			
		||||
		stylecop.json = stylecop.json
 | 
			
		||||
		Directory.Packages.props = Directory.Packages.props
 | 
			
		||||
	EndProjectSection
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub", "GitHub", "{C3E2CB5C-1517-4C75-B59A-93D4E22BEC8D}"
 | 
			
		||||
	ProjectSection(SolutionItems) = preProject
 | 
			
		||||
		..\.github\workflows\ci.yaml = ..\.github\workflows\ci.yaml
 | 
			
		||||
		..\.github\workflows\docs.yaml = ..\.github\workflows\docs.yaml
 | 
			
		||||
		..\.github\workflows\publish.yaml = ..\.github\workflows\publish.yaml
 | 
			
		||||
	EndProjectSection
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.ImageSharp", "Spectre.Console.ImageSharp\Spectre.Console.ImageSharp.csproj", "{0EFE694D-0770-4E71-BF4E-EC2B41362F79}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.ImageSharp", "Extensions\Spectre.Console.ImageSharp\Spectre.Console.ImageSharp.csproj", "{0EFE694D-0770-4E71-BF4E-EC2B41362F79}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Testing", "Spectre.Console.Testing\Spectre.Console.Testing.csproj", "{7D5F6704-8249-46DD-906C-9E66419F215F}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{E0E45070-123C-4A4D-AA98-2A780308876C}"
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{E0E45070-123C-4A4D-AA98-2A780308876C}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Tests", "..\test\Spectre.Console.Tests\Spectre.Console.Tests.csproj", "{60A4CADD-2B3D-48ED-89C0-1637A1F111AE}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Tests", "Tests\Spectre.Console.Tests\Spectre.Console.Tests.csproj", "{60A4CADD-2B3D-48ED-89C0-1637A1F111AE}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Cli", "Spectre.Console.Cli\Spectre.Console.Cli.csproj", "{1B67B74F-1243-4381-9A2B-86EA66D135C5}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Cli.Tests", "..\test\Spectre.Console.Cli.Tests\Spectre.Console.Cli.Tests.csproj", "{E07C46D2-714F-4116-BADD-FEE09617A9C4}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Cli.Tests", "Tests\Spectre.Console.Cli.Tests\Spectre.Console.Cli.Tests.csproj", "{E07C46D2-714F-4116-BADD-FEE09617A9C4}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Json", "Spectre.Console.Json\Spectre.Console.Json.csproj", "{579E6E31-1E2F-4FE1-8F8C-9770878993E9}"
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spectre.Console.Json", "Extensions\Spectre.Console.Json\Spectre.Console.Json.csproj", "{579E6E31-1E2F-4FE1-8F8C-9770878993E9}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F34EFD87-6CEA-453F-858B-094EA413578C}"
 | 
			
		||||
	ProjectSection(SolutionItems) = preProject
 | 
			
		||||
		Tests\Directory.Build.props = Tests\Directory.Build.props
 | 
			
		||||
		Tests\.editorconfig = Tests\.editorconfig
 | 
			
		||||
	EndProjectSection
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
@@ -138,6 +144,8 @@ Global
 | 
			
		||||
		{C3E2CB5C-1517-4C75-B59A-93D4E22BEC8D} = {20595AD4-8D75-4AF8-B6BC-9C38C160423F}
 | 
			
		||||
		{0EFE694D-0770-4E71-BF4E-EC2B41362F79} = {E0E45070-123C-4A4D-AA98-2A780308876C}
 | 
			
		||||
		{579E6E31-1E2F-4FE1-8F8C-9770878993E9} = {E0E45070-123C-4A4D-AA98-2A780308876C}
 | 
			
		||||
		{60A4CADD-2B3D-48ED-89C0-1637A1F111AE} = {F34EFD87-6CEA-453F-858B-094EA413578C}
 | 
			
		||||
		{E07C46D2-714F-4116-BADD-FEE09617A9C4} = {F34EFD87-6CEA-453F-858B-094EA413578C}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
 | 
			
		||||
	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CheckNamespace/@EntryIndexedValue">DO_NOT_SHOW</s:String></wpf:ResourceDictionary>
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
<SolutionConfiguration>
 | 
			
		||||
  <Settings>
 | 
			
		||||
    <AllowParallelTestExecution>True</AllowParallelTestExecution>
 | 
			
		||||
    <SolutionConfigured>True</SolutionConfigured>
 | 
			
		||||
  </Settings>
 | 
			
		||||
</SolutionConfiguration>
 | 
			
		||||
@@ -52,11 +52,19 @@ public static partial class AnsiConsoleExtensions
 | 
			
		||||
            {
 | 
			
		||||
                if (text.Length > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var lastChar = text.Last();
 | 
			
		||||
                    text = text.Substring(0, text.Length - 1);
 | 
			
		||||
 | 
			
		||||
                    if (mask != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        console.Write("\b \b");
 | 
			
		||||
                        if (UnicodeCalculator.GetWidth(lastChar) == 1)
 | 
			
		||||
                        {
 | 
			
		||||
                            console.Write("\b \b");
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (UnicodeCalculator.GetWidth(lastChar) == 2)
 | 
			
		||||
                        {
 | 
			
		||||
                            console.Write("\b \b\b \b");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,10 +10,11 @@ public static class CalendarExtensions
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="calendar">The calendar to add the calendar event to.</param>
 | 
			
		||||
    /// <param name="date">The calendar event date.</param>
 | 
			
		||||
    /// <param name="customEventHighlightStyle">The calendar event custom highlight style.</param>
 | 
			
		||||
    /// <returns>The same instance so that multiple calls can be chained.</returns>
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date)
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date, Style? customEventHighlightStyle = null)
 | 
			
		||||
    {
 | 
			
		||||
        return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day);
 | 
			
		||||
        return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day, customEventHighlightStyle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -22,10 +23,11 @@ public static class CalendarExtensions
 | 
			
		||||
    /// <param name="calendar">The calendar to add the calendar event to.</param>
 | 
			
		||||
    /// <param name="description">The calendar event description.</param>
 | 
			
		||||
    /// <param name="date">The calendar event date.</param>
 | 
			
		||||
    /// <param name="customEventHighlightStyle">The calendar event custom highlight style.</param>
 | 
			
		||||
    /// <returns>The same instance so that multiple calls can be chained.</returns>
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date)
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date, Style? customEventHighlightStyle = null)
 | 
			
		||||
    {
 | 
			
		||||
        return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day);
 | 
			
		||||
        return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day, customEventHighlightStyle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -35,10 +37,11 @@ public static class CalendarExtensions
 | 
			
		||||
    /// <param name="year">The year of the calendar event.</param>
 | 
			
		||||
    /// <param name="month">The month of the calendar event.</param>
 | 
			
		||||
    /// <param name="day">The day of the calendar event.</param>
 | 
			
		||||
    /// <param name="customEventHighlightStyle">The calendar event custom highlight style.</param>
 | 
			
		||||
    /// <returns>The same instance so that multiple calls can be chained.</returns>
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day)
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day, Style? customEventHighlightStyle = null)
 | 
			
		||||
    {
 | 
			
		||||
        return AddCalendarEvent(calendar, string.Empty, year, month, day);
 | 
			
		||||
        return AddCalendarEvent(calendar, string.Empty, year, month, day, customEventHighlightStyle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -49,15 +52,16 @@ public static class CalendarExtensions
 | 
			
		||||
    /// <param name="year">The year of the calendar event.</param>
 | 
			
		||||
    /// <param name="month">The month of the calendar event.</param>
 | 
			
		||||
    /// <param name="day">The day of the calendar event.</param>
 | 
			
		||||
    /// <param name="customEventHighlightStyle">The calendar event custom highlight style.</param>
 | 
			
		||||
    /// <returns>The same instance so that multiple calls can be chained.</returns>
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day)
 | 
			
		||||
    public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day, Style? customEventHighlightStyle = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (calendar is null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(calendar));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day));
 | 
			
		||||
        calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day, customEventHighlightStyle));
 | 
			
		||||
        return calendar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +69,7 @@ public static class CalendarExtensions
 | 
			
		||||
    /// Sets the calendar's highlight <see cref="Style"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="calendar">The calendar.</param>
 | 
			
		||||
    /// <param name="style">The highlight style.</param>
 | 
			
		||||
    /// <param name="style">The default highlight style.</param>
 | 
			
		||||
    /// <returns>The same instance so that multiple calls can be chained.</returns>
 | 
			
		||||
    public static Calendar HighlightStyle(this Calendar calendar, Style? style)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,7 @@ internal sealed class HtmlEncoder : IAnsiConsoleEncoder
 | 
			
		||||
            css.Add("font-weight: bold");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((style.Decoration & Decoration.Bold) != 0)
 | 
			
		||||
        if ((style.Decoration & Decoration.Italic) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            css.Add("font-style: italic");
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ internal sealed class ListPrompt<T>
 | 
			
		||||
 | 
			
		||||
    public async Task<ListPromptState<T>> Show(
 | 
			
		||||
        ListPromptTree<T> tree,
 | 
			
		||||
        Func<T, string> converter,
 | 
			
		||||
        SelectionMode selectionMode,
 | 
			
		||||
        bool skipUnselectableItems,
 | 
			
		||||
        bool searchEnabled,
 | 
			
		||||
@@ -41,7 +42,12 @@ internal sealed class ListPrompt<T>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var nodes = tree.Traverse().ToList();
 | 
			
		||||
        var state = new ListPromptState<T>(nodes, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, skipUnselectableItems, searchEnabled);
 | 
			
		||||
        if (nodes.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidOperationException("Cannot show an empty selection prompt. Please call the AddChoice() method to configure the prompt.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var state = new ListPromptState<T>(nodes, converter, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize), wrapAround, selectionMode, skipUnselectableItems, searchEnabled);
 | 
			
		||||
        var hook = new ListPromptRenderHook<T>(_console, () => BuildRenderable(state));
 | 
			
		||||
 | 
			
		||||
        using (new RenderHookScope(_console, hook))
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,15 @@ internal sealed class ListPromptConstants
 | 
			
		||||
    public const string InstructionsMarkup = "[grey](Press <space> to select, <enter> to accept)[/]";
 | 
			
		||||
    public const string MoreChoicesMarkup = "[grey](Move up and down to reveal more choices)[/]";
 | 
			
		||||
    public const string SearchPlaceholderMarkup = "[grey](Type to search)[/]";
 | 
			
		||||
 | 
			
		||||
    public static string GetSelectedCheckbox(bool isGroup, SelectionMode mode, Style? style = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (style != null)
 | 
			
		||||
        {
 | 
			
		||||
            return "[[" + $"[{style.ToMarkup()}]X[/]" + "]]";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return isGroup && mode == SelectionMode.Leaf
 | 
			
		||||
            ? GroupSelectedCheckbox : SelectedCheckbox;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,8 @@ namespace Spectre.Console;
 | 
			
		||||
internal sealed class ListPromptState<T>
 | 
			
		||||
    where T : notnull
 | 
			
		||||
{
 | 
			
		||||
    private readonly Func<T, string> _converter;
 | 
			
		||||
 | 
			
		||||
    public int Index { get; private set; }
 | 
			
		||||
    public int ItemCount => Items.Count;
 | 
			
		||||
    public int PageSize { get; }
 | 
			
		||||
@@ -16,8 +18,15 @@ internal sealed class ListPromptState<T>
 | 
			
		||||
    public ListPromptItem<T> Current => Items[Index];
 | 
			
		||||
    public string SearchText { get; private set; }
 | 
			
		||||
 | 
			
		||||
    public ListPromptState(IReadOnlyList<ListPromptItem<T>> items, int pageSize, bool wrapAround, SelectionMode mode, bool skipUnselectableItems, bool searchEnabled)
 | 
			
		||||
    public ListPromptState(
 | 
			
		||||
        IReadOnlyList<ListPromptItem<T>> items,
 | 
			
		||||
        Func<T, string> converter,
 | 
			
		||||
        int pageSize, bool wrapAround,
 | 
			
		||||
        SelectionMode mode,
 | 
			
		||||
        bool skipUnselectableItems,
 | 
			
		||||
        bool searchEnabled)
 | 
			
		||||
    {
 | 
			
		||||
        _converter = converter ?? throw new ArgumentNullException(nameof(converter));
 | 
			
		||||
        Items = items;
 | 
			
		||||
        PageSize = pageSize;
 | 
			
		||||
        WrapAround = wrapAround;
 | 
			
		||||
@@ -126,7 +135,11 @@ internal sealed class ListPromptState<T>
 | 
			
		||||
            if (!char.IsControl(keyInfo.KeyChar))
 | 
			
		||||
            {
 | 
			
		||||
                search = SearchText + keyInfo.KeyChar;
 | 
			
		||||
                var item = Items.FirstOrDefault(x => x.Data.ToString()?.Contains(search, StringComparison.OrdinalIgnoreCase) == true && (!x.IsGroup || Mode != SelectionMode.Leaf));
 | 
			
		||||
 | 
			
		||||
                var item = Items.FirstOrDefault(x =>
 | 
			
		||||
                    _converter.Invoke(x.Data).Contains(search, StringComparison.OrdinalIgnoreCase)
 | 
			
		||||
                    && (!x.IsGroup || Mode != SelectionMode.Leaf));
 | 
			
		||||
 | 
			
		||||
                if (item != null)
 | 
			
		||||
                {
 | 
			
		||||
                    index = Items.IndexOf(item);
 | 
			
		||||
@@ -140,7 +153,10 @@ internal sealed class ListPromptState<T>
 | 
			
		||||
                    search = search.Substring(0, search.Length - 1);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var item = Items.FirstOrDefault(x => x.Data.ToString()?.Contains(search, StringComparison.OrdinalIgnoreCase) == true && (!x.IsGroup || Mode != SelectionMode.Leaf));
 | 
			
		||||
                var item = Items.FirstOrDefault(x =>
 | 
			
		||||
                    _converter.Invoke(x.Data).Contains(search, StringComparison.OrdinalIgnoreCase) &&
 | 
			
		||||
                    (!x.IsGroup || Mode != SelectionMode.Leaf));
 | 
			
		||||
 | 
			
		||||
                if (item != null)
 | 
			
		||||
                {
 | 
			
		||||
                    index = Items.IndexOf(item);
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,8 @@ public sealed class MultiSelectionPrompt<T> : IPrompt<List<T>>, IListPromptStrat
 | 
			
		||||
    {
 | 
			
		||||
        // Create the list prompt
 | 
			
		||||
        var prompt = new ListPrompt<T>(console, this);
 | 
			
		||||
        var result = await prompt.Show(Tree, Mode, false, false, PageSize, WrapAround, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
        var converter = Converter ?? TypeConverterHelper.ConvertToString;
 | 
			
		||||
        var result = await prompt.Show(Tree, converter, Mode, false, false, PageSize, WrapAround, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
        if (Mode == SelectionMode.Leaf)
 | 
			
		||||
        {
 | 
			
		||||
@@ -256,8 +257,7 @@ public sealed class MultiSelectionPrompt<T> : IPrompt<List<T>>, IListPromptStrat
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var checkbox = item.Node.IsSelected
 | 
			
		||||
                ? (item.Node.IsGroup && Mode == SelectionMode.Leaf
 | 
			
		||||
                    ? ListPromptConstants.GroupSelectedCheckbox : ListPromptConstants.SelectedCheckbox)
 | 
			
		||||
                ? ListPromptConstants.GetSelectedCheckbox(item.Node.IsGroup, Mode, HighlightStyle)
 | 
			
		||||
                : ListPromptConstants.Checkbox;
 | 
			
		||||
 | 
			
		||||
            grid.AddRow(new Markup(indent + prompt + " " + checkbox + " " + text, style));
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,8 @@ public sealed class SelectionPrompt<T> : IPrompt<T>, IListPromptStrategy<T>
 | 
			
		||||
    {
 | 
			
		||||
        // Create the list prompt
 | 
			
		||||
        var prompt = new ListPrompt<T>(console, this);
 | 
			
		||||
        var result = await prompt.Show(_tree, Mode, true, SearchEnabled, PageSize, WrapAround, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
        var converter = Converter ?? TypeConverterHelper.ConvertToString;
 | 
			
		||||
        var result = await prompt.Show(_tree, converter, Mode, true, SearchEnabled, PageSize, WrapAround, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
        // Return the selected item
 | 
			
		||||
        return result.Items[result.Index].Data;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,22 +2,22 @@
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <TargetFrameworks>net8.0;net7.0;net6.0;netstandard2.0</TargetFrameworks>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
    <IsPackable>true</IsPackable>
 | 
			
		||||
    <NoWarn>SA1633</NoWarn>
 | 
			
		||||
    <DefineConstants>$(DefineConstants)TRACE;WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="..\stylecop.json" Link="Properties/stylecop.json" />
 | 
			
		||||
    <EmbeddedResource Include="Widgets\Figlet\Fonts\Standard.flf" />
 | 
			
		||||
    <None Remove="Widgets\Figlet\Fonts\Standard.flf" />
 | 
			
		||||
    <None Include="../../resources/gfx/small-logo.png" Pack="true" PackagePath="\" Link="Properties/small-logo.png" />
 | 
			
		||||
    <InternalsVisibleTo Include="$(AssemblyName).Tests" />
 | 
			
		||||
  <ItemGroup Label="REMOVE THIS">
 | 
			
		||||
    <InternalsVisibleTo Include="$(AssemblyName).Tests"/>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Memory" Version="4.5.5" />
 | 
			
		||||
    <PackageReference Include="Wcwidth.Sources" Version="2.0.0">
 | 
			
		||||
  <ItemGroup Label="Standard Figlet font">
 | 
			
		||||
    <EmbeddedResource Include="Widgets\Figlet\Fonts\Standard.flf"/>
 | 
			
		||||
    <None Remove="Widgets\Figlet\Fonts\Standard.flf"/>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Label="Dependencies">
 | 
			
		||||
    <PackageReference Condition="'$(TargetFramework)' == 'netstandard2.0'" Include="System.Memory"/>
 | 
			
		||||
    <PackageReference Include="Wcwidth.Sources">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
@@ -28,17 +28,12 @@
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
 | 
			
		||||
    <PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" Version="1.0.0-alpha.160" PrivateAssets="all" />
 | 
			
		||||
    <PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]" />
 | 
			
		||||
    <PackageReference Include="Nullable" Version="1.3.1">
 | 
			
		||||
    <PackageReference Include="TunnelVisionLabs.ReferenceAssemblyAnnotator" PrivateAssets="all"/>
 | 
			
		||||
    <PackageDownload Include="Microsoft.NETCore.App.Ref" Version="[$(AnnotatedReferenceAssemblyVersion)]"/>
 | 
			
		||||
    <PackageReference Include="Nullable">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <DefineConstants>$(DefineConstants)TRACE;WCWIDTH_VISIBILITY_INTERNAL</DefineConstants>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -196,9 +196,10 @@ public sealed class Calendar : JustInTimeRenderable, IHasCulture, IHasTableBorde
 | 
			
		||||
        {
 | 
			
		||||
            if (weekdays[currentDay - 1] == weekday)
 | 
			
		||||
            {
 | 
			
		||||
                if (_calendarEvents.Any(e => e.Month == Month && e.Day == currentDay))
 | 
			
		||||
                var todayEvent = _calendarEvents.LastOrDefault(e => e.Month == Month && e.Day == currentDay);
 | 
			
		||||
                if (todayEvent != null)
 | 
			
		||||
                {
 | 
			
		||||
                    row.Add(new Markup(currentDay.ToString(CultureInfo.InvariantCulture) + "*", _highlightStyle));
 | 
			
		||||
                    row.Add(new Markup(currentDay.ToString(CultureInfo.InvariantCulture) + "*", todayEvent.CustomHighlightStyle ?? _highlightStyle));
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,14 +25,20 @@ public sealed class CalendarEvent
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public int Day { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the custom highlight style of the calendar event.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public Style? CustomHighlightStyle { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="CalendarEvent"/> class.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="year">The year of the calendar event.</param>
 | 
			
		||||
    /// <param name="month">The month of the calendar event.</param>
 | 
			
		||||
    /// <param name="day">The day of the calendar event.</param>
 | 
			
		||||
    public CalendarEvent(int year, int month, int day)
 | 
			
		||||
        : this(string.Empty, year, month, day)
 | 
			
		||||
    /// <param name="customHighlightStyle">The custom highlight style of the calendar event.</param>
 | 
			
		||||
    public CalendarEvent(int year, int month, int day, Style? customHighlightStyle = null)
 | 
			
		||||
        : this(string.Empty, year, month, day, customHighlightStyle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -43,11 +49,13 @@ public sealed class CalendarEvent
 | 
			
		||||
    /// <param name="year">The year of the calendar event.</param>
 | 
			
		||||
    /// <param name="month">The month of the calendar event.</param>
 | 
			
		||||
    /// <param name="day">The day of the calendar event.</param>
 | 
			
		||||
    public CalendarEvent(string description, int year, int month, int day)
 | 
			
		||||
    /// <param name="customHighlightStyle">The custom highlight style of the calendar event.</param>
 | 
			
		||||
    public CalendarEvent(string description, int year, int month, int day, Style? customHighlightStyle = null)
 | 
			
		||||
    {
 | 
			
		||||
        Description = description ?? string.Empty;
 | 
			
		||||
        Year = year;
 | 
			
		||||
        Month = month;
 | 
			
		||||
        Day = day;
 | 
			
		||||
        CustomHighlightStyle = customHighlightStyle;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -150,9 +150,9 @@ internal static class TableRenderer
 | 
			
		||||
                result.Add(Segment.LineBreak);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Show row separator?
 | 
			
		||||
            // Show row separator, if headers are hidden show separator after the first row
 | 
			
		||||
            if (context.Border.SupportsRowSeparator && context.ShowRowSeparators
 | 
			
		||||
                                                    && !isFirstRow && !isLastRow)
 | 
			
		||||
                                                    && (!isFirstRow || (isFirstRow && !context.ShowHeaders)) && !isLastRow)
 | 
			
		||||
            {
 | 
			
		||||
                var hasVisibleFootes = context is { ShowFooters: true, HasFooters: true };
 | 
			
		||||
                var isNextLastLine = index == context.Rows.Count - 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ namespace Spectre.Console;
 | 
			
		||||
public sealed class Tree : Renderable, IHasTreeNodes
 | 
			
		||||
{
 | 
			
		||||
    private readonly TreeNode _root;
 | 
			
		||||
    private bool _expanded = true;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets or sets the tree style.
 | 
			
		||||
@@ -26,7 +27,15 @@ public sealed class Tree : Renderable, IHasTreeNodes
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets or sets a value indicating whether or not the tree is expanded or not.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public bool Expanded { get; set; } = true;
 | 
			
		||||
    public bool Expanded
 | 
			
		||||
    {
 | 
			
		||||
        get => _expanded;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            _expanded = value;
 | 
			
		||||
            _root.Expand(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="Tree"/> class.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										107
									
								
								src/Tests/.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/Tests/.editorconfig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
root = false
 | 
			
		||||
 | 
			
		||||
[*.cs]
 | 
			
		||||
# Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules'
 | 
			
		||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none
 | 
			
		||||
 | 
			
		||||
# IDE0055: Fix formatting
 | 
			
		||||
dotnet_diagnostic.IDE0055.severity = warning
 | 
			
		||||
 | 
			
		||||
# SA1101: Prefix local calls with this
 | 
			
		||||
dotnet_diagnostic.SA1101.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1633: File should have header
 | 
			
		||||
dotnet_diagnostic.SA1633.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1201: Elements should appear in the correct order
 | 
			
		||||
dotnet_diagnostic.SA1201.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1202: Public members should come before private members
 | 
			
		||||
dotnet_diagnostic.SA1202.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1309: Field names should not begin with underscore
 | 
			
		||||
dotnet_diagnostic.SA1309.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1404: Code analysis suppressions should have justification
 | 
			
		||||
dotnet_diagnostic.SA1404.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1516: Elements should be separated by a blank line
 | 
			
		||||
dotnet_diagnostic.SA1516.severity = none
 | 
			
		||||
 | 
			
		||||
# CA1303: Do not pass literals as localized parameters
 | 
			
		||||
dotnet_diagnostic.CA1303.severity = none
 | 
			
		||||
 | 
			
		||||
# CSA1204: Static members should appear before non-static members
 | 
			
		||||
dotnet_diagnostic.SA1204.severity = none
 | 
			
		||||
 | 
			
		||||
# IDE0052: Remove unread private members
 | 
			
		||||
dotnet_diagnostic.IDE0052.severity = warning
 | 
			
		||||
 | 
			
		||||
# IDE0063: Use simple 'using' statement
 | 
			
		||||
csharp_prefer_simple_using_statement = false:suggestion
 | 
			
		||||
 | 
			
		||||
# IDE0018: Variable declaration can be inlined
 | 
			
		||||
dotnet_diagnostic.IDE0018.severity = warning
 | 
			
		||||
 | 
			
		||||
# SA1625: Element documenation should not be copied and pasted
 | 
			
		||||
dotnet_diagnostic.SA1625.severity = none
 | 
			
		||||
 | 
			
		||||
# IDE0005: Using directive is unnecessary
 | 
			
		||||
dotnet_diagnostic.IDE0005.severity = warning
 | 
			
		||||
 | 
			
		||||
# SA1117: Parameters should be on same line or separate lines
 | 
			
		||||
dotnet_diagnostic.SA1117.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1404: Code analysis suppression should have justification
 | 
			
		||||
dotnet_diagnostic.SA1404.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1101: Prefix local calls with this
 | 
			
		||||
dotnet_diagnostic.SA1101.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1633: File should have header
 | 
			
		||||
dotnet_diagnostic.SA1633.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1649: File name should match first type name
 | 
			
		||||
dotnet_diagnostic.SA1649.severity = none
 | 
			
		||||
 | 
			
		||||
# SA1402: File may only contain a single type
 | 
			
		||||
dotnet_diagnostic.SA1402.severity = none
 | 
			
		||||
 | 
			
		||||
# CA1814: Prefer jagged arrays over multidimensional
 | 
			
		||||
dotnet_diagnostic.CA1814.severity = none
 | 
			
		||||
 | 
			
		||||
# RCS1194: Implement exception constructors.
 | 
			
		||||
dotnet_diagnostic.RCS1194.severity = none
 | 
			
		||||
 | 
			
		||||
# CA1032: Implement standard exception constructors
 | 
			
		||||
dotnet_diagnostic.CA1032.severity = none
 | 
			
		||||
 | 
			
		||||
# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
 | 
			
		||||
dotnet_diagnostic.CA1826.severity = none
 | 
			
		||||
 | 
			
		||||
# RCS1079: Throwing of new NotImplementedException.
 | 
			
		||||
dotnet_diagnostic.RCS1079.severity = warning
 | 
			
		||||
 | 
			
		||||
# RCS1057: Add empty line between declarations.
 | 
			
		||||
dotnet_diagnostic.RCS1057.severity = none
 | 
			
		||||
 | 
			
		||||
# RCS1057: Validate arguments correctly
 | 
			
		||||
dotnet_diagnostic.RCS1227.severity = none
 | 
			
		||||
 | 
			
		||||
# IDE0004: Remove Unnecessary Cast
 | 
			
		||||
dotnet_diagnostic.IDE0004.severity = warning
 | 
			
		||||
 | 
			
		||||
# CA1810: Initialize reference type static fields inline
 | 
			
		||||
dotnet_diagnostic.CA1810.severity = none
 | 
			
		||||
 | 
			
		||||
# IDE0044: Add readonly modifier
 | 
			
		||||
dotnet_diagnostic.IDE0044.severity = warning
 | 
			
		||||
 | 
			
		||||
# RCS1047: Non-asynchronous method name should not end with 'Async'.
 | 
			
		||||
dotnet_diagnostic.RCS1047.severity = none
 | 
			
		||||
 | 
			
		||||
# RCS1090: Call 'ConfigureAwait(false)'.
 | 
			
		||||
dotnet_diagnostic.RCS1090.severity = warning
 | 
			
		||||
 | 
			
		||||
# CS1591: Missing XML comment for publicly visible type or member
 | 
			
		||||
dotnet_diagnostic.CS1591.severity = none
 | 
			
		||||
							
								
								
									
										13
									
								
								src/Tests/Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/Tests/Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<Project>
 | 
			
		||||
  <PropertyGroup Label="Settings">
 | 
			
		||||
    <LangVersion>12</LangVersion>
 | 
			
		||||
    <IsPackable>false</IsPackable>
 | 
			
		||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
			
		||||
    <SignAssembly>true</SignAssembly>
 | 
			
		||||
    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\..\..\resources\spectre.snk</AssemblyOriginatorKeyFile>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <AdditionalFiles Include="$(MSBuildThisFileDirectory)/../stylecop.json" Link="Properties/stylecop.json"/>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										18
									
								
								src/Tests/Spectre.Console.Cli.Tests/Constants.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Tests/Spectre.Console.Cli.Tests/Constants.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
namespace Spectre.Console.Tests;
 | 
			
		||||
 | 
			
		||||
public static class Constants
 | 
			
		||||
{
 | 
			
		||||
    public static string[] VersionCommand { get; } =
 | 
			
		||||
        new[]
 | 
			
		||||
        {
 | 
			
		||||
                CliConstants.Commands.Branch,
 | 
			
		||||
                CliConstants.Commands.Version,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    public static string[] XmlDocCommand { get; } =
 | 
			
		||||
        new[]
 | 
			
		||||
        {
 | 
			
		||||
                CliConstants.Commands.Branch,
 | 
			
		||||
                CliConstants.Commands.XmlDoc,
 | 
			
		||||
        };
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
using SystemConsole = System.Console;
 | 
			
		||||
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public abstract class AnimalCommand<TSettings> : Command<TSettings>
 | 
			
		||||
    where TSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class AsynchronousCommand : AsyncCommand<AsynchronousCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
    public AsynchronousCommand(IAnsiConsole console)
 | 
			
		||||
    {
 | 
			
		||||
        _console = console;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async override Task<int> ExecuteAsync(CommandContext context, AsynchronousCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        // Simulate a long running asynchronous task
 | 
			
		||||
        await Task.Delay(200);
 | 
			
		||||
 | 
			
		||||
        if (settings.ThrowException)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"Throwing exception asynchronously");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            _console.WriteLine($"Finished executing asynchronously");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public class CatCommand : AnimalCommand<CatSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, CatSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
[Description("The dog command.")]
 | 
			
		||||
public class DogCommand : AnimalCommand<DogSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override ValidationResult Validate(CommandContext context, DogSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        if (context is null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.ArgumentNullException(nameof(context));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (settings is null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.ArgumentNullException(nameof(settings));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (settings.Age > 100 && !context.Remaining.Raw.Contains("zombie"))
 | 
			
		||||
        {
 | 
			
		||||
            return ValidationResult.Error("Dog is too old...");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.Validate(context, settings);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, DogSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class DumpRemainingCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
    public DumpRemainingCommand(IAnsiConsole console)
 | 
			
		||||
    {
 | 
			
		||||
        _console = console;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        if (context.Remaining.Raw.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            _console.WriteLine("# Raw");
 | 
			
		||||
            foreach (var item in context.Remaining.Raw)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine(item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context.Remaining.Parsed.Count > 0)
 | 
			
		||||
        {
 | 
			
		||||
            _console.WriteLine("# Parsed");
 | 
			
		||||
            foreach (var item in context.Remaining.Parsed)
 | 
			
		||||
            {
 | 
			
		||||
                _console.WriteLine(string.Format("{0}={1}", item.Key, string.Join(",", item.Select(x => x))));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class EmptyCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class GenericCommand<TSettings> : Command<TSettings>
 | 
			
		||||
    where TSettings : CommandSettings
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, TSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
[Description("The giraffe command.")]
 | 
			
		||||
public sealed class GiraffeCommand : Command<GiraffeSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, GiraffeSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
using Spectre.Console;
 | 
			
		||||
 | 
			
		||||
public class GreeterCommand : Command<OptionalArgumentWithDefaultValueSettings>
 | 
			
		||||
{
 | 
			
		||||
    private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
    public GreeterCommand(IAnsiConsole console)
 | 
			
		||||
    {
 | 
			
		||||
        _console = console;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, OptionalArgumentWithDefaultValueSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        _console.WriteLine(settings.Greeting);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class HiddenOptionsCommand : Command<HiddenOptionSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, HiddenOptionSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
[Description("The horse command.")]
 | 
			
		||||
public class HorseCommand : AnimalCommand<HorseSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, HorseSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class InvalidCommand : Command<InvalidSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, InvalidSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
[Description("The lion command.")]
 | 
			
		||||
public class LionCommand : AnimalCommand<LionSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, LionSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class NoDescriptionCommand : Command<EmptyCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    [CommandOption("-f|--foo <VALUE>")]
 | 
			
		||||
    public int Foo { get; set; }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, EmptyCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public class OptionVectorCommand : Command<OptionVectorSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, OptionVectorSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class ThrowingCommand : Command<ThrowingCommandSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, ThrowingCommandSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        throw new InvalidOperationException("W00t?");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
[Description("The turtle command.")]
 | 
			
		||||
public class TurtleCommand : AnimalCommand<TurtleSettings>
 | 
			
		||||
{
 | 
			
		||||
    public override int Execute(CommandContext context, TurtleSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class VersionCommand : Command<VersionSettings>
 | 
			
		||||
{
 | 
			
		||||
    private readonly IAnsiConsole _console;
 | 
			
		||||
 | 
			
		||||
    public VersionCommand(IAnsiConsole console)
 | 
			
		||||
    {
 | 
			
		||||
        _console = console;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override int Execute(CommandContext context, VersionSettings settings)
 | 
			
		||||
    {
 | 
			
		||||
        _console.WriteLine($"VersionCommand ran, Version: {settings.Version ?? string.Empty}");
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class CatAgilityConverter : TypeConverter
 | 
			
		||||
{
 | 
			
		||||
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
    {
 | 
			
		||||
        if (value is string stringValue)
 | 
			
		||||
        {
 | 
			
		||||
            return stringValue.Length;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.ConvertFrom(context, culture, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
namespace Spectre.Console.Tests.Data;
 | 
			
		||||
 | 
			
		||||
public sealed class StringToIntegerConverter : TypeConverter
 | 
			
		||||
{
 | 
			
		||||
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
 | 
			
		||||
    {
 | 
			
		||||
        if (value is string stringValue)
 | 
			
		||||
        {
 | 
			
		||||
            return int.Parse(stringValue, CultureInfo.InvariantCulture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return base.ConvertFrom(context, culture, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user