コード例 #1
0
        private CommandResult ExecuteLine(string line)
        {
            CommandResult next = CommandResult.Normal;

            if (line.StartsWith("#"))
            {
                // Comments start with "#", just ignore them
            }
            else if (line.StartsWith("@"))
            {
                // A line beginning with an "@" indicates a script to execute.
                string scriptFile = line.Substring(1);

                next = ExecuteScript(scriptFile);
            }
            else
            {
                string[]        args    = null;
                DebuggerCommand command = GetDebuggerCommandFromCommandString(line, out args);

                if (command == null)
                {
                    // Not a command.
                    Console.WriteLine("Invalid command.");
                }
                else
                {
                    next = InvokeConsoleMethod(command, args);
                }
            }

            return(next);
        }
コード例 #2
0
        public void AddSubNode(List <string> words, MethodInfo method, object instance)
        {
            // We should never hit this case.
            if (words.Count == 0)
            {
                throw new InvalidOperationException("Out of words building command node.");
            }

            // Check the root to see if a node for the first incoming word has already been added
            DebuggerCommand subNode = FindSubNodeByName(words[0]);

            if (subNode == null)
            {
                // No, it has not -- create one and add it now.
                subNode = new DebuggerCommand(instance, words[0], null, null, null);
                this.SubCommands.Add(subNode);

                if (words.Count == 1)
                {
                    // This is the last stop -- set the method and be done with it now.
                    subNode.Methods.Add(method);

                    // early return.
                    return;
                }
            }
            else
            {
                // The node already exists, we will be adding a subnode, hopefully.
                if (words.Count == 1)
                {
                    //
                    // If we're on the last word at this point then this is an overloaded command.
                    // Check that we don't have any other commands with this number of arguments.
                    //
                    int argCount = method.GetParameters().Length;
                    foreach (MethodInfo info in subNode.Methods)
                    {
                        if (info.GetParameters().Length == argCount)
                        {
                            throw new InvalidOperationException("Duplicate overload for console command");
                        }
                    }

                    //
                    // We're ok.  Add it to the method list.
                    //
                    subNode.Methods.Add(method);

                    // and return early.
                    return;
                }
            }

            // We have more words to go.
            words.RemoveAt(0);
            subNode.AddSubNode(words, method, instance);
        }
コード例 #3
0
        private DebuggerCommand GetDebuggerCommandFromCommandString(string command, out string[] args)
        {
            args = null;

            List <string> cmdArgs = SplitArgs(command);

            DebuggerCommand current      = _commandRoot;
            int             commandIndex = 0;

            while (true)
            {
                // If this node has an executor and no subnodes, or if this node has an executor
                // and there are no further arguments, then we're done.
                if ((current.Methods.Count > 0 && current.SubCommands.Count == 0) ||
                    (current.Methods.Count > 0 && commandIndex > cmdArgs.Count - 1))
                {
                    break;
                }

                if (commandIndex > cmdArgs.Count - 1)
                {
                    // Out of args with no match.
                    return(null);
                }

                // Otherwise we continue down the tree.
                DebuggerCommand next = current.FindSubNodeByName(cmdArgs[commandIndex]);

                commandIndex++;

                if (next == null)
                {
                    //
                    // If a matching subcommand was not found, then if we had a previous node with an
                    // executor, use that; otherwise the command is invalid.
                    //
                    if (current.Methods.Count > 0)
                    {
                        break;
                    }
                    else
                    {
                        return(null);
                    }
                }

                current = next;
            }

            // Now current should point to the command with the executor
            // and commandIndex should point to the first argument to the command.

            cmdArgs.RemoveRange(0, commandIndex);

            args = cmdArgs.ToArray();
            return(current);
        }
コード例 #4
0
        public DebuggerCommand FindSubNodeByName(string name)
        {
            DebuggerCommand found = null;

            foreach (DebuggerCommand sub in SubCommands)
            {
                if (sub.Name == name)
                {
                    found = sub;
                    break;
                }
            }

            return(found);
        }
