예제 #1
0
        public void AddSubNode(List <string> words, MethodInfo method)
        {
            // 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(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 debug 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);
        }
예제 #2
0
        /// <summary>
        /// Builds the debugger command tree.
        /// </summary>
        private void BuildCommandTree()
        {
            // Build the flat list which will be built into the tree.
            // I'm kinda overloading the use of DebuggerCommand here.  Sue me.
            _commandList = new List <DebuggerCommand>();

            Type[] debugTypes =
            {
                typeof(PERQSystem),
                typeof(PERQCpu),
                typeof(Z80System),
                typeof(IO.Z80_new.Z80System),
                typeof(Debugger)
            };

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

                    if (attribs.Length > 1)
                    {
                        throw new InvalidOperationException(String.Format("More than one DebugFunction 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.
                        DebugFunction function = (DebugFunction)attribs[0];

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

                        _commandList.Add(newCommand);
                    }
                }
            }

            // Now actually build the command tree from the above list!
            _commandRoot = new DebuggerCommand("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]);
            }
        }
예제 #3
0
        public DebuggerCommand FindSubNodeByName(string name)
        {
            DebuggerCommand found = null;

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

            return(found);
        }
예제 #4
0
        private List <MethodInfo> GetMethodsFromCommandString(string command, out string[] args)
        {
            args = null;

            List <string> cmdArgs =
                new List <string>(
                    command.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));

            DebuggerCommand current      = _commandRoot;
            int             commandIndex = 0;

            while (true)
            {
                // If this node has an executor, then we're done
                // (We assume that the tree is correctly built and that only
                // leaves have executors)
                if (current.Methods.Count > 0)
                {
                    break;
                }

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

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

                if (current == null)
                {
                    // If the node was not found, then the command is invalid.
                    return(null);
                }
            }

            // 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.Methods);
        }
예제 #5
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;
            bool            exactMatch = false;

            // 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;
                    exactMatch = true;
                    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 > 0)
                    {
                        // Just show the completions for this node.
                        PrintCompletions(match.SubCommands);
                    }
                }

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