13#include <QtCore/qfile.h>
14#include <QtCore/qregularexpression.h>
15#include <QtCore/qtextstream.h>
23using namespace Qt::StringLiterals;
138} cmds[] = { {
"a",
CMD_A,
true },
140 {
"b",
CMD_B,
true },
145 {
"c",
CMD_C,
true },
153 {
"e",
CMD_E,
true },
178 {
"i",
CMD_I,
true },
250 qsizetype colonPos = link.indexOf(
':');
251 if ((colonPos == -1) || (!link.startsWith(
"file:") && !link.startsWith(
"mailto:")))
253 return link.mid(colonPos + 1).simplified();
262 while (cmds[i]
.name) {
266 Location::internalError(QStringLiteral(
"command %1 missing").arg(i));
272 const auto &outputFormats = config.getOutputFormats();
273 for (
const auto &format : outputFormats)
274 DocParser::s_quoting = DocParser::s_quoting
279 DocParser::file_resolver = &file_resolver;
283
284
285
286
287
288
289
290
292 const QSet<QString> &metaCommandSet,
const QSet<QString> &possibleTopics)
296 m_inputLength = m_input.size();
297 m_cachedLocation = docPrivate->m_start_loc;
298 m_cachedPosition = 0;
299 m_private = docPrivate;
303 m_paragraphState = OutsideParagraph;
304 m_inTableHeader =
false;
305 m_inTableRow =
false;
306 m_inTableItem =
false;
307 m_indexStartedParagraph =
false;
313 m_openedCommands.push(CMD_OMIT);
317 Atom *currentLinkAtom =
nullptr;
319 QStack<
bool> preprocessorSkipping;
320 int numPreprocessorSkipping = 0;
322 while (m_position < m_inputLength) {
323 QChar ch = m_input.at(m_position);
325 switch (ch.unicode()) {
328 m_backslashPosition = m_position;
330 while (m_position < m_inputLength) {
331 ch = m_input.at(m_position);
332 if (ch.isLetterOrNumber()) {
339 m_endPosition = m_position;
340 if (cmdStr.isEmpty()) {
341 if (m_position < m_inputLength) {
343 if (m_input.at(m_position).isSpace()) {
345 appendChar(QLatin1Char(
' '));
347 appendChar(m_input.at(m_position++));
364 m_private->m_params.insert(p1);
368 appendAtom(Atom(Atom::CodeBad,
369 getCode(CMD_BADCODE, marker, getMetaCommandArgument(cmdStr))));
376 location().warning(QStringLiteral(
"'\\bold' is deprecated. Use '\\b'"));
383 enterPara(Atom::BriefLeft, Atom::BriefRight);
387 p1 = untabifyEtc(getArgument(ArgumentParsingOptions::Verbatim));
388 marker = CodeMarker::markerForCode(p1);
389 appendAtom(
Atom(
Atom::C, marker->markedUpCode(p1,
nullptr, location())));
393 enterPara(Atom::CaptionLeft, Atom::CaptionRight);
397 appendAtom(Atom(Atom::Code, getCode(CMD_CODE,
nullptr, getMetaCommandArgument(cmdStr))));
401 appendAtom(Atom(Atom::Qml,
402 getCode(CMD_QML, CodeMarker::markerForLanguage(QLatin1String(
"QML")),
403 getMetaCommandArgument(cmdStr))));
407 appendAtom(Atom(Atom::DetailsLeft, getArgument()));
408 m_openedCommands.push(cmd);
417 p1 = getArgument(ArgumentParsingOptions::Verbatim);
419 m_openedCommands.push(cmd);
431 if (isCode(m_lastAtom) && m_lastAtom->string().endsWith(
"\n\n"))
436 QString arg = getOptionalArgument();
443 if (isCode(m_lastAtom) && m_lastAtom->string().endsWith(
"\n\n"))
446 int indent = arg.toInt();
447 for (
int i = 0; i < indent; ++i)
449 appendToCode(
"...\n");
453 if (!preprocessorSkipping.empty()) {
454 if (preprocessorSkipping.top()) {
455 --numPreprocessorSkipping;
457 ++numPreprocessorSkipping;
459 preprocessorSkipping.top() = !preprocessorSkipping.top();
460 (
void)getRestOfLine();
461 if (numPreprocessorSkipping)
462 skipToNextPreprocessorCommand();
465 QStringLiteral(
"Unexpected '\\%1'").arg(cmdName(
CMD_ELSE)));
475 if (closeCommand(cmd)) {
481 if (preprocessorSkipping.size() > 0) {
482 if (preprocessorSkipping.pop())
483 --numPreprocessorSkipping;
484 (
void)getRestOfLine();
485 if (numPreprocessorSkipping)
486 skipToNextPreprocessorCommand();
489 QStringLiteral(
"Unexpected '\\%1'").arg(cmdName(
CMD_ENDIF)));
493 if (closeCommand(cmd)) {
499 if (closeCommand(cmd)) {
507 if (closeCommand(cmd)) {
509 if (m_openedLists.top().isStarted()) {
510 appendAtom(Atom(Atom::ListItemRight, m_openedLists.top().styleString()));
511 appendAtom(Atom(Atom::ListRight, m_openedLists.top().styleString()));
520 if (closeCommand(cmd)) {
527 QStringLiteral(
"Unexpected '\\%1'").arg(cmdName(
CMD_ENDRAW)));
542 if (closeCommand(cmd)) {
548 if (closeCommand(cmd)) {
554 if (openCommand(cmd)) {
561 if (isLeftBracketAhead())
562 p2 = getBracketedArgument();
565 appendAtom(Atom(Atom::AnnotatedList, getArgument(), p2));
569 appendAtom(Atom(Atom::SinceList, getRestOfLine().simplified()));
573 if (isLeftBracketAhead())
574 p2 = getBracketedArgument();
577 QString arg1 = getArgument();
578 QString arg2 = getOptionalArgument();
581 appendAtom(Atom(Atom::GeneratedList, arg1, p2));
584 if (m_openedCommands.top() == CMD_TABLE) {
587 m_inTableHeader =
true;
589 if (m_openedCommands.contains(CMD_TABLE))
590 location().warning(QStringLiteral(
"Cannot use '\\%1' within '\\%2'")
591 .arg(cmdName(CMD_HEADER),
592 cmdName(m_openedCommands.top())));
595 QStringLiteral(
"Cannot use '\\%1' outside of '\\%2'")
600 location().warning(QStringLiteral(
601 "'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item"));
611 preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine()));
612 if (preprocessorSkipping.top())
613 ++numPreprocessorSkipping;
614 if (numPreprocessorSkipping)
615 skipToNextPreprocessorCommand();
622 enterPara(Atom::ImportantLeft, Atom::ImportantRight);
626 QString fileName = getArgument();
627 QStringList parameters;
629 if (isLeftBraceAhead()) {
630 identifier = getArgument();
631 while (isLeftBraceAhead() && parameters.size() < 9)
632 parameters << getArgument();
634 identifier = getRestOfLine();
636 include(fileName, identifier, parameters);
643 if (m_paragraphState == OutsideParagraph) {
645 m_indexStartedParagraph =
true;
648 if (m_indexStartedParagraph
651 m_indexStartedParagraph =
false;
657 insertKeyword(getRestOfLine());
660 if (m_openedCommands.top() != CMD_TOC) {
661 location().warning(
"Command '\\%1' outside of '\\%2'"_L1
662 .arg(cmdName(cmd), cmdName(CMD_TOC)));
668 if (isLeftBracketAhead())
669 p2 = getBracketedArgument();
673 appendAtom(LinkAtom(p1, p2, location()));
675 if (isLeftBraceAhead()) {
680 appendAtom(Atom(Atom::String, cleanLink(p1)));
689 if (openCommand(cmd))
694 if (openCommand(cmd)) {
699 skipSpacesOrOneEndl();
703 if (openCommand(cmd)) {
705 m_openedLists.push(OpenedList(location(), getOptionalArgument()));
711 m_private->extra->m_metaMap.insert(p1, getArgument());
715 enterPara(Atom::NoteLeft, Atom::NoteRight);
717 case CMD_NOTRANSLATE:
721 location().warning(QStringLiteral(
"'\\o' is deprecated. Use '\\li'"));
725 if (m_openedCommands.top() == CMD_LIST) {
726 if (m_openedLists.top().isStarted())
727 appendAtom(Atom(Atom::ListItemRight, m_openedLists.top().styleString()));
729 appendAtom(Atom(Atom::ListLeft, m_openedLists.top().styleString()));
730 m_openedLists.top().next();
731 appendAtom(Atom(Atom::ListItemNumber, m_openedLists.top().numberString()));
732 appendAtom(Atom(Atom::ListItemLeft, m_openedLists.top().styleString()));
734 }
else if (m_openedCommands.top() == CMD_TABLE) {
737 if (isLeftBraceAhead()) {
739 if (isLeftBraceAhead())
743 if (!m_inTableHeader && !m_inTableRow) {
745 QStringLiteral(
"Missing '\\%1' or '\\%2' before '\\%3'")
750 }
else if (m_inTableItem) {
752 m_inTableItem =
false;
755 appendAtom(Atom(Atom::TableItemLeft, p1, p2));
756 m_inTableItem =
true;
759 QStringLiteral(
"Command '\\%1' outside of '\\%2' and '\\%3'")
768 if (!m_private->m_enumItemList.contains(p1))
769 m_private->m_enumItemList.append(p1);
770 if (!m_private->m_omitEnumItemList.contains(p1))
771 m_private->m_omitEnumItemList.append(p1);
772 skipSpacesOrOneEndl();
774 while (m_position < m_inputLength && !isBlankLine()) {
776 if (qsizetype pos = m_position; pos < m_input.size()
777 && m_input.at(pos++).unicode() ==
'\\') {
779 while (pos < m_input.size() && m_input[pos].isLetterOrNumber())
780 nextCmdStr += m_input[pos++];
782 if (nextCmd == cmd || nextCmd ==
CMD_VALUE)
791 p1 = getRestOfLine();
792 if (openCommand(cmd))
796 if (closeCommand(cmd)) {
804 QString rest = getRestOfLine();
809 appendToCode(m_quoter.quoteLine(location(), cmdStr, rest));
814 QString rest = getRestOfLine();
819 appendToCode(m_quoter.quoteTo(location(), cmdStr, rest));
824 QString rest = getRestOfLine();
829 appendToCode(m_quoter.quoteUntil(location(), cmdStr, rest));
833 if (openCommand(cmd)) {
841 QString fileName = getArgument();
842 quoteFromFile(fileName);
847 appendAtom(Atom(Atom::Code, m_quoter.quoteTo(location(), cmdStr, QString())));
853 QString arg = getArgument();
863 p1 = getRestOfLine();
865 location().warning(QStringLiteral(
"Missing format name after '\\%1'")
868 appendAtom(Atom(Atom::RawString, untabifyEtc(getUntilEnd(cmd))));
873 if (m_openedCommands.top() == CMD_TABLE) {
875 if (isLeftBraceAhead())
876 p1 = getArgument(ArgumentParsingOptions::Verbatim);
881 if (m_openedCommands.contains(CMD_TABLE))
882 location().warning(QStringLiteral(
"Cannot use '\\%1' within '\\%2'")
883 .arg(cmdName(CMD_ROW),
884 cmdName(m_openedCommands.top())));
886 location().warning(QStringLiteral(
"Cannot use '\\%1' outside of '\\%2'")
906 if (openCommand(cmd)) {
913 QString rest = getRestOfLine();
918 m_quoter.quoteLine(location(), cmdStr, rest);
923 QString rest = getRestOfLine();
928 m_quoter.quoteTo(location(), cmdStr, rest);
933 QString rest = getRestOfLine();
938 m_quoter.quoteUntil(location(), cmdStr, rest);
943 startFormat(p1, cmd);
947 QString snippet = getArgument();
948 QString identifier = getRestOfLine();
954 marker = CodeMarker::markerForFileName(snippet);
955 quoteFromFile(snippet);
956 appendToCode(m_quoter.quoteSnippet(location(), identifier), marker->atomType());
967 p1 = getOptionalArgument();
968 p2 = getOptionalArgument();
969 if (openCommand(cmd)) {
971 appendAtom(Atom(Atom::TableLeft, p1, p2));
972 m_inTableHeader =
false;
973 m_inTableRow =
false;
974 m_inTableItem =
false;
977 case CMD_TABLEOFCONTENTS:
978 location().report(
"\\%1 is deprecated and will be removed in a future version."_L1.arg(cmdName(cmd)));
979 if (isLeftBraceAhead())
983 if (m_openedCommands.top() == CMD_TABLE && !m_inTableItem) {
984 location().warning(
"Found a \\target command outside table item in a table.\n"
985 "Move the \\target inside the \\li to resolve this warning.");
987 insertTarget(getRestOfLine());
991 if (m_paragraphState != InSingleLineParagraph)
995 if (openCommand(cmd)) {
1001 if (closeCommand(cmd)) {
1019 uint unicodeChar = p1.toUInt(&ok, 0);
1020 if (!ok || (unicodeChar == 0x0000) || (unicodeChar > 0xFFFE))
1022 QStringLiteral(
"Invalid Unicode character '%1' specified with '%2'")
1030 if (m_openedLists.top().style() == OpenedList::Value) {
1033 if (p1.startsWith(QLatin1String(
"[since "))
1034 && p1.endsWith(QLatin1String(
"]"))) {
1035 p2 = p1.mid(7, p1.size() - 8);
1038 if (!m_private->m_enumItemList.contains(p1))
1039 m_private->m_enumItemList.append(p1);
1041 m_openedLists.top().next();
1045 if (!p2.isEmpty()) {
1052 skipSpacesOrOneEndl();
1061 enterPara(Atom::WarningLeft, Atom::WarningRight);
1067 if (metaCommandSet.contains(cmdStr)) {
1069 QString bracketedArg;
1070 m_private->m_metacommandsUsed.insert(cmdStr);
1071 if (isLeftBracketAhead())
1072 bracketedArg = getBracketedArgument();
1075 if (m_position < m_inputLength
1076 && (cmdStr == QLatin1String(
"obsolete")
1077 || cmdStr == QLatin1String(
"deprecated")))
1078 m_input[m_position] =
'\n';
1080 arg = getMetaCommandArgument(cmdStr);
1082 if (possibleTopics.contains(cmdStr)) {
1083 if (!cmdStr.endsWith(QLatin1String(
"propertygroup")))
1086 }
else if (s_utilities
.macroHash.contains(cmdStr)) {
1088 QStringList macroArgs;
1089 int numPendingFi = 0;
1090 int numFormatDefs = 0;
1091 for (
auto it = macro.m_otherDefs.constBegin();
1092 it != macro.m_otherDefs.constEnd(); ++it) {
1093 if (it.key() !=
"match") {
1094 if (numFormatDefs == 0)
1095 macroArgs = getMacroArguments(cmdStr, macro);
1097 expandMacro(*it, macroArgs);
1099 if (it == macro.m_otherDefs.constEnd()) {
1107 while (numPendingFi-- > 0)
1110 if (!macro.m_defaultDef.isEmpty()) {
1111 if (numFormatDefs > 0) {
1112 macro.m_defaultDefLocation.warning(
1113 QStringLiteral(
"Macro cannot have both "
1114 "format-specific and qdoc-"
1115 "syntax definitions"));
1117 QString expanded = expandMacroToString(cmdStr, macro);
1118 m_input.replace(m_backslashPosition,
1119 m_endPosition - m_backslashPosition, expanded);
1120 m_inputLength = m_input.size();
1121 m_position = m_backslashPosition;
1124 }
else if (isAutoLinkString(cmdStr)) {
1127 if (!cmdStr.endsWith(
"propertygroup")) {
1130 location().warning(QStringLiteral(
"Unknown command '\\%1'").arg(cmdStr),
1131 detailsUnknownCommand(metaCommandSet, cmdStr));
1142 qsizetype dashCount = 1;
1146 while ((m_position < m_inputLength) && (m_input.at(m_position) ==
'-')) {
1151 if (dashCount == 3) {
1153 const QChar emDash(8212);
1155 }
else if (dashCount == 2) {
1157 const QChar enDash(8211);
1163 for (qsizetype i = 0; i < dashCount; ++i)
1178 auto format = m_pendingFormats.find(m_braceDepth);
1179 if (format == m_pendingFormats.end()) {
1186 if (m_indexStartedParagraph)
1191 if (currentLinkAtom && currentLinkAtom->string().endsWith(
"::")) {
1195 currentLinkAtom->concatenateString(suffix);
1197 currentLinkAtom =
nullptr;
1201 m_pendingFormats.erase(format);
1207 if (m_position + 2 < m_inputLength)
1208 if (m_input.at(m_position + 1) ==
'/')
1209 if (m_input.at(m_position + 2) ==
'!') {
1212 if (m_input.at(m_position - 1) ==
'\n')
1228 if (m_paragraphState == OutsideParagraph) {
1240 && (m_paragraphState == InSingleLineParagraph || isBlankLine())) {
1253 qsizetype startPos = m_position;
1255 bool autolink = (!m_pendingFormats.isEmpty() &&
1257 false : isAutoLinkString(m_input, m_position);
1258 if (m_position == startPos) {
1259 if (!ch.isSpace()) {
1264 QString word = m_input.mid(startPos, m_position - startPos);
1266 if (s_ignoreWords.contains(word) || word.startsWith(QString(
"__")))
1281 if (m_openedCommands.top() == CMD_LEGALESE) {
1283 m_openedCommands.pop();
1286 if (m_openedCommands.top() != CMD_OMIT) {
1288 QStringLiteral(
"Missing '\\%1'").arg(endCmdName(m_openedCommands.top())));
1289 }
else if (preprocessorSkipping.size() > 0) {
1290 location().warning(QStringLiteral(
"Missing '\\%1'").arg(cmdName(
CMD_ENDIF)));
1294 appendAtom(Atom(Atom::SectionRight, QString::number(m_currentSection)));
1302
1303
1306 while (!m_openedInputs.isEmpty() && m_openedInputs.top() <= m_position) {
1307 m_cachedLocation.pop();
1308 m_cachedPosition = m_openedInputs.pop();
1310 while (m_cachedPosition < m_position)
1311 m_cachedLocation.advance(m_input.at(m_cachedPosition++));
1312 return m_cachedLocation;
1315QString
DocParser::detailsUnknownCommand(
const QSet<QString> &metaCommandSet,
const QString &str)
1317 QSet<QString> commandSet = metaCommandSet;
1319 while (cmds[i]
.name !=
nullptr) {
1320 commandSet.insert(cmds[i]
.name);
1324 QString best = nearestName(str, commandSet);
1327 return QStringLiteral(
"Maybe you meant '\\%1'?").arg(best);
1331
1332
1333
1334
1335
1336
1337
1339 const QString &cmdString,
const QString &previousDefinition)
1341 if (duplicateDefinition.isEmpty()) {
1342 location.warning(
"Expected an argument for \\%1"_L1.arg(cmdString));
1345 "Duplicate %3 name '%1'. The previous occurrence is here: %2"_L1
1346 .arg(duplicateDefinition, previousDefinition, cmdString));
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364void DocParser::insertTarget(
const QString &target)
1366 if (target.isEmpty() || m_targetMap.contains(target))
1367 return warnAboutEmptyOrPreexistingTarget(location(), target,
1368 s_utilities.cmdHash.key(CMD_TARGET), m_targetMap[target].toString());
1370 m_targetMap.insert(target, location());
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391void DocParser::insertKeyword(
const QString &keyword)
1393 if (keyword.isEmpty() || m_targetMap.contains(keyword))
1394 return warnAboutEmptyOrPreexistingTarget(location(), keyword,
1395 s_utilities.cmdHash.key(CMD_KEYWORD), m_targetMap[keyword].toString());
1397 m_targetMap.insert(keyword, location());
1404void DocParser::include(
const QString &fileName,
const QString &identifier,
const QStringList ¶meters)
1407 location().fatal(QStringLiteral(
"Too many nested '\\%1's").arg(cmdName(
CMD_INCLUDE)));
1408 QString filePath = Config::instance().getIncludeFilePath(fileName);
1409 if (filePath.isEmpty()) {
1410 location().warning(QStringLiteral(
"Cannot find qdoc include file '%1'").arg(fileName));
1412 QFile inFile(filePath);
1413 if (!inFile.open(QFile::ReadOnly)) {
1415 QStringLiteral(
"Cannot open qdoc include file '%1'").arg(filePath));
1417 location().push(fileName);
1418 QTextStream inStream(&inFile);
1419 QString includedContent = inStream.readAll();
1422 if (identifier.isEmpty()) {
1423 expandArgumentsInString(includedContent, parameters);
1424 m_input.insert(m_position, includedContent);
1425 m_inputLength = m_input.size();
1426 m_openedInputs.push(m_position + includedContent.size());
1428 QStringList lineBuffer = includedContent.split(QLatin1Char(
'\n'));
1429 qsizetype bufLen{lineBuffer.size()};
1431 QStringView trimmedLine;
1432 for (i = 0; i < bufLen; ++i) {
1433 trimmedLine = QStringView{lineBuffer[i]}.trimmed();
1434 if (trimmedLine.startsWith(QLatin1String(
"//!")) &&
1435 trimmedLine.contains(identifier))
1438 if (i < bufLen - 1) {
1442 QStringLiteral(
"Cannot find '%1' in '%2'").arg(identifier, filePath));
1447 trimmedLine = QStringView{lineBuffer[i]}.trimmed();
1448 if (trimmedLine.startsWith(QLatin1String(
"//!")) &&
1449 trimmedLine.contains(identifier))
1452 result += lineBuffer[i] + QLatin1Char(
'\n');
1454 }
while (i < bufLen);
1456 expandArgumentsInString(result, parameters);
1457 if (result.isEmpty()) {
1458 location().warning(QStringLiteral(
"Empty qdoc snippet '%1' in '%2'")
1459 .arg(identifier, filePath));
1461 m_input.insert(m_position, result);
1462 m_inputLength = m_input.size();
1463 m_openedInputs.push(m_position + result.size());
1470void DocParser::startFormat(
const QString &format,
int cmd)
1474 for (
const auto &item : std::as_const(m_pendingFormats)) {
1475 if (item == format) {
1476 location().warning(QStringLiteral(
"Cannot nest '\\%1' commands").arg(cmdName(cmd)));
1483 if (isLeftBraceAhead()) {
1484 skipSpacesOrOneEndl();
1485 m_pendingFormats.insert(m_braceDepth, format);
1489 const auto &arg{getArgument()};
1494 m_indexStartedParagraph =
false;
1503 int outer = m_openedCommands.top();
1506 if ((cmd == CMD_COMPARESWITH || cmd == CMD_TOC)
1507 && m_openedCommands.contains(cmd)) {
1508 location().warning(u"Cannot nest '\\%1' commands"_s.arg(cmdName(cmd)));
1525 m_openedCommands.push(cmd);
1528 QStringLiteral(
"Can't use '\\%1' in '\\%2'").arg(cmdName(cmd), cmdName(outer)));
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610inline bool DocParser::isAutoLinkString(
const QString &word)
1612 qsizetype start = 0;
1613 return isAutoLinkString(word, start) && (start == word.size());
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637bool DocParser::isAutoLinkString(
const QString &word, qsizetype &curPos)
1639 qsizetype len = word.size();
1640 qsizetype startPos = curPos;
1641 int numUppercase = 0;
1642 int numLowercase = 0;
1643 int numStrangeSymbols = 0;
1645 while (curPos < len) {
1646 unsigned char latin1Ch = word.at(curPos).toLatin1();
1647 if (islower(latin1Ch)) {
1650 }
else if (isupper(latin1Ch)) {
1651 if (curPos > startPos)
1654 }
else if (isdigit(latin1Ch)) {
1655 if (curPos > startPos)
1659 }
else if (latin1Ch ==
'_' || latin1Ch ==
'@') {
1660 ++numStrangeSymbols;
1662 }
else if ((latin1Ch ==
':') && (curPos < len - 1)
1663 && (word.at(curPos + 1) == QLatin1Char(
':'))) {
1664 ++numStrangeSymbols;
1666 }
else if (latin1Ch ==
'(') {
1667 if ((curPos < len - 1) && (word.at(curPos + 1) == QLatin1Char(
')'))) {
1668 ++numStrangeSymbols;
1678 return ((numUppercase >= 1 && numLowercase >= 2) || (numStrangeSymbols > 0 && (numUppercase + numLowercase >= 1)));
1683 if (endCmdFor(m_openedCommands.top()) == endCmd && m_openedCommands.size() > 1) {
1684 m_openedCommands.pop();
1687 bool contains =
false;
1688 QStack<
int> opened2 = m_openedCommands;
1689 while (opened2.size() > 1) {
1698 while (endCmdFor(m_openedCommands.top()) != endCmd && m_openedCommands.size() > 1) {
1700 QStringLiteral(
"Missing '\\%1' before '\\%2'")
1701 .arg(endCmdName(m_openedCommands.top()), cmdName(endCmd)));
1702 m_openedCommands.pop();
1705 location().warning(QStringLiteral(
"Unexpected '\\%1'").arg(cmdName(endCmd)));
1716 m_currentSection =
static_cast<
Doc::
Sections>(unit);
1719 endSection(unit, cmd);
1722 appendAtom(Atom(Atom::SectionLeft, QString::number(unit)));
1725 m_private
->extra->m_tableOfContentsLevels.append(unit);
1726 enterPara(Atom::SectionHeadingLeft, Atom::SectionHeadingRight, QString::number(unit));
1727 m_currentSection = unit;
1733 appendAtom(Atom(Atom::SectionRight, QString::number(m_currentSection)));
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1767 const QString imageFileName = getArgument();
1769 bool hasAltTextArgument{
false};
1770 if (isLeftBraceAhead()) {
1771 hasAltTextArgument =
true;
1772 imageText = getArgument();
1774 imageText = getRestOfLine();
1777 if (imageText.length() > 1) {
1778 if (imageText.front() ==
'"' && imageText.back() ==
'"') {
1779 imageText.removeFirst();
1780 imageText.removeLast();
1784 if (!hasAltTextArgument && imageText.isEmpty() && Config::instance().reportMissingAltTextForImages())
1785 location().report(QStringLiteral(
"\\%1 %2 is without a textual description, "
1786 "QDoc will not generate an alt text for the image.")
1788 .arg(imageFileName));
1789 appendAtom(
Atom(imageAtom, imageFileName));
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1808 const QString cmd{
"overload"};
1811 m_private->m_metacommandsUsed.insert(cmd);
1812 QString overloadArgument = isBlankLine() ? getMetaCommandArgument(cmd) : getRestOfLine();
1817 if (overloadArgument.trimmed() ==
"primary") {
1818 overloadArgument.clear();
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1839 auto line_comment = [
this]() ->
bool {
1841 if (m_position + 2 > m_inputLength)
1843 if (m_input[m_position].unicode() ==
'/') {
1844 if (m_input[m_position + 1].unicode() ==
'/') {
1845 if (m_input[m_position + 2].unicode() ==
'!') {
1853 auto skip_everything_until_newline = [
this]() ->
void {
1854 while (m_position < m_inputLength && m_input[m_position] !=
'\n')
1860 while (m_position < m_inputLength && m_input[m_position] !=
'\n') {
1863 bool skipMe =
false;
1865 if (m_input[m_position] ==
'{') {
1866 target = getArgument();
1868 if (m_position < m_inputLength && m_input[m_position] ==
'{') {
1869 str = getArgument();
1872 if (target.endsWith(
"::"))
1878 target = getArgument();
1879 str = cleanLink(target);
1880 if (target == QLatin1String(
"and") || target == QLatin1String(
"."))
1894 skip_everything_until_newline();
1896 if (m_position < m_inputLength && m_input[m_position] ==
',') {
1899 skip_everything_until_newline();
1900 skipSpacesOrOneEndl();
1901 }
else if (m_position >= m_inputLength || m_input[m_position] !=
'\n') {
1902 location().warning(QStringLiteral(
"Missing comma in '\\%1'").arg(cmdName(
CMD_SA)));
1920 if (ch == QLatin1Char(
' ')) {
1921 if (!atom->string().endsWith(QLatin1Char(
' ')))
1922 atom->appendChar(QLatin1Char(
' '));
1924 atom->appendChar(ch);
1927void DocParser::appendWord(
const QString &word)
1935void DocParser::appendToCode(
const QString &markedCode)
1937 if (!isCode(m_lastAtom)) {
1941 m_lastAtom->concatenateString(markedCode);
1946 if (!isCode(m_lastAtom)) {
1947 appendAtom(
Atom(defaultType, markedCode));
1950 m_lastAtom->concatenateString(markedCode);
1956 if (m_paragraphState != OutsideParagraph)
1965 appendAtom(
Atom(leftType, string));
1966 m_indexStartedParagraph =
false;
1967 m_pendingParagraphLeftType = leftType;
1968 m_pendingParagraphRightType = rightType;
1969 m_pendingParagraphString = string;
1971 m_paragraphState = InSingleLineParagraph;
1973 m_paragraphState = InMultiLineParagraph;
1975 skipSpacesOrOneEndl();
1980 if (m_paragraphState == OutsideParagraph)
1983 if (!m_pendingFormats.isEmpty()) {
1984 location().warning(QStringLiteral(
"Missing '}'"));
1985 m_pendingFormats.clear();
1995 appendAtom(Atom(m_pendingParagraphRightType, m_pendingParagraphString));
1997 m_paragraphState = OutsideParagraph;
1998 m_indexStartedParagraph =
false;
1999 m_pendingParagraphRightType =
Atom::Nop;
2000 m_pendingParagraphString.clear();
2006 if (m_openedLists.isEmpty()) {
2007 m_openedLists.push(OpenedList(OpenedList::Value));
2019 if (!m_openedLists.isEmpty() && (m_openedLists.top().style() == OpenedList::Value)) {
2024 m_openedLists.pop();
2030 if (m_inTableItem) {
2033 m_inTableItem =
false;
2035 if (m_inTableHeader) {
2037 m_inTableHeader =
false;
2041 m_inTableRow =
false;
2045void DocParser::quoteFromFile(
const QString &filename)
2058 auto maybe_resolved_file{(*file_resolver).resolve(filename)};
2059 if (!maybe_resolved_file) {
2068 QString details = std::transform_reduce(
2069 (*file_resolver).get_search_directories().cbegin(),
2070 (*file_resolver).get_search_directories().cend(),
2071 u"Searched directories:"_s,
2073 [](
const DirectoryPath &directory_path) -> QString {
return u' ' + directory_path.value(); }
2076 location().warning(u"Cannot find file to quote from: %1"_s.arg(filename), details);
2092 CodeMarker *marker = CodeMarker::markerForFileName(QString{});
2093 m_quoter.quoteFromFile(filename, QString{}, marker->markedUpCode(QString{},
nullptr, location()));
2094 }
else Doc::quoteFromFile(location(), m_quoter, *maybe_resolved_file);
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122bool DocParser::expandMacro(ArgumentParsingOptions options)
2124 Q_ASSERT(m_input[m_position].unicode() ==
'\\');
2126 if (options == ArgumentParsingOptions::Verbatim)
2130 qsizetype backslashPos = m_position++;
2131 while (m_position < m_input.size() && m_input[m_position].isLetterOrNumber())
2132 cmdStr += m_input[m_position++];
2134 m_endPosition = m_position;
2135 if (!cmdStr.isEmpty()) {
2136 if (s_utilities
.macroHash.contains(cmdStr)) {
2138 if (!macro.m_defaultDef.isEmpty()) {
2139 QString expanded = expandMacroToString(cmdStr, macro);
2140 m_input.replace(backslashPos, m_position - backslashPos, expanded);
2141 m_inputLength = m_input.size();
2142 m_position = backslashPos;
2145 location().warning(
"Macro '%1' does not have a default definition"_L1.arg(cmdStr));
2149 m_position = backslashPos;
2150 if (options != ArgumentParsingOptions::MacroArguments
2152 location().warning(
"Unknown macro '%1'"_L1.arg(cmdStr));
2156 }
else if (m_input[m_position].isSpace()) {
2158 }
else if (m_input[m_position].unicode() ==
'\\') {
2160 m_input.remove(m_position--, 1);
2166void DocParser::expandMacro(
const QString &def,
const QStringList &args)
2168 if (args.isEmpty()) {
2173 for (
int j = 0; j < def.size(); ++j) {
2174 if (
int paramNo = def[j].unicode(); paramNo >= 1 && paramNo <= args.length()) {
2175 if (!rawString.isEmpty()) {
2181 rawString += def[j];
2184 if (!rawString.isEmpty())
2189QString
DocParser::expandMacroToString(
const QString &name,
const Macro ¯o)
2191 const QString &def{macro.m_defaultDef};
2195 rawString = macro.m_defaultDef;
2197 QStringList args{getMacroArguments(name, macro)};
2199 for (
int j = 0; j < def.size(); ++j) {
2200 int paramNo = def[j].unicode();
2201 rawString += (paramNo >= 1 && paramNo <= args.length()) ? args[paramNo - 1] : def[j];
2204 QString matchExpr{macro.m_otherDefs.value(
"match")};
2205 if (matchExpr.isEmpty())
2209 QRegularExpression re(matchExpr);
2210 int capStart = (re.captureCount() > 0) ? 1 : 0;
2212 QRegularExpressionMatch match;
2213 while ((match = re.match(rawString, i)).hasMatch()) {
2214 for (
int c = capStart; c <= re.captureCount(); ++c)
2215 result += match.captured(c);
2216 i = match.capturedEnd();
2224 QString name = getOptionalArgument();
2226 if (name ==
"section1") {
2228 }
else if (name ==
"section2") {
2230 }
else if (name ==
"section3") {
2232 }
else if (name ==
"section4") {
2234 }
else if (name.isEmpty()) {
2237 location().warning(QStringLiteral(
"Invalid section '%1'").arg(name));
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252QString
DocParser::getBracedArgument(ArgumentParsingOptions options)
2256 if (m_position < m_input.size() && m_input[m_position] ==
'{') {
2258 while (m_position < m_input.size() && delimDepth >= 0) {
2259 switch (m_input[m_position].unicode()) {
2262 arg += QLatin1Char(
'{');
2267 if (delimDepth >= 0)
2268 arg += QLatin1Char(
'}');
2272 if (!expandMacro(options))
2273 arg += m_input[m_position++];
2276 if (m_input[m_position].isSpace() && options != ArgumentParsingOptions::Verbatim)
2279 arg += m_input[m_position];
2284 location().warning(QStringLiteral(
"Missing '}'"));
2286 m_endPosition = m_position;
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306QString
DocParser::getArgument(ArgumentParsingOptions options)
2308 skipSpacesOrOneEndl();
2311 qsizetype startPos = m_position;
2312 QString arg = getBracedArgument(options);
2313 if (arg.isEmpty()) {
2314 while ((m_position < m_input.size())
2315 && ((delimDepth > 0) || ((delimDepth == 0) && !m_input[m_position].isSpace()))) {
2316 switch (m_input[m_position].unicode()) {
2321 arg += m_input[m_position];
2328 if (m_position == startPos || delimDepth >= 0) {
2329 arg += m_input[m_position];
2334 if (!expandMacro(options))
2335 arg += m_input[m_position++];
2338 arg += m_input[m_position];
2342 m_endPosition = m_position;
2343 if ((arg.size() > 1) && (QString(
".,:;!?").indexOf(m_input[m_position - 1]) != -1)
2344 && !arg.endsWith(
"...")) {
2345 arg.truncate(arg.size() - 1);
2348 if (arg.size() > 2 && m_input.mid(m_position - 2, 2) ==
"'s") {
2349 arg.truncate(arg.size() - 2);
2353 return arg.simplified();
2357
2358
2359
2360
2361
2362QString
DocParser::getBracketedArgument()
2366 skipSpacesOrOneEndl();
2367 if (m_position < m_input.size() && m_input[m_position] ==
'[') {
2369 while (m_position < m_input.size() && delimDepth >= 0) {
2370 switch (m_input[m_position].unicode()) {
2373 arg += QLatin1Char(
'[');
2378 if (delimDepth >= 0)
2379 arg += QLatin1Char(
']');
2383 arg += m_input[m_position];
2387 arg += m_input[m_position];
2392 location().warning(QStringLiteral(
"Missing ']'"));
2399
2400
2401
2402
2403
2404QStringList
DocParser::getMacroArguments(
const QString &name,
const Macro ¯o)
2408 if (macro
.numParams == 1 || isLeftBraceAhead()) {
2409 args << getArgument(ArgumentParsingOptions::MacroArguments);
2411 location().warning(QStringLiteral(
"Macro '\\%1' invoked with too few"
2412 " arguments (expected %2, got %3)")
2423
2424
2425
2426
2429 skipSpacesOrOneEndl();
2430 if (m_position + 1 < m_input.size() && m_input[m_position] ==
'\\'
2431 && m_input[m_position + 1].isLetterOrNumber()) {
2434 return getArgument();
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2455 auto lineHasTrailingBackslash = [
this](
bool trailingBackslash) ->
bool {
2456 while (m_position < m_inputLength && m_input[m_position] !=
'\n') {
2457 if (m_input[m_position] ==
'\\' && !trailingBackslash) {
2458 trailingBackslash =
true;
2462 trailingBackslash =
false;
2466 return trailingBackslash;
2469 QString rest_of_line;
2471 bool trailing_backslash{
false };
2472 bool return_simplified_string{
false };
2474 for (qsizetype start_position = m_position; m_position < m_inputLength; ++m_position) {
2475 trailing_backslash = lineHasTrailingBackslash(trailing_backslash);
2477 if (!rest_of_line.isEmpty())
2478 rest_of_line += QLatin1Char(
' ');
2479 rest_of_line += m_input.sliced(start_position, m_position - start_position);
2481 if (trailing_backslash) {
2482 rest_of_line.truncate(rest_of_line.lastIndexOf(
'\\'));
2483 return_simplified_string =
true;
2486 if (m_position < m_inputLength)
2489 if (!trailing_backslash)
2491 start_position = m_position;
2494 if (return_simplified_string)
2495 return rest_of_line.simplified();
2497 return rest_of_line.trimmed();
2501
2502
2503
2504
2505QString
DocParser::getMetaCommandArgument(
const QString &cmdStr)
2509 qsizetype begin = m_position;
2512 while (m_position < m_input.size() && (m_input[m_position] !=
'\n' || parenDepth > 0)) {
2513 if (m_input.at(m_position) ==
'(')
2515 else if (m_input.at(m_position) ==
')')
2517 else if (m_input.at(m_position) ==
'\\' && expandMacro(ArgumentParsingOptions::Default))
2521 if (m_position == m_input.size() && parenDepth > 0) {
2523 location().warning(QStringLiteral(
"Unbalanced parentheses in '%1'").arg(cmdStr));
2526 QString t = m_input.mid(begin, m_position - begin).simplified();
2534 QRegularExpression rx(
"\\\\" + cmdName(endCmd) +
"\\b");
2536 auto match = rx.match(m_input, m_position);
2538 if (!match.hasMatch()) {
2539 location().warning(QStringLiteral(
"Missing '\\%1'").arg(cmdName(endCmd)));
2540 m_position = m_input.size();
2542 qsizetype end = match.capturedStart();
2543 t = m_input.mid(m_position, end - m_position);
2544 m_position = match.capturedEnd();
2549void DocParser::expandArgumentsInString(QString &str,
const QStringList &args)
2556 while (j < str.size()) {
2557 if (str[j] ==
'\\' && j < str.size() - 1 && (paramNo = str[j + 1].digitValue()) >= 1
2558 && paramNo <= args.size()) {
2559 const QString &r = args[paramNo - 1];
2560 str.replace(j, 2, r);
2561 j += qMin(1, r.size());
2569
2570
2571
2572
2573
2574
2577 QString code = untabifyEtc(getUntilEnd(cmd));
2578 expandArgumentsInString(code, argStr.split(
" ", Qt::SkipEmptyParts));
2580 int indent = indentLevel(code);
2581 code = dedent(indent, code);
2584 if (!marker && !m_private->m_topics.isEmpty()
2585 && m_private->m_topics[0].m_topic.startsWith(
"qml")) {
2586 auto qmlMarker = CodeMarker::markerForLanguage(
"QML");
2587 marker = (qmlMarker && qmlMarker->recognizeCode(code)) ? qmlMarker :
nullptr;
2589 if (marker ==
nullptr)
2590 marker = CodeMarker::markerForCode(code);
2591 return marker->markedUpCode(code,
nullptr, location());
2596 qsizetype i = m_position;
2598 while (i < m_inputLength && m_input[i].isSpace()) {
2599 if (m_input[i] ==
'\n')
2609 qsizetype i = m_position;
2611 while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) {
2613 if (m_input[i] ==
'\n')
2617 return numEndl < 2 && i < m_inputLength && m_input[i] ==
'{';
2623 qsizetype i = m_position;
2625 while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) {
2627 if (m_input[i] ==
'\n')
2631 return numEndl < 2 && i < m_inputLength && m_input[i] ==
'[';
2635
2636
2639 while ((m_position < m_input.size()) && m_input[m_position].isSpace()
2640 && (m_input[m_position].unicode() !=
'\n'))
2645
2646
2649 qsizetype firstEndl = -1;
2650 while (m_position < m_input.size() && m_input[m_position].isSpace()) {
2651 QChar ch = m_input[m_position];
2653 if (firstEndl == -1) {
2654 firstEndl = m_position;
2656 m_position = firstEndl;
2666 while (m_position < m_inputLength && m_input[m_position].isSpace())
2670void DocParser::skipToNextPreprocessorCommand()
2672 QRegularExpression rx(
"\\\\(?:" + cmdName(CMD_IF) + QLatin1Char(
'|') + cmdName(CMD_ELSE)
2673 + QLatin1Char(
'|') + cmdName(CMD_ENDIF) +
")\\b");
2674 auto match = rx.match(m_input, m_position + 1);
2676 if (!match.hasMatch())
2677 m_position = m_input.size();
2679 m_position = match.capturedStart();
2732 return cmds[cmd]
.name;
2737 return cmdName(endCmdFor(cmd));
2743 result.reserve(str.size());
2746 for (
const auto &character : str) {
2747 if (character == QLatin1Char(
'\r'))
2749 if (character == QLatin1Char(
'\t')) {
2750 result += &
" "[column % s_tabSize];
2751 column = ((column / s_tabSize) + 1) * s_tabSize;
2754 if (character == QLatin1Char(
'\n')) {
2755 while (result.endsWith(QLatin1Char(
' ')))
2757 result += character;
2761 result += character;
2765 while (result.endsWith(
"\n\n"))
2766 result.truncate(result.size() - 1);
2767 while (result.startsWith(QLatin1Char(
'\n')))
2768 result = result.mid(1);
2775 int minIndent = INT_MAX;
2778 for (
const auto &character : str) {
2779 if (character ==
'\n') {
2782 if (character !=
' ' && column < minIndent)
2798 for (
const auto &character : str) {
2799 if (character == QLatin1Char(
'\n')) {
2803 if (column >= level)
2804 result += character;
2812
2813
2821
2822
2832
2833
2834
2835
2836
2837
2838
2839
2842 static auto take_while = [](QStringView input,
auto predicate) {
2843 QStringView::size_type end{0};
2845 while (end < input.size() &&
std::invoke(predicate, input[end]))
2848 return std::make_tuple(input.sliced(0, end), input.sliced(end));
2851 static auto peek = [](QStringView input, QChar c) {
2852 return !input.empty() && input.first() == c;
2855 static auto skip_one = [](QStringView input) {
2856 if (input.empty())
return std::make_tuple(QStringView{}, input);
2857 else return std::make_tuple(input.sliced(0, 1), input.sliced(1));
2860 static auto enclosed = [](QStringView input, QChar open, QChar close) {
2861 if (!peek(input, open))
return std::make_tuple(QStringView{}, input);
2863 auto [opened, without_open] = skip_one(input);
2864 auto [parsed, remaining] = take_while(without_open, [close](QChar c){
return c != close; });
2866 if (remaining.empty())
return std::make_tuple(QStringView{}, input);
2868 auto [closed, without_close] = skip_one(remaining);
2870 return std::make_tuple(parsed.trimmed(), without_close);
2873 static auto one_of = [](
auto first,
auto second) {
2874 return [first, second](QStringView input) {
2875 auto [parsed, remaining] =
std::invoke(first, input);
2877 if (parsed.empty())
return std::invoke(second, input);
2878 else return std::make_tuple(parsed, remaining);
2882 static auto collect = [](QStringView input,
auto parser) {
2883 QStringList collected{};
2886 auto [parsed, remaining] =
std::invoke(parser, input);
2888 if (parsed.empty())
break;
2889 collected.append(parsed.toString());
2897 static auto spaces = [](QStringView input) {
2898 return take_while(input, [](QChar c){
return c.isSpace(); });
2901 static auto word = [](QStringView input) {
2902 return take_while(input, [](QChar c){
return !c.isSpace(); });
2905 static auto parse_argument = [](QStringView input) {
2906 auto [_, without_spaces] = spaces(input);
2909 [](QStringView input){
return enclosed(input,
'{',
'}'); },
2914 const QString cmd{DocParser::cmdName(CMD_COMPARESWITH)};
2918 QStringList segments = collect(atom->string(), parse_argument);
2920 QString categoryString;
2921 if (!segments.isEmpty())
2922 categoryString = segments.takeFirst();
2923 auto category = comparisonCategoryFromString(categoryString.toStdString());
2925 if (category == ComparisonCategory::None) {
2926 location.warning(u"Invalid argument to \\%1 command: `%2`"_s.arg(cmd, categoryString),
2927 u"Valid arguments are `strong`, `weak`, `partial`, or `equality`."_s);
2931 if (segments.isEmpty()) {
2932 location.warning(u"Missing argument to \\%1 command."_s.arg(cmd),
2933 u"Provide at least one type name, or a list of types separated by spaces."_s);
2938 segments.removeDuplicates();
2939 atom->setString(segments.join(QLatin1Char(
';')));
2943 priv->m_metacommandsUsed.insert(cmd);
2946 const auto end{priv
->extra->m_comparesWithMap.cend()};
2947 priv
->extra->m_comparesWithMap.insert(end, category, text);
#define ATOM_FORMATTING_TELETYPE
#define ATOM_FORMATTING_UNDERLINE
#define ATOM_FORMATTING_NOTRANSLATE
#define ATOM_FORMATTING_SPAN
#define ATOM_FORMATTING_SUBSCRIPT
#define ATOM_FORMATTING_BOLD
#define ATOM_FORMATTING_TRADEMARK
#define ATOM_FORMATTING_ITALIC
#define ATOM_FORMATTING_LINK
#define ATOM_FORMATTING_SUPERSCRIPT
#define ATOM_FORMATTING_INDEX
#define ATOM_FORMATTING_UICONTROL
#define ATOM_FORMATTING_PARAMETER
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
void chopString()
\also string()
The Config class contains the configuration variables for controlling how qdoc produces documentation...
static QStringList s_ignoreWords
void parse(const QString &source, DocPrivate *docPrivate, const QSet< QString > &metaCommandSet, const QSet< QString > &possibleTopics)
Parse the source string to build a Text data structure in docPrivate.
static int endCmdFor(int cmd)
static void initialize(const Config &config, FileResolver &file_resolver)
void addAlso(const Text &also)
CommandMap m_metaCommandMap
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
The Location class provides a way to mark a location in a file.
static Text subText(const Atom *begin, const Atom *end=nullptr)
Text splitAtFirst(Atom::AtomType start)
Splits the current Text from start to end into a new Text object.
#define CONFIG_IGNOREWORDS
#define CONFIG_QUOTINGINFORMATION
std::pair< QString, QString > ArgPair
static void warnAboutEmptyOrPreexistingTarget(const Location &location, const QString &duplicateDefinition, const QString &cmdString, const QString &previousDefinition)
bool is_formatting_command
static void processComparesWithCommand(DocPrivate *priv, const Location &location)
static QString cleanLink(const QString &link)
QHash_QString_Macro macroHash
QHash_QString_int cmdHash
Simple structure used by the Doc and DocParser classes.