diff options
Diffstat (limited to 'src/qdoc/docparser.cpp')
-rw-r--r-- | src/qdoc/docparser.cpp | 2489 |
1 files changed, 0 insertions, 2489 deletions
diff --git a/src/qdoc/docparser.cpp b/src/qdoc/docparser.cpp deleted file mode 100644 index 1294f5d7a..000000000 --- a/src/qdoc/docparser.cpp +++ /dev/null @@ -1,2489 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "docparser.h" - -#include "codemarker.h" -#include "doc.h" -#include "docprivate.h" -#include "editdistance.h" -#include "macro.h" -#include "openedlist.h" -#include "tokenizer.h" - -#include <QtCore/qfile.h> -#include <QtCore/qregularexpression.h> -#include <QtCore/qtextstream.h> - -#include <cctype> -#include <climits> - -QT_BEGIN_NAMESPACE - -DocUtilities &DocParser::s_utilities = DocUtilities::instance(); - -enum { - CMD_A, - CMD_ANNOTATEDLIST, - CMD_B, - CMD_BADCODE, - CMD_BOLD, - CMD_BR, - CMD_BRIEF, - CMD_C, - CMD_CAPTION, - CMD_CODE, - CMD_CODELINE, - CMD_DIV, - CMD_DOTS, - CMD_E, - CMD_ELSE, - CMD_ENDCODE, - CMD_ENDDIV, - CMD_ENDFOOTNOTE, - CMD_ENDIF, - CMD_ENDLEGALESE, - CMD_ENDLINK, - CMD_ENDLIST, - CMD_ENDMAPREF, - CMD_ENDOMIT, - CMD_ENDQUOTATION, - CMD_ENDRAW, - CMD_ENDSECTION1, - CMD_ENDSECTION2, - CMD_ENDSECTION3, - CMD_ENDSECTION4, - CMD_ENDSIDEBAR, - CMD_ENDTABLE, - CMD_FOOTNOTE, - CMD_GENERATELIST, - CMD_HEADER, - CMD_HR, - CMD_I, - CMD_IF, - CMD_IMAGE, - CMD_IMPORTANT, - CMD_INCLUDE, - CMD_INLINEIMAGE, - CMD_INDEX, - CMD_INPUT, - CMD_KEYWORD, - CMD_L, - CMD_LEGALESE, - CMD_LI, - CMD_LINK, - CMD_LIST, - CMD_META, - CMD_NEWCODE, - CMD_NOTE, - CMD_O, - CMD_OLDCODE, - CMD_OMIT, - CMD_OMITVALUE, - CMD_OVERLOAD, - CMD_PRINTLINE, - CMD_PRINTTO, - CMD_PRINTUNTIL, - CMD_QUOTATION, - CMD_QUOTEFILE, - CMD_QUOTEFROMFILE, - CMD_QUOTEFUNCTION, - CMD_RAW, - CMD_ROW, - CMD_SA, - CMD_SECTION1, - CMD_SECTION2, - CMD_SECTION3, - CMD_SECTION4, - CMD_SIDEBAR, - CMD_SINCELIST, - CMD_SKIPLINE, - CMD_SKIPTO, - CMD_SKIPUNTIL, - CMD_SNIPPET, - CMD_SPAN, - CMD_SUB, - CMD_SUP, - CMD_TABLE, - CMD_TABLEOFCONTENTS, - CMD_TARGET, - CMD_TT, - CMD_UICONTROL, - CMD_UNDERLINE, - CMD_UNICODE, - CMD_VALUE, - CMD_WARNING, - CMD_QML, - CMD_ENDQML, - CMD_CPP, - CMD_ENDCPP, - CMD_QMLTEXT, - CMD_ENDQMLTEXT, - CMD_CPPTEXT, - CMD_ENDCPPTEXT, - CMD_JS, - CMD_ENDJS, - NOT_A_CMD -}; - -static struct -{ - const char *english; - int no; - QString *alias; -} cmds[] = { { "a", CMD_A, nullptr }, - { "annotatedlist", CMD_ANNOTATEDLIST, nullptr }, - { "b", CMD_B, nullptr }, - { "badcode", CMD_BADCODE, nullptr }, - { "bold", CMD_BOLD, nullptr }, - { "br", CMD_BR, nullptr }, - { "brief", CMD_BRIEF, nullptr }, - { "c", CMD_C, nullptr }, - { "caption", CMD_CAPTION, nullptr }, - { "code", CMD_CODE, nullptr }, - { "codeline", CMD_CODELINE, nullptr }, - { "div", CMD_DIV, nullptr }, - { "dots", CMD_DOTS, nullptr }, - { "e", CMD_E, nullptr }, - { "else", CMD_ELSE, nullptr }, - { "endcode", CMD_ENDCODE, nullptr }, - { "enddiv", CMD_ENDDIV, nullptr }, - { "endfootnote", CMD_ENDFOOTNOTE, nullptr }, - { "endif", CMD_ENDIF, nullptr }, - { "endlegalese", CMD_ENDLEGALESE, nullptr }, - { "endlink", CMD_ENDLINK, nullptr }, - { "endlist", CMD_ENDLIST, nullptr }, - { "endmapref", CMD_ENDMAPREF, nullptr }, - { "endomit", CMD_ENDOMIT, nullptr }, - { "endquotation", CMD_ENDQUOTATION, nullptr }, - { "endraw", CMD_ENDRAW, nullptr }, - { "endsection1", CMD_ENDSECTION1, nullptr }, // ### don't document for now - { "endsection2", CMD_ENDSECTION2, nullptr }, // ### don't document for now - { "endsection3", CMD_ENDSECTION3, nullptr }, // ### don't document for now - { "endsection4", CMD_ENDSECTION4, nullptr }, // ### don't document for now - { "endsidebar", CMD_ENDSIDEBAR, nullptr }, - { "endtable", CMD_ENDTABLE, nullptr }, - { "footnote", CMD_FOOTNOTE, nullptr }, - { "generatelist", CMD_GENERATELIST, nullptr }, - { "header", CMD_HEADER, nullptr }, - { "hr", CMD_HR, nullptr }, - { "i", CMD_I, nullptr }, - { "if", CMD_IF, nullptr }, - { "image", CMD_IMAGE, nullptr }, - { "important", CMD_IMPORTANT, nullptr }, - { "include", CMD_INCLUDE, nullptr }, - { "inlineimage", CMD_INLINEIMAGE, nullptr }, - { "index", CMD_INDEX, nullptr }, // ### don't document for now - { "input", CMD_INPUT, nullptr }, - { "keyword", CMD_KEYWORD, nullptr }, - { "l", CMD_L, nullptr }, - { "legalese", CMD_LEGALESE, nullptr }, - { "li", CMD_LI, nullptr }, - { "link", CMD_LINK, nullptr }, - { "list", CMD_LIST, nullptr }, - { "meta", CMD_META, nullptr }, - { "newcode", CMD_NEWCODE, nullptr }, - { "note", CMD_NOTE, nullptr }, - { "o", CMD_O, nullptr }, - { "oldcode", CMD_OLDCODE, nullptr }, - { "omit", CMD_OMIT, nullptr }, - { "omitvalue", CMD_OMITVALUE, nullptr }, - { "overload", CMD_OVERLOAD, nullptr }, - { "printline", CMD_PRINTLINE, nullptr }, - { "printto", CMD_PRINTTO, nullptr }, - { "printuntil", CMD_PRINTUNTIL, nullptr }, - { "quotation", CMD_QUOTATION, nullptr }, - { "quotefile", CMD_QUOTEFILE, nullptr }, - { "quotefromfile", CMD_QUOTEFROMFILE, nullptr }, - { "quotefunction", CMD_QUOTEFUNCTION, nullptr }, - { "raw", CMD_RAW, nullptr }, - { "row", CMD_ROW, nullptr }, - { "sa", CMD_SA, nullptr }, - { "section1", CMD_SECTION1, nullptr }, - { "section2", CMD_SECTION2, nullptr }, - { "section3", CMD_SECTION3, nullptr }, - { "section4", CMD_SECTION4, nullptr }, - { "sidebar", CMD_SIDEBAR, nullptr }, - { "sincelist", CMD_SINCELIST, nullptr }, - { "skipline", CMD_SKIPLINE, nullptr }, - { "skipto", CMD_SKIPTO, nullptr }, - { "skipuntil", CMD_SKIPUNTIL, nullptr }, - { "snippet", CMD_SNIPPET, nullptr }, - { "span", CMD_SPAN, nullptr }, - { "sub", CMD_SUB, nullptr }, - { "sup", CMD_SUP, nullptr }, - { "table", CMD_TABLE, nullptr }, - { "tableofcontents", CMD_TABLEOFCONTENTS, nullptr }, - { "target", CMD_TARGET, nullptr }, - { "tt", CMD_TT, nullptr }, - { "uicontrol", CMD_UICONTROL, nullptr }, - { "underline", CMD_UNDERLINE, nullptr }, - { "unicode", CMD_UNICODE, nullptr }, - { "value", CMD_VALUE, nullptr }, - { "warning", CMD_WARNING, nullptr }, - { "qml", CMD_QML, nullptr }, - { "endqml", CMD_ENDQML, nullptr }, - { "cpp", CMD_CPP, nullptr }, - { "endcpp", CMD_ENDCPP, nullptr }, - { "qmltext", CMD_QMLTEXT, nullptr }, - { "endqmltext", CMD_ENDQMLTEXT, nullptr }, - { "cpptext", CMD_CPPTEXT, nullptr }, - { "endcpptext", CMD_ENDCPPTEXT, nullptr }, - { "js", CMD_JS, nullptr }, - { "endjs", CMD_ENDJS, nullptr }, - { nullptr, 0, nullptr } }; - -int DocParser::s_tabSize; -QStringList DocParser::s_exampleFiles; -QStringList DocParser::s_exampleDirs; -QStringList DocParser::s_sourceFiles; -QStringList DocParser::s_sourceDirs; -QStringList DocParser::s_ignoreWords; -bool DocParser::s_quoting = false; - -static QString cleanLink(const QString &link) -{ - qsizetype colonPos = link.indexOf(':'); - if ((colonPos == -1) || (!link.startsWith("file:") && !link.startsWith("mailto:"))) - return link; - return link.mid(colonPos + 1).simplified(); -} - -void DocParser::initialize(const Config &config) -{ - s_tabSize = config.getInt(CONFIG_TABSIZE); - s_exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES); - s_exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); - s_sourceFiles = config.getCanonicalPathList(CONFIG_SOURCES); - s_sourceDirs = config.getCanonicalPathList(CONFIG_SOURCEDIRS); - s_ignoreWords = config.getStringList(CONFIG_IGNOREWORDS); - - int i = 0; - while (cmds[i].english) { - cmds[i].alias = new QString(Doc::alias(cmds[i].english)); - s_utilities.cmdHash.insert(*cmds[i].alias, cmds[i].no); - - if (cmds[i].no != i) - Location::internalError(QStringLiteral("command %1 missing").arg(i)); - ++i; - } - - // If any of the formats define quotinginformation, activate quoting - DocParser::s_quoting = config.getBool(CONFIG_QUOTINGINFORMATION); - for (const auto &format : config.getOutputFormats()) - DocParser::s_quoting = DocParser::s_quoting - || config.getBool(format + Config::dot + CONFIG_QUOTINGINFORMATION); -} - -void DocParser::terminate() -{ - s_exampleFiles.clear(); - s_exampleDirs.clear(); - s_sourceFiles.clear(); - s_sourceDirs.clear(); - - int i = 0; - while (cmds[i].english) { - delete cmds[i].alias; - cmds[i].alias = nullptr; - ++i; - } -} - -/*! - Parse the \a source string to build a Text data structure - in \a docPrivate. The Text data structure is a linked list - of Atoms. - - \a metaCommandSet is the set of metacommands that may be - found in \a source. These metacommands are not markup text - commands. They are topic commands and related metacommands. - */ -void DocParser::parse(const QString &source, DocPrivate *docPrivate, - const QSet<QString> &metaCommandSet, const QSet<QString> &possibleTopics) -{ - m_input = source; - m_position = 0; - m_inputLength = m_input.length(); - m_cachedLocation = docPrivate->m_start_loc; - m_cachedPosition = 0; - m_private = docPrivate; - m_private->m_text << Atom::Nop; - m_private->m_topics.clear(); - - m_paragraphState = OutsideParagraph; - m_inTableHeader = false; - m_inTableRow = false; - m_inTableItem = false; - m_indexStartedParagraph = false; - m_pendingParagraphLeftType = Atom::Nop; - m_pendingParagraphRightType = Atom::Nop; - - m_braceDepth = 0; - m_currentSection = Doc::NoSection; - m_openedCommands.push(CMD_OMIT); - m_quoter.reset(); - - CodeMarker *marker = nullptr; - Atom *currentLinkAtom = nullptr; - QString p1, p2; - QStack<bool> preprocessorSkipping; - int numPreprocessorSkipping = 0; - - while (m_position < m_inputLength) { - QChar ch = m_input.at(m_position); - - switch (ch.unicode()) { - case '\\': { - QString cmdStr; - m_backslashPosition = m_position; - ++m_position; - while (m_position < m_inputLength) { - ch = m_input.at(m_position); - if (ch.isLetterOrNumber()) { - cmdStr += ch; - ++m_position; - } else { - break; - } - } - m_endPosition = m_position; - if (cmdStr.isEmpty()) { - if (m_position < m_inputLength) { - enterPara(); - if (m_input.at(m_position).isSpace()) { - skipAllSpaces(); - appendChar(QLatin1Char(' ')); - } else { - appendChar(m_input.at(m_position++)); - } - } - } else { - // Ignore quoting atoms to make appendToCode() - // append to the correct atom. - if (!s_quoting || !isQuote(m_private->m_text.lastAtom())) - m_lastAtom = m_private->m_text.lastAtom(); - - int cmd = s_utilities.cmdHash.value(cmdStr, NOT_A_CMD); - switch (cmd) { - case CMD_A: - enterPara(); - p1 = getArgument(); - append(Atom::FormattingLeft, ATOM_FORMATTING_PARAMETER); - append(Atom::String, p1); - append(Atom::FormattingRight, ATOM_FORMATTING_PARAMETER); - m_private->m_params.insert(p1); - break; - case CMD_BADCODE: - leavePara(); - append(Atom::CodeBad, - getCode(CMD_BADCODE, marker, getMetaCommandArgument(cmdStr))); - break; - case CMD_BR: - enterPara(); - append(Atom::BR); - break; - case CMD_BOLD: - location().warning(QStringLiteral("'\\bold' is deprecated. Use '\\b'")); - Q_FALLTHROUGH(); - case CMD_B: - startFormat(ATOM_FORMATTING_BOLD, cmd); - break; - case CMD_BRIEF: - leavePara(); - enterPara(Atom::BriefLeft, Atom::BriefRight); - break; - case CMD_C: - enterPara(); - p1 = untabifyEtc(getArgument(true)); - marker = CodeMarker::markerForCode(p1); - append(Atom::C, marker->markedUpCode(p1, nullptr, location())); - break; - case CMD_CAPTION: - leavePara(); - enterPara(Atom::CaptionLeft, Atom::CaptionRight); - break; - case CMD_CODE: - leavePara(); - append(Atom::Code, getCode(CMD_CODE, nullptr, getMetaCommandArgument(cmdStr))); - break; - case CMD_QML: - leavePara(); - append(Atom::Qml, - getCode(CMD_QML, CodeMarker::markerForLanguage(QLatin1String("QML")), - getMetaCommandArgument(cmdStr))); - break; - case CMD_QMLTEXT: - append(Atom::QmlText); - break; - case CMD_JS: - leavePara(); - append(Atom::JavaScript, - getCode(CMD_JS, - CodeMarker::markerForLanguage(QLatin1String("JavaScript")), - getMetaCommandArgument(cmdStr))); - break; - case CMD_DIV: - leavePara(); - p1 = getArgument(true); - append(Atom::DivLeft, p1); - m_openedCommands.push(cmd); - break; - case CMD_ENDDIV: - leavePara(); - append(Atom::DivRight); - closeCommand(cmd); - break; - case CMD_CODELINE: - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " "); - } - if (isCode(m_lastAtom) && m_lastAtom->string().endsWith("\n\n")) - m_lastAtom->chopString(); - appendToCode("\n"); - break; - case CMD_DOTS: { - QString arg = getOptionalArgument(); - if (arg.isEmpty()) - arg = "4"; - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, arg); - } - if (isCode(m_lastAtom) && m_lastAtom->string().endsWith("\n\n")) - m_lastAtom->chopString(); - - int indent = arg.toInt(); - for (int i = 0; i < indent; ++i) - appendToCode(" "); - appendToCode("...\n"); - break; - } - case CMD_ELSE: - if (!preprocessorSkipping.empty()) { - if (preprocessorSkipping.top()) { - --numPreprocessorSkipping; - } else { - ++numPreprocessorSkipping; - } - preprocessorSkipping.top() = !preprocessorSkipping.top(); - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } else { - location().warning( - QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ELSE))); - } - break; - case CMD_ENDCODE: - closeCommand(cmd); - break; - case CMD_ENDQML: - closeCommand(cmd); - break; - case CMD_ENDQMLTEXT: - append(Atom::EndQmlText); - break; - case CMD_ENDJS: - closeCommand(cmd); - break; - case CMD_ENDFOOTNOTE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::FootnoteRight); - } - break; - case CMD_ENDIF: - if (preprocessorSkipping.count() > 0) { - if (preprocessorSkipping.pop()) - --numPreprocessorSkipping; - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } else { - location().warning( - QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ENDIF))); - } - break; - case CMD_ENDLEGALESE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::LegaleseRight); - } - break; - case CMD_ENDLINK: - if (closeCommand(cmd)) { - if (m_private->m_text.lastAtom()->type() == Atom::String - && m_private->m_text.lastAtom()->string().endsWith(QLatin1Char(' '))) - m_private->m_text.lastAtom()->chopString(); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - break; - case CMD_ENDLIST: - if (closeCommand(cmd)) { - leavePara(); - if (m_openedLists.top().isStarted()) { - append(Atom::ListItemRight, m_openedLists.top().styleString()); - append(Atom::ListRight, m_openedLists.top().styleString()); - } - m_openedLists.pop(); - } - break; - case CMD_ENDOMIT: - closeCommand(cmd); - break; - case CMD_ENDQUOTATION: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::QuotationRight); - } - break; - case CMD_ENDRAW: - location().warning( - QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ENDRAW))); - break; - case CMD_ENDSECTION1: - endSection(Doc::Section1, cmd); - break; - case CMD_ENDSECTION2: - endSection(Doc::Section2, cmd); - break; - case CMD_ENDSECTION3: - endSection(Doc::Section3, cmd); - break; - case CMD_ENDSECTION4: - endSection(Doc::Section4, cmd); - break; - case CMD_ENDSIDEBAR: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::SidebarRight); - } - break; - case CMD_ENDTABLE: - if (closeCommand(cmd)) { - leaveTableRow(); - append(Atom::TableRight); - } - break; - case CMD_FOOTNOTE: - if (openCommand(cmd)) { - enterPara(); - append(Atom::FootnoteLeft); - } - break; - case CMD_ANNOTATEDLIST: - append(Atom::AnnotatedList, getArgument()); - break; - case CMD_SINCELIST: - append(Atom::SinceList, getRestOfLine().simplified()); - break; - case CMD_GENERATELIST: { - QString arg1 = getArgument(); - QString arg2 = getOptionalArgument(); - if (!arg2.isEmpty()) - arg1 += " " + arg2; - append(Atom::GeneratedList, arg1); - } break; - case CMD_HEADER: - if (m_openedCommands.top() == CMD_TABLE) { - leaveTableRow(); - append(Atom::TableHeaderLeft); - m_inTableHeader = true; - } else { - if (m_openedCommands.contains(CMD_TABLE)) - location().warning(QStringLiteral("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_HEADER), - cmdName(m_openedCommands.top()))); - else - location().warning( - QStringLiteral("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_HEADER), cmdName(CMD_TABLE))); - } - break; - case CMD_I: - location().warning(QStringLiteral( - "'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item")); - Q_FALLTHROUGH(); - case CMD_E: - startFormat(ATOM_FORMATTING_ITALIC, cmd); - break; - case CMD_HR: - leavePara(); - append(Atom::HR); - break; - case CMD_IF: - preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine())); - if (preprocessorSkipping.top()) - ++numPreprocessorSkipping; - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - break; - case CMD_IMAGE: - leaveValueList(); - append(Atom::Image, getArgument()); - append(Atom::ImageText, getRestOfLine()); - break; - case CMD_IMPORTANT: - leavePara(); - enterPara(Atom::ImportantLeft, Atom::ImportantRight); - break; - case CMD_INCLUDE: - case CMD_INPUT: { - QString fileName = getArgument(); - QString identifier = getRestOfLine(); - include(fileName, identifier); - break; - } - case CMD_INLINEIMAGE: - enterPara(); - append(Atom::InlineImage, getArgument()); - append(Atom::ImageText, getRestOfLine()); - append(Atom::String, " "); - break; - case CMD_INDEX: - if (m_paragraphState == OutsideParagraph) { - enterPara(); - m_indexStartedParagraph = true; - } else { - const Atom *last = m_private->m_text.lastAtom(); - if (m_indexStartedParagraph - && (last->type() != Atom::FormattingRight - || last->string() != ATOM_FORMATTING_INDEX)) - m_indexStartedParagraph = false; - } - startFormat(ATOM_FORMATTING_INDEX, cmd); - break; - case CMD_KEYWORD: - insertTarget(getRestOfLine(), true); - break; - case CMD_L: - enterPara(); - if (isLeftBracketAhead()) - p2 = getBracketedArgument(); - if (isLeftBraceAhead()) { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(m_private->m_text.lastAtom()->error().isEmpty())) - location().warning( - QStringLiteral( - "Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(m_private->m_text.lastAtom()->error())); - if (isLeftBraceAhead()) { - currentLinkAtom = m_private->m_text.lastAtom(); - startFormat(ATOM_FORMATTING_LINK, cmd); - } else { - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - } else { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(m_private->m_text.lastAtom()->error().isEmpty())) - location().warning( - QStringLiteral( - "Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(m_private->m_text.lastAtom()->error())); - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - p2.clear(); - break; - case CMD_LEGALESE: - leavePara(); - if (openCommand(cmd)) - append(Atom::LegaleseLeft); - docPrivate->m_hasLegalese = true; - break; - case CMD_LINK: - if (openCommand(cmd)) { - enterPara(); - p1 = getArgument(); - append(p1); - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - skipSpacesOrOneEndl(); - } - break; - case CMD_LIST: - if (openCommand(cmd)) { - leavePara(); - m_openedLists.push(OpenedList(location(), getOptionalArgument())); - } - break; - case CMD_META: - m_private->constructExtra(); - p1 = getArgument(); - m_private->extra->m_metaMap.insert(p1, getArgument()); - break; - case CMD_NEWCODE: - location().warning( - QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE))); - break; - case CMD_NOTE: - leavePara(); - enterPara(Atom::NoteLeft, Atom::NoteRight); - break; - case CMD_O: - location().warning(QStringLiteral("'\\o' is deprecated. Use '\\li'")); - Q_FALLTHROUGH(); - case CMD_LI: - leavePara(); - if (m_openedCommands.top() == CMD_LIST) { - if (m_openedLists.top().isStarted()) - append(Atom::ListItemRight, m_openedLists.top().styleString()); - else - append(Atom::ListLeft, m_openedLists.top().styleString()); - m_openedLists.top().next(); - append(Atom::ListItemNumber, m_openedLists.top().numberString()); - append(Atom::ListItemLeft, m_openedLists.top().styleString()); - enterPara(); - } else if (m_openedCommands.top() == CMD_TABLE) { - p1 = "1,1"; - p2.clear(); - if (isLeftBraceAhead()) { - p1 = getArgument(); - if (isLeftBraceAhead()) - p2 = getArgument(); - } - - if (!m_inTableHeader && !m_inTableRow) { - location().warning( - QStringLiteral("Missing '\\%1' or '\\%2' before '\\%3'") - .arg(cmdName(CMD_HEADER), cmdName(CMD_ROW), - cmdName(CMD_LI))); - append(Atom::TableRowLeft); - m_inTableRow = true; - } else if (m_inTableItem) { - append(Atom::TableItemRight); - m_inTableItem = false; - } - - append(Atom::TableItemLeft, p1, p2); - m_inTableItem = true; - } else - location().warning( - QStringLiteral("Command '\\%1' outside of '\\%2' and '\\%3'") - .arg(cmdName(cmd), cmdName(CMD_LIST), cmdName(CMD_TABLE))); - break; - case CMD_OLDCODE: - leavePara(); - append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); - append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); - break; - case CMD_OMIT: - getUntilEnd(cmd); - break; - case CMD_OMITVALUE: { - p1 = getArgument(); - if (!m_private->m_enumItemList.contains(p1)) - m_private->m_enumItemList.append(p1); - if (!m_private->m_omitEnumItemList.contains(p1)) - m_private->m_omitEnumItemList.append(p1); - skipSpacesOrOneEndl(); - // Skip potential description paragraph - while (m_position < m_inputLength && !isBlankLine()) { - skipAllSpaces(); - if (qsizetype pos = m_position; pos < m_input.size() - && m_input.at(pos++).unicode() == '\\') { - QString nextCmdStr; - while (pos < m_input.size() && m_input[pos].isLetterOrNumber()) - nextCmdStr += m_input[pos++]; - int nextCmd = s_utilities.cmdHash.value(cmdStr, NOT_A_CMD); - if (nextCmd == cmd || nextCmd == CMD_VALUE) - break; - } - getRestOfLine(); - } - break; - } - case CMD_PRINTLINE: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(m_quoter.quoteLine(location(), cmdStr, rest)); - break; - } - case CMD_PRINTTO: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(m_quoter.quoteTo(location(), cmdStr, rest)); - break; - } - case CMD_PRINTUNTIL: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(m_quoter.quoteUntil(location(), cmdStr, rest)); - break; - } - case CMD_QUOTATION: - if (openCommand(cmd)) { - leavePara(); - append(Atom::QuotationLeft); - } - break; - case CMD_QUOTEFILE: { - leavePara(); - QString fileName = getArgument(); - Doc::quoteFromFile(location(), m_quoter, fileName); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, fileName); - } - append(Atom::Code, m_quoter.quoteTo(location(), cmdStr, QString())); - m_quoter.reset(); - break; - } - case CMD_QUOTEFROMFILE: { - leavePara(); - QString arg = getArgument(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, arg); - } - Doc::quoteFromFile(location(), m_quoter, arg); - break; - } - case CMD_QUOTEFUNCTION: { - leavePara(); - marker = quoteFromFile(); - p1 = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, slashed(marker->functionEndRegExp(p1))); - } - m_quoter.quoteTo(location(), cmdStr, slashed(marker->functionBeginRegExp(p1))); - append(Atom::Code, - m_quoter.quoteUntil(location(), cmdStr, - slashed(marker->functionEndRegExp(p1)))); - m_quoter.reset(); - break; - } - case CMD_RAW: - leavePara(); - p1 = getRestOfLine(); - if (p1.isEmpty()) - location().warning(QStringLiteral("Missing format name after '\\%1'") - .arg(cmdName(CMD_RAW))); - append(Atom::FormatIf, p1); - append(Atom::RawString, untabifyEtc(getUntilEnd(cmd))); - append(Atom::FormatElse); - append(Atom::FormatEndif); - break; - case CMD_ROW: - if (m_openedCommands.top() == CMD_TABLE) { - p1.clear(); - if (isLeftBraceAhead()) - p1 = getArgument(true); - leaveTableRow(); - append(Atom::TableRowLeft, p1); - m_inTableRow = true; - } else { - if (m_openedCommands.contains(CMD_TABLE)) - location().warning(QStringLiteral("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_ROW), - cmdName(m_openedCommands.top()))); - else - location().warning(QStringLiteral("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_ROW), cmdName(CMD_TABLE))); - } - break; - case CMD_SA: - parseAlso(); - break; - case CMD_SECTION1: - startSection(Doc::Section1, cmd); - break; - case CMD_SECTION2: - startSection(Doc::Section2, cmd); - break; - case CMD_SECTION3: - startSection(Doc::Section3, cmd); - break; - case CMD_SECTION4: - startSection(Doc::Section4, cmd); - break; - case CMD_SIDEBAR: - if (openCommand(cmd)) { - leavePara(); - append(Atom::SidebarLeft); - } - break; - case CMD_SKIPLINE: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - m_quoter.quoteLine(location(), cmdStr, rest); - break; - } - case CMD_SKIPTO: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - m_quoter.quoteTo(location(), cmdStr, rest); - break; - } - case CMD_SKIPUNTIL: { - leavePara(); - QString rest = getRestOfLine(); - if (s_quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - m_quoter.quoteUntil(location(), cmdStr, rest); - break; - } - case CMD_SPAN: - p1 = ATOM_FORMATTING_SPAN + getArgument(true); - startFormat(p1, cmd); - break; - case CMD_SNIPPET: { - leavePara(); - QString snippet = getArgument(); - QString identifier = getRestOfLine(); - if (s_quoting) { - append(Atom::SnippetCommand, cmdStr); - append(Atom::SnippetLocation, snippet); - append(Atom::SnippetIdentifier, identifier); - } - marker = Doc::quoteFromFile(location(), m_quoter, snippet); - appendToCode(m_quoter.quoteSnippet(location(), identifier), marker->atomType()); - break; - } - case CMD_SUB: - startFormat(ATOM_FORMATTING_SUBSCRIPT, cmd); - break; - case CMD_SUP: - startFormat(ATOM_FORMATTING_SUPERSCRIPT, cmd); - break; - case CMD_TABLE: - p1 = getOptionalArgument(); - p2 = getOptionalArgument(); - if (openCommand(cmd)) { - leavePara(); - append(Atom::TableLeft, p1, p2); - m_inTableHeader = false; - m_inTableRow = false; - m_inTableItem = false; - } - break; - case CMD_TABLEOFCONTENTS: - p1 = "1"; - if (isLeftBraceAhead()) - p1 = getArgument(); - p1 += QLatin1Char(','); - p1 += QString::number((int)getSectioningUnit()); - append(Atom::TableOfContents, p1); - break; - case CMD_TARGET: - insertTarget(getRestOfLine(), false); - break; - case CMD_TT: - startFormat(ATOM_FORMATTING_TELETYPE, cmd); - break; - case CMD_UICONTROL: - startFormat(ATOM_FORMATTING_UICONTROL, cmd); - break; - case CMD_UNDERLINE: - startFormat(ATOM_FORMATTING_UNDERLINE, cmd); - break; - case CMD_UNICODE: { - enterPara(); - p1 = getArgument(); - bool ok; - uint unicodeChar = p1.toUInt(&ok, 0); - if (!ok || (unicodeChar == 0x0000) || (unicodeChar > 0xFFFE)) - location().warning( - QStringLiteral("Invalid Unicode character '%1' specified with '%2'") - .arg(p1, cmdName(CMD_UNICODE))); - else - append(Atom::String, QChar(unicodeChar)); - break; - } - case CMD_VALUE: - leaveValue(); - if (m_openedLists.top().style() == OpenedList::Value) { - QString p2; - p1 = getArgument(); - if (p1.startsWith(QLatin1String("[since ")) - && p1.endsWith(QLatin1String("]"))) { - p2 = p1.mid(7, p1.length() - 8); - p1 = getArgument(); - } - if (!m_private->m_enumItemList.contains(p1)) - m_private->m_enumItemList.append(p1); - - m_openedLists.top().next(); - append(Atom::ListTagLeft, ATOM_LIST_VALUE); - append(Atom::String, p1); - append(Atom::ListTagRight, ATOM_LIST_VALUE); - if (!p2.isEmpty()) { - append(Atom::SinceTagLeft, ATOM_LIST_VALUE); - append(Atom::String, p2); - append(Atom::SinceTagRight, ATOM_LIST_VALUE); - } - append(Atom::ListItemLeft, ATOM_LIST_VALUE); - - skipSpacesOrOneEndl(); - if (isBlankLine()) - append(Atom::Nop); - } else { - // ### unknown problems - } - break; - case CMD_WARNING: - leavePara(); - enterPara(Atom::WarningLeft, Atom::WarningRight); - break; - case CMD_OVERLOAD: - m_private->m_metacommandsUsed.insert(cmdStr); - p1.clear(); - if (!isBlankLine()) - p1 = getRestOfLine(); - if (!p1.isEmpty()) { - append(Atom::ParaLeft); - append(Atom::String, "This function overloads "); - append(Atom::AutoLink, p1); - append(Atom::String, "."); - append(Atom::ParaRight); - } else { - append(Atom::ParaLeft); - append(Atom::String, "This is an overloaded function."); - append(Atom::ParaRight); - p1 = getMetaCommandArgument(cmdStr); - } - m_private->m_metaCommandMap[cmdStr].append(ArgPair(p1, QString())); - break; - case NOT_A_CMD: - if (metaCommandSet.contains(cmdStr)) { - QString arg; - QString bracketedArg; - m_private->m_metacommandsUsed.insert(cmdStr); - if (isLeftBracketAhead()) - bracketedArg = getBracketedArgument(); - // Force a linebreak after \obsolete or \deprecated - // to treat potential arguments as a new text paragraph. - if (m_position < m_inputLength - && (cmdStr == QLatin1String("obsolete") - || cmdStr == QLatin1String("deprecated"))) - m_input[m_position] = '\n'; - else - arg = getMetaCommandArgument(cmdStr); - m_private->m_metaCommandMap[cmdStr].append(ArgPair(arg, bracketedArg)); - if (possibleTopics.contains(cmdStr)) { - if (!cmdStr.endsWith(QLatin1String("propertygroup"))) - m_private->m_topics.append(Topic(cmdStr, arg)); - } - } else if (s_utilities.macroHash.contains(cmdStr)) { - const Macro ¯o = s_utilities.macroHash.value(cmdStr); - int numPendingFi = 0; - int numFormatDefs = 0; - QString matchExpr; - for (auto it = macro.m_otherDefs.constBegin(); - it != macro.m_otherDefs.constEnd(); ++it) { - if (it.key() == "match") { - matchExpr = it.value(); - } else { - append(Atom::FormatIf, it.key()); - expandMacro(cmdStr, *it, macro.numParams); - ++numFormatDefs; - if (it == macro.m_otherDefs.constEnd()) { - append(Atom::FormatEndif); - } else { - append(Atom::FormatElse); - ++numPendingFi; - } - } - } - while (numPendingFi-- > 0) - append(Atom::FormatEndif); - - if (!macro.m_defaultDef.isEmpty()) { - if (numFormatDefs > 0) { - macro.m_defaultDefLocation.warning( - QStringLiteral("Macro cannot have both " - "format-specific and qdoc-" - "syntax definitions")); - } else { - QString expanded = expandMacroToString(cmdStr, macro.m_defaultDef, - macro.numParams, matchExpr); - m_input.replace(m_backslashPosition, - m_endPosition - m_backslashPosition, expanded); - m_inputLength = m_input.length(); - m_position = m_backslashPosition; - } - } - } else if (isAutoLinkString(cmdStr)) { - appendWord(cmdStr); - } else { - if (!cmdStr.endsWith("propertygroup")) { - // The QML and JS property group commands are no longer required - // for grouping QML and JS properties. They are allowed but ignored. - location().warning(QStringLiteral("Unknown command '\\%1'").arg(cmdStr), - detailsUnknownCommand(metaCommandSet, cmdStr)); - } - enterPara(); - append(Atom::UnknownCommand, cmdStr); - } - } - } // case '\\' (qdoc markup command) - break; - } - case '{': - enterPara(); - appendChar('{'); - ++m_braceDepth; - ++m_position; - break; - case '}': { - --m_braceDepth; - ++m_position; - - auto format = m_pendingFormats.find(m_braceDepth); - if (format == m_pendingFormats.end()) { - enterPara(); - appendChar('}'); - } else { - append(Atom::FormattingRight, *format); - if (*format == ATOM_FORMATTING_INDEX) { - if (m_indexStartedParagraph) - skipAllSpaces(); - } else if (*format == ATOM_FORMATTING_LINK) { - // hack for C++ to support links like - // \l{QString::}{count()} - if (currentLinkAtom && currentLinkAtom->string().endsWith("::")) { - QString suffix = - Text::subText(currentLinkAtom, m_private->m_text.lastAtom()) - .toString(); - currentLinkAtom->appendString(suffix); - } - currentLinkAtom = nullptr; - } - m_pendingFormats.erase(format); - } - break; - } - // Do not parse content after '//!' comments - case '/': { - if (m_position + 2 < m_inputLength) - if (m_input.at(m_position + 1) == '/') - if (m_input.at(m_position + 2) == '!') { - m_position += 2; - getRestOfLine(); - break; - } - Q_FALLTHROUGH(); // fall through - } - default: { - bool newWord; - switch (m_private->m_text.lastAtom()->type()) { - case Atom::ParaLeft: - newWord = true; - break; - default: - newWord = false; - } - - if (m_paragraphState == OutsideParagraph) { - if (ch.isSpace()) { - ++m_position; - newWord = false; - } else { - enterPara(); - newWord = true; - } - } else { - if (ch.isSpace()) { - ++m_position; - if ((ch == '\n') - && (m_paragraphState == InSingleLineParagraph || isBlankLine())) { - leavePara(); - newWord = false; - } else { - appendChar(' '); - newWord = true; - } - } else { - newWord = true; - } - } - - if (newWord) { - qsizetype startPos = m_position; - bool autolink = isAutoLinkString(m_input, m_position); - if (m_position == startPos) { - if (!ch.isSpace()) { - appendChar(ch); - ++m_position; - } - } else { - QString word = m_input.mid(startPos, m_position - startPos); - if (autolink) { - if (s_ignoreWords.contains(word) || word.startsWith(QString("__"))) - appendWord(word); - else - append(Atom::AutoLink, word); - } else { - appendWord(word); - } - } - } - } // default: - } // switch (ch.unicode()) - } - leaveValueList(); - - // for compatibility - if (m_openedCommands.top() == CMD_LEGALESE) { - append(Atom::LegaleseRight); - m_openedCommands.pop(); - } - - if (m_openedCommands.top() != CMD_OMIT) { - location().warning( - QStringLiteral("Missing '\\%1'").arg(endCmdName(m_openedCommands.top()))); - } else if (preprocessorSkipping.count() > 0) { - location().warning(QStringLiteral("Missing '\\%1'").arg(cmdName(CMD_ENDIF))); - } - - if (m_currentSection > Doc::NoSection) { - append(Atom::SectionRight, QString::number(m_currentSection)); - m_currentSection = Doc::NoSection; - } - - m_private->m_text.stripFirstAtom(); -} - -/*! - Returns the current location. - */ -Location &DocParser::location() -{ - while (!m_openedInputs.isEmpty() && m_openedInputs.top() <= m_position) { - m_cachedLocation.pop(); - m_cachedPosition = m_openedInputs.pop(); - } - while (m_cachedPosition < m_position) - m_cachedLocation.advance(m_input.at(m_cachedPosition++)); - return m_cachedLocation; -} - -QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet, const QString &str) -{ - QSet<QString> commandSet = metaCommandSet; - int i = 0; - while (cmds[i].english != nullptr) { - commandSet.insert(*cmds[i].alias); - ++i; - } - - if (s_utilities.aliasMap.contains(str)) - return QStringLiteral("The command '\\%1' was renamed '\\%2' by the configuration" - " file. Use the new name.") - .arg(str, s_utilities.aliasMap[str]); - - QString best = nearestName(str, commandSet); - if (best.isEmpty()) - return QString(); - return QStringLiteral("Maybe you meant '\\%1'?").arg(best); -} - -void DocParser::insertTarget(const QString &target, bool keyword) -{ - if (m_targetMap.contains(target)) { - location().warning(QStringLiteral("Duplicate target name '%1'").arg(target)); - m_targetMap[target].warning(QStringLiteral("(The previous occurrence is here)")); - } else { - m_targetMap.insert(target, location()); - m_private->constructExtra(); - if (keyword) { - append(Atom::Keyword, target); - m_private->extra->m_keywords.append(m_private->m_text.lastAtom()); - } else { - append(Atom::Target, target); - m_private->extra->m_targets.append(m_private->m_text.lastAtom()); - } - } -} - -void DocParser::include(const QString &fileName, const QString &identifier) -{ - if (location().depth() > 16) - location().fatal(QStringLiteral("Too many nested '\\%1's").arg(cmdName(CMD_INCLUDE))); - QString filePath = Config::instance().getIncludeFilePath(fileName); - if (filePath.isEmpty()) { - location().warning(QStringLiteral("Cannot find qdoc include file '%1'").arg(fileName)); - } else { - QFile inFile(filePath); - if (!inFile.open(QFile::ReadOnly)) { - location().warning( - QStringLiteral("Cannot open qdoc include file '%1'").arg(filePath)); - } else { - location().push(fileName); - QTextStream inStream(&inFile); - QString includedStuff = inStream.readAll(); - inFile.close(); - - if (identifier.isEmpty()) { - m_input.insert(m_position, includedStuff); - m_inputLength = m_input.length(); - m_openedInputs.push(m_position + includedStuff.length()); - } else { - QStringList lineBuffer = includedStuff.split(QLatin1Char('\n')); - int i = 0; - int startLine = -1; - while (i < lineBuffer.size()) { - if (lineBuffer[i].startsWith("//!")) { - if (lineBuffer[i].contains(identifier)) { - startLine = i + 1; - break; - } - } - ++i; - } - if (startLine < 0) { - location().warning( - QStringLiteral("Cannot find '%1' in '%2'").arg(identifier, filePath)); - return; - } - QString result; - i = startLine; - do { - if (lineBuffer[i].startsWith("//!")) { - if (i < lineBuffer.size()) { - if (lineBuffer[i].contains(identifier)) { - break; - } - } - } else - result += lineBuffer[i] + QLatin1Char('\n'); - ++i; - } while (i < lineBuffer.size()); - if (result.isEmpty()) { - location().warning(QStringLiteral("Empty qdoc snippet '%1' in '%2'") - .arg(identifier, filePath)); - } else { - m_input.insert(m_position, result); - m_inputLength = m_input.length(); - m_openedInputs.push(m_position + result.length()); - } - } - } - } -} - -void DocParser::startFormat(const QString &format, int cmd) -{ - enterPara(); - - for (const auto &item : qAsConst(m_pendingFormats)) { - if (item == format) { - location().warning(QStringLiteral("Cannot nest '\\%1' commands").arg(cmdName(cmd))); - return; - } - } - - append(Atom::FormattingLeft, format); - - if (isLeftBraceAhead()) { - skipSpacesOrOneEndl(); - m_pendingFormats.insert(m_braceDepth, format); - ++m_braceDepth; - ++m_position; - } else { - append(Atom::String, getArgument()); - append(Atom::FormattingRight, format); - if (format == ATOM_FORMATTING_INDEX && m_indexStartedParagraph) { - skipAllSpaces(); - m_indexStartedParagraph = false; - } - } -} - -bool DocParser::openCommand(int cmd) -{ - int outer = m_openedCommands.top(); - bool ok = true; - - if (cmd != CMD_LINK) { - if (outer == CMD_LIST) { - ok = (cmd == CMD_FOOTNOTE || cmd == CMD_LIST); - } else if (outer == CMD_SIDEBAR) { - ok = (cmd == CMD_LIST || cmd == CMD_QUOTATION || cmd == CMD_SIDEBAR); - } else if (outer == CMD_QUOTATION) { - ok = (cmd == CMD_LIST); - } else if (outer == CMD_TABLE) { - ok = (cmd == CMD_LIST || cmd == CMD_FOOTNOTE || cmd == CMD_QUOTATION); - } else if (outer == CMD_FOOTNOTE || outer == CMD_LINK) { - ok = false; - } - } - - if (ok) { - m_openedCommands.push(cmd); - } else { - location().warning( - QStringLiteral("Can't use '\\%1' in '\\%2'").arg(cmdName(cmd), cmdName(outer))); - } - return ok; -} - -/*! - Returns \c true if \a word qualifies for auto-linking. -*/ -inline bool DocParser::isAutoLinkString(const QString &word) -{ - qsizetype start = 0; - return isAutoLinkString(word, start); -} - -bool DocParser::isAutoLinkString(const QString &word, qsizetype &curPos) -{ - qsizetype len = word.size(); - qsizetype startPos = curPos; - int numUppercase = 0; - int numLowercase = 0; - int numStrangeSymbols = 0; - - while (curPos < len) { - unsigned char latin1Ch = word.at(curPos).toLatin1(); - if (islower(latin1Ch)) { - ++numLowercase; - ++curPos; - } else if (isupper(latin1Ch)) { - if (curPos > startPos) - ++numUppercase; - ++curPos; - } else if (isdigit(latin1Ch)) { - if (curPos > startPos) - ++curPos; - else - break; - } else if (latin1Ch == '_' || latin1Ch == '@') { - ++numStrangeSymbols; - ++curPos; - } else if ((latin1Ch == ':') && (curPos < len - 1) - && (word.at(curPos + 1) == QLatin1Char(':'))) { - ++numStrangeSymbols; - curPos += 2; - } else if (latin1Ch == '(') { - if (curPos > startPos) { - if ((curPos < len - 1) && (word.at(curPos + 1) == QLatin1Char(')'))) { - ++numStrangeSymbols; - m_position += 2; - break; - } else { - break; - } - } else { - break; - } - } else { - break; - } - } - return ((numUppercase >= 1 && numLowercase >= 2) || numStrangeSymbols > 0); -} - -bool DocParser::closeCommand(int endCmd) -{ - if (endCmdFor(m_openedCommands.top()) == endCmd && m_openedCommands.size() > 1) { - m_openedCommands.pop(); - return true; - } else { - bool contains = false; - QStack<int> opened2 = m_openedCommands; - while (opened2.size() > 1) { - if (endCmdFor(opened2.top()) == endCmd) { - contains = true; - break; - } - opened2.pop(); - } - - if (contains) { - while (endCmdFor(m_openedCommands.top()) != endCmd && m_openedCommands.size() > 1) { - location().warning( - QStringLiteral("Missing '\\%1' before '\\%2'") - .arg(endCmdName(m_openedCommands.top()), cmdName(endCmd))); - m_openedCommands.pop(); - } - } else { - location().warning(QStringLiteral("Unexpected '\\%1'").arg(cmdName(endCmd))); - } - return false; - } -} - -void DocParser::startSection(Doc::Sections unit, int cmd) -{ - leaveValueList(); - - if (m_currentSection == Doc::NoSection) { - m_currentSection = (Doc::Sections)(unit); - m_private->constructExtra(); - } else - endSection(unit, cmd); - - append(Atom::SectionLeft, QString::number(unit)); - m_private->constructExtra(); - m_private->extra->m_tableOfContents.append(m_private->m_text.lastAtom()); - m_private->extra->m_tableOfContentsLevels.append(unit); - enterPara(Atom::SectionHeadingLeft, Atom::SectionHeadingRight, QString::number(unit)); - m_currentSection = unit; -} - -void DocParser::endSection(int, int) // (int unit, int endCmd) -{ - leavePara(); - append(Atom::SectionRight, QString::number(m_currentSection)); - m_currentSection = (Doc::NoSection); -} - -void DocParser::parseAlso() -{ - leavePara(); - skipSpacesOnLine(); - while (m_position < m_inputLength && m_input[m_position] != '\n') { - QString target; - QString str; - bool skipMe = false; - - if (m_input[m_position] == '{') { - target = getArgument(); - skipSpacesOnLine(); - if (m_position < m_inputLength && m_input[m_position] == '{') { - str = getArgument(); - - // hack for C++ to support links like \l{QString::}{count()} - if (target.endsWith("::")) - target += str; - } else { - str = target; - } - } else { - target = getArgument(); - str = cleanLink(target); - if (target == QLatin1String("and") || target == QLatin1String(".")) - skipMe = true; - } - - if (!skipMe) { - Text also; - also << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << str << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - m_private->addAlso(also); - } - - skipSpacesOnLine(); - if (m_position < m_inputLength && m_input[m_position] == ',') { - m_position++; - skipSpacesOrOneEndl(); - } else if (m_position >= m_inputLength || m_input[m_position] != '\n') { - location().warning(QStringLiteral("Missing comma in '\\%1'").arg(cmdName(CMD_SA))); - } - } -} - -void DocParser::append(Atom::AtomType type, const QString &string) -{ - Atom::AtomType lastType = m_private->m_text.lastAtom()->type(); - if ((lastType == Atom::Code) - && m_private->m_text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - m_private->m_text.lastAtom()->chopString(); - m_private->m_text << Atom(type, string); -} - -void DocParser::append(const QString &string) -{ - Atom::AtomType lastType = m_private->m_text.lastAtom()->type(); - if ((lastType == Atom::Code) - && m_private->m_text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - m_private->m_text.lastAtom()->chopString(); - m_private->m_text << Atom(Atom::Link, string); -} - -void DocParser::append(Atom::AtomType type, const QString &p1, const QString &p2) -{ - Atom::AtomType lastType = m_private->m_text.lastAtom()->type(); - if ((lastType == Atom::Code) - && m_private->m_text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - m_private->m_text.lastAtom()->chopString(); - m_private->m_text << Atom(type, p1, p2); -} - -void DocParser::append(const QString &p1, const QString &p2) -{ - Atom::AtomType lastType = m_private->m_text.lastAtom()->type(); - if ((lastType == Atom::Code) - && m_private->m_text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - m_private->m_text.lastAtom()->chopString(); - if (p2.isEmpty()) - m_private->m_text << Atom(Atom::Link, p1); - else - m_private->m_text << LinkAtom(p1, p2); -} - -void DocParser::appendChar(QChar ch) -{ - if (m_private->m_text.lastAtom()->type() != Atom::String) - append(Atom::String); - Atom *atom = m_private->m_text.lastAtom(); - if (ch == QLatin1Char(' ')) { - if (!atom->string().endsWith(QLatin1Char(' '))) - atom->appendChar(QLatin1Char(' ')); - } else - atom->appendChar(ch); -} - -void DocParser::appendWord(const QString &word) -{ - if (m_private->m_text.lastAtom()->type() != Atom::String) { - append(Atom::String, word); - } else - m_private->m_text.lastAtom()->appendString(word); -} - -void DocParser::appendToCode(const QString &markedCode) -{ - if (!isCode(m_lastAtom)) { - append(Atom::Code); - m_lastAtom = m_private->m_text.lastAtom(); - } - m_lastAtom->appendString(markedCode); -} - -void DocParser::appendToCode(const QString &markedCode, Atom::AtomType defaultType) -{ - if (!isCode(m_lastAtom)) { - append(defaultType, markedCode); - m_lastAtom = m_private->m_text.lastAtom(); - } else { - m_lastAtom->appendString(markedCode); - } -} - -void DocParser::enterPara(Atom::AtomType leftType, Atom::AtomType rightType, const QString &string) -{ - if (m_paragraphState == OutsideParagraph) { - - if ((m_private->m_text.lastAtom()->type() != Atom::ListItemLeft) - && (m_private->m_text.lastAtom()->type() != Atom::DivLeft)) { - leaveValueList(); - } - - append(leftType, string); - m_indexStartedParagraph = false; - m_pendingParagraphLeftType = leftType; - m_pendingParagraphRightType = rightType; - m_pendingParagraphString = string; - if (leftType == Atom::SectionHeadingLeft) { - m_paragraphState = InSingleLineParagraph; - } else { - m_paragraphState = InMultiLineParagraph; - } - skipSpacesOrOneEndl(); - } -} - -void DocParser::leavePara() -{ - if (m_paragraphState != OutsideParagraph) { - if (!m_pendingFormats.isEmpty()) { - location().warning(QStringLiteral("Missing '}'")); - m_pendingFormats.clear(); - } - - if (m_private->m_text.lastAtom()->type() == m_pendingParagraphLeftType) { - m_private->m_text.stripLastAtom(); - } else { - if (m_private->m_text.lastAtom()->type() == Atom::String - && m_private->m_text.lastAtom()->string().endsWith(QLatin1Char(' '))) { - m_private->m_text.lastAtom()->chopString(); - } - append(m_pendingParagraphRightType, m_pendingParagraphString); - } - m_paragraphState = OutsideParagraph; - m_indexStartedParagraph = false; - m_pendingParagraphRightType = Atom::Nop; - m_pendingParagraphString.clear(); - } -} - -void DocParser::leaveValue() -{ - leavePara(); - if (m_openedLists.isEmpty()) { - m_openedLists.push(OpenedList(OpenedList::Value)); - append(Atom::ListLeft, ATOM_LIST_VALUE); - } else { - if (m_private->m_text.lastAtom()->type() == Atom::Nop) - m_private->m_text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - } -} - -void DocParser::leaveValueList() -{ - leavePara(); - if (!m_openedLists.isEmpty() && (m_openedLists.top().style() == OpenedList::Value)) { - if (m_private->m_text.lastAtom()->type() == Atom::Nop) - m_private->m_text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - append(Atom::ListRight, ATOM_LIST_VALUE); - m_openedLists.pop(); - } -} - -void DocParser::leaveTableRow() -{ - if (m_inTableItem) { - leavePara(); - append(Atom::TableItemRight); - m_inTableItem = false; - } - if (m_inTableHeader) { - append(Atom::TableHeaderRight); - m_inTableHeader = false; - } - if (m_inTableRow) { - append(Atom::TableRowRight); - m_inTableRow = false; - } -} - -CodeMarker *DocParser::quoteFromFile() -{ - return Doc::quoteFromFile(location(), m_quoter, getArgument()); -} - -/*! - Expands a macro in-place in input. - - Expects the current \e pos in the input to point to a backslash, and the macro to have a - default definition. Format-specific macros are currently not expanded. - - \note In addition to macros, a valid use for a backslash in an argument include - escaping non-alnum characters, and splitting a single argument across multiple - lines by escaping newlines. Escaping is also handled here. - - Returns \c true on successful macro expansion. - */ -bool DocParser::expandMacro() -{ - Q_ASSERT(m_input[m_position].unicode() == '\\'); - - QString cmdStr; - qsizetype backslashPos = m_position++; - while (m_position < m_input.length() && m_input[m_position].isLetterOrNumber()) - cmdStr += m_input[m_position++]; - - m_endPosition = m_position; - if (!cmdStr.isEmpty()) { - if (s_utilities.macroHash.contains(cmdStr)) { - const Macro ¯o = s_utilities.macroHash.value(cmdStr); - if (!macro.m_defaultDef.isEmpty()) { - QString expanded = expandMacroToString(cmdStr, macro.m_defaultDef, macro.numParams, - macro.m_otherDefs.value("match")); - m_input.replace(backslashPos, m_position - backslashPos, expanded); - m_inputLength = m_input.length(); - m_position = backslashPos; - return true; - } else { - location().warning(QStringLiteral("Macro '%1' does not have a default definition") - .arg(cmdStr)); - } - } else { - location().warning(QStringLiteral("Unknown macro '%1'").arg(cmdStr)); - m_position = ++backslashPos; - } - } else if (m_input[m_position].isSpace()) { - skipAllSpaces(); - } else if (m_input[m_position].unicode() == '\\') { - // allow escaping a backslash - m_input.remove(m_position--, 1); - --m_inputLength; - } - return false; -} - -void DocParser::expandMacro(const QString &name, const QString &def, int numParams) -{ - if (numParams == 0) { - append(Atom::RawString, def); - } else { - QStringList args; - QString rawString; - - for (int i = 0; i < numParams; ++i) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(); - } else { - location().warning(QStringLiteral("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name) - .arg(numParams) - .arg(i)); - numParams = i; - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && (paramNo <= numParams)) { - if (!rawString.isEmpty()) { - append(Atom::RawString, rawString); - rawString.clear(); - } - append(Atom::String, args[paramNo - 1]); - j += 1; - } else { - rawString += def[j++]; - } - } - if (!rawString.isEmpty()) - append(Atom::RawString, rawString); - } -} - -QString DocParser::expandMacroToString(const QString &name, const QString &def, int numParams, - const QString &matchExpr) -{ - QString rawString; - - if (numParams == 0) { - rawString = def; - } else { - QStringList args; - for (int i = 0; i < numParams; ++i) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(true); - } else { - location().warning(QStringLiteral("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name) - .arg(numParams) - .arg(i)); - numParams = i; - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && (paramNo <= numParams)) { - rawString += args[paramNo - 1]; - j += 1; - } else { - rawString += def[j++]; - } - } - } - if (matchExpr.isEmpty()) - return rawString; - - QString result; - QRegularExpression re(matchExpr); - int capStart = (re.captureCount() > 0) ? 1 : 0; - qsizetype i = 0; - QRegularExpressionMatch match; - while ((match = re.match(rawString, i)).hasMatch()) { - for (int c = capStart; c <= re.captureCount(); ++c) - result += match.captured(c); - i = match.capturedEnd(); - } - - return result; -} - -Doc::Sections DocParser::getSectioningUnit() -{ - QString name = getOptionalArgument(); - - if (name == "section1") { - return Doc::Section1; - } else if (name == "section2") { - return Doc::Section2; - } else if (name == "section3") { - return Doc::Section3; - } else if (name == "section4") { - return Doc::Section4; - } else if (name.isEmpty()) { - return Doc::NoSection; - } else { - location().warning(QStringLiteral("Invalid section '%1'").arg(name)); - return Doc::NoSection; - } -} - -/*! - Gets an argument that is enclosed in braces and returns it - without the enclosing braces. On entry, the current character - is the left brace. On exit, the current character is the one - that comes after the right brace. - - If \a verbatim is true, extra whitespace is retained in the - returned string. Otherwise, extra whitespace is removed. - */ -QString DocParser::getBracedArgument(bool verbatim) -{ - QString arg; - int delimDepth = 0; - if (m_position < m_input.length() && m_input[m_position] == '{') { - ++m_position; - while (m_position < m_input.length() && delimDepth >= 0) { - switch (m_input[m_position].unicode()) { - case '{': - ++delimDepth; - arg += QLatin1Char('{'); - ++m_position; - break; - case '}': - --delimDepth; - if (delimDepth >= 0) - arg += QLatin1Char('}'); - ++m_position; - break; - case '\\': - if (verbatim || !expandMacro()) - arg += m_input[m_position++]; - break; - default: - if (m_input[m_position].isSpace() && !verbatim) - arg += QChar(' '); - else - arg += m_input[m_position]; - ++m_position; - } - } - if (delimDepth > 0) - location().warning(QStringLiteral("Missing '}'")); - } - m_endPosition = m_position; - return arg; -} - -/*! - Typically, an argument ends at the next white-space. However, - braces can be used to group words: - - {a few words} - - Also, opening and closing parentheses have to match. Thus, - - printf("%d\n", x) - - is an argument too, although it contains spaces. Finally, - trailing punctuation is not included in an argument, nor is 's. -*/ -QString DocParser::getArgument(bool verbatim) -{ - skipSpacesOrOneEndl(); - - int delimDepth = 0; - qsizetype startPos = m_position; - QString arg = getBracedArgument(verbatim); - if (arg.isEmpty()) { - while ((m_position < m_input.length()) - && ((delimDepth > 0) || ((delimDepth == 0) && !m_input[m_position].isSpace()))) { - switch (m_input[m_position].unicode()) { - case '(': - case '[': - case '{': - ++delimDepth; - arg += m_input[m_position]; - ++m_position; - break; - case ')': - case ']': - case '}': - --delimDepth; - if (m_position == startPos || delimDepth >= 0) { - arg += m_input[m_position]; - ++m_position; - } - break; - case '\\': - if (verbatim || !expandMacro()) - arg += m_input[m_position++]; - break; - default: - arg += m_input[m_position]; - ++m_position; - } - } - m_endPosition = m_position; - if ((arg.length() > 1) && (QString(".,:;!?").indexOf(m_input[m_position - 1]) != -1) - && !arg.endsWith("...")) { - arg.truncate(arg.length() - 1); - --m_position; - } - if (arg.length() > 2 && m_input.mid(m_position - 2, 2) == "'s") { - arg.truncate(arg.length() - 2); - m_position -= 2; - } - } - return arg.simplified(); -} - -/*! - Gets an argument that is enclosed in brackets and returns it - without the enclosing brackets. On entry, the current character - is the left bracket. On exit, the current character is the one - that comes after the right bracket. - */ -QString DocParser::getBracketedArgument() -{ - QString arg; - int delimDepth = 0; - skipSpacesOrOneEndl(); - if (m_position < m_input.length() && m_input[m_position] == '[') { - ++m_position; - while (m_position < m_input.length() && delimDepth >= 0) { - switch (m_input[m_position].unicode()) { - case '[': - ++delimDepth; - arg += QLatin1Char('['); - ++m_position; - break; - case ']': - --delimDepth; - if (delimDepth >= 0) - arg += QLatin1Char(']'); - ++m_position; - break; - case '\\': - arg += m_input[m_position]; - ++m_position; - break; - default: - arg += m_input[m_position]; - ++m_position; - } - } - if (delimDepth > 0) - location().warning(QStringLiteral("Missing ']'")); - } - return arg; -} - -QString DocParser::getOptionalArgument() -{ - skipSpacesOrOneEndl(); - if (m_position + 1 < m_input.length() && m_input[m_position] == '\\' - && m_input[m_position + 1].isLetterOrNumber()) { - return QString(); - } else { - return getArgument(); - } -} - -QString DocParser::getRestOfLine() -{ - QString t; - - skipSpacesOnLine(); - - bool trailingSlash = false; - - do { - qsizetype begin = m_position; - - while (m_position < m_input.size() && m_input[m_position] != '\n') { - if (m_input[m_position] == '\\' && !trailingSlash) { - trailingSlash = true; - ++m_position; - while ((m_position < m_input.size()) && m_input[m_position].isSpace() - && (m_input[m_position] != '\n')) - ++m_position; - } else { - trailingSlash = false; - ++m_position; - } - } - - if (!t.isEmpty()) - t += QLatin1Char(' '); - t += m_input.mid(begin, m_position - begin).simplified(); - - if (trailingSlash) { - t.chop(1); - t = t.simplified(); - } - if (m_position < m_input.size()) - ++m_position; - } while (m_position < m_input.size() && trailingSlash); - - return t; -} - -/*! - The metacommand argument is normally the remaining text to - the right of the metacommand itself. The extra blanks are - stripped and the argument string is returned. - */ -QString DocParser::getMetaCommandArgument(const QString &cmdStr) -{ - skipSpacesOnLine(); - - qsizetype begin = m_position; - int parenDepth = 0; - - while (m_position < m_input.size() && (m_input[m_position] != '\n' || parenDepth > 0)) { - if (m_input.at(m_position) == '(') - ++parenDepth; - else if (m_input.at(m_position) == ')') - --parenDepth; - else if (m_input.at(m_position) == '\\' && expandMacro()) - continue; - ++m_position; - } - if (m_position == m_input.size() && parenDepth > 0) { - m_position = begin; - location().warning(QStringLiteral("Unbalanced parentheses in '%1'").arg(cmdStr)); - } - - QString t = m_input.mid(begin, m_position - begin).simplified(); - skipSpacesOnLine(); - return t; -} - -QString DocParser::getUntilEnd(int cmd) -{ - int endCmd = endCmdFor(cmd); - QRegularExpression rx("\\\\" + cmdName(endCmd) + "\\b"); - QString t; - auto match = rx.match(m_input, m_position); - - if (!match.hasMatch()) { - location().warning(QStringLiteral("Missing '\\%1'").arg(cmdName(endCmd))); - m_position = m_input.length(); - } else { - qsizetype end = match.capturedStart(); - t = m_input.mid(m_position, end - m_position); - m_position = match.capturedEnd(); - } - return t; -} - -QString DocParser::getCode(int cmd, CodeMarker *marker, const QString &argStr) -{ - QString code = untabifyEtc(getUntilEnd(cmd)); - - if (!argStr.isEmpty()) { - QStringList args = argStr.split(" ", Qt::SkipEmptyParts); - qsizetype paramNo, j = 0; - while (j < code.size()) { - if (code[j] == '\\' && j < code.size() - 1 && (paramNo = code[j + 1].digitValue()) >= 1 - && paramNo <= args.size()) { - QString p = args[paramNo - 1]; - code.replace(j, 2, p); - j += qMin(1, p.size()); - } else { - ++j; - } - } - } - - int indent = indentLevel(code); - code = dedent(indent, code); - if (marker == nullptr) - marker = CodeMarker::markerForCode(code); - return marker->markedUpCode(code, nullptr, location()); -} - -bool DocParser::isBlankLine() -{ - qsizetype i = m_position; - - while (i < m_inputLength && m_input[i].isSpace()) { - if (m_input[i] == '\n') - return true; - ++i; - } - return false; -} - -bool DocParser::isLeftBraceAhead() -{ - int numEndl = 0; - qsizetype i = m_position; - - while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (m_input[i] == '\n') - numEndl++; - ++i; - } - return numEndl < 2 && i < m_inputLength && m_input[i] == '{'; -} - -bool DocParser::isLeftBracketAhead() -{ - int numEndl = 0; - qsizetype i = m_position; - - while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (m_input[i] == '\n') - numEndl++; - ++i; - } - return numEndl < 2 && i < m_inputLength && m_input[i] == '['; -} - -/*! - Skips to the next non-space character or EOL. - */ -void DocParser::skipSpacesOnLine() -{ - while ((m_position < m_input.length()) && m_input[m_position].isSpace() - && (m_input[m_position].unicode() != '\n')) - ++m_position; -} - -/*! - Skips spaces and one EOL. - */ -void DocParser::skipSpacesOrOneEndl() -{ - qsizetype firstEndl = -1; - while (m_position < m_input.length() && m_input[m_position].isSpace()) { - QChar ch = m_input[m_position]; - if (ch == '\n') { - if (firstEndl == -1) { - firstEndl = m_position; - } else { - m_position = firstEndl; - break; - } - } - ++m_position; - } -} - -void DocParser::skipAllSpaces() -{ - while (m_position < m_inputLength && m_input[m_position].isSpace()) - ++m_position; -} - -void DocParser::skipToNextPreprocessorCommand() -{ - QRegularExpression rx("\\\\(?:" + cmdName(CMD_IF) + QLatin1Char('|') + cmdName(CMD_ELSE) - + QLatin1Char('|') + cmdName(CMD_ENDIF) + ")\\b"); - auto match = rx.match(m_input, m_position + 1); // ### + 1 necessary? - - if (!match.hasMatch()) - m_position = m_input.length(); - else - m_position = match.capturedStart(); -} - -int DocParser::endCmdFor(int cmd) -{ - switch (cmd) { - case CMD_BADCODE: - return CMD_ENDCODE; - case CMD_CODE: - return CMD_ENDCODE; - case CMD_DIV: - return CMD_ENDDIV; - case CMD_QML: - return CMD_ENDQML; - case CMD_QMLTEXT: - return CMD_ENDQMLTEXT; - case CMD_JS: - return CMD_ENDJS; - case CMD_FOOTNOTE: - return CMD_ENDFOOTNOTE; - case CMD_LEGALESE: - return CMD_ENDLEGALESE; - case CMD_LINK: - return CMD_ENDLINK; - case CMD_LIST: - return CMD_ENDLIST; - case CMD_NEWCODE: - return CMD_ENDCODE; - case CMD_OLDCODE: - return CMD_NEWCODE; - case CMD_OMIT: - return CMD_ENDOMIT; - case CMD_QUOTATION: - return CMD_ENDQUOTATION; - case CMD_RAW: - return CMD_ENDRAW; - case CMD_SECTION1: - return CMD_ENDSECTION1; - case CMD_SECTION2: - return CMD_ENDSECTION2; - case CMD_SECTION3: - return CMD_ENDSECTION3; - case CMD_SECTION4: - return CMD_ENDSECTION4; - case CMD_SIDEBAR: - return CMD_ENDSIDEBAR; - case CMD_TABLE: - return CMD_ENDTABLE; - default: - return cmd; - } -} - -QString DocParser::cmdName(int cmd) -{ - return *cmds[cmd].alias; -} - -QString DocParser::endCmdName(int cmd) -{ - return cmdName(endCmdFor(cmd)); -} - -QString DocParser::untabifyEtc(const QString &str) -{ - QString result; - result.reserve(str.length()); - int column = 0; - - for (const auto &character : str) { - if (character == QLatin1Char('\r')) - continue; - if (character == QLatin1Char('\t')) { - result += &" "[column % s_tabSize]; - column = ((column / s_tabSize) + 1) * s_tabSize; - continue; - } - if (character == QLatin1Char('\n')) { - while (result.endsWith(QLatin1Char(' '))) - result.chop(1); - result += character; - column = 0; - continue; - } - result += character; - ++column; - } - - while (result.endsWith("\n\n")) - result.truncate(result.length() - 1); - while (result.startsWith(QLatin1Char('\n'))) - result = result.mid(1); - - return result; -} - -int DocParser::indentLevel(const QString &str) -{ - int minIndent = INT_MAX; - int column = 0; - - for (const auto &character : str) { - if (character == '\n') { - column = 0; - } else { - if (character != ' ' && column < minIndent) - minIndent = column; - ++column; - } - } - return minIndent; -} - -QString DocParser::dedent(int level, const QString &str) -{ - if (level == 0) - return str; - - QString result; - int column = 0; - - for (const auto &character : str) { - if (character == QLatin1Char('\n')) { - result += '\n'; - column = 0; - } else { - if (column >= level) - result += character; - ++column; - } - } - return result; -} - -QString DocParser::slashed(const QString &str) -{ - QString result = str; - result.replace(QLatin1Char('/'), "\\/"); - return QLatin1Char('/') + result + QLatin1Char('/'); -} - -/*! - Returns \c true if \a atom represents a code snippet. - */ -bool DocParser::isCode(const Atom *atom) -{ - Atom::AtomType type = atom->type(); - return (type == Atom::Code || type == Atom::Qml || type == Atom::JavaScript); -} - -/*! - Returns \c true if \a atom represents quoting information. - */ -bool DocParser::isQuote(const Atom *atom) -{ - Atom::AtomType type = atom->type(); - return (type == Atom::CodeQuoteArgument || type == Atom::CodeQuoteCommand - || type == Atom::SnippetCommand || type == Atom::SnippetIdentifier - || type == Atom::SnippetLocation); -} - -QT_END_NAMESPACE |