// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include #include QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; // An emprical value to avoid too much content static constexpr qsizetype firstIndexOfParagraphTag = 400; // A paragraph can start with

, or

// We need smallest value to use QString::indexOf static constexpr auto lengthOfStartParagraphTag = qsizetype(std::char_traits::length("

")); static constexpr auto lengthOfEndParagraphTag = qsizetype(std::char_traits::length("

")); static QString getContentsByMarks(const QString &html, QString startMark, QString endMark) { startMark.prepend("$$$"_L1); endMark.prepend(""_L1, start); if (start != -1) { qsizetype end = html.indexOf(endMark, start); if (end != -1) { start += qsizetype(std::char_traits::length("-->")); contents = html.mid(start, end - start); } } } return contents; } static void stripAllHtml(QString *html) { Q_ASSERT(html); html->remove(QRegularExpression("<.*?>"_L1)); } /*! \internal \brief Process the string obtained from start mark to end mark. This is duplicated from QtC's Utils::HtmlExtractor, modified on top of it. */ static void processOutput(QString *html) { Q_ASSERT(html); if (html->isEmpty()) return; // Do not write the first paragraph in case it has extra tags below. //

This is only used on the Maemo platform.

// or:

This is used on Windows only.

// or:

[Conditional]

const auto skipFirstParagraphIfNeeded = [html](qsizetype &index){ const bool shouldSkipFirstParagraph = html->indexOf(QLatin1String("

")) == index || html->indexOf(QLatin1String("

")) == index || html->indexOf(QLatin1String("

")) == index || html->indexOf(QLatin1String("

[Conditional]

")) == index; if (shouldSkipFirstParagraph) index = html->indexOf(QLatin1String("

"), index) + lengthOfEndParagraphTag; }; // Try to get the entire first paragraph, but if one is not found or if its opening // tag is not in the very beginning (using an empirical value as the limit) // the html is cleared out to avoid too much content. qsizetype index = html->indexOf(QLatin1String("

")); if (index != -1 && index < firstIndexOfParagraphTag) { skipFirstParagraphIfNeeded(index); qsizetype endIndex = html->indexOf(QLatin1String("

"), index + lengthOfStartParagraphTag); if (endIndex != -1) { *html = html->mid(index, endIndex - index); } else { html->clear(); } } else { html->clear(); } } class ExtractQmlType : public HtmlExtractor { public: QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override; }; class ExtractQmlProperty : public HtmlExtractor { public: QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override; }; class ExtractQmlMethodOrSignal : public HtmlExtractor { public: QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override; }; QString ExtractQmlType::extract(const QString &code, const QString &element, ExtractionMode mode) { QString result; // Get brief description if (mode == ExtractionMode::Simplified) { result = getContentsByMarks(code, element + "-brief"_L1 , element); // Remove More... if (!result.isEmpty()) { const auto tailToRemove = "More..."_L1; const auto lastIndex = result.lastIndexOf(tailToRemove); if (lastIndex != -1) result.remove(lastIndex, tailToRemove.length()); } } else { result = getContentsByMarks(code, element + "-description"_L1, element); // Remove header if (!result.isEmpty()) { const auto headerToRemove = "Detailed Description"_L1; const auto firstIndex = result.indexOf(headerToRemove); if (firstIndex != -1) result.remove(firstIndex, headerToRemove.length()); } } stripAllHtml(&result); return result.trimmed(); } QString ExtractQmlProperty::extract(const QString &code, const QString &keyword, ExtractionMode mode) { QString result; // Qt 5.15 way of finding properties in doc QString startMark = QString::fromLatin1("").arg(keyword); qsizetype startIndex = code.indexOf(startMark); if (startIndex == -1) { // if not found, try Qt6 startMark = QString::fromLatin1( "

\n%1") .arg(keyword); startIndex = code.indexOf(startMark); } if (startIndex != -1) { result = code.mid(startIndex + startMark.size()); startIndex = result.indexOf(QLatin1String("

")); } else { result = getContentsByMarks(code, keyword + "-prop"_L1, keyword ); startIndex = result.indexOf(QLatin1String("

")); } if (startIndex == -1) return {}; result = result.mid(startIndex); if (mode == ExtractionMode::Simplified) processOutput(&result); stripAllHtml(&result); return result.trimmed(); } QString ExtractQmlMethodOrSignal::extract(const QString &code, const QString &keyword, ExtractionMode mode) { // the case with QString mark = QString::fromLatin1("$$$%1[overload1]$$$%1").arg(keyword); qsizetype startIndex = code.indexOf(mark); if (startIndex != -1) { startIndex = code.indexOf("-->"_L1, startIndex + mark.length()); if (startIndex == -1) return {}; } else { // it could be part of the method list mark = QString::fromLatin1("%1") .arg(keyword); startIndex = code.indexOf(mark); if (startIndex != -1) startIndex += mark.length(); else return {}; } startIndex = code.indexOf(QLatin1String("

"), startIndex); if (startIndex == -1) return {}; QString endMark = QString::fromLatin1("