コード例 #5
0
        /// <summary>
        /// Builds the debugger command tree.
        /// </summary>
        private void BuildCommandTree(List <object> commandObjects)
        {
            // Build the flat list which will be built into the tree, by walking
            // the classes that provide the methods
            _commandList = new List <DebuggerCommand>();

            // Add ourself to the list
            commandObjects.Add(this);

            foreach (object commandObject in commandObjects)
            {
                Type type = commandObject.GetType();
                foreach (MethodInfo info in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    object[] attribs = info.GetCustomAttributes(typeof(DebuggerFunction), true);

                    if (attribs.Length > 1)
                    {
                        throw new InvalidOperationException(String.Format("More than one ConsoleFunction attribute set on {0}", info.Name));
                    }
                    else if (attribs.Length == 1)
                    {
                        // we have a debugger attribute set on this method
                        // this cast should always succeed given that we're filtering for this type above.
                        DebuggerFunction function = (DebuggerFunction)attribs[0];

                        DebuggerCommand newCommand = new DebuggerCommand(commandObject, function.CommandName, function.Description, function.Usage, info);

                        _commandList.Add(newCommand);
                    }
                }
            }

            // Now actually build the command tree from the above list!
            _commandRoot = new DebuggerCommand(null, "Root", null, null, null);

            foreach (DebuggerCommand c in _commandList)
            {
                string[] commandWords = c.Name.Split(' ');

                // This is kind of ugly, we know that at this point every command built above have only
                // one method.  When building the tree, overloaded commands may end up with more than one.
                _commandRoot.AddSubNode(new List <string>(commandWords), c.Methods[0], c.Instance);
            }
        }
コード例 #6
0
        private CommandResult InvokeConsoleMethod(DebuggerCommand command, string[] args)
        {
            MethodInfo method = null;

            //
            // Find the method that matches the arg count we were passed
            // (i.e. handle overloaded commands).
            // That this only matches on argument count is somewhat of a kluge...
            //
            foreach (MethodInfo m in command.Methods)
            {
                ParameterInfo[] paramInfo = m.GetParameters();

                if (args == null && paramInfo.Length == 0 ||
                    paramInfo.Length == args.Length)
                {
                    // found a match
                    method = m;
                    break;
                }
            }

            if (method == null)
            {
                // invalid argument count.
                throw new ArgumentException(String.Format("Invalid argument count to command."));
            }

            ParameterInfo[] parameterInfo = method.GetParameters();
            object[]        invokeParams;

            if (args == null)
            {
                invokeParams = null;
            }
            else
            {
                invokeParams = new object[parameterInfo.Length];
            }

            int argIndex = 0;

            for (int paramIndex = 0; paramIndex < parameterInfo.Length; paramIndex++)
            {
                ParameterInfo p = parameterInfo[paramIndex];

                if (p.ParameterType.IsEnum)
                {
                    //
                    // This is an enumeration type.
                    // See if we can find an enumerant that matches the argument.
                    //
                    FieldInfo[] fields = p.ParameterType.GetFields();

                    foreach (FieldInfo f in fields)
                    {
                        if (!f.IsSpecialName && args[argIndex].ToLower() == f.Name.ToLower())
                        {
                            invokeParams[paramIndex] = f.GetRawConstantValue();
                            break;
                        }
                    }

                    if (invokeParams[paramIndex] == null)
                    {
                        // no match, provide possible values
                        StringBuilder sb = new StringBuilder(String.Format("Invalid value for parameter {0}.  Possible values are:", paramIndex));

                        foreach (FieldInfo f in fields)
                        {
                            if (!f.IsSpecialName)
                            {
                                sb.AppendFormat("{0} ", f.Name);
                            }
                        }

                        sb.AppendLine();

                        throw new ArgumentException(sb.ToString());
                    }

                    argIndex++;
                }
                else if (p.ParameterType.IsArray)
                {
                    //
                    // If a function takes an array type, i should do something here, yeah.
                    //
                    argIndex++;
                }
                else
                {
                    if (p.ParameterType == typeof(bool))
                    {
                        invokeParams[paramIndex] = bool.Parse(args[argIndex++]);
                    }
                    else if (p.ParameterType == typeof(uint))
                    {
                        invokeParams[paramIndex] = TryParseUint(args[argIndex++]);
                    }
                    else if (p.ParameterType == typeof(ushort))
                    {
                        invokeParams[paramIndex] = TryParseUshort(args[argIndex++]);
                    }
                    else if (p.ParameterType == typeof(string))
                    {
                        invokeParams[paramIndex] = args[argIndex++];
                    }
                    else if (p.ParameterType == typeof(char))
                    {
                        invokeParams[paramIndex] = (char)args[argIndex++][0];
                    }
                    else if (p.ParameterType == typeof(float))
                    {
                        invokeParams[paramIndex] = float.Parse(args[argIndex++]);
                    }
                    else
                    {
                        throw new ArgumentException(String.Format("Unhandled type for parameter {0}, type {1}", paramIndex, p.ParameterType));
                    }
                }
            }

            //
            // If we've made it THIS far, then we were able to parse all the commands into what they should be.
            // Invoke the method on the object instance associated with the command.
            //
            return((CommandResult)method.Invoke(command.Instance, invokeParams));
        }
