36 std::sort( m_options.begin() , m_options.end() , sort_fn ) ;
40 m_space_margin =
'M' ;
41 m_space_separator =
'S' ;
42 m_space_indent =
'I' ;
43 m_space_padding =
'P' ;
44 m_space_overflow =
'_' ;
45 m_space_syntax =
'.' ;
50 const std::string & exe ,
const std::string & args )
const
52 Config config = config_in ;
53 config.setDefaults() ;
55 const char * usage =
txt(
"usage: " ) ;
56 const char * alt_usage =
txt(
"abbreviated usage: " ) ;
57 std::string s = std::string()
61 .append(summaryPartOne(config))
62 .append(summaryPartTwo(config))
63 .append(args.empty()||args.at(0U)==
' '?
"":
" ")
65 std::string indent( 2U ,
' ' ) ;
71 Config config = config_in ;
72 config.setDefaults() ;
73 config.setWidthsWrtMargin() ;
75 if( overflow_p ==
nullptr )
77 bool overflow = false ;
78 std::string s = helpImp( config ,
false , overflow ) ;
80 s = helpImp( config ,
true , overflow ) ;
85 bool overflow = *overflow_p ;
86 return helpImp( config , overflow , *overflow_p ) ;
91 const std::string & exe ,
const std::string & args )
const
94 << summary(config,exe,args) << std::endl
99std::string G::OptionsUsage::summaryPartOne(
const Config & config )
const
102 std::ostringstream ss ;
104 for(
const auto & option : m_options )
106 if( option.c !=
'\0' && !option.valued() && option.visible({config.level_min,config.level_max},config.main_tag,config.tag_bits) )
115 std::string s = ss.str() ;
116 if( !s.empty() ) s.append(
"] " ) ;
120std::string G::OptionsUsage::summaryPartTwo(
const Config & config )
const
122 std::ostringstream ss ;
123 const char * sep =
"" ;
124 for(
const auto & option : m_options )
126 if( option.visible({config.level_min,config.level_max},config.main_tag,config.tag_bits) )
129 if( !option.name.empty() )
131 ss <<
"--" << option.name ;
135 G_ASSERT( option.c !=
'\0' ) ;
136 ss <<
"-" << option.c ;
138 if( option.valued() )
140 std::string vd = option.value_description ;
141 if( vd.empty() ) vd =
"value" ;
142 ss <<
"=<" << vd <<
">" ;
151std::string G::OptionsUsage::helpImp(
const Config & config ,
bool overflow ,
bool & overflow_out )
const
154 for(
const auto & option : m_options )
156 if( option.visible({config.level_min,config.level_max},config.main_tag,config.tag_bits) )
158 result.append( optionHelp(config,option,overflow,overflow_out) ).append( 1U ,
'\n' ) ;
164std::string G::OptionsUsage::optionHelp(
const Config & config ,
const Option & option ,
165 bool overflow ,
bool & overflow_out )
const
167 char syntax_non_space =
'\x01' ;
168 std::string syntax_simple = helpSyntax( option ) ;
169 std::string syntax_aligned = helpSyntax( option ,
true , syntax_non_space ) ;
170 std::string description = helpDescription( option , config.extra ) ;
171 std::string separator = helpSeparator( config , syntax_aligned.length() ) ;
174 std::string line = helpWrap( config , syntax_simple , syntax_aligned , separator , description , overflow , overflow_out ) ;
179 std::string margin = std::string( config.margin , m_space_margin ) ;
181 line = margin + line ;
190std::string G::OptionsUsage::helpWrap(
const Config & config ,
const std::string & syntax_simple ,
191 const std::string & syntax_aligned ,
const std::string & separator ,
const std::string & description ,
192 bool overflow_in ,
bool & overflow_out )
const
194 std::string text = std::string(syntax_aligned).append(separator).append(description) ;
195 if( config.width == 0 )
200 else if( config.separator ==
"\t" )
203 return StringWrap::wrap( text ,
"" ,
"\t" , config.width , config.width2 ,
true ) ;
205 else if( overflow_in )
208 std::string indent( config.overflow_spaces , m_space_overflow ) ;
209 return syntax_simple +
"\n" +
StringWrap::wrap( description , indent , indent , config.width2 , config.width2 ,
true ) ;
211 else if( config.separator.empty() )
215 config.width , config.width2 ,
true ) ;
218 if( !overflow_out && std::min(config.width,config.width2) <= config.overflow )
219 overflow_out = true ;
227 return StringWrap::wrap( text ,
"" , std::string(config.separator_spaces,m_space_separator) ,
228 config.width , config.width2 ,
true ) ;
232std::string G::OptionsUsage::helpSyntax(
const Option & option ,
bool with_non_space ,
char non_space )
const
235 if( option.c !=
'\0' )
237 syntax.append( 1U ,
'-' ) ;
238 syntax.append( 1U , option.c ) ;
239 if( !option.name.empty() )
240 syntax.append(
", " ) ;
242 else if( with_non_space )
244 syntax.append( 4U , non_space ) ;
246 if( !option.name.empty() )
248 syntax.append(
"--" ) ;
249 syntax.append( option.name ) ;
251 if( option.valued() )
253 std::string vd = option.value_description ;
254 if( vd.empty() ) vd =
"value" ;
255 if( option.defaulting() ) syntax.append(
"[" ) ;
256 syntax.append(
"=<" ) ;
257 syntax.append( vd ) ;
258 syntax.append(
">" ) ;
259 if( option.defaulting() ) syntax.append(
"]" ) ;
264std::string G::OptionsUsage::helpDescription(
const Option & option ,
bool config_extra )
const
266 std::string description = option.description ;
268 description.append( option.description_extra ) ;
272std::string G::OptionsUsage::helpSeparator(
const Config & config , std::size_t syntax_length )
const
274 if( !config.separator.empty() )
275 return config.separator ;
276 else if( (config.margin+syntax_length) >= config.column )
277 return std::string( 1U , m_space_separator ) ;
279 return std::string( config.column-syntax_length-config.margin , m_space_separator ) ;
282std::string G::OptionsUsage::helpPadding(
const Config & config )
const
284 std::size_t n = std::max( std::size_t(1U) , config.column - std::min(config.column,config.margin) ) ;
285 return std::string( n , m_space_padding ) ;
292 return a.level == b.level ?
G::Str::iless(a.name,b.name) : ( a.level < b.level ) ;
300 if( width == Config::default_ )
310 width -= std::min( width , margin ) ;
311 width = std::max( width , std::size_t(1U) ) ;
312 width2 -= std::min( width2 , margin ) ;
313 width2 = std::max( width2 , std::size_t(1U) ) ;
static std::string get(const std::string &name, const std::string &default_)
Returns the environment variable value or the given default.
static SortFn sort()
Returns the default sort function that sorts by level first and then by name.
std::string summary(const Config &, const std::string &exe, const std::string &args={}) const
Returns a one-line (or line-wrapped) usage summary, as "usage: <exe> <options> <args>".
void output(const Config &, std::ostream &stream, const std::string &exe, const std::string &args={}) const
Streams out multi-line usage text using summary() and help().
std::string help(const Config &, bool *overflow_p=nullptr) const
Returns a multi-line string giving help on each option.
OptionsUsage(const std::vector< Option > &, SortFn=sort())
Constructor.
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
static bool replace(std::string &s, std::string_view from, std::string_view to, std::size_t *pos_p=nullptr)
A std::string_view overload.
static bool iless(std::string_view, std::string_view) noexcept
Returns true if the first string is lexicographically less than the first, after seven-bit lower-case...
static std::string wrap(const std::string &text, const std::string &prefix_first, const std::string &prefix_other, std::size_t width_first=70U, std::size_t width_other=0U, bool preserve_spaces=false)
Does word-wrapping of UTF-8 text.
static bool enabled() noexcept
Returns true if test features are enabled.
const char * txt(const char *p) noexcept
A briefer alternative to G::gettext().
A structure representing a G::Options command-line option.
A configuration structure for G::OptionsUsage.
bool alt_usage
use alternate "usage:" string
std::size_t width
overall width for wrapping, or zero for none, defaults to $COLUMNS