Initial commit with code already here.
This commit is contained in:
commit
9fdd499d7a
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Visual Studio things.
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Build Stuff
|
||||||
|
*/bin
|
||||||
|
*/obj
|
||||||
25
ArgumentBase.sln
Normal file
25
ArgumentBase.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34309.116
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArgumentBase", "ArgumentBase\ArgumentBase.csproj", "{E6AFC35D-D69A-4956-9ED4-AF0276192EE8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{E6AFC35D-D69A-4956-9ED4-AF0276192EE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E6AFC35D-D69A-4956-9ED4-AF0276192EE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E6AFC35D-D69A-4956-9ED4-AF0276192EE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E6AFC35D-D69A-4956-9ED4-AF0276192EE8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {DF77961F-683C-444B-9866-FB4C081B3E24}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
12
ArgumentBase/ArgFlagInfo.cs
Normal file
12
ArgumentBase/ArgFlagInfo.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
public class ArgFlagInfo
|
||||||
|
{
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required string Description { get; init; }
|
||||||
|
public required PropertyInfo Property { get; init; }
|
||||||
|
|
||||||
|
internal ArgFlagInfo() { }
|
||||||
|
}
|
||||||
13
ArgumentBase/ArgParameterInfo.cs
Normal file
13
ArgumentBase/ArgParameterInfo.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
public class ArgParameterInfo
|
||||||
|
{
|
||||||
|
public required int Order { get; init; }
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required string Description { get; init; }
|
||||||
|
public required PropertyInfo Property { get; init; }
|
||||||
|
|
||||||
|
internal ArgParameterInfo() { }
|
||||||
|
}
|
||||||
12
ArgumentBase/ArgVariableInfo.cs
Normal file
12
ArgumentBase/ArgVariableInfo.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
public class ArgVariableInfo
|
||||||
|
{
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required string Description { get; init; }
|
||||||
|
public required PropertyInfo Property { get; init; }
|
||||||
|
|
||||||
|
internal ArgVariableInfo() { }
|
||||||
|
}
|
||||||
291
ArgumentBase/ArgumentBase.cs
Normal file
291
ArgumentBase/ArgumentBase.cs
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
#pragma warning disable IL2070, IL2090 // Shut up.
|
||||||
|
|
||||||
|
public abstract class ArgumentBase<TSelf> where TSelf : ArgumentBase<TSelf>, new()
|
||||||
|
{
|
||||||
|
public static ReadOnlyCollection<ArgParameterInfo> Parameters { get; private set; }
|
||||||
|
public static ReadOnlyCollection<ArgVariableInfo> Variables { get; private set; }
|
||||||
|
public static ReadOnlyCollection<ArgFlagInfo> Flags { get; private set; }
|
||||||
|
|
||||||
|
public static ReadOnlyDictionary<string, string> ParameterDescriptions { get; private set; }
|
||||||
|
public static ReadOnlyDictionary<string, string> VariableDescriptions { get; private set; }
|
||||||
|
public static ReadOnlyDictionary<string, string> FlagDescriptions { get; private set; }
|
||||||
|
public static ReadOnlyDictionary<string, PropertyInfo> VariableTable { get; private set; }
|
||||||
|
public static ReadOnlyDictionary<string, PropertyInfo> FlagTable { get; private set; }
|
||||||
|
|
||||||
|
static ArgumentBase()
|
||||||
|
{
|
||||||
|
IEnumerable<PropertyInfo> allProps = typeof(TSelf).GetProperties().Where(x => x.SetMethod is not null);
|
||||||
|
|
||||||
|
List<ArgParameterInfo> parameters = [];
|
||||||
|
List<ArgVariableInfo> variables = [];
|
||||||
|
List<ArgFlagInfo> flags = [];
|
||||||
|
|
||||||
|
Dictionary<string, string> paramDesc = [], varDesc = [], flagDesc = [];
|
||||||
|
Dictionary<string, PropertyInfo> varTable = [], flagTable = [];
|
||||||
|
foreach (PropertyInfo prop in allProps)
|
||||||
|
{
|
||||||
|
IsParameterAttribute? paramAtt = prop.GetCustomAttribute<IsParameterAttribute>();
|
||||||
|
IsVariableAttribute? varAtt = prop.GetCustomAttribute<IsVariableAttribute>();
|
||||||
|
IsFlagAttribute? flagAtt = prop.GetCustomAttribute<IsFlagAttribute>();
|
||||||
|
|
||||||
|
if (paramAtt is not null)
|
||||||
|
{
|
||||||
|
ArgParameterInfo info = new()
|
||||||
|
{
|
||||||
|
Order = paramAtt.order,
|
||||||
|
Name = paramAtt.name ?? prop.Name,
|
||||||
|
Description = paramAtt.description,
|
||||||
|
Property = prop
|
||||||
|
};
|
||||||
|
parameters.Add(info);
|
||||||
|
|
||||||
|
string trueName = info.Name.Trim();
|
||||||
|
paramDesc.Add(trueName, info.Description);
|
||||||
|
}
|
||||||
|
if (varAtt is not null)
|
||||||
|
{
|
||||||
|
ArgVariableInfo info = new()
|
||||||
|
{
|
||||||
|
Name = varAtt.name ?? prop.Name,
|
||||||
|
Description = varAtt.description,
|
||||||
|
Property = prop
|
||||||
|
};
|
||||||
|
variables.Add(info);
|
||||||
|
|
||||||
|
string trueName = $"-{info.Name.Trim()}";
|
||||||
|
varDesc.Add(trueName, info.Description);
|
||||||
|
varTable.Add(trueName, info.Property);
|
||||||
|
}
|
||||||
|
if (flagAtt is not null)
|
||||||
|
{
|
||||||
|
ArgFlagInfo info = new()
|
||||||
|
{
|
||||||
|
Name = flagAtt.name ?? prop.Name,
|
||||||
|
Description = flagAtt.description,
|
||||||
|
Property = prop
|
||||||
|
};
|
||||||
|
flags.Add(info);
|
||||||
|
|
||||||
|
string trueName = $"--{info.Name.Trim()}";
|
||||||
|
flagDesc.Add(trueName, info.Description);
|
||||||
|
flagTable.Add(trueName, info.Property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.Sort((a, b) => a.Order.CompareTo(b.Order));
|
||||||
|
Parameters = parameters.AsReadOnly();
|
||||||
|
Variables = variables.AsReadOnly();
|
||||||
|
Flags = flags.AsReadOnly();
|
||||||
|
|
||||||
|
// I would sort these, but I would need yet another for loop to do that.
|
||||||
|
ParameterDescriptions = paramDesc.AsReadOnly();
|
||||||
|
VariableDescriptions = varDesc.AsReadOnly();
|
||||||
|
FlagDescriptions = flagDesc.AsReadOnly();
|
||||||
|
VariableTable = varTable.AsReadOnly();
|
||||||
|
FlagTable = flagTable.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TSelf Parse(string[] args)
|
||||||
|
{
|
||||||
|
TSelf result = new();
|
||||||
|
if (args.Length == 0) return result;
|
||||||
|
|
||||||
|
result.anyArguments = true;
|
||||||
|
int parameterIndex = 0;
|
||||||
|
List<string> unknownParams = [], unknownVars = [], unknownFlags = [];
|
||||||
|
List<string> badValParams = [], badValVars = [];
|
||||||
|
foreach (string arg in args)
|
||||||
|
{
|
||||||
|
if (arg.StartsWith("--")) // Flag
|
||||||
|
{
|
||||||
|
string name = arg[2..];
|
||||||
|
ArgFlagInfo? flag = Flags.SingleOrDefault(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (flag is null)
|
||||||
|
{
|
||||||
|
// Unknown flag.
|
||||||
|
unknownFlags.Add(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip flag.
|
||||||
|
bool original = (bool)flag.Property.GetValue(result)!;
|
||||||
|
flag.Property.SetValue(result, !original);
|
||||||
|
result.anyFlags = true;
|
||||||
|
}
|
||||||
|
else if (arg.StartsWith('-')) // Variable
|
||||||
|
{
|
||||||
|
int splitter = arg.IndexOf(':');
|
||||||
|
string name = arg[1..splitter], valueStr = arg[(splitter + 1)..];
|
||||||
|
ArgVariableInfo? var = Variables.SingleOrDefault(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (var is null)
|
||||||
|
{
|
||||||
|
// Unknown variable.
|
||||||
|
unknownVars.Add(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
object? value = parseObject(valueStr, var.Property.PropertyType);
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
// Issue parsing the object.
|
||||||
|
badValVars.Add(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var.Property.SetValue(result, value);
|
||||||
|
result.anyVars = true;
|
||||||
|
}
|
||||||
|
else // Parameter
|
||||||
|
{
|
||||||
|
if (parameterIndex >= Parameters.Count)
|
||||||
|
{
|
||||||
|
// Too many parameters.
|
||||||
|
unknownParams.Add(arg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ArgParameterInfo param = Parameters[parameterIndex];
|
||||||
|
parameterIndex++;
|
||||||
|
|
||||||
|
object? value = parseObject(arg, param.Property.PropertyType);
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
// Issue parsing the object.
|
||||||
|
badValParams.Add(arg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
param.Property.SetValue(result, value);
|
||||||
|
result.anyParams = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int unknownArgs = unknownParams.Count + unknownVars.Count + unknownFlags.Count;
|
||||||
|
if (unknownArgs > 0)
|
||||||
|
{
|
||||||
|
// Unknown arguments.
|
||||||
|
StringBuilder warnMsg = new();
|
||||||
|
warnMsg.Append($" \x1b[3;33m{unknownArgs} {(unknownArgs == 1 ? "argument was" : "arguments were")} not recognized:\n ");
|
||||||
|
int lineLen = 2, maxLineLen = (int)(0.65 * Console.WindowWidth - 1);
|
||||||
|
|
||||||
|
foreach (string badParam in unknownParams)
|
||||||
|
{
|
||||||
|
if (lineLen + badParam.Length + 3 > maxLineLen)
|
||||||
|
{
|
||||||
|
warnMsg.Append("\n ");
|
||||||
|
lineLen = 2;
|
||||||
|
}
|
||||||
|
warnMsg.Append($"\"\x1b[37m{badParam}\x1b[33m\" ");
|
||||||
|
lineLen += badParam.Length + 3;
|
||||||
|
}
|
||||||
|
foreach (string badVar in unknownVars)
|
||||||
|
{
|
||||||
|
if (lineLen + badVar.Length + 4 > maxLineLen)
|
||||||
|
{
|
||||||
|
warnMsg.Append("\n ");
|
||||||
|
lineLen = 2;
|
||||||
|
}
|
||||||
|
warnMsg.Append($"\"\x1b[36m-{badVar}\x1b[33m\" ");
|
||||||
|
lineLen += badVar.Length + 4;
|
||||||
|
}
|
||||||
|
foreach (string badFlag in unknownFlags)
|
||||||
|
{
|
||||||
|
if (lineLen + badFlag.Length + 5 > maxLineLen)
|
||||||
|
{
|
||||||
|
warnMsg.Append("\n ");
|
||||||
|
lineLen = 2;
|
||||||
|
}
|
||||||
|
warnMsg.Append($"\"\x1b[90m--{badFlag}\x1b[33m\" ");
|
||||||
|
lineLen += badFlag.Length + 5;
|
||||||
|
}
|
||||||
|
warnMsg.AppendLine("\x1b[0m");
|
||||||
|
Console.WriteLine(warnMsg);
|
||||||
|
}
|
||||||
|
int badValArgs = badValParams.Count + badValVars.Count;
|
||||||
|
if (badValArgs > 0)
|
||||||
|
{
|
||||||
|
// Issue parsing arguments.
|
||||||
|
StringBuilder warnMsg = new();
|
||||||
|
warnMsg.Append($" \x1b[3;33m{badValArgs} {(badValArgs == 1 ? "value" : "values")} couldn't be parsed:\n ");
|
||||||
|
int lineLen = 2, maxLineLen = (int)(0.65 * Console.WindowWidth - 1);
|
||||||
|
|
||||||
|
foreach (string badParam in badValParams)
|
||||||
|
{
|
||||||
|
if (lineLen + badParam.Length + 3 > maxLineLen)
|
||||||
|
{
|
||||||
|
warnMsg.Append("\n ");
|
||||||
|
lineLen = 2;
|
||||||
|
}
|
||||||
|
warnMsg.Append($"\"\x1b[37m{badParam}\x1b[33m\" ");
|
||||||
|
lineLen += badParam.Length + 3;
|
||||||
|
}
|
||||||
|
foreach (string badVar in badValVars)
|
||||||
|
{
|
||||||
|
if (lineLen + badVar.Length + 4 > maxLineLen)
|
||||||
|
{
|
||||||
|
warnMsg.Append("\n ");
|
||||||
|
lineLen = 2;
|
||||||
|
}
|
||||||
|
warnMsg.Append($"\"\x1b[36m-{badVar}\x1b[33m\" ");
|
||||||
|
lineLen += badVar.Length + 4;
|
||||||
|
}
|
||||||
|
warnMsg.AppendLine("\x1b[0m");
|
||||||
|
Console.WriteLine(warnMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
static object? parseObject(string value, Type desired)
|
||||||
|
{
|
||||||
|
if (desired == typeof(string)) return value;
|
||||||
|
else if (desired.IsEnum) return Enum.TryParse(desired, value, true, out object? enumResult) ? enumResult : null;
|
||||||
|
else if (desired.GetInterface("IParsable`1") is null) throw new("Type must derive from IParsable. Sorry.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A bit large. Couldn't condense into a single lambda because I wanted to cache the parameters.
|
||||||
|
// I have to do all this weird stuff as a whole to be able to parse any object that derives
|
||||||
|
// from IParsable, making extra stuff easier to implement.
|
||||||
|
MethodInfo tryParseMethod = (from x in desired.GetMethods()
|
||||||
|
let parameters = x.GetParameters()
|
||||||
|
let goodName = x.Name == "TryParse"
|
||||||
|
let goodAttributes = x.IsPublic && x.IsStatic
|
||||||
|
let goodParams = parameters.Length == 2
|
||||||
|
&& parameters[0].ParameterType == typeof(string)
|
||||||
|
&& parameters[1].ParameterType.GetElementType() == desired
|
||||||
|
where goodName && goodAttributes && goodParams
|
||||||
|
select x).Single(); // Must exist according to IParsable.
|
||||||
|
|
||||||
|
// Output parameters are placed in the array.
|
||||||
|
object?[] methodParams = [value, null];
|
||||||
|
bool success = (bool)tryParseMethod.Invoke(null, methodParams)!;
|
||||||
|
return success ? methodParams[1] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void PrintParameters(string? keyFormat = null)
|
||||||
|
{
|
||||||
|
if (Parameters.Count == 0) return;
|
||||||
|
else PrintHelper.PrintKeyValues("Parameters", 2, ParameterDescriptions.ToDictionary(), keyFormat: keyFormat ?? "\x1b[37m");
|
||||||
|
}
|
||||||
|
public static void PrintVariables()
|
||||||
|
{
|
||||||
|
if (Variables.Count == 0) return;
|
||||||
|
else PrintHelper.PrintKeyValues("Variables", 2, VariableDescriptions.ToDictionary(), keyFormat: "\x1b[36m");
|
||||||
|
}
|
||||||
|
public static void PrintFlags()
|
||||||
|
{
|
||||||
|
if (Flags.Count == 0) return;
|
||||||
|
else PrintHelper.PrintKeyValues("Flags", 2, FlagDescriptions.ToDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool anyArguments;
|
||||||
|
public bool anyParams, anyVars, anyFlags;
|
||||||
|
}
|
||||||
32
ArgumentBase/ArgumentBase.csproj
Normal file
32
ArgumentBase/ArgumentBase.csproj
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
<PackageId>ArgumentBase</PackageId>
|
||||||
|
<Title>ArgumentBase</Title>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<Authors>That_One_Nerd</Authors>
|
||||||
|
<Description>A small library that handles parsing console arguments.</Description>
|
||||||
|
<Copyright>MIT</Copyright>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\README.md">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath>\</PackagePath>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
21
ArgumentBase/IsFlagAttribute.cs
Normal file
21
ArgumentBase/IsFlagAttribute.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class IsFlagAttribute : Attribute
|
||||||
|
{
|
||||||
|
public readonly string description;
|
||||||
|
public readonly string? name;
|
||||||
|
|
||||||
|
public IsFlagAttribute(string description)
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
public IsFlagAttribute(string name, string description)
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
ArgumentBase/IsParameterAttribute.cs
Normal file
24
ArgumentBase/IsParameterAttribute.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class IsParameterAttribute : Attribute
|
||||||
|
{
|
||||||
|
public readonly int order;
|
||||||
|
public readonly string description;
|
||||||
|
public readonly string? name;
|
||||||
|
|
||||||
|
public IsParameterAttribute(int order, string description)
|
||||||
|
{
|
||||||
|
this.order = order;
|
||||||
|
this.description = description;
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
public IsParameterAttribute(int order, string name, string description)
|
||||||
|
{
|
||||||
|
this.order = order;
|
||||||
|
this.description = description;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
ArgumentBase/IsVariableAttribute.cs
Normal file
21
ArgumentBase/IsVariableAttribute.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class IsVariableAttribute : Attribute
|
||||||
|
{
|
||||||
|
public readonly string description;
|
||||||
|
public readonly string? name;
|
||||||
|
|
||||||
|
public IsVariableAttribute(string description)
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
public IsVariableAttribute(string name, string description)
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
ArgumentBase/PrintHelper.cs
Normal file
48
ArgumentBase/PrintHelper.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ArgumentBase;
|
||||||
|
|
||||||
|
internal static class PrintHelper
|
||||||
|
{
|
||||||
|
public static void PrintKeyValues(string title, int indent, Dictionary<string, string> values,
|
||||||
|
string? keyFormat = null, string? separatorFormat = null, string? valueFormat = null)
|
||||||
|
{
|
||||||
|
StringBuilder result = new();
|
||||||
|
result.Append($"{new string(' ', indent)}\x1b[1;97m{title}:\x1b[22m\n");
|
||||||
|
|
||||||
|
int maxLength = 0;
|
||||||
|
StringBuilder[] lines = new StringBuilder[values.Count];
|
||||||
|
IEnumerator<KeyValuePair<string, string>> iterator = values.GetEnumerator();
|
||||||
|
for (int i = 0; i < values.Count; i++)
|
||||||
|
{
|
||||||
|
iterator.MoveNext();
|
||||||
|
KeyValuePair<string, string> kv = iterator.Current;
|
||||||
|
lines[i] = new StringBuilder().Append($"{new string(' ', indent + 2)}{keyFormat ?? "\x1b[90m"}{kv.Key}");
|
||||||
|
|
||||||
|
int rawKeyLength = visibleStringLength(kv.Key);
|
||||||
|
if (rawKeyLength > maxLength) maxLength = kv.Key.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int desired = maxLength + 2;
|
||||||
|
iterator.Reset();
|
||||||
|
for (int i = 0; i < values.Count; i++)
|
||||||
|
{
|
||||||
|
iterator.MoveNext();
|
||||||
|
KeyValuePair<string, string> kv = iterator.Current;
|
||||||
|
int rawKeyLength = visibleStringLength(kv.Key);
|
||||||
|
int remaining = desired - rawKeyLength;
|
||||||
|
|
||||||
|
lines[i].Append($"{new string(' ', remaining)}{separatorFormat ?? "\x1b[91m- "}{valueFormat ?? "\x1b[37m"}{kv.Value}\x1b[0m");
|
||||||
|
result.Append(lines[i]);
|
||||||
|
result.AppendLine();
|
||||||
|
}
|
||||||
|
Console.WriteLine(result);
|
||||||
|
|
||||||
|
static int visibleStringLength(string str) => str.ToCharArray().Where(x => !char.IsControl(x)).Count();
|
||||||
|
}
|
||||||
|
}
|
||||||
38
README.md
Normal file
38
README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# ArgumentBase
|
||||||
|
|
||||||
|
This is a small library that will parse your command-line arguments for you in a pretty easy-to-use fashion.
|
||||||
|
This library only exists because I wrote this code for a different project and then found myself copy-pasting
|
||||||
|
it constantly. This is to ease my own suffering.
|
||||||
|
|
||||||
|
This is largely purpose-built for me, but feel free to use it. That's why it's here.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Import the package using your preferred method. Then, once it's installed, create a class like this:
|
||||||
|
```csharp
|
||||||
|
public class YourArguments : ArgumentBase<YourArguments>
|
||||||
|
{
|
||||||
|
// Positional arguments are called "parameters." No prefix is necessary.
|
||||||
|
[IsParameter(1, "An example description for the parameter.")]
|
||||||
|
public string ExampleParameter { get; set; } // It must be a property with a set method or it won't be identified.
|
||||||
|
|
||||||
|
// Variables are formatted like this: "-var:3.14"
|
||||||
|
[IsVariable("var", "An example description for the variable.")]
|
||||||
|
public double ExampleVariable { get; set; } // Parameters and variables can be any object that derives from IParsable.
|
||||||
|
|
||||||
|
// Flags are formatted like this: "--flag"
|
||||||
|
[IsFlag("flag", "An example description for the flag.")]
|
||||||
|
public bool ExampleFlag { get; set; } // Flags, however, can only be booleans.
|
||||||
|
// Whenever a flag is included as an argument, its value is flipped.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, in your Main method, paste the following:
|
||||||
|
```csharp
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
YourArguments args = YourArguments.Parse(args);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it. Not too bad, right?
|
||||||
Loading…
x
Reference in New Issue
Block a user