ENH: support line-breaks in option usage text

- for finer control of the '-help' output text
This commit is contained in:
Mark Olesen
2018-10-10 14:07:21 +02:00
parent c006a10bd8
commit 1933cffffe
2 changed files with 122 additions and 102 deletions

View File

@ -51,6 +51,7 @@ License
bool Foam::argList::argsMandatory_ = true; bool Foam::argList::argsMandatory_ = true;
bool Foam::argList::checkProcessorDirectories_ = true; bool Foam::argList::checkProcessorDirectories_ = true;
Foam::SLList<Foam::string> Foam::argList::validArgs; Foam::SLList<Foam::string> Foam::argList::validArgs;
Foam::HashSet<Foam::string> Foam::argList::advancedOptions; Foam::HashSet<Foam::string> Foam::argList::advancedOptions;
Foam::HashTable<Foam::string> Foam::argList::validOptions; Foam::HashTable<Foam::string> Foam::argList::validOptions;
@ -59,10 +60,11 @@ Foam::HashTable<Foam::string> Foam::argList::optionUsage;
Foam::HashTable<std::pair<Foam::word,int>> Foam::argList::validOptionsCompat; Foam::HashTable<std::pair<Foam::word,int>> Foam::argList::validOptionsCompat;
Foam::HashTable<std::pair<bool,int>> Foam::argList::ignoreOptionsCompat; Foam::HashTable<std::pair<bool,int>> Foam::argList::ignoreOptionsCompat;
Foam::SLList<Foam::string> Foam::argList::notes; Foam::SLList<Foam::string> Foam::argList::notes;
Foam::string::size_type Foam::argList::usageMin = 20;
Foam::string::size_type Foam::argList::usageMax = 80;
Foam::word Foam::argList::postProcessOptionName("postProcess"); Foam::word Foam::argList::postProcessOptionName("postProcess");
std::string::size_type Foam::argList::usageMin = 20;
std::string::size_type Foam::argList::usageMax = 80;
Foam::argList::initValidTables::initValidTables() Foam::argList::initValidTables::initValidTables()
{ {
argList::addOption argList::addOption
@ -256,7 +258,7 @@ void Foam::argList::addBoolOption
( (
const word& optName, const word& optName,
const string& usage, const string& usage,
const bool advanced bool advanced
) )
{ {
addOption(optName, "", usage, advanced); addOption(optName, "", usage, advanced);
@ -268,7 +270,7 @@ void Foam::argList::addOption
const word& optName, const word& optName,
const string& param, const string& param,
const string& usage, const string& usage,
const bool advanced bool advanced
) )
{ {
validOptions.set(optName, param); validOptions.set(optName, param);
@ -283,6 +285,19 @@ void Foam::argList::addOption
} }
void Foam::argList::setAdvanced(const word& optName, bool advanced)
{
if (advanced && validOptions.found(optName))
{
advancedOptions.set(optName);
}
else
{
advancedOptions.erase(optName);
}
}
void Foam::argList::addOptionCompat void Foam::argList::addOptionCompat
( (
const word& optName, const word& optName,
@ -300,7 +315,7 @@ void Foam::argList::addOptionCompat
void Foam::argList::ignoreOptionCompat void Foam::argList::ignoreOptionCompat
( (
std::pair<const char*,int> compat, std::pair<const char*,int> compat,
const bool expectArg bool expectArg
) )
{ {
ignoreOptionsCompat.insert ignoreOptionsCompat.insert
@ -417,101 +432,108 @@ void Foam::argList::noCheckProcessorDirectories()
void Foam::argList::printOptionUsage void Foam::argList::printOptionUsage
( (
const label location, std::string::size_type start,
const string& str const string& str
) )
{ {
const string::size_type textWidth = usageMax - usageMin; const auto strLen = str.length();
const string::size_type strLen = str.size();
if (strLen) if (!strLen)
{ {
// Minimum of 2 spaces between option and usage:
if (string::size_type(location) + 2 <= usageMin)
{
for (string::size_type i = location; i < usageMin; ++i)
{
Info<<' ';
}
}
else
{
// or start a new line
Info<< nl; Info<< nl;
for (string::size_type i = 0; i < usageMin; ++i) return;
{
Info<<' ';
}
} }
// Text wrap // Indent the first line. Min 2 spaces between option and usage
string::size_type pos = 0; if (start + 2 > usageMin)
while (pos != string::npos && pos + textWidth < strLen) {
Info<< nl;
start = 0;
}
while (start < usageMin)
{
Info<<' ';
++start;
}
const std::string::size_type textWidth = (usageMax - usageMin);
// Output with text wrapping
for (std::string::size_type pos = 0; pos < strLen; /*ni*/)
{ {
// Potential end point and next point // Potential end point and next point
string::size_type curr = pos + textWidth - 1; std::string::size_type end = pos + textWidth - 1;
string::size_type next = string::npos; std::string::size_type eol = str.find('\n', pos);
std::string::size_type next = string::npos;
if (isspace(str[curr])) if (end >= strLen)
{ {
// We were lucky: ended on a space // No more wrapping needed
next = str.find_first_not_of(" \t\n", curr); end = strLen;
if (std::string::npos != eol && eol <= end)
{
end = eol;
next = str.find_first_not_of(" \t\n", end); // Next non-space
} }
else if (isspace(str[curr+1])) }
else if (std::string::npos != eol && eol <= end)
{
// Embedded '\n' char
end = eol;
next = str.find_first_not_of(" \t\n", end); // Next non-space
}
else if (isspace(str[end]))
{
// Ended on a space - can use this directly
next = str.find_first_not_of(" \t\n", end); // Next non-space
}
else if (isspace(str[end+1]))
{ {
// The next one is a space - so we are okay // The next one is a space - so we are okay
++curr; // otherwise the length is wrong ++end; // Otherwise the length is wrong
next = str.find_first_not_of(" \t\n", curr); next = str.find_first_not_of(" \t\n", end); // Next non-space
} }
else else
{ {
// Search for end of a previous word break // Line break will be mid-word
string::size_type prev = str.find_last_of(" \t\n", curr); auto prev = str.find_last_of(" \t\n", end); // Prev word break
// Reposition to the end of previous word if possible if (std::string::npos != prev && prev > pos)
if (prev != string::npos && prev > pos)
{ {
curr = prev; end = prev;
next = prev + 1; // Continue from here
} }
} }
if (next == string::npos) // The next position to continue from
if (std::string::npos == next)
{ {
next = curr + 1; next = end + 1;
} }
// Indent following lines (not the first one) // Has a length
if (end > pos)
{
// Indent following lines. The first one was already done.
if (pos) if (pos)
{ {
for (string::size_type i = 0; i < usageMin; ++i) for (std::string::size_type i = 0; i < usageMin; ++i)
{ {
Info<<' '; Info<<' ';
} }
} }
Info<< str.substr(pos, (curr - pos)).c_str() << nl; while (pos < end)
pos = next;
}
// Output the remainder of the string
if (pos != string::npos)
{ {
// Indent following lines (not the first one) Info<< str[pos];
if (pos) ++pos;
{
for (string::size_type i = 0; i < usageMin; ++i)
{
Info<<' ';
} }
}
Info<< str.substr(pos).c_str() << nl;
}
}
else
{
Info<< nl; Info<< nl;
} }
pos = next;
}
} }
@ -761,7 +783,7 @@ Foam::argList::argList
char**& argv, char**& argv,
bool checkArgs, bool checkArgs,
bool checkOpts, bool checkOpts,
const bool initialise bool initialise
) )
: :
args_(argc), args_(argc),
@ -1618,7 +1640,9 @@ void Foam::argList::printUsage(bool full) const
} }
Info<< " -" << optName; Info<< " -" << optName;
label len = optName.size() + 3; // Length includes leading ' -'
// Length includes leading ' -'
label len = optName.size() + 3;
const auto optIter = validOptions.cfind(optName); const auto optIter = validOptions.cfind(optName);
if (optIter().size()) if (optIter().size())

View File

@ -157,7 +157,7 @@ class argList
//- Helper function for printUsage //- Helper function for printUsage
static void printOptionUsage static void printOptionUsage
( (
const label location, std::string::size_type start,
const string& str const string& str
); );
@ -222,19 +222,17 @@ public:
static SLList<string> notes; static SLList<string> notes;
//- Min offset for displaying usage (default: 20) //- Min offset for displaying usage (default: 20)
static string::size_type usageMin; static std::string::size_type usageMin;
//- Max screen width for displaying usage (default: 80) //- Max screen width for displaying usage (default: 80)
static string::size_type usageMax; static std::string::size_type usageMax;
//- Standard name for the post-processing option //- Standard name for the post-processing option
static word postProcessOptionName; static word postProcessOptionName;
//! \cond internalClass //! \cond internalClass
class initValidTables struct initValidTables
{ {
public:
initValidTables(); initValidTables();
}; };
//! \endcond //! \endcond
@ -274,12 +272,7 @@ public:
//- Scan for -help, -doc options etc prior to checking the validity //- Scan for -help, -doc options etc prior to checking the validity
//- of other args/opts and finally initialising. //- of other args/opts and finally initialising.
void parse void parse(bool checkArgs, bool checkOpts, bool initialise);
(
bool checkArgs,
bool checkOpts,
bool initialise
);
// Access // Access
@ -398,7 +391,7 @@ public:
( (
const word& optName, const word& optName,
const string& usage = "", const string& usage = "",
const bool advanced = false bool advanced = false
); );
//- Add an option to validOptions with usage information //- Add an option to validOptions with usage information
@ -408,9 +401,12 @@ public:
const word& optName, const word& optName,
const string& param = "", const string& param = "",
const string& usage = "", const string& usage = "",
const bool advanced = false bool advanced = false
); );
//- Set an existing option as being 'advanced' or normal
static void setAdvanced(const word& optName, bool advanced = true);
//- Specify an alias for the option name. //- Specify an alias for the option name.
// //
// \param optName the currently used option name // \param optName the currently used option name
@ -434,7 +430,7 @@ public:
static void ignoreOptionCompat static void ignoreOptionCompat
( (
std::pair<const char*,int> compat, std::pair<const char*,int> compat,
const bool expectArg bool expectArg
); );
//- Add option usage information to optionUsage //- Add option usage information to optionUsage