From 5a1983f9240e52be6df4cd3260d13eb4e9338dcd Mon Sep 17 00:00:00 2001 From: Leandro Melo <leandro.melo@nokia.com> Date: Wed, 21 Jul 2010 17:25:58 +0200 Subject: [PATCH] C++ tooltip: Integration with qdocs now only with 4.7 html marks. --- src/libs/utils/htmldocextractor.cpp | 240 +++++----------------- src/libs/utils/htmldocextractor.h | 37 +--- src/plugins/cppeditor/cpphoverhandler.cpp | 69 +++---- src/plugins/cppeditor/cpphoverhandler.h | 10 +- 4 files changed, 97 insertions(+), 259 deletions(-) diff --git a/src/libs/utils/htmldocextractor.cpp b/src/libs/utils/htmldocextractor.cpp index 90d2ee6e0ff..cbaa37fc477 100644 --- a/src/libs/utils/htmldocextractor.cpp +++ b/src/libs/utils/htmldocextractor.cpp @@ -59,182 +59,108 @@ void HtmlDocExtractor::setLengthReference(const int length, const bool truncateA void HtmlDocExtractor::setFormatContents(const bool format) { m_formatContents = format; } -QString HtmlDocExtractor::assemble(const QString &elementAttr, - const QString &elementTemplate) const +QString HtmlDocExtractor::getClassOrNamespaceBrief(const QString &html, const QString &mark) const { - const QString &cleanAttr = cleanReference(elementAttr); - return QString(elementTemplate).arg(cleanAttr); -} - -QString HtmlDocExtractor::getClassOrNamespaceBrief(const QString &html, const QString &name) const -{ - QString contents = getContentsByMarks(html, name + QLatin1String("-brief"), false); - if (contents.isEmpty()) { - QLatin1String pattern("<h1 class=\"title\">.*</p>"); - contents = findByPattern(html, pattern); - if (!contents.isEmpty()) - contents.remove(QRegExp(QLatin1String("<h1.*</h1>"))); - } - if (!contents.isEmpty()) { + QString contents = getContentsByMarks(html, mark + QLatin1String("-brief"), mark); + if (!contents.isEmpty() && m_formatContents) { contents.remove(QLatin1String("<a href=\"#details\">More...</a>")); - if (m_formatContents) { - contents.prepend(QLatin1String("<nobr>")); - contents.append(QLatin1String("</nobr>")); - } + contents.prepend(QLatin1String("<nobr>")); + contents.append(QLatin1String("</nobr>")); + formatContents(&contents); } - formatContents(&contents); return contents; } QString HtmlDocExtractor::getClassOrNamespaceDescription(const QString &html, - const QString &name) const + const QString &mark) const { - QString contents = getContentsByMarks(html, name + QLatin1String("-description"), false); - if (contents.isEmpty()) { - QLatin1String pattern("<a name=\"details\"></a>.*<hr />.*<hr />"); - contents = findByPattern(html, pattern); - } - if (!contents.isEmpty()) + QString contents = getContentsByMarks(html, mark + QLatin1String("-description"), mark); + if (!contents.isEmpty() && m_formatContents) { contents.remove(QLatin1String("Detailed Description")); + formatContents(&contents); + } - formatContents(&contents); - return contents; -} - -QString HtmlDocExtractor::getEnumDescription(const QString &html, const QString &name) const -{ - const QString &enumm = name + QLatin1String("-enum"); - QString contents = getClassOrNamespaceMemberDescription(html, name, enumm, false); - formatContents(&contents); return contents; } -QString HtmlDocExtractor::getTypedefDescription(const QString &html, const QString &name) const +QString HtmlDocExtractor::getEnumDescription(const QString &html, const QString &mark) const { - const QString &typedeff = name + QLatin1String("-typedef"); - QString contents = getClassOrNamespaceMemberDescription(html, name, typedeff, false); - formatContents(&contents); - return contents; + return getClassOrNamespaceMemberDescription(html, mark, mark); } -QString HtmlDocExtractor::getVarDescription(const QString &html, const QString &name) const +QString HtmlDocExtractor::getTypedefDescription(const QString &html, const QString &mark) const { - const QString &var = name + QLatin1String("-var"); - QString contents = getClassOrNamespaceMemberDescription(html, name, var, false); - formatContents(&contents); - return contents; + return getClassOrNamespaceMemberDescription(html, mark, mark); } QString HtmlDocExtractor::getMacroDescription(const QString &html, - const QString &mark, - const QString &anchorName) const + const QString &mark) const { - QString contents = getClassOrNamespaceMemberDescription(html, mark, anchorName, false, true); - formatContents(&contents); - return contents; + return getClassOrNamespaceMemberDescription(html, mark, mark); } QString HtmlDocExtractor::getFunctionDescription(const QString &html, const QString &mark, - const QString &anchorName, const bool mainOverload) const { - QString contents = getClassOrNamespaceMemberDescription(html, mark, anchorName, mainOverload); + QString cleanMark = mark; + QString startMark = mark; + const int parenthesis = mark.indexOf(QLatin1Char('(')); + if (parenthesis != -1) { + startMark = mark.left(parenthesis); + cleanMark = startMark; + if (mainOverload) { + startMark.append(QLatin1String("[overload1]")); + } else { + QString complement = mark.right(mark.length() - parenthesis); + complement.remove(QRegExp(QLatin1String("[\\(\\), ]"))); + startMark.append(complement); + } + } + + QString contents = getClassOrNamespaceMemberDescription(html, startMark, cleanMark); if (contents.isEmpty()) { - // Maybe marks are not present and/or this is a property. Besides setX/isX/hasX there are - // other (not so usual) names for property based functions. A few examples of those: + // Maybe this is a property function, which is documented differently. Besides + // setX/isX/hasX there are other (not so usual) names for them. A few examples of those: // - toPlainText / Prop. plainText from QPlainTextEdit. // - resize / Prop. size from QWidget. // - move / Prop. pos from QWidget (nothing similar in the names in this case). // So I try to find the link to this property in the list of properties, extract its // anchor and then follow by the name found. - QString pattern = assemble(anchorName, - QLatin1String("<a href=\"[a-z\\.]+#([A-Za-z]+-prop)\">%1</a>")); + const QString &pattern = + QString(QLatin1String("<a href=\"[a-z\\.]+#([A-Za-z]+)-prop\">%1</a>")).arg(cleanMark); QRegExp exp = createMinimalExp(pattern); if (exp.indexIn(html) != -1) { const QString &prop = exp.cap(1); - contents = getClassOrNamespaceMemberDescription(html, prop, prop, false); + contents = getClassOrNamespaceMemberDescription(html, + prop + QLatin1String("-prop"), + prop); } } - formatContents(&contents); + return contents; } QString HtmlDocExtractor::getClassOrNamespaceMemberDescription(const QString &html, - const QString &mark, - const QString &anchorName, - const bool mainOverload, - const bool relaxedMatch) const + const QString &startMark, + const QString &endMark) const { - // Try with extraction marks (present in newer verions of the docs). If nothing is found try - // with the anchor. - QString contents; - if (!mark.isEmpty()) - contents = getContentsByMarks(html, mark, mainOverload); - if (contents.isEmpty()) - contents = getContentsByAnchor(html, anchorName, relaxedMatch); - - return contents; -} + QString contents = getContentsByMarks(html, startMark, endMark); -QString HtmlDocExtractor::getContentsByAnchor(const QString &html, - const QString &name, - const bool relaxedMatch) const -{ - // This approach is not very accurate. - QString pattern; - if (relaxedMatch) { - pattern = QLatin1String( - "(?:<h3 class=\"[a-z]+\">)?<a name=\"%1.*(?:<h3 class|<p />|<hr />|</div>)"); - } else { - // When there are duplicates the HTML generator incrementally appends 'x' to references. - pattern = QLatin1String( - "(?:<h3 class=\"[a-z]+\">)?<a name=\"%1x*\">.*(?:<h3 class|<p />|<hr />|</div>)"); - } + if (!contents.isEmpty()) + formatContents(&contents); - return findByPattern(html, assemble(name, pattern)); + return contents; } QString HtmlDocExtractor::getContentsByMarks(const QString &html, - const QString &id, - const bool mainOverload) const + QString startMark, + QString endMark) const { - QString endMark; - QString startMark; - if (id.contains(QLatin1Char('('))) { - const int index = id.indexOf(QLatin1Char('(')); - startMark = id.left(index); - endMark = startMark; - if (mainOverload) { - startMark.append(QLatin1String("[overload1]")); - } else { - QString complementaryId = id.right(id.length() - index); - complementaryId.remove(QRegExp(QLatin1String("[\\(\\), ]"))); - startMark.append(complementaryId); - } - } else { - startMark = id; - } startMark.prepend(QLatin1String("$$$")); - - if (endMark.isEmpty()) { - if (id.contains(QLatin1Char('-'))) { - const int index = id.indexOf(QLatin1Char('-')); - endMark = id.left(index); - } else { - endMark = id; - } - } endMark.prepend(QLatin1String("<!-- @@@")); - return findByMarks(html, startMark, endMark); -} - -QString HtmlDocExtractor::findByMarks(const QString &html, - const QString &startMark, - const QString &endMark) const -{ QString contents; int start = html.indexOf(startMark); if (start != -1) { @@ -250,16 +176,6 @@ QString HtmlDocExtractor::findByMarks(const QString &html, return contents; } -QString HtmlDocExtractor::findByPattern(const QString &html, const QString &pattern) const -{ - QRegExp exp(pattern); - exp.setMinimal(true); - const int match = exp.indexIn(html); - if (match != -1) - return html.mid(match, exp.matchedLength()); - return QString(); -} - void HtmlDocExtractor::formatContents(QString *html) const { if (html->isEmpty()) @@ -379,61 +295,3 @@ void HtmlDocExtractor::replaceListsForSimpleLines(QString *html) html->replace(QLatin1String("<li>"), QLatin1String(" ")); html->replace(QLatin1String("</li>"), QLatin1String("<br />")); } - -/* - @todo: We need to clean the anchor in the same way qtdoc does. Currently, this method is a - duplicate of HtmlGenerator::cleanRef. It would be good to reuse the same code either by exposing - parts of qtdocs or by refactoring the behavior to use some Qt component for example. - */ -QString HtmlDocExtractor::cleanReference(const QString &reference) -{ - QString clean; - - if (reference.isEmpty()) - return clean; - - clean.reserve(reference.size() + 20); - const QChar c = reference[0]; - const uint u = c.unicode(); - - if ((u >= QLatin1Char('a') && u <= QLatin1Char('z')) || - (u >= QLatin1Char('A') && u <= QLatin1Char('Z')) || - (u >= QLatin1Char('0') && u <= QLatin1Char('9'))) { - clean += c; - } else if (u == QLatin1Char('~')) { - clean += QLatin1String("dtor."); - } else if (u == QLatin1Char('_')) { - clean += QLatin1String("underscore."); - } else { - clean += QLatin1String("A"); - } - - for (int i = 1; i < (int) reference.length(); i++) { - const QChar c = reference[i]; - const uint u = c.unicode(); - if ((u >= QLatin1Char('a') && u <= QLatin1Char('z')) || - (u >= QLatin1Char('A') && u <= QLatin1Char('Z')) || - (u >= QLatin1Char('0') && u <= QLatin1Char('9')) || u == QLatin1Char('-') || - u == QLatin1Char('_') || u == QLatin1Char(':') || u == QLatin1Char('.')) { - clean += c; - } else if (c.isSpace()) { - clean += QLatin1String("-"); - } else if (u == QLatin1Char('!')) { - clean += QLatin1String("-not"); - } else if (u == QLatin1Char('&')) { - clean += QLatin1String("-and"); - } else if (u == QLatin1Char('<')) { - clean += QLatin1String("-lt"); - } else if (u == QLatin1Char('=')) { - clean += QLatin1String("-eq"); - } else if (u == QLatin1Char('>')) { - clean += QLatin1String("-gt"); - } else if (u == QLatin1Char('#')) { - clean += QLatin1String("#"); - } else { - clean += QLatin1String("-"); - clean += QString::number((int)u, 16); - } - } - return clean; -} diff --git a/src/libs/utils/htmldocextractor.h b/src/libs/utils/htmldocextractor.h index 819e7a5bc9c..67f23df369a 100644 --- a/src/libs/utils/htmldocextractor.h +++ b/src/libs/utils/htmldocextractor.h @@ -44,37 +44,22 @@ public: void setLengthReference(const int reference, const bool truncateAtParagraph); void setFormatContents(const bool format); - QString getClassOrNamespaceBrief(const QString &html, const QString &name) const; - QString getClassOrNamespaceDescription(const QString &html, const QString &name) const; - QString getEnumDescription(const QString &html, const QString &name) const; - QString getTypedefDescription(const QString &html, const QString &name) const; - QString getVarDescription(const QString &html, const QString &name) const; - QString getMacroDescription(const QString &html, - const QString &mark, - const QString &anchorName) const; + QString getClassOrNamespaceBrief(const QString &html, const QString &mark) const; + QString getClassOrNamespaceDescription(const QString &html, const QString &mark) const; + QString getEnumDescription(const QString &html, const QString &mark) const; + QString getTypedefDescription(const QString &html, const QString &mark) const; + QString getMacroDescription(const QString &html, const QString &mark) const; QString getFunctionDescription(const QString &html, const QString &mark, - const QString &anchorName, const bool mainOverload = true) const; private: - QString assemble(const QString& elementAttr, const QString &elementTemplate) const; - QString getContentsByAnchor(const QString &html, - const QString &name, - const bool relaxedMatch) const; - QString getContentsByMarks(const QString &html, - const QString &id, - const bool mainOverload) const; QString getClassOrNamespaceMemberDescription(const QString &html, - const QString &mark, - const QString &anchorName, - const bool mainOverload, - const bool relaxedMatch = false) const; - - QString findByMarks(const QString &html, - const QString &startMark, - const QString &endMark) const; - QString findByPattern(const QString &html, const QString &pattern) const; + const QString &startMark, + const QString &endMark) const; + QString getContentsByMarks(const QString &html, + QString startMark, + QString endMark) const; void formatContents(QString *html) const; @@ -91,8 +76,6 @@ private: static void replaceTablesForSimpleLines(QString *html); static void replaceListsForSimpleLines(QString *html); - static QString cleanReference(const QString &reference); - int m_lengthReference; bool m_truncateAtParagraph; bool m_formatContents; diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index ecb2cecc957..a8848e8752b 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -63,14 +63,6 @@ using namespace CPlusPlus; using namespace Core; namespace { - QString removeQualificationIfAny(const QString &name) { - int index = name.lastIndexOf(QLatin1Char(':')); - if (index == -1) - return name; - else - return name.right(name.length() - index - 1); - } - void moveCursorToEndOfName(QTextCursor *tc) { QTextDocument *doc = tc->document(); if (!doc) @@ -334,33 +326,43 @@ void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, } } - HelpCandidate::Category helpCategory; + HelpCandidate::Category helpCategory = HelpCandidate::Unknown; if (matchingDeclaration->isNamespace() || matchingDeclaration->isClass() || matchingDeclaration->isForwardClassDeclaration()) { helpCategory = HelpCandidate::ClassOrNamespace; - } else if (matchingDeclaration->isEnum()) { + } else if (matchingDeclaration->isEnum() || + matchingDeclaration->enclosingSymbol()->isEnum()) { helpCategory = HelpCandidate::Enum; } else if (matchingDeclaration->isTypedef()) { helpCategory = HelpCandidate::Typedef; - } else if (matchingDeclaration->isStatic() && - !matchingDeclaration->type()->isFunctionType()) { - helpCategory = HelpCandidate::Var; - } else { + } else if (matchingDeclaration->isFunction() || + (matchingType.isValid() && matchingType->isFunctionType())){ helpCategory = HelpCandidate::Function; } - // Help identifiers are simply the name with no signature, arguments or return type. - // They might or might not include a qualification. This is why two candidates are created. - overview.setShowArgumentNames(false); - overview.setShowReturnTypes(false); - overview.setShowFunctionSignatures(false); - const QString &simpleName = overview.prettyName(matchingDeclaration->name()); - overview.setShowFunctionSignatures(true); - const QString &specifierId = overview.prettyType(matchingType, simpleName); - - m_helpCandidates.append(HelpCandidate(simpleName, specifierId, helpCategory)); - m_helpCandidates.append(HelpCandidate(qualifiedName, specifierId, helpCategory)); + if (helpCategory != HelpCandidate::Unknown) { + // Help identifiers are simply the name with no signature, arguments or return type. + // They might or might not include a qualification. So two candidates are created. + overview.setShowArgumentNames(false); + overview.setShowReturnTypes(false); + overview.setShowFunctionSignatures(false); + const QString &simpleName = overview.prettyName(matchingDeclaration->name()); + + QString mark; + if (matchingType.isValid() && matchingType->isFunctionType()) { + overview.setShowFunctionSignatures(true); + mark = overview.prettyType(matchingType, simpleName); + } else if (matchingDeclaration->enclosingSymbol()->isEnum()) { + Symbol *enumSymbol = matchingDeclaration->enclosingSymbol()->asEnum(); + mark = overview.prettyName(enumSymbol->name()); + } else { + mark = simpleName; + } + + m_helpCandidates.append(HelpCandidate(simpleName, mark, helpCategory)); + m_helpCandidates.append(HelpCandidate(qualifiedName, mark, helpCategory)); + } } } @@ -395,30 +397,25 @@ QString CppHoverHandler::getDocContents(const HelpCandidate &help) const QMap<QString, QUrl> helpLinks = Core::HelpManager::instance()->linksForIdentifier(help.m_helpId); foreach (const QUrl &url, helpLinks) { - // The help id might or might not be qualified. But anchors and marks are not qualified. - const QString &name = removeQualificationIfAny(help.m_helpId); const QByteArray &html = Core::HelpManager::instance()->fileData(url); switch (help.m_category) { case HelpCandidate::Brief: - contents = m_htmlDocExtractor.getClassOrNamespaceBrief(html, name); + contents = m_htmlDocExtractor.getClassOrNamespaceBrief(html, help.m_docMark); break; case HelpCandidate::ClassOrNamespace: - contents = m_htmlDocExtractor.getClassOrNamespaceDescription(html, name); + contents = m_htmlDocExtractor.getClassOrNamespaceDescription(html, help.m_docMark); break; case HelpCandidate::Function: - contents = m_htmlDocExtractor.getFunctionDescription(html, help.m_markId, name); + contents = m_htmlDocExtractor.getFunctionDescription(html, help.m_docMark); break; case HelpCandidate::Enum: - contents = m_htmlDocExtractor.getEnumDescription(html, name); + contents = m_htmlDocExtractor.getEnumDescription(html, help.m_docMark); break; case HelpCandidate::Typedef: - contents = m_htmlDocExtractor.getTypedefDescription(html, name); - break; - case HelpCandidate::Var: - contents = m_htmlDocExtractor.getVarDescription(html, name); + contents = m_htmlDocExtractor.getTypedefDescription(html, help.m_docMark); break; case HelpCandidate::Macro: - contents = m_htmlDocExtractor.getMacroDescription(html, help.m_markId, name); + contents = m_htmlDocExtractor.getMacroDescription(html, help.m_docMark); break; default: break; diff --git a/src/plugins/cppeditor/cpphoverhandler.h b/src/plugins/cppeditor/cpphoverhandler.h index 59c987d6d5f..464fda0e4f9 100644 --- a/src/plugins/cppeditor/cpphoverhandler.h +++ b/src/plugins/cppeditor/cpphoverhandler.h @@ -82,17 +82,17 @@ private: ClassOrNamespace, Enum, Typedef, - Var, Macro, Brief, - Function + Function, + Unknown }; - HelpCandidate(const QString &helpId, const QString &markId, Category category) : - m_helpId(helpId), m_markId(markId), m_category(category) + HelpCandidate(const QString &helpId, const QString &docMark, Category category) : + m_helpId(helpId), m_docMark(docMark), m_category(category) {} QString m_helpId; - QString m_markId; + QString m_docMark; Category m_category; }; -- GitLab