/// <summary> /// Gets a specific verb from a <see cref="TerminalCommandBase"/> by the verb's name. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to retrieve the verb from.</param> /// <param name="verbName">The name of the verb to retrieve.</param> /// <returns>A <see cref="Dictionary{MethodInfo, VerbAttribute}"/> containing all the <see cref="MethodInfo"/> objects with the specified verb name.</returns> internal static Dictionary <MethodInfo, VerbAttribute> GetVerb(TerminalCommandBase command, string verbName) { var result = new Dictionary <MethodInfo, VerbAttribute>(); var methods = command.GetType().GetCType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); foreach (var m in methods) { var verb = m.GetCustomAttributes(false).OfType <VerbAttribute>().FirstOrDefault(); if (verb != null) { if (string.IsNullOrEmpty(verbName)) { var def = m.GetCustomAttributes(false).OfType <DefaultVerbAttribute>().FirstOrDefault(); if (def != null) { result.Add(m, verb); } } else if (string.Equals(verb.Name, verbName, StringComparison.InvariantCultureIgnoreCase) || string.Equals(verb.Alias, verbName, StringComparison.InvariantCultureIgnoreCase)) { result.Add(m, verb); } } } return(result); }
/// <summary> /// Prints the associated command's help. /// </summary> /// <param name="command">The command to print help for.</param> /// <param name="name">The name of the name of the command.</param> private void PrintCommandHelp(TerminalCommandBase command, string name) { var sb = new StringBuilder(); var help = Helpers.GetCommandHelpFromAttribute(command); sb.AppendLine(); sb.AppendLine(FormatHelpCommandMethod(name)); if (!string.IsNullOrEmpty(help)) { sb.AppendLine(FormatHelpTextMethod(help)); } sb.AppendLine(); sb.AppendLine(formatHelpVerbMethod("Verbs")); sb.AppendLine(formatHelpTextMethod("-----")); var verbs = Helpers.GetVerbs(command); var nameWidth = 0; if (verbs.Count > 0) { nameWidth = verbs.Max(v => v.Value.Name.Length); } nameWidth = Math.Max(nameWidth, 10); var details = new List <VerbAttribute>(); foreach (var kvp in verbs.OrderBy(t => t.Value.Name)) { if (details.Where(d => d.Name == kvp.Value.Name).Count() == 0) { details.Add(kvp.Value); if (string.IsNullOrEmpty(kvp.Value.Name)) { sb.Append(FormatHelpVerbMethod("<none>".PadRight(nameWidth))); } else { sb.Append(FormatHelpVerbMethod(kvp.Value.Name.PadRight(nameWidth))); } sb.Append(' ', 6); sb.Append(FormatHelpTextMethod(kvp.Value.Help)); sb.AppendLine(); } } sb.AppendLine(); sb.AppendLine(FormatHelpFlagMethod("Flags")); sb.AppendLine(FormatHelpTextMethod("-----")); sb.Append(FormatHelpFlagMethod("--Help, -h".PadRight(nameWidth))); sb.Append(' ', 6); sb.Append(FormatHelpTextMethod("Prints help for this command.")); sb.AppendLine(); WriteHelpMethod(sb.ToString()); }
/// <summary> /// Removes the specified command from the global command's handler, provided the command is registered. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to remove.</param> /// <returns>True if a command was removed, false if no command existed with that name.</returns> public bool RemoveCommand(TerminalCommandBase command) { if (IsCommandRegistered(command)) { return(RemoveCommand(command.Name)); } return(false); }
/// <summary> /// Registers the specified command with a <see cref="GlobalCommand"/> with the specified name. /// </summary> /// <param name="consoleCommandName">The name of the <see cref="GlobalCommand"/> to register the command with.</param> /// <param name="command">The <see cref="TerminalCommandBase"/> to register with the specified <see cref="GlobalCommand"/>.</param> /// <returns>A <see cref="RegisterResult"/>.</returns> public static RegisterResult Register(string consoleCommandName, TerminalCommandBase command) { if (consoleCommandNames.ContainsKey(consoleCommandName)) { return(consoleCommandNames[consoleCommandName].AddCommand(command)); } return(RegisterResult.GlobalCommandNotFound); }
/// <summary> /// Unregisters a <see cref="TerminalCommandBase"/> from a registered <see cref="GlobalCommand"/> with the specified name. /// </summary> /// <param name="globalCommandName">The name of the <see cref="GlobalCommand"/> to unregister the command from.</param> /// <param name="command">The <see cref="TerminalCommandBase"/> to unregister from the specified <see cref="GlobalCommand"/>.</param> /// <returns><see langword="true"/> if the un-registration succeeded, otherwise <see langword="false"/>.</returns> public static bool Unregister(string globalCommandName, TerminalCommandBase command) { if (consoleCommandNames.ContainsKey(globalCommandName)) { return(consoleCommandNames[globalCommandName].RemoveCommand(command)); } return(false); }
/// <summary> /// Removes the specified command from the global command's handler, provided the command is registered. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to remove.</param> /// <returns>True if a command was removed, false if no command existed with that name.</returns> public bool RemoveCommand(TerminalCommandBase command) { if (IsCommandRegistered(command)) { aliasedCommands.Remove(command.Alias); return(commands.Remove(command.Name)); } return(false); }
/// <summary> /// Add a new terminal command to the global command. /// <para>Unlike the Global commands, these can be added at any point in program execution.</para> /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to add to the global command's handler.</param> /// <returns>The result of the registration attempt as a <see cref="RegisterResult"/>.</returns> public RegisterResult AddCommand(TerminalCommandBase command) { var name = Helpers.GetCommandNameFromAttribute(command); if (string.IsNullOrEmpty(name)) { return(RegisterResult.NoCommandAttributeFound); } return(AddCommand(command, name)); }
/// <summary> /// Gets the name of a command from the <see cref="CommandAttribute"/> associated with a <see cref="TerminalCommandBase"/> object. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to get a name for.</param> /// <returns>A <see langword="string"/> with the name retrieved, or <see cref="String.Empty"/> if no name was found.</returns> internal static string GetCommandNameFromAttribute(TerminalCommandBase command) { var name = string.Empty; var ca = command.GetType().GetCType().GetCustomAttributes(false).OfType <CommandAttribute>().FirstOrDefault(); if (ca != null) { name = ca.Name; } return(name); }
/// <summary> /// Gets the help text from a <see cref="CommandAttribute"/> associated with a <see cref="TerminalCommandBase"/> object. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to get the help text for.</param> /// <returns>A <see langword="string"/> with the help text, or <see cref="String.Empty"/> if no help text was found.</returns> internal static string GetCommandHelpFromAttribute(TerminalCommandBase command) { var help = string.Empty; var ca = command.GetType().GetCType().GetCustomAttributes(false).OfType <CommandAttribute>().FirstOrDefault(); if (ca != null) { help = ca.Help; } return(help); }
/// <summary> /// Gets the alias of a command from the <see cref="CommandAttribute"/> associated with a <see cref="TerminalCommandBase"/> object. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to get an alias for.</param> /// <returns>A <see langword="string"/> with the alias, or <see langword="string.Empty"/> if no alias was found.</returns> internal static string GetCommandAliasFromAttribute(TerminalCommandBase command) { var alias = string.Empty; var ca = command.GetType().GetCType().GetCustomAttributes(false).OfType <CommandAttribute>().FirstOrDefault(); if (ca != null) { alias = ca.Alias; } return(alias); }
/// <summary> /// Gets whether the specified command is registered with this global command. /// </summary> /// <param name="command">The command to check registration of.</param> /// <returns><see langword="True"/> if the command is registered.</returns> public bool IsCommandRegistered(TerminalCommandBase command) { syncRoot.Enter(); try { return(this.commands.ContainsKey(command.Name.ToLower()) && this.commands[command.Name.ToLower()] == command); } finally { syncRoot.Leave(); } }
/// <summary> /// Add a new terminal command to the global command. /// <para>Unlike the Global commands, these can be added at any point in program execution.</para> /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to add to the global command's handler.</param> /// <param name="name">The name to add the command using. If this is specified the class's <see cref="Attributes.CommandAttribute.Name"/> value will not be used.</param> /// <returns><see cref="RegisterResult"/>.</returns> public RegisterResult AddCommand(TerminalCommandBase command, string name) { RegisterResult result; if (!commands.ContainsKey(name.ToLower())) { commands.Add(name.ToLower(), command); result = RegisterResult.Success; } else { result = RegisterResult.CommandNameAlreadyExists; } return(result); }
/// <summary> /// Gets the verbs associated with a specific <see cref="TerminalCommandBase"/> object. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> object to get the verbs of.</param> /// <returns>A <see cref="Dictionary{MethodInfo, VerbAttribute}"/> with any verbs found.</returns> internal static Dictionary <MethodInfo, VerbAttribute> GetVerbs(TerminalCommandBase command) { var result = new Dictionary <MethodInfo, VerbAttribute>(); var methods = command.GetType().GetCType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); foreach (var m in methods) { var verb = m.GetCustomAttributes(false).OfType <VerbAttribute>().FirstOrDefault(); if (verb != null) { result.Add(m, verb); } } return(result); }
/// <summary> /// Gets the command help formatted name from a <see cref="TerminalCommandBase"/> object. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to get the help formatted name for.</param> /// <returns>A <see langword="string"/> with the name retrieved.</returns> internal static string GetCommandNameHelp(TerminalCommandBase command) { var nameHelp = string.Empty; nameHelp = string.Format("{0}{1}", SanitizeHelpName(command.Name), string.IsNullOrEmpty(command.Alias) ? string.Empty : string.Format(" ({0})", command.Alias.ToLower())); if (string.IsNullOrEmpty(nameHelp)) { var ca = command.GetType().GetCType().GetCustomAttributes(false).OfType <CommandAttribute>().FirstOrDefault(); if (ca != null) { nameHelp = ca.HelpFormattedName; } } return(nameHelp); }
/// <summary> /// Removes the specified command from the global command's handler, provided the command is registered. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to remove.</param> /// <returns>True if a command was removed, false if no command existed with that name.</returns> public bool RemoveCommand(TerminalCommandBase command) { syncRoot.Enter(); try { if (IsCommandRegistered(command)) { aliasedCommands.Remove(command.Alias.ToLower()); return(commands.Remove(command.Name.ToLower())); } return(false); } finally { syncRoot.Leave(); } }
/// <summary> /// Gets the examples associated with a specific verb. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to check for verbs.</param> /// <param name="verbName">The name of the verb to retrieve.</param> /// <returns>A list of <see cref="SampleAttribute"/>s.</returns> internal static List <SampleAttribute> GetVerbExamples(TerminalCommandBase command, string verbName) { var result = new List <SampleAttribute>(); var verbs = GetVerb(command, verbName); foreach (var vm in verbs.Keys) { var eas = vm.GetCustomAttributes(false).OfType <SampleAttribute>(); foreach (var ea in eas) { if (ea != null) { result.Add(ea); } } } return(result); }
/// <summary> /// Add a new terminal command to the global command. /// <para>Unlike the Global commands, these can be added at any point in program execution.</para> /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to add to the global command's handler.</param> /// <returns><see cref="RegisterResult"/>.</returns> public RegisterResult AddCommand(TerminalCommandBase command) { RegisterResult result; if (!commands.ContainsKey(command.Name.ToLower()) && !string.IsNullOrEmpty(command.Alias) ? !aliasedCommands.ContainsKey(command.Alias.ToLower()) : true) { commands.Add(command.Name.ToLower(), command); if (!string.IsNullOrEmpty(command.Alias)) { aliasedCommands.Add(command.Alias.ToLower(), command); } result = RegisterResult.Success; } else { result = RegisterResult.CommandNameAlreadyExists; } return(result); }
/// <summary> /// Add a new terminal command to the global command. /// <para>Unlike the Global commands, these can be added at any point in program execution.</para> /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to add to the global command's handler.</param> /// <returns><see cref="RegisterResult"/>.</returns> public RegisterResult AddCommand(TerminalCommandBase command) { syncRoot.Enter(); try { RegisterResult result; var commandName = command.Name.ToLower(); if (string.IsNullOrEmpty(commandName)) { return(RegisterResult.NoCommandAttributeFound); } var commandAlias = !string.IsNullOrEmpty(command.Alias) ? command.Alias.ToLower() : string.Empty; if (!commands.ContainsKey(commandName) && !aliasedCommands.ContainsKey(commandAlias)) { commands.Add(commandName, command); if (!string.IsNullOrEmpty(commandAlias)) { aliasedCommands.Add(commandAlias, command); } result = RegisterResult.Success; } else { result = RegisterResult.CommandNameAlreadyExists; } return(result); } finally { syncRoot.Leave(); } }
/// <summary> /// Gets an array of <see cref="GlobalCommand"/> objects that the specified <see cref="TerminalCommandBase"/> is registered to. /// </summary> /// <param name="command">The <see cref="TerminalCommandBase"/> to check for registrations.</param> /// <returns>An array of <see cref="GlobalCommand"/> objects.</returns> public static GlobalCommand[] ReturnAllTerminalCommandIsRegisteredTo(TerminalCommandBase command) { return(consoleCommandNames.Values.Where(gc => gc.IsCommandRegistered(command)).ToArray()); }
/// <summary> /// Prints the associated verb's help. /// </summary> /// <param name="command">The command to check for verbs.</param> /// <param name="verbName">The name of the verb to print help for.</param> private void PrintVerbHelp(TerminalCommandBase command, string verbName) { var sb = new StringBuilder(); var verbs = Helpers.GetVerb(command, verbName); if (verbs.Count > 0) { sb.AppendLine(); sb.Append(string.Format("{0}", FormatHelpVerbMethod(verbs.First().Value.Name))); sb.Append(' ', 6); sb.AppendLine(FormatHelpTextMethod(string.Format("{0}", verbs.First().Value.Help))); sb.AppendLine(); var examples = Helpers.GetVerbExamples(command, verbName); if (examples.Count > 0) { sb.AppendLine(FormatHelpTextMethod("Examples")); foreach (var e in examples) { sb.AppendLine(FormatHelpSampleMethod(string.Format("'{0}'", e.Sample))); sb.Append(' ', 5); sb.AppendLine(FormatHelpTextMethod(e.Description)); sb.AppendLine(); } } List <OperandAttribute> operands = new List <OperandAttribute>(); List <FlagAttribute> flags = new List <FlagAttribute>(); foreach (var v in verbs) { var ec = EqualityComparer <KeyValuePair <ParameterInfo, OperandAttribute> > .Default; var ops = Helpers.GetOperands(v.Key); if (ops.Count > 0) { foreach (var val in ops.Values) { if (!operands.Any(o => o.Name == val.Name)) { operands.Add(val); } } } var fl = Helpers.GetFlags(v.Key); if (fl.Count > 0) { foreach (var val in fl.Values) { if (!flags.Any(f => f.Name == val.Name)) { flags.Add(val); } } } } var nameWidth = 0; if (operands.Count > 0) { nameWidth = operands.Max(op => op.Name.Length); } if (flags.Count > 0) { nameWidth = Math.Max(nameWidth, flags.Max(fa => fa.Name.Length + 2 + (fa.ShortName.HasValue ? 4 : 0))); } sb.Append(FormatHelpOperandMethod("Operands")); sb.Append(FormatHelpTextMethod("/")); sb.AppendLine(FormatHelpFlagMethod("Flags")); sb.AppendLine(); foreach (var op in operands) { if (!string.IsNullOrEmpty(op.Name)) { sb.Append(FormatHelpOperandMethod(string.Format("--{0}", op.Name.PadRight(nameWidth - 2)))); sb.Append(' ', 6); sb.AppendLine(FormatHelpTextMethod(op.Help)); } } foreach (var flag in flags) { var value = string.Format("--{0}", flag.Name); if (flag.ShortName.HasValue) { value = string.Format("{0}, -{1}", value, flag.ShortName); } value = FormatHelpFlagMethod(value.PadRight(nameWidth)); sb.Append(value); sb.Append(' ', 6); sb.AppendLine(FormatHelpTextMethod(flag.Help)); } } else { sb.Append(FormatHelpTextMethod(string.Format("There is no help available for '{0}'", verbName))); } WriteHelpMethod(sb.ToString()); }
private void ProcessCommand(string commandName, string verb, string defaultValue, Dictionary <string, string> operandsAndFlags) { TerminalCommandBase command = null; if (string.IsNullOrEmpty(commandName) && (operandsAndFlags.ContainsKey("help") || operandsAndFlags.ContainsKey("h"))) { PrintGlobalCommandsHelp(); return; } if (!commands.ContainsKey(commandName)) { WriteErrorMethod(string.Format("No command with the name '{0}' exists. Enter '--help' to view all available commands.", commandName)); return; } else { command = commands[commandName]; } if (string.IsNullOrEmpty(verb) && (operandsAndFlags.ContainsKey("help") || operandsAndFlags.ContainsKey("h"))) { PrintCommandHelp(command, commandName); return; } else { var verbEntries = Helpers.GetVerb(command, verb); if (verbEntries.Count == 0) { if (string.IsNullOrEmpty(verb)) { WriteErrorMethod(string.Format("The command '{0}' requires a verb. Enter '{0} --help' to view all available verbs.", commandName)); } else { WriteErrorMethod(string.Format("No verb with the specified name '{1}' exists. Enter '{0} --help' to view all available verbs.", commandName, verb)); } return; } else { if (operandsAndFlags.ContainsKey("help") || operandsAndFlags.ContainsKey("h")) { PrintVerbHelp(command, verb); return; } if (!string.IsNullOrEmpty(defaultValue)) { operandsAndFlags.Add(string.Empty, defaultValue); } foreach (var entry in verbEntries) { var operandAttributes = Helpers.GetOperands(entry.Key); var flagAttributes = Helpers.GetFlags(entry.Key); var names = operandAttributes.Where((a) => operandsAndFlags.ContainsKey(a.Value.Name.ToLower())).Select(n => n.Value.Name.ToLower()).ToList(); names.AddRange(flagAttributes.Where(a => operandsAndFlags.ContainsKey(a.Value.Name.ToLower()) || operandsAndFlags.ContainsKey(a.Value.ShortName.ToString().ToLower()) || a.Value.IsOptional).Select(n => n.Value.Name.ToLower())); var optional = flagAttributes.Where(a => a.Value.IsOptional).Count(); var parameterCount = entry.Key.GetParameters().Length; var success = true; foreach (var oaf in operandsAndFlags.Keys) { if (operandAttributes.Values.Any(oa => oa.Name.ToLower() == oaf)) { continue; } if (flagAttributes.Values.Any(fa => fa.Name.ToLower() == oaf || (fa.ShortName.HasValue && fa.ShortName.Value.ToString() == oaf))) { continue; } success = false; } if (!success) { continue; } if ((names.Count == operandsAndFlags.Count && operandsAndFlags.Count == parameterCount) || (parameterCount - names.Count <= optional && optional > 0)) { if (parameterCount > 0) { var parameterList = new object[parameterCount]; try { foreach (var oa in operandAttributes) { var index = oa.Key.Position; var type = oa.Key.ParameterType; var operandName = operandsAndFlags[oa.Value.Name.ToLower()]; var value = PrepareParameterValue(type, operandName); if (value != null) { parameterList[index] = value; } else { WriteErrorMethod(string.Format("Unable to convert the operand '{0}' with the value '{1}' to the expected type value '{2}'.", operandName, operandsAndFlags[operandName], type.ToString())); return; } } foreach (var fa in flagAttributes) { if (operandsAndFlags.ContainsKey(fa.Value.Name.ToLower()) || (fa.Value.ShortName.HasValue && operandsAndFlags.ContainsKey(fa.Value.ShortName.ToString().ToLower()))) { parameterList[fa.Key.Position] = true; } else { parameterList[fa.Key.Position] = false; } } } catch { success = false; } if (success) { entry.Key.Invoke(command, parameterList); } } else { entry.Key.Invoke(command, null); } if (success) { return; } } } WriteErrorMethod(string.Format("The verb '{0}' requires a different combination of operands than what was provided. Enter '{1} {0} --help' for more information.", verb, commandName)); } } }
/// <summary> /// Gets whether the specified command is registered with this global command. /// </summary> /// <param name="command">The command to check registration of.</param> /// <returns><see langword="True"/> if the command is registered.</returns> public bool IsCommandRegistered(TerminalCommandBase command) { return(this.commands.ContainsKey(command.Name) && this.commands[command.Name] == command); }