Commit 5a1983f9 authored by Leandro Melo's avatar Leandro Melo
Browse files

C++ tooltip: Integration with qdocs now only with 4.7 html marks.

parent aae95a24
......@@ -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("&nbsp;&nbsp;&nbsp;&nbsp;"));
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;
}
......@@ -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;
......
......@@ -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;
......
......@@ -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;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment