/// <summary> /// Generates help info for the given command. /// </summary> /// <param name="prog">The program from which the help command is being run.</param> /// <param name="cmd">The command for which to generate the help info.</param> /// <returns>A string containing the help information.</returns> /// <seealso cref="Help()" /> /// <seealso cref="Help(Commander.Program,Commander.Cog)" /> public string Help(Program program, CommandObj cmd) { /* * [Command Name] * Description: * <description> * * Usage: * <usage> * * Examples: * <examples> */ var cmdName = program.IsCaseSensitive ? cmd.Name : cmd.Name.ToLower(); var info = new StringBuilder(); info.Append('[').Append(cmdName).Append("]\n").Append("Description:\n").Append(cmd.Description); info.Append("\n\nUsage:\n").Append(cmd.Usage(program)); if (cmd.Examples.Length > 0) { info.Append("\n\nExamples:\n"); foreach (var example in cmd.Examples) { info.Append(example).Append('\n'); } // remove trailing \n char info.Remove(info.Length - 1, 1); } return(info.ToString()); }
public void AddChild(CommandObj cmd) { if (Children.ContainsKey(cmd.Name)) { return; } Children.Add(cmd.Name, cmd); cmd._parent = this; }
public CommandObj(object cog, CommandObj parent, MethodInfo methodInfo, bool invokable, string name, string description, string[] examples) { _cog = cog; _parent = null; Name = name; Description = description; Examples = examples; Invokable = invokable; _methodInfo = methodInfo; Children = new Dictionary <string, CommandObj>(); parent?.AddChild(this); }
/// <summary> /// Generates the call string for the given command. /// </summary> /// <param name="cmd">The command for which to generate the call string.</param> /// <returns>The call string for the given command.</returns> public static string CallString(CommandObj cmd) { var names = new Stack <string>(); while (cmd != null) { names.Push(cmd.Name); cmd = cmd._parent; } var callstring = ""; var name = ""; while (names.TryPop(out name)) { callstring += name + " "; } callstring = callstring.Substring(0, callstring.Length - 1); return(callstring); }
public Cog(Program prog, string name = "", string description = "") { IsCaseSensitive = prog.IsCaseSensitive; IsGroup = false; Commands = new Dictionary <string, CommandObj>(); // process attributes // set name, description and IsGroup based on presence of attributes and variables var attr = GetType().GetCustomAttribute(typeof(CommandGroup)); if (attr != null) { var cmdGrp = attr as CommandGroup; Name = IsCaseSensitive ? cmdGrp.Name.ToLower() : cmdGrp.Name; Description = StringProcessor.Process(cmdGrp.Description, prog); IsGroup = true; Commands.Add(Name, new CommandObj(this, null, false, Name, Description, new string[] { })); } else { if (name.Length == 0) { Name = GetType().Name; } else { Name = name; } if (description.Length == 0) { Description = "Not given."; } else { Description = StringProcessor.Process(description, prog); } } Utils.Debug($"Cog: {Name}, {Description}\nIsGroup: {IsGroup.ToString()}"); CommandObj group = null; if (IsGroup) { @group = Commands[Name]; } // process functions var methodInfo = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (var method in methodInfo) { var rawAttrib = method.GetCustomAttribute(typeof(Command)); if (rawAttrib == null) { continue; } var attrib = rawAttrib as Command; // process command // check that command function return value is string if (method.ReturnType != typeof(string)) { throw new AttributeError($"cog: {Name}.{method.Name}() does not return a string"); } var cmdName = attrib.Name == null ? method.Name : attrib.Name; // parse examples var examples = new List <string>(); var attribs = method.GetCustomAttributes(typeof(Example)); foreach (var a in attribs) { examples.Add((a as Example).Val); } CommandObj parent = null; // check if command is a subcommand if (attrib.Parent != null) { var attrParent = IsCaseSensitive ? attrib.Parent : attrib.Parent.ToLower(); if (Commands.ContainsKey(attrParent)) { parent = Commands[attrParent]; } else { CommandObj FindParent(CommandObj command, string strParent) { var p = IsCaseSensitive ? strParent : strParent.ToLower(); var cName = IsCaseSensitive ? command.Name : command.Name.ToLower(); if (cName == p) { return(command); } return(command.AllChildren().Select(commandObj => FindParent(commandObj, strParent)) .FirstOrDefault()); } parent = Commands.Values.Select(c => FindParent(c, attrParent)).FirstOrDefault(); if (parent == null) { throw new AttributeError($"could not find parent: {attrParent} in the scope of this cog"); } } } var cmd = new CommandObj(this, parent, method, true, cmdName, attrib.Description, examples.ToArray()); cmd.Description = StringProcessor.Process(cmd.Description, prog, cmd); for (var i = 0; i < cmd.Examples.Length; i++) { cmd.Examples[i] = StringProcessor.Process(cmd.Examples[i], prog, cmd); } if (group != null && parent == null) { @group.AddChild(cmd); } else if (parent == null) { Commands.Add(cmdName, cmd); } } }
/// <summary> /// Processes the arguments and dispatches the input to the appropriate cog/command. /// </summary> /// <param name="args">The input arguments to the program.</param> /// <returns>The result of the execution from the program based on the given input arguments.</returns> /// <exception cref="ProgramError"></exception> private string DispatchCommand(string[] args) { if (args.Length == 0) { throw new ProgramError("No command given."); } // check for command group name var name = args[0]; Utils.ShiftArgs(ref args); if (!IsCaseSensitive) { name = name.ToLower(); } if (UseProgramNamePrefix) { var pn = IsCaseSensitive ? Name : Name.ToLower(); if (name != pn) { throw new ProgramError("Must prefix command with program name!"); } if (args.Length < 1) { throw new ProgramError("No command given!"); } name = args[0]; Utils.ShiftArgs(ref args); if (!IsCaseSensitive) { name = name.ToLower(); } } // utility function for running the command tree CommandObj FindCommand(string cmdName) { foreach (var pair in _cogs) { var obj = pair.Value.GetCommand(cmdName); if (obj != null) { return(obj); } } return(null); } // handle help command if (name == "help") { // help called with no args if (args.Length <= 0) { return(Help.Help()); } var cogName = args[0]; var cg = GetCog(cogName); CommandObj cmd = null; if (cg != null) { Utils.ShiftArgs(ref args); if (args.Length <= 0) { return(Help.Help(this, cg)); } cmd = cg.GetCommand(args.First()); } // if cmd is still null, perform cog independent search if (cmd == null) { cmd = FindCommand(args.First()); } if (cmd == null) { // help was called on itself if (args.First() == "help" || args.Last() == "help") { return(Help.Help()); } throw new ProgramError($@"could not find any command called: {args.First()}"); } return(Help.Help(this, cmd)); } var result = ""; var cog = GetCog(name); if (cog != null) { result = cog.Execute(this, name, args); } else { Utils.Debug($"cog not found for name: {name}, attempting to find function..."); // attempt to find function var cmd = FindCommand(name); if (cmd == null) { throw new ProgramError($"could not find any command called: {name}"); } result = cmd.Invoke(this, args); } return(result); }