Skip to content

Instantly share code, notes, and snippets.

@DrizztDoUrden
Created September 27, 2017 14:12
Show Gist options
  • Save DrizztDoUrden/6694356f2fd8a5eec64413fcbaf874c0 to your computer and use it in GitHub Desktop.
Save DrizztDoUrden/6694356f2fd8a5eec64413fcbaf874c0 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Text;
namespace Validator
{
public class ArgsParser
{
public event Action OnExecute;
public event Action<string> OnUnresolvedKey;
public event Action<string> OnDuplicateArgument;
public bool IsRunning { get; private set; }
public string Description { get; set; }
public void Stop() => IsRunning = false;
public void AddCommand(string id, Action<Command> def)
{
var cmd = new Command(Command.Types.Command, id, this);
def(cmd);
cmd.Parser.OnUnresolvedKey += key => OnUnresolvedKey?.Invoke(key);
cmd.Parser.OnDuplicateArgument += aid => OnDuplicateArgument?.Invoke(aid);
_commands.Add(cmd);
}
public void AddFlag(string id, Action<Command> def)
{
var cmd = new Command(Command.Types.Flag, id, this);
def(cmd);
_commands.Add(cmd);
}
public void AddArgument(string id, Action<Command> def)
{
var cmd = new Command(Command.Types.SingleValue, id, this);
def(cmd);
_commands.Add(cmd);
}
public void AddMultiArgument(string id, Action<Command> def)
{
var cmd = new Command(Command.Types.MultiValue, id, this);
def(cmd);
_commands.Add(cmd);
}
public void AddHelpCommand(params string[] aliases)
{
AddCommand("help", def =>
{
def.Desc = "Show help.";
def.Parser.OnExecute += () => ShowHelp();
foreach (var alias in aliases)
def.Alias(alias);
});
}
public int Execute(ArraySegment<string> args)
{
IsRunning = true;
OnExecute?.Invoke();
foreach (var cmd in _commands)
cmd.Found = false;
var i = 0;
for (; i < args.Count && IsRunning; i++)
{
if (!_aliases.TryGetValue(args[i], out var cmd))
{
OnUnresolvedKey?.Invoke(args[i]);
continue;
}
if (cmd.Found && cmd.Type != Command.Types.MultiValue)
{
OnDuplicateArgument?.Invoke(cmd.Id);
continue;
}
switch (cmd.Type)
{
case Command.Types.Command:
i += cmd.Parser.Execute(new ArraySegment<string>(args.ToArray(), i, args.Count - i));
break;
case Command.Types.MultiValue:
case Command.Types.SingleValue:
cmd.OnValue(args[++i]);
break;
case Command.Types.Flag:
cmd.OnValue("true");
break;
}
cmd.Found = true;
}
return i;
}
public void ShowHelp(string intend = "")
{
Console.WriteLine($"{intend}{Description}");
foreach (var cmd in _commands)
{
Console.WriteLine();
cmd.PrintHelp(intend);
}
}
internal void RegisterAlias(string alias, Command command)
{
_aliases.Add(alias, command);
}
private readonly List<Command> _commands = new List<Command>();
private readonly Dictionary<string, Command> _aliases = new Dictionary<string, Command>();
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Validator
{
public class Command
{
public enum Types
{
Command,
Flag,
SingleValue,
MultiValue,
}
public Action<string> OnValue;
public ArgsParser Parser = new ArgsParser();
public string Id { get; }
public string Desc { get => Parser.Description; set => Parser.Description = value; }
public Types Type { get; }
public bool Found { get; set; }
public Command(Types type, string id, ArgsParser parser)
{
Type = type;
Id = id;
_parser = parser;
}
public void Alias(string alias)
{
_parser.RegisterAlias(alias, this);
_aliases.Add(alias);
}
public void PrintHelp(string intend = "")
{
var aliases = string.Join(", ", _aliases);
var tags = $"[{TypeStr()}]";
Intend(aliases, $"{intend} ");
Intend(tags, $"{intend} ");
Parser.ShowHelp($"{intend} ");
}
private readonly ArgsParser _parser;
private readonly List<string> _aliases = new List<string>();
private void Intend(string line, string intend)
{
var cw = Console.BufferWidth - intend.Length;
while (line.Length > 0)
{
if (line.Length <= cw)
{
Console.WriteLine($"{intend}{line}");
line = "";
break;
}
Console.WriteLine($"{intend}{line.Substring(0, cw)}");
line = line.Substring(cw);
}
}
private string TypeStr()
{
switch (Type)
{
case Types.Command:
return "Command";
case Types.Flag:
return "Flag";
case Types.MultiValue:
return "Argument with multiple values";
case Types.SingleValue:
return "Argument";
default:
throw new ArgumentOutOfRangeException(nameof(Type));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment