private static void ParseOptions(ref DidactClient client, string[] args, string parentName) { for (var i = 1; i < args.Length; i++) { var option = client.Options.FirstOrDefault(o => args[i - 1] == o.ShortCommand || args[i - 1] == o.LongCommand && o.ParentName == parentName); if (option != null) { // Read option argument - null if not present var val = args.Length >= i ? args[i] : null; // Parse if (option.Parse != null) { val = option.Parse(val); } // Validate if (option.Validate == null) { option.Value = val; } else { if (option.Validate(val)) { option.Value = val; } else { throw new FormatException($"The option '{option.ShortCommand}' failed data validation."); } } } } }
public static DidactClient Command(this DidactClient didact, string commandStr, string description, Action <Dictionary <string, string>, Dictionary <string, string> > action) { if (action == null) { throw new ArgumentNullException($"The {nameof(action)} argument cannot be null", nameof(action)); } return(didact.Command(commandStr, description, action: action, actionAsync: null)); }
public static void Parse(this DidactClient didact, string[] args) { try { didact.ParseAsync(args).Wait(); } catch (AggregateException ex) { ExceptionDispatchInfo.Capture(ex.Flatten().InnerExceptions.First()).Throw(); } }
public static DidactClient Option(this DidactClient didact, string flags, string description, Func <string, bool> validate = null, Func <string, string> parse = null, string defaultValue = default(string)) { var parentName = didact.Commands.LastOrDefault()?.Name; var option = new Option { DefaultValue = defaultValue, Description = description, Flags = flags, OptionType = parentName == null ? OptionType.Global : OptionType.Command, ParentName = parentName, Parse = parse, Validate = validate }; // Check format of flags var match = Regex.Match(flags, @"(\-[a-z]),[ ]([\-]{2}[a-z\-]+)[ ]?([\<\>\[\]a-z0-9\- ]+)?", RegexOptions.IgnoreCase); if (!match.Success || match.Groups.Count != 4) { throw new ArgumentException($"The Flags format is malformed for '{flags}'.", nameof(flags)); } option.ShortCommand = match.Groups[1].Value; option.LongCommand = match.Groups[2].Value; // Parse arguments out from flags var arguments = match.Groups[3].Value.Trim().Split(' '); if (arguments.Count() > 1) { throw new ArgumentException($"The Flags format is malformed for the argument. You can have only one argument on an option.", nameof(flags)); } if (arguments.Any()) { var argument = arguments.First(); var argRegex = Regex.Match(argument, @"(\<[a-z]+[a-z0-9\-]+\>|\[[a-z]+[a-z0-9\-]+\])", RegexOptions.IgnoreCase); if (!argRegex.Success) { throw new ArgumentException($"The Flags format is malformed for the argument '{argument}'.", nameof(flags)); } option.IsRequired = argument.StartsWith("<"); option.Name = argument.Trim('<', '>', '[', ']'); } didact.Options.Add(option); return(didact); }
internal static void PrintHelp(DidactClient client) { if (client.Metadata.Usage == null) { // Generate Usage var sb = new StringBuilder(); sb.Append(client.Metadata.CliName); if (client.Commands.Any()) { sb.Append(" [command]"); } if (client.Commands.Any(c => c.Arguments.Any())) { sb.Append(" [arguments]"); } if (client.Options.Any(o => o.OptionType == OptionType.Command)) { sb.Append(" [command-options]"); } if (client.Options.Any(o => o.OptionType == OptionType.Global)) { sb.Append(" [global-options]"); } client.Metadata.Usage = sb.ToString(); } WriteLine(); Write(client.Metadata.Name); if (client.Metadata.Version != null) { Write($" - ({client.Metadata.Version})"); } Write("\n"); WriteLine(); WriteLine($"Usage: {client.Metadata.Usage}"); WriteLine(); // Print Global Options WriteLine("Global Options:"); var options = client.Options.Where(o => o.OptionType == OptionType.Global); var largestLinePosition = 4 + options.OrderByDescending(o => o.ShortCommand.Length).First().ShortCommand.Length + options.OrderByDescending(o => o.LongCommand.Length).First().LongCommand.Length; foreach (var option in options) { var line = $" {option.ShortCommand}, {option.LongCommand}"; var padding = largestLinePosition - line.Length; WriteLine($"{line.PadRight(padding, ' ')} {option.Description}"); } // TODO: print commands with their respective options }
private static DidactClient Command(this DidactClient didact, string commandStr, string description, Action <Dictionary <string, string>, Dictionary <string, string> > action = null, Func <Dictionary <string, string>, Dictionary <string, string>, Task> actionAsync = null) { var command = new Command { CommandStr = commandStr, Action = action, ActionAsync = actionAsync }; var match = Regex.Match(commandStr, @"([a-z]+[a-z0-9\-]+)[ ]?([\<\>\[\]a-z0-9 ]+)?", RegexOptions.IgnoreCase); if (!match.Success || match.Groups.Count != 3) { throw new ArgumentException($"The Command format is malformed for '{commandStr}'.", nameof(commandStr)); } command.Name = match.Groups[1].Value; var arguments = match.Groups[2].Value.Trim().Split(' '); foreach (var argumentStr in arguments) { if (string.IsNullOrWhiteSpace(argumentStr)) { continue; } var trimmedArgumentStr = argumentStr.Trim('<', '>', '[', ']'); var argument = new Argument { Name = trimmedArgumentStr, IsRequired = argumentStr.StartsWith("<") }; var argRegex = Regex.Match(argumentStr, @"(\<[a-z]+[a-z0-9\-]+\>|\[[a-z]+[a-z0-9\-]+\])", RegexOptions.IgnoreCase); if (!argRegex.Success) { throw new ArgumentException($"The Command format is malformed for the argument '{argumentStr}'.", nameof(commandStr)); } command.Arguments.Add(argument); } didact.Commands.Add(command); return(didact); }
public static void DebugPrintValues(this DidactClient client) { WriteLine(); WriteLine("Printing Internal Values"); WriteLine(); WriteLine($" Global Options"); foreach (var option in client.Options.Where(o => o.OptionType == OptionType.Global)) { WriteLine($" {option.ShortCommand}, {option.LongCommand} - {option.Value}"); } WriteLine(); WriteLine($" Commands"); foreach (var command in client.Commands) { WriteLine($" {command.Name}'s Details"); WriteLine($" Arguments"); foreach (var argument in command.Arguments) { WriteLine($" {argument.Name} - {argument.Value}"); } WriteLine($" Arguments"); foreach (var argument in command.Arguments) { WriteLine($" {argument.Name} - {argument.Value}"); } WriteLine($" Options"); foreach (var option in client.Options.Where(o => o.ParentName == command.Name)) { WriteLine($" {option.ShortCommand}, {option.LongCommand} - {option.Value}"); } WriteLine(); } }
public async static Task ParseAsync(this DidactClient didact, string[] args) { if (args == null || !args.Any()) { PrintHelp(didact); return; } // Match all global options ParseOptions(ref didact, args, null); // Check if first command matches any commands var command = didact.Commands.FirstOrDefault(c => c.Name == args[0]); if (command != null) { // Parse the next few into commands arguments for (var i = 1; i < args.Length; i++) { var argument = command.Arguments.ElementAtOrDefault(i - 1); if (argument != null && args.Length >= i) { argument.Value = args[i]; } } // Check if required arguments exist var missingArgument = command.Arguments.FirstOrDefault(a => a.Value == null && a.IsRequired); if (missingArgument != null) { throw new ArgumentException($"The {missingArgument.Name} argument is required.", missingArgument.Name); } // Parse all command specific options ParseOptions(ref didact, args, command.Name); // Populate null, non-required, non-validation-failed options with their default values, if they have them foreach (var option in didact.Options.Where(o => o.IsRequired && o.DefaultValue != null && o.Value == null)) { option.Value = option.DefaultValue; } // Throw exception if a required command is missing var missingOption = didact.Options .FirstOrDefault(o => (o.OptionType == OptionType.Global || o.ParentName == command.Name) && o.IsRequired && o.Value == null); if (missingOption != null) { throw new ArgumentNullException($"The {missingOption.Name} option is required for this command."); } // Create dictionaries of arguments and options to pass into the action var arguments = command.Arguments .Select(a => new KeyValuePair <string, string>(a.Name, a.Value)) .ToDictionary(d => d.Key, d => d.Value); var options = didact.Options .Where(o => o.ParentName == command.Name || o.OptionType == OptionType.Global) .Select(a => new KeyValuePair <string, string>(a.ShortCommand.Remove(0, 1), a.Value)) .ToDictionary(d => d.Key, d => d.Value); if (command.Action != null) { command.Action(arguments, options); } else if (command.ActionAsync != null) { await command.ActionAsync(arguments, options); } else { throw new InvalidOperationException("There is no action to call. Help."); } } if (command == null) { PrintHelp(didact); } }