LaunchArgumentParser.HelpMessageHeader

This commit is contained in:
Timerix 2025-04-26 04:19:14 +05:00
parent ee20c9c5ec
commit 823169ca91

View File

@ -2,32 +2,123 @@ namespace DTLib.Console;
public class LaunchArgumentParser public class LaunchArgumentParser
{ {
public string HelpMessageHeader = "USAGE:";
public bool IsAllowedNoArguments; public bool IsAllowedNoArguments;
private readonly Dictionary<string, LaunchArgument> argDict = new(); private readonly Dictionary<string, LaunchArgument> argDict = new();
private readonly List<LaunchArgument> argList = new(); private readonly List<LaunchArgument> argList = new();
public class ExitAfterHelpException : Exception public LaunchArgumentParser()
{ {
internal ExitAfterHelpException() : base("your program can use this exception to exit after displaying help message") var help = new LaunchArgument(new[] { "h", "help" },
{ } "shows help message", HelpHandler);
Add(help);
var helpArg = new LaunchArgument(new[] { "ha", "helparg" },
"shows help message for specific argument",
HelpArgHandler, "argument");
Add(helpArg);
} }
public LaunchArgumentParser(ICollection<LaunchArgument> arguments) : this() => WithArgs(arguments);
public LaunchArgumentParser(params LaunchArgument[] arguments) : this() => WithArgs(arguments);
public LaunchArgumentParser WithArgs(IEnumerable<LaunchArgument> args)
{
foreach (var arg in args)
Add(arg);
return this;
}
public LaunchArgumentParser WithArgs(params LaunchArgument[] args)
{
foreach (var arg in args)
Add(arg);
return this;
}
public LaunchArgumentParser WithHelpMessageHeader(string header)
{
HelpMessageHeader = header;
return this;
}
public LaunchArgumentParser AllowNoArguments()
{
IsAllowedNoArguments = true;
return this;
}
public string CreateHelpMessage() public string CreateHelpMessage()
{ {
StringBuilder b = new(); StringBuilder b = new(HelpMessageHeader);
foreach (var arg in argList) foreach (var arg in argList)
arg.AppendHelpInfo(b).Append('\n'); {
b.Remove(b.Length-1, 1); b.Append('\n');
arg.AppendHelpInfo(b);
}
return b.ToString(); return b.ToString();
} }
public string CreateHelpArgMessage(string argAlias) public string CreateHelpArgMessage(string argAlias)
{ {
StringBuilder b = new(); StringBuilder b = new();
var arg = Parse(argAlias); var arg = ParseArg(argAlias);
arg.AppendHelpInfo(b); arg.AppendHelpInfo(b);
return b.ToString(); return b.ToString();
} }
public void Add(LaunchArgument arg)
{
argList.Add(arg);
foreach (string alias in arg.Aliases)
argDict.Add(alias, arg);
}
public LaunchArgument ParseArg(string argAlias)
{
// different argument providing patterns
if (!argDict.TryGetValue(argAlias, out var arg) && // arg
!(argAlias.StartsWith("--") && argDict.TryGetValue(argAlias.Substring(2), out arg)) && // --arg
!(argAlias.StartsWith('-') && argDict.TryGetValue(argAlias.Substring(1), out arg)) && // -arg
!(argAlias.StartsWith('/') && argDict.TryGetValue(argAlias.Substring(1), out arg))) // /arg
throw new Exception($"invalid argument: {argAlias}\n{CreateHelpMessage()}");
return arg;
}
/// <param name="args">program launch args</param>
/// <exception cref="Exception">argument {args[i]} should have a parameter after it</exception>
/// <exception cref="NullReferenceException">argument hasn't got any handlers</exception>
/// <exception cref="ExitAfterHelpException">happens after help message is displayed</exception>
public void ParseAndHandle(string[] args)
{
// show help message and throw ExitAfterHelpException
if (args.Length == 0 && !IsAllowedNoArguments)
HelpHandler();
List<LaunchArgument> execQueue = new();
for (int i = 0; i < args.Length; i++)
{
var arg = ParseArg(args[i]);
for (int j = 0; j < arg.Params.Length; j++)
{
if (++i >= args.Length)
throw new Exception(
$"argument '{arg.Aliases[0]}' should have parameter '{arg.Params[j]}' after it");
arg.Params[j].Value = args[i];
}
execQueue.Add(arg);
}
// ascending sort by priority
execQueue.Sort((a0, a1) => a0.Priority - a1.Priority);
// finally executing handlers
foreach (var a in execQueue)
a.Handle();
}
private void HelpHandler() private void HelpHandler()
{ {
System.Console.WriteLine(CreateHelpMessage()); System.Console.WriteLine(CreateHelpMessage());
@ -40,83 +131,11 @@ public class LaunchArgumentParser
throw new ExitAfterHelpException(); throw new ExitAfterHelpException();
} }
public class ExitAfterHelpException : Exception
public LaunchArgumentParser()
{ {
var help = new LaunchArgument(new[] { "h", "help" }, public ExitAfterHelpException()
"shows help message", HelpHandler); : base("your program can use this exception to exit after displaying help message")
Add(help);
var helpArg = new LaunchArgument( new[]{ "ha", "helparg" },
"shows help message for particular argument",
HelpArgHandler, "argAlias");
Add(helpArg);
}
public LaunchArgumentParser AllowNoArguments()
{
IsAllowedNoArguments = true;
return this;
}
public LaunchArgumentParser(ICollection<LaunchArgument> arguments) : this()
{
foreach (var arg in arguments)
Add(arg);
}
public LaunchArgumentParser(params LaunchArgument[] arguments) : this()
{
foreach (var arg in arguments)
Add(arg);
}
public void Add(LaunchArgument arg)
{
argList.Add(arg);
foreach (string alias in arg.Aliases)
argDict.Add(alias, arg);
}
public LaunchArgument Parse(string argAlias)
{
// different argument providing patterns
if (!argDict.TryGetValue(argAlias, out var arg) && // arg
!(argAlias.StartsWith("--") && argDict.TryGetValue(argAlias.Substring(2), out arg)) && // --arg
!(argAlias.StartsWith('-') && argDict.TryGetValue(argAlias.Substring(1), out arg)) && // -arg
!(argAlias.StartsWith('/') && argDict.TryGetValue(argAlias.Substring(1), out arg))) // /arg
throw new Exception($"invalid argument: {argAlias}\n{CreateHelpMessage()}");
return arg;
}
/// <param name="args">program launch args</param>
/// <exception cref="Exception">argument {args[i]} should have a parameter after it</exception>
/// <exception cref="NullReferenceException">argument hasn't got any handlers</exception>
/// <exception cref="ExitAfterHelpException">happens after help message is displayed</exception>
public void ParseAndHandle(string[] args)
{
// show help message and throw ExitAfterHelpException
if (args.Length == 0 && !IsAllowedNoArguments)
HelpHandler();
List<LaunchArgument> execQueue = new();
for (int i = 0; i < args.Length; i++)
{ {
LaunchArgument arg = Parse(args[i]);
for (int j = 0; j < arg.Params.Length; j++)
{
if (++i >= args.Length)
throw new Exception($"argument '{arg.Aliases[0]}' should have parameter '{arg.Params[j]}' after it");
arg.Params[j].Value = args[i];
}
execQueue.Add(arg);
} }
// ascending sort by priority
execQueue.Sort((a0, a1) => a0.Priority-a1.Priority);
// finally executing handlers
foreach (var a in execQueue)
a.Handle();
} }
} }