コード例 #7
0
        private string FuzzyMatch(DebuggerCommand root, List <string> tokens, bool silent)
        {
            if (tokens.Count == 0)
            {
                if (!silent)
                {
                    // If there are no tokens, just show the completion for the root.
                    PrintCompletions(root.SubCommands);
                }
                return(String.Empty);
            }

            DebuggerCommand match = null;

            // Search for exact matches.  If we find one it's guaranteed to be unique
            // so we can follow that node.
            foreach (DebuggerCommand c in root.SubCommands)
            {
                if (c.Name.ToLower() == tokens[0].ToLower())
                {
                    match = c;
                    break;
                }
            }

            if (match == null)
            {
                // No exact match.  Try a substring match.
                // If we have an unambiguous match then we can complete it automatically.
                // If the match is ambiguous, display possible completions and return String.Empty.
                List <DebuggerCommand> completions = new List <DebuggerCommand>();

                foreach (DebuggerCommand c in root.SubCommands)
                {
                    if (c.Name.StartsWith(tokens[0], StringComparison.InvariantCultureIgnoreCase))
                    {
                        completions.Add(c);
                    }
                }

                if (completions.Count == 1)
                {
                    // unambiguous match.  use it.
                    match = completions[0];
                }
                else if (completions.Count > 1)
                {
                    // ambiguous match.  display possible completions.
                    if (!silent)
                    {
                        PrintCompletions(completions);
                    }
                }
            }

            if (match == null)
            {
                // If we reach this point then no matches are available.  return the tokens we have...
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < tokens.Count; i++)
                {
                    if (i < tokens.Count - 1)
                    {
                        sb.AppendFormat("{0} ", tokens[i]);
                    }
                    else
                    {
                        sb.AppendFormat("{0}", tokens[i]);
                    }
                }

                return(sb.ToString());
            }
            else
            {
                // A match was found
                tokens.RemoveAt(0);

                string subMatch = String.Empty;

                if (tokens.Count > 0)
                {
                    subMatch = FuzzyMatch(match, tokens, silent);
                }
                else // if (exactMatch)
                {
                    if (!silent && match.SubCommands.Count > 1)
                    {
                        // More than one possible completion
                        // Just show the completions for this node.
                        PrintCompletions(match.SubCommands);
                    }
                    else if (!silent && match.SubCommands.Count == 1)
                    {
                        // Just one possible completion; fill it out.
                        DebuggerCommand next = match.SubCommands[0];
                        StringBuilder   sb   =
                            new StringBuilder(String.Format("{0} {1}", match.Name, next.Name));

                        while (next.SubCommands.Count > 0)
                        {
                            if (next.SubCommands.Count > 1)
                            {
                                break;
                            }

                            next = next.SubCommands[0];
                            sb.AppendFormat(" {0}", next.Name);
                        }

                        return(sb.ToString());
                    }
                }

                if (subMatch == String.Empty)
                {
                    return(String.Format("{0} ", match.Name));
                }
                else
                {
                    return(String.Format("{0} {1}", match.Name, subMatch));
                }
            }
        }
コード例 #8
0
 public DebuggerPrompt(DebuggerCommand root)
 {
     _commandTree    = root;
     _commandHistory = new List <string>(64);
     _historyIndex   = 0;
 }