tools: nfdc help command

refs #3780

Change-Id: Ibd0e37bad127a38e582864fadd81afadc74baf48
diff --git a/tools/nfdc/command-parser.cpp b/tools/nfdc/command-parser.cpp
index 6b21d8b..b4c4558 100644
--- a/tools/nfdc/command-parser.cpp
+++ b/tools/nfdc/command-parser.cpp
@@ -47,6 +47,9 @@
   if ((modes & AVAILABLE_IN_BATCH) != 0) {
     os << sep << "batch";
   }
+  if ((modes & AVAILABLE_IN_HELP) == 0) {
+    os << sep << "hidden";
+  }
 
   if (sep.getCount() == 0) {
     os << "none";
@@ -73,6 +76,11 @@
   BOOST_ASSERT(modes != AVAILABLE_IN_NONE);
   m_commands[{def.getNoun(), def.getVerb()}].reset(
     new Command{def, execute, static_cast<AvailableIn>(modes)});
+
+  if ((modes & AVAILABLE_IN_HELP) != 0) {
+    m_commandOrder.push_back(m_commands.find({def.getNoun(), def.getVerb()}));
+  }
+
   return *this;
 }
 
@@ -83,6 +91,20 @@
   return *this;
 }
 
+std::vector<const CommandDefinition*>
+CommandParser::listCommands(const std::string& noun, ParseMode mode) const
+{
+  std::vector<const CommandDefinition*> results;
+  for (CommandContainer::const_iterator i : m_commandOrder) {
+    const Command& command = *i->second;
+    if ((command.modes & static_cast<AvailableIn>(mode)) != 0 &&
+        (noun.empty() || noun == command.def.getNoun())) {
+      results.push_back(&command.def);
+    }
+  }
+  return results;
+}
+
 std::tuple<std::string, std::string, CommandArguments, ExecuteCommand>
 CommandParser::parse(const std::vector<std::string>& tokens, ParseMode mode) const
 {