31#ifndef ARGS__HELP_PRINTER_HPP__INCLUDED 
   32#define ARGS__HELP_PRINTER_HPP__INCLUDED 
   68    using ArgPtr = std::unique_ptr< ArgIface, details::Deleter< ArgIface > >;
 
   86        Command * parent = 
nullptr ) 
override;
 
  109        bool required ) 
const;
 
  115        String::size_type currentPos, String::size_type leftMargin,
 
  116        String::size_type rightMargin ) 
const;
 
  120    void sortArg( 
const ArgPtr & arg,
 
  121        std::vector< Command* > & commands,
 
  122        std::vector< ArgIface* > & required,
 
  123        std::vector< ArgIface* > & optional,
 
  124        String::size_type & maxFlag,
 
  125        String::size_type & maxName,
 
  126        String::size_type & maxCommand,
 
  127        bool requiredAllOfGroup = 
false ) 
const;
 
  130        String::size_type beforeDescription, String::size_type maxFlag ) 
const;
 
  142    String::size_type m_lineLength;
 
 
  145static const String c_positional = 
SL( 
"[positional]" );
 
  147static const String c_commands = 
SL( 
"<command>" );
 
  149static const String c_options = 
SL( 
"<options>" );
 
  169printOffset( 
OutStreamType & to, String::size_type currentPos,
 
  170    String::size_type leftMargin )
 
  172    if( currentPos < leftMargin )
 
  173        to << 
String( leftMargin - currentPos, 
' ' );
 
  177calcMaxFlagAndName( ArgIface * arg, String::size_type & maxFlag,
 
  178    String::size_type & maxName )
 
  180    String::size_type f = 1;
 
  181    String::size_type n = ( !arg->argumentName().empty() ?
 
  182        arg->argumentName().length() : ( arg->flag().empty() ?
 
  183            arg->name().length() : 0 ) );
 
  185    if( arg->isWithValue() )
 
  188            n += 3 + arg->valueSpecifier().length();
 
  190            f += 3 + arg->valueSpecifier().length();
 
  201HelpPrinter::sortArg( 
const ArgPtr & arg,
 
  202    std::vector< Command* > & commands,
 
  203    std::vector< ArgIface* > & required,
 
  204    std::vector< ArgIface* > & optional,
 
  205    String::size_type & maxFlag,
 
  206    String::size_type & maxName,
 
  207    String::size_type & maxCommand,
 
  208    bool requiredAllOfGroup )
 const 
  210    GroupIface * g = 
dynamic_cast< GroupIface* 
> ( arg.get() );
 
  216        commands.push_back( cmd );
 
  218        String::size_type length = cmd->name().length() + ( cmd->isWithValue() ?
 
  219            3 + cmd->valueSpecifier().length() : 0 );
 
  221        if( length > maxCommand )
 
  227            requiredAllOfGroup = 
true;
 
  229            requiredAllOfGroup = 
false;
 
  231        auto f = std::bind( &HelpPrinter::sortArg, 
this, std::placeholders::_1,
 
  232            std::ref( commands ), std::ref( required ),
 
  233            std::ref( optional ), std::ref( maxFlag ),
 
  234            std::ref( maxName ), std::ref( maxCommand ),
 
  235            requiredAllOfGroup );
 
  237        std::for_each( g->children().cbegin(),
 
  238            g->children().cend(), f );
 
  242        if( arg->isRequired() || requiredAllOfGroup )
 
  243            required.push_back( arg.get() );
 
  245            optional.push_back( arg.get() );
 
  247        calcMaxFlagAndName( arg.get(), maxFlag, maxName );
 
  252HelpPrinter::printOnlyFor( ArgIface * arg, 
OutStreamType & to,
 
  253    String::size_type beforeDescription, String::size_type )
 const 
  255    String::size_type pos = 0;
 
  257    if( !arg->flag().empty() )
 
  261        to << 
