diff --git a/Unvirt/CmdHelper.cpp b/Unvirt/CmdHelper.cpp index dfb03f0..36cb47b 100644 --- a/Unvirt/CmdHelper.cpp +++ b/Unvirt/CmdHelper.cpp @@ -211,20 +211,27 @@ namespace Unvirt::CmdHelper { void HelpDocument::Print() { for (auto& cmd : m_Results) { // syntax - YYCC::ConsoleHelper::WriteLine(u8"Syntax: "); + // check whether all description of argument are emtpty. + bool empty_arg_desc = true; + YYCC::ConsoleHelper::Write(YYCC_COLOR_LIGHT_YELLOW(u8"Syntax: ")); for (const auto& arg : cmd.m_ArgDesc) { + if (!arg.m_Desc.empty()) empty_arg_desc = false; YYCC::ConsoleHelper::Format(u8"%s ", arg.m_Name.c_str()); } YYCC::ConsoleHelper::WriteLine(u8""); // command description if (!cmd.m_CmdDesc.empty()) { - YYCC::ConsoleHelper::FormatLine(u8"Description: %s", cmd.m_CmdDesc.c_str()); + YYCC::ConsoleHelper::FormatLine(YYCC_COLOR_LIGHT_YELLOW(u8"Description: ") "%s", cmd.m_CmdDesc.c_str()); } // argument description - YYCC::ConsoleHelper::WriteLine(u8"Arguments:"); - for (auto& arg : cmd.m_ArgDesc) { - if (!arg.m_Desc.empty()) { - YYCC::ConsoleHelper::FormatLine(u8"\t%s: %s", arg.m_Name.c_str(), arg.m_Desc.c_str()); + if (!empty_arg_desc) { + YYCC::ConsoleHelper::WriteLine(YYCC_COLOR_LIGHT_YELLOW(u8"Arguments:")); + for (auto& arg : cmd.m_ArgDesc) { + if (!arg.m_Desc.empty()) { + YYCC::ConsoleHelper::FormatLine(u8"\t" YYCC_COLOR_LIGHT_GREEN("%s") ": % s", + arg.m_Name.c_str(), arg.m_Desc.c_str() + ); + } } } // space between each commands @@ -465,7 +472,7 @@ if (!this->IsRootNode()) { \ const ConflictSet& Choice::GetConflictSet() { return m_ConflictSet; } std::u8string Choice::GetHelpSymbol() { return YYCC::StringHelper::Printf(u8"[%s]", - YYCC::StringHelper::Join(m_Vocabulary, u8" | ").c_str() + YYCC::StringHelper::Join(m_Vocabulary.begin(), m_Vocabulary.end(), u8" | ").c_str() ); } bool Choice::BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) { diff --git a/Unvirt/CmdHelper.hpp b/Unvirt/CmdHelper.hpp index 0da8d01..1bd6fe0 100644 --- a/Unvirt/CmdHelper.hpp +++ b/Unvirt/CmdHelper.hpp @@ -137,8 +137,8 @@ namespace Unvirt::CmdHelper { if (finder == m_Data.end()) throw std::runtime_error("try to get a non-existent key."); // get stored value data - const AMItems::AbstractItem& value = *finder->second.get(); - return static_cast(value); + const _Ty* value = static_cast(finder->second.get()); + return *value; } void Remove(const std::u8string_view& key) { // check argument @@ -150,17 +150,24 @@ namespace Unvirt::CmdHelper { } }; + // Forward declaration for Nodes::AbstractNode + namespace Nodes { class AbstractNode; } + class HelpDocument { + friend class Nodes::AbstractNode; public: HelpDocument(); ~HelpDocument(); YYCC_DEF_CLS_COPY_MOVE(HelpDocument); public: + void Print(); + + // AbstractNode used + protected: void Push(const std::u8string& arg_name, const std::u8string& arg_desc); void Pop(); void Terminate(std::u8string& command_desc); - void Print(); protected: struct StackItem { @@ -345,14 +352,16 @@ namespace Unvirt::CmdHelper { * @return Return self for chain calling. */ template && !std::is_same_v, int> = 0> - AbstractNode& Then(_Ty&& node) { + AbstractNode& Then(AbstractNode& node) { // create node first - auto new_node = std::make_shared<_Ty>(std::forward<_Ty>(node)); + auto new_node = std::make_shared<_Ty>(static_cast<_Ty&>(node)); + // get its abstract pointer for checking + AbstractNode* new_node_ptr = new_node.get(); // check root node. - if (new_node->IsRootNode()) + if (new_node_ptr->IsRootNode()) throw std::invalid_argument("root node should not be inserted as child node."); // check conflict - const auto& new_node_set = new_node->GetConflictSet(); + const auto& new_node_set = new_node_ptr->GetConflictSet(); for (auto& node : m_Nodes) { const auto& node_set = node->GetConflictSet(); if (new_node_set.IsConflictWith(node_set)) @@ -528,23 +537,4 @@ namespace Unvirt::CmdHelper { Nodes::RootNode m_RootNode; }; - //class CommandRoot : public AbstractNode { - //public: - // CommandRoot(); - // virtual ~CommandRoot(); - // YYCC_DEL_CLS_COPY_MOVE(CommandRoot); - - // // Root use special consume and help functions. - // bool RootConsume(std::deque&); - // HelpDocument* RootHelp(); - - //public: - //protected: - // virtual NodeType GetNodeType() override { throw std::logic_error("Root can not be called."); } - // virtual bool IsConflictWith(AbstractNode*) override { throw std::logic_error("Root can not be called."); } - // virtual std::string GetHelpSymbol() override { throw std::logic_error("Root can not be called."); } - // virtual bool BeginAccept(const std::string&, ArgumentsMap*) override { throw std::logic_error("Root can not be called."); } - // virtual void EndAccept(ArgumentsMap*) override { throw std::logic_error("Root can not be called."); } - //}; - }