feat: finish ArgParser help text output

This commit is contained in:
2024-07-29 19:31:17 +08:00
parent d1c1743dc9
commit e8a0299fbc
3 changed files with 73 additions and 12 deletions

View File

@ -1,6 +1,7 @@
#include "ArgParser.hpp"
#include "EncodingHelper.hpp"
#include "ConsoleHelper.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
#include "WinImportPrefix.hpp"
@ -63,7 +64,7 @@ namespace YYCC::ArgParser {
++m_ArgumentsIterator;
}
const yycc_u8string& ArgumentList::Current() const {
const yycc_u8string& ArgumentList::Argument() const {
if (IsEOF()) throw std::runtime_error("attempt to get data on the tail of iterator.");
return *m_ArgumentsIterator;
}
@ -114,7 +115,7 @@ namespace YYCC::ArgParser {
return true;
}
bool ArgumentList::IsValue(yycc_u8string* val) const {
bool ArgumentList::IsParameter(yycc_u8string* val) const {
bool is_value = !IsSwitch();
if (is_value && val != nullptr)
*val = *m_ArgumentsIterator;
@ -240,7 +241,7 @@ namespace YYCC::ArgParser {
while (!al.IsEOF()) {
// if we can not find any switches, return with error
if (!al.IsSwitch(&is_long_name, &long_name, &short_name)) return false;
// find corresponding argument by long name or short name.
// if we can not find it, return with error.
AbstractArgument* arg;
@ -288,6 +289,60 @@ namespace YYCC::ArgParser {
}
}
void OptionContext::Help() const {
// print summary and description if necessary
if (!m_Summary.empty())
YYCC::ConsoleHelper::WriteLine(m_Summary.c_str());
if (!m_Description.empty())
YYCC::ConsoleHelper::WriteLine(m_Description.c_str());
// blank line
YYCC::ConsoleHelper::WriteLine(YYCC_U8(""));
// print argument list
for (const auto* arg : m_Arguments) {
yycc_u8string argstr;
// print indent
argstr += YYCC_U8("\t");
// print optional head
bool is_optional = arg->IsOptional();
if (is_optional) argstr += YYCC_U8("[");
// switch name
bool short_name = arg->HasShortName(), long_name = arg->HasLongName();
if (short_name) {
argstr += YYCC_U8("-");
argstr += arg->GetShortName();
}
if (long_name) {
if (short_name) argstr += YYCC_U8(", ");
argstr += YYCC_U8("--");
argstr += arg->GetLongName();
}
// argument example
if (arg->HasArgumentExample()) {
argstr += YYCC_U8(" ");
argstr += arg->GetArgumentExample();
}
// optional tail
if (is_optional) argstr += YYCC_U8("]");
// argument description
if (arg->HasDescription()) {
// eol and double indent
argstr += YYCC_U8("\n\t\t");
// description
argstr += arg->GetDescription();
}
// write into console
YYCC::ConsoleHelper::WriteLine(argstr.c_str());
}
}
#pragma endregion
}

View File

@ -28,12 +28,12 @@ namespace YYCC::ArgParser {
public:
void Prev();
void Next();
const yycc_u8string& Current() const;
const yycc_u8string& Argument() const;
bool IsSwitch(
bool* is_long_name = nullptr,
yycc_u8string* long_name = nullptr,
yycc_char8_t* short_name = nullptr) const;
bool IsValue(yycc_u8string* val = nullptr) const;
bool IsParameter(yycc_u8string* val = nullptr) const;
bool IsEOF() const;
void Reset();
private:
@ -104,6 +104,7 @@ namespace YYCC::ArgParser {
public:
bool Parse(ArgumentList& al);
void Reset();
void Help() const;
private:
yycc_u8string m_Summary;
@ -138,7 +139,7 @@ namespace YYCC::ArgParser {
// try get corresponding value
yycc_u8string strval;
al.Next();
if (al.IsEOF() || !al.IsValue(&strval)) {
if (al.IsEOF() || !al.IsParameter(&strval)) {
al.Prev();
return false;
}
@ -163,8 +164,10 @@ namespace YYCC::ArgParser {
public:
SwitchArgument(
const yycc_char8_t* long_name, yycc_char8_t short_name,
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr) :
AbstractArgument(long_name, short_name, description, argument_example, true), m_Data(false) {} // bool switch must be optional, because it is false if no given switch.
const yycc_char8_t* description = nullptr) :
// bool switch must be optional, because it is false if no given switch.
// bool switch doesn't have argument, so it doesn't have example property.
AbstractArgument(long_name, short_name, description, nullptr, true), m_Data(false) {}
virtual ~SwitchArgument() {}
public:
@ -201,7 +204,7 @@ namespace YYCC::ArgParser {
virtual bool Parse(ArgumentList& al) override {
// try get corresponding value
al.Next();
if (al.IsEOF() || !al.IsValue(&m_Data)) {
if (al.IsEOF() || !al.IsParameter(&m_Data)) {
al.Prev();
return false;
}