'-' << arg->flag();
 
  262        pos += arg->flag().length() + 1;
 
  264        if( !arg->argumentName().empty() )
 
  269        else if( arg->isWithValue() )
 
  271            to << 
" <" << arg->valueSpecifier() << 
'>';
 
  272            pos += arg->valueSpecifier().length() + 3;
 
  277        printOffset( to, pos, 4 );
 
  281    if( !arg->argumentName().empty() )
 
  285        to << 
"--" << arg->argumentName();
 
  286        pos += arg->argumentName().length() + 2;
 
  288        if( arg->isWithValue() )
 
  290            to << 
" <" << arg->valueSpecifier() << 
'>';
 
  291            pos += arg->valueSpecifier().length() + 3;
 
  294    else if( arg->flag().empty() && arg->argumentName().empty() )
 
  299        pos += arg->name().length();
 
  301        if( arg->isWithValue() )
 
  303            to << 
" <" << arg->valueSpecifier() << 
'>';
 
  304            pos += arg->valueSpecifier().length() + 3;
 
  308    printString( to, splitToWords( arg->description() ), pos,
 
  309        beforeDescription, 0 );
 
  318template< 
typename T >
 
  319bool argNameLess( 
const T & a1, 
const T & a2 )
 
  321    static const Char dash = 
SL( 
'-' );
 
  323    if( !a1->name().empty() && !a2->name().empty() )
 
  325        if( *( a1->name().cbegin() ) != dash &&
 
  326                *( a2->name().cbegin() ) == dash )
 
  328        else if( *( a1->name().cbegin() ) == dash &&
 
  329                *( a2->name().cbegin() ) != dash )
 
  331        else if( a1->argumentName().empty() && !a2->argumentName().empty() )
 
  333        else if( !a1->argumentName().empty() && a2->argumentName().empty() )
 
  336            return ( a1->name() < a2->name() );
 
  339        return ( a1->name() < a2->name() );
 
  347    std::vector< ArgIface* > required;
 
  348    std::vector< ArgIface* > optional;
 
  349    std::vector< Command* > commands;
 
  351    String::size_type maxFlag = 0;
 
  352    String::size_type maxName = 0;
 
  353    String::size_type maxCommand = 0;
 
  355    bool requiredAllOfGroup = 
