QCommandLineParser: add word-wrapping algorithm

Rather than breaking at column 79 precisely, break entire words,
to improve readability.

Change-Id: Ie30db00f0e6ed95cce87480c3b91804826c6076b
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
This commit is contained in:
David Faure 2013-09-02 10:26:21 +02:00 committed by The Qt Project
parent afe8e36872
commit 2026e50259
3 changed files with 83 additions and 28 deletions

View File

@ -845,11 +845,50 @@ static QString wrapText(const QString &names, int longestOptionNameString, const
{
const QLatin1Char nl('\n');
QString text = QStringLiteral(" ") + names.leftJustified(longestOptionNameString) + QLatin1Char(' ');
const int leftColumnWidth = text.length();
const int rightColumnWidth = 79 - leftColumnWidth;
text += description.left(rightColumnWidth) + nl;
for (int n = rightColumnWidth; n < description.length(); n += rightColumnWidth)
text += QStringLiteral(" ").repeated(leftColumnWidth) + description.mid(n, rightColumnWidth) + nl;
const int indent = text.length();
int lineStart = 0;
int lastBreakable = -1;
const int max = 79 - indent;
int x = 0;
const int len = description.length();
for (int i = 0; i < len; ++i) {
++x;
const QChar c = description.at(i);
if (c.isSpace())
lastBreakable = i;
int breakAt = -1;
int nextLineStart = -1;
if (x > max && lastBreakable != -1) {
// time to break and we know where
breakAt = lastBreakable;
nextLineStart = lastBreakable + 1;
} else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
// time to break but found nowhere [-> break here], or end of last line
breakAt = i + 1;
nextLineStart = breakAt;
} else if (c == nl) {
// forced break
breakAt = i;
nextLineStart = i + 1;
}
if (breakAt != -1) {
const int numChars = breakAt - lineStart;
//qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
if (lineStart > 0)
text += QString(indent, QLatin1Char(' '));
text += description.midRef(lineStart, numChars) + nl;
x = 0;
lastBreakable = -1;
lineStart = nextLineStart;
if (lineStart < len && description.at(lineStart).isSpace())
++lineStart; // don't start a line with a space
i = lineStart;
}
}
return text;
}

View File

@ -69,9 +69,18 @@ int main(int argc, char *argv[])
// An option with a longer description, to test wrapping
QCommandLineOption noImplicitIncludesOption(QStringList() << QStringLiteral("n") << QStringLiteral("no-implicit-includes"));
noImplicitIncludesOption.setDescription(QStringLiteral("Disable automatic generation of implicit #include-directives."));
noImplicitIncludesOption.setDescription(QStringLiteral("Disable magic generation of implicit #include-directives."));
parser.addOption(noImplicitIncludesOption);
QCommandLineOption newlineOption(QStringList() << QStringLiteral("newline"));
newlineOption.setDescription(QString::fromLatin1("This is an option with a rather long\n"
"description using explicit newline characters "
"(but testing automatic wrapping too). In addition, "
"here, we test breaking after a comma. Testing -option. "
"Long URL: http://qt-project.org/wiki/How_to_create_a_library_with_Qt_and_use_it_in_an_application "
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"));
parser.addOption(newlineOption);
// This program supports different options depending on the "command" (first argument).
// Call parse() to find out the positional arguments.
parser.parse(QCoreApplication::arguments());

View File

@ -459,27 +459,40 @@ void tst_QCommandLineParser::testVersionOption()
#endif // !QT_NO_PROCESS
}
void tst_QCommandLineParser::testHelpOption_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QString>("expectedHelpOutput");
QString expectedOutput =
"Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n"
"Test helper\n"
"\n"
static const char expectedOptionsHelp[] =
"Options:\n"
" -h, --help Displays this help.\n"
" -v, --version Displays version information.\n"
" --load <url> Load file from URL.\n"
" -o, --output <file> Set output file.\n"
" -D <key=value> Define macro.\n"
" -n, --no-implicit-includes Disable automatic generation of implicit #include\n"
" -directives.\n"
" -n, --no-implicit-includes Disable magic generation of implicit\n"
" #include-directives.\n"
" --newline This is an option with a rather long\n"
" description using explicit newline characters (but\n"
" testing automatic wrapping too). In addition,\n"
" here, we test breaking after a comma. Testing\n"
" -option. Long URL:\n"
" http://qt-project.org/wiki/How_to_create_a_library\n"
" _with_Qt_and_use_it_in_an_application\n"
" abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx\n"
" yzabcdefghijklmnopqrstuvwxyz\n";
void tst_QCommandLineParser::testHelpOption_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QString>("expectedHelpOutput");
QString expectedOutput = QString::fromLatin1(
"Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n"
"Test helper\n"
"\n")
+ QString::fromLatin1(expectedOptionsHelp) +
QString::fromLatin1(
"\n"
"Arguments:\n"
" parsingMode The parsing mode to test.\n"
" command The command to execute.\n";
" command The command to execute.\n");
#ifdef Q_OS_WIN
expectedOutput.replace(" -h, --help Displays this help.\n",
" -?, -h, --help Displays this help.\n");
@ -510,6 +523,7 @@ void tst_QCommandLineParser::testHelpOption()
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QCOMPARE(output.split('\n'), expectedHelpOutput.split('\n')); // easier to debug than the next line, on failure
QCOMPARE(output, expectedHelpOutput);
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "resize" << "--help");
@ -519,18 +533,11 @@ void tst_QCommandLineParser::testHelpOption()
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QByteArray expectedResizeHelp =
QByteArray expectedResizeHelp = QByteArrayLiteral(
"Usage: testhelper/qcommandlineparser_test_helper [options] resize [resize_options]\n"
"Test helper\n"
"\n"
"Options:\n"
" -h, --help Displays this help.\n"
" -v, --version Displays version information.\n"
" --load <url> Load file from URL.\n"
" -o, --output <file> Set output file.\n"
" -D <key=value> Define macro.\n"
" -n, --no-implicit-includes Disable automatic generation of implicit #include\n"
" -directives.\n"
"\n")
+ expectedOptionsHelp +
" --size <size> New size.\n"
"\n"
"Arguments:\n"