false;
 
  357    auto f = std::bind( &HelpPrinter::sortArg, 
this, std::placeholders::_1,
 
  358        std::ref( commands ), std::ref( required ),
 
  359        std::ref( optional ), std::ref( maxFlag ),
 
  360        std::ref( maxName ), std::ref( maxCommand ),
 
  361        requiredAllOfGroup );
 
  363    std::for_each( m_cmdLine->
arguments().cbegin(),
 
  367    std::sort( required.begin(), required.end(),
 
  368        [] ( 
const auto & a1, 
const auto & a2 )
 
  369            { return details::argNameLess( a1, a2 ); } );
 
  371    std::sort( optional.begin(), optional.end(),
 
  372        [] ( 
const auto & a1, 
const auto & a2 )
 
  373            { return details::argNameLess( a1, a2 ); } );
 
  375    std::sort( commands.begin(), commands.end(),
 
  376        [] ( 
const auto & c1, 
const auto & c2 )
 
  377            { return details::argNameLess( c1, c2 ); } );
 
  383    printString( to, splitToWords( m_appDescription ), 0, 0, 0 );
 
  387    if( commands.empty() )
 
  391        usage.push_back( m_exeName );
 
  393        bool requiredFlag = 
true;
 
  395        std::function< void ( 
ArgIface* ) > createUsageAndAppend =
 
  398                const StringList words = createUsageString( arg,
 
  402                    usage.push_back( w );
 
  405        std::for_each( required.cbegin(), required.cend(),
 
  406            createUsageAndAppend );
 
  408        requiredFlag = 
false;
 
  410        std::for_each( optional.cbegin(), optional.cend(),
 
  411            createUsageAndAppend );
 
  419        printString( to, usage, 7, 7, 1 );
 
  427        usage.push_back( m_exeName );
 
  428        usage.push_back( c_commands );
 
  430        if( !optional.empty() || !required.empty() )
 
  431            usage.push_back( c_options );
 
  439        printString( to, usage, 7, 7, 1 );
 
  443        std::for_each( commands.cbegin(), commands.cend(),
 
  446                String::size_type pos = 2;
 
  448                to << 
"  " << cmd->name();
 
  450                pos += cmd->name().length();
 
  452                if( cmd->isWithValue() )
 
  454                    to << 
" <" << cmd->valueSpecifier() << 
">";
 
  456                    pos += 3 + cmd->valueSpecifier().length();
 
  459                printString( to, splitToWords( cmd->
description() ), pos,
 
  468    auto printArg = std::bind( &HelpPrinter::printOnlyFor, 
this,
 
  469        std::placeholders::_1, std::ref( to ),
 
  470            ( maxFlag == 1 ? maxName + 6 : ( maxName + 6 > maxFlag + 1 ?
 
  471                maxName + 6 : maxFlag + 1 ) ),
 
  474    if( !required.empty() )
 
  476        to << 
"REQUIRED:" << 
"\n";
 
  478        std::for_each( required.cbegin(), required.cend(), printArg );
 
  481    if( !optional.empty() )
 
  483        to << 
"OPTIONAL:" << 
"\n";
 
  485        std::for_each( optional.cbegin(), optional.cend(), printArg );
 
 
  497        arg = m_cmdLine->findArgument( name );
 
  499    if( arg && arg->type() == ArgType::Command )
 
  504        std::vector< ArgIface* > grequired;
 
  505        std::vector< ArgIface* > goptional;
 
  506        std::vector< Command* > gcommands;
 
  508        String::size_type gmaxFlag = 0;
 
  509        String::size_type gmaxName = 0;
 
  510        String::size_type gmaxCommand = 0;
 
  512        bool requiredAllOfGroup = 
false;
 
  514        auto gf = std::bind( &HelpPrinter::sortArg, 
this, std::placeholders::_1,
 
  515            std::ref( gcommands ), std::ref( grequired ),
 
  516            std::ref( goptional ), std::ref( gmaxFlag ),
 
  517            std::ref( gmaxName ), std::ref( gmaxCommand ),
 
  518            requiredAllOfGroup );
 
  520        std::for_each( m_cmdLine->arguments().cbegin(),
 
  521            m_cmdLine->arguments().cend(), gf );
 
  524        std::sort( grequired.begin(), grequired.end(),
 
  525            [] ( 
const auto & a1, 
const auto & a2 )
 
  526                { return details::argNameLess( a1, a2 ); } );
 
  528        std::sort( goptional.begin(), goptional.end(),
 
  529            [] ( 
const auto & a1, 
const auto & a2 )
 
  530                { return details::argNameLess( a1, a2 ); } );
 
  536        std::vector< ArgIface* > required;
 
  537        std::vector< ArgIface* > optional;
 
  538        std::vector< Command* > commands;
 
  540        String::size_type maxFlag = 0;
 
  541        String::size_type maxName = 0;
 
  542        String::size_type maxCommand = 0;
 
  544        requiredAllOfGroup = 
false;
 
  546        auto f = std::bind( &HelpPrinter::sortArg, 
this, std::placeholders::_1,
 
  547            std::ref( commands ), std::ref( required ),
 
  548            std::ref( optional ), std::ref( maxFlag ),
 
  549            std::ref( maxName ), std::ref( maxCommand ),
 
  550            requiredAllOfGroup );
 
  552        std::for_each( cmd->
children().cbegin(),
 
  556        std::sort( required.begin(), required.end(),
 
  557            [] ( 
const auto & a1, 
const auto & a2 )
 
  558                { return details::argNameLess( a1, a2 ); } );
 
  560        std::sort( optional.begin(), optional.end(),
 
  561            [] ( 
const auto & a1, 
const auto & a2 )
 
  562                { return details::argNameLess( a1, a2 ); } );
 
  564        std::sort( commands.begin(), commands.end(),
 
  565            [] ( 
const auto & c1, 
const auto & c2 )
 
  566                { return details::argNameLess( c1, c2 ); } );
 
  577        if( commands.empty() )
 
  579            to << 
"USAGE: " << name;
 
  584            if( !grequired.empty() || !goptional.empty() ||
 
  585                !required.empty() || !optional.empty() )
 
  592            to << 
"USAGE: " << name << 
" <command>";
 
  594            if( !optional.empty() || !required.empty() )
 
  599            std::for_each( commands.cbegin(), commands.cend(),
 
  602                    String::size_type pos = 2;
 
  604                    to << 
"  " << c->name();
 
  606                    pos += c->name().length();
 
  608                    if( c->isWithValue() )
 
  610                        to << 
" <" << c->valueSpecifier() << 
">";
 
  612                        pos += 3 + c->valueSpecifier().length();
 
  615                    printString( to, splitToWords( c->
description() ), pos,
 
  625        auto printArg = std::bind( &HelpPrinter::printOnlyFor, 
this,
 
  626            std::placeholders::_1, std::ref( to ),
 
  627            ( maxFlag == 1 ? maxName + 6 : ( maxName + 6 > maxFlag + 1 ?
 
  628                maxName + 6 : maxFlag + 1 ) ),
 
  631        if( !required.empty() )
 
  633            to << 
"REQUIRED:" << 
"\n";
 
  635            std::for_each( required.cbegin(), required.cend(), printArg );
 
  638        if( !optional.empty() )
 
  640            to << 
"OPTIONAL:" << 
"\n";
 
  642            std::for_each( optional.cbegin(), optional.cend(), printArg );
 
  646        if( !grequired.empty() || !goptional.empty() )
 
  648            auto printGlobalArg = std::bind( &HelpPrinter::printOnlyFor, 
this,
 
  649                std::placeholders::_1, std::ref( to ),
 
  650                ( gmaxFlag == 1 ? gmaxName + 6 : ( gmaxName + 6 > gmaxFlag + 1 ?
 
  651                    gmaxName + 6 : gmaxFlag + 1 ) ), gmaxFlag );
 
  653            if( !grequired.empty() )
 
  655                to << 
"GLOBAL REQUIRED:" << 
"\n";
 
  657                std::for_each( grequired.cbegin(), grequired.cend(),
 
  661            if( !goptional.empty() )
 
  663                to << 
"GLOBAL OPTIONAL:" << 
"\n";
 
  665                std::for_each( goptional.cbegin(), goptional.cend(),
 
 
  679HelpPrinter::print( ArgIface * arg, OutStreamType & to )
 const 
  681    StringList usage = createUsageString( arg,
 
  686    std::for_each( usage.cbegin(), usage.cend(),
 
  687        [ & ] ( 
const String & s )
 
  693    printString( to, splitToWords( arg->longDescription() ),
 
  702HelpPrinter::setExecutable( 
const String & exe )
 
 
  708HelpPrinter::setAppDescription( 
const String & desc )
 
  710    m_appDescription = desc;
 
 
  720HelpPrinter::setLineLength( String::size_type length )
 
  723        m_lineLength = length;
 
 
  729HelpPrinter::createUsageString( 
ArgIface * arg, 
bool required )
 const 
  736        usage.append( 
SL( 
"[ " ) );
 
  738    if( !arg->
flag().empty() )
 
  740        usage.append( 
SL( 
"-" ) );
 
  741        usage.append( arg->
flag() );
 
  745            usage.append( 
SL( 
"," ) );
 
  747            result.push_back( usage );
 
  755        usage.append( 
SL( 
"--" ) );
 
  759        usage.append( arg->
name() );
 
  763        usage.append( 
SL( 
" <" ) );
 
  765        usage.append( 
SL( 
">" ) );
 
  769        usage.append( 
SL( 
" ]" ) );
 
  771    result.push_back( usage );
 
  777isSpaceChar( 
const Char & c )
 
  779    static const String spaceChars = 
SL( 
" \n\t\r" );
 
  781    return ( spaceChars.find( c ) != String::npos );
 
  785HelpPrinter::splitToWords( 
const String & s )
 const 
  790    std::for_each( s.cbegin(), s.cend(),
 
  791        [ &word, &result ] ( 
const Char & c )
 
  793            if( isSpaceChar( c ) )
 
  796                    result.push_back( word );
 
  806        result.push_back( word );
 
  812HelpPrinter::printString( OutStreamType & to,
 
  813    const StringList & words,
 
  814    String::size_type currentPos, String::size_type leftMargin,
 
  815    String::size_type rightMargin )
 const 
  817    const String::size_type occupied = leftMargin + rightMargin;
 
  819    String::size_type maxLineLength = ( occupied < m_lineLength ?
 
  820        m_lineLength - occupied : 0 );
 
  822    if( maxLineLength < 20 )
 
  826        maxLineLength = m_lineLength - 20;
 
  833    String::size_type length = 0;
 
  835    bool makeOffset = ( currentPos < leftMargin );
 
  837    std::for_each( words.cbegin(), words.cend(),
 
  838        [ & ] ( 
const String & word )
 
  842                printOffset( to, currentPos, leftMargin );
 
  847            if( length + word.length() < maxLineLength )
 
  849                length += word.length();
 
  853                if( length < maxLineLength )
 
  865                maxLineLength = m_lineLength - leftMargin - rightMargin;
 
  869                printOffset( to, currentPos, leftMargin );
 
  873                length += word.length();
 
  875                if( length < maxLineLength )
 
virtual ArgIface * findArgument(const String &name)=0
 
virtual const String & valueSpecifier() const =0
 
virtual String name() const =0
 
virtual const String & argumentName() const =0
 
virtual bool isWithValue() const =0
 
virtual const String & flag() const =0
 
CmdLine is class that holds all rguments and parse command line arguments in the correspondence with ...
 
void clear()
Clear state of the arguments.
 
@ HandlePositionalArguments
Handle positional arguments.
 
const String & positionalDescription() const
 
ArgIface * findArgument(const String &name)
 
const Arguments & arguments() const
 
CmdLineOpts parserOptions() const
 
Command in the command line interface.
 
ArgIface * findChild(const String &name)
 
bool isWithValue() const override
 
const String & longDescription() const override
 
const String & description() const override
 
const String & valueSpecifier() const override
 
const Arguments & children() const
 
HelpPrinter is a class that prints help.
 
void setCmdLine(CmdLine *cmd) override
Set command line.
 
std::unique_ptr< ArgIface, details::Deleter< ArgIface > > ArgPtr
Smart pointer to the argument.
 
void setExecutable(const String &exe) override
Set executable name.
 
ArgIface * findArgument(const String &name) override
 
void setLineLength(String::size_type length) override
Set line length for the help.
 
void setAppDescription(const String &desc) override
Set description for the application.
 
void print(OutStreamType &to) override
Print help for all arguments.
 
Interface for HelpPrinter.
 
constexpr std::add_const< T >::type & asConst(T &t) noexcept
Adds const to non-const objects.
 
std::string String
String type.
 
std::vector< String > StringList
List of strings.
 
@ AllOfGroup
"All of" group.
 
std::ostream OutStreamType
Out stream type.
 
String::value_type Char
Char type.
 
#define DISABLE_COPY(Class)
Macro for disabling copy.