forked from qt-creator/qt-creator
QmlJS: Implement context help and tooltips for properties.
This commit is contained in:
@@ -137,11 +137,32 @@ QString HtmlDocExtractor::getFunctionDescription(const QString &html,
|
|||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HtmlDocExtractor::getQMLItemDescription(const QString &html, const QString &mark) const
|
QString HtmlDocExtractor::getQmlComponentDescription(const QString &html, const QString &mark) const
|
||||||
{
|
{
|
||||||
return getClassOrNamespaceDescription(html, mark);
|
return getClassOrNamespaceDescription(html, mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString HtmlDocExtractor::getQmlPropertyDescription(const QString &html, const QString &mark) const
|
||||||
|
{
|
||||||
|
QString startMark = QString("<a name=\"%1-prop\">").arg(mark);
|
||||||
|
int index = html.indexOf(startMark);
|
||||||
|
if (index == -1) {
|
||||||
|
startMark = QString("<a name=\"%1-signal\">").arg(mark);
|
||||||
|
index = html.indexOf(startMark);
|
||||||
|
}
|
||||||
|
if (index == -1)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
QString contents = html.mid(index + startMark.size());
|
||||||
|
index = contents.indexOf(QLatin1String("<p>"));
|
||||||
|
if (index == -1)
|
||||||
|
return QString();
|
||||||
|
contents = contents.mid(index);
|
||||||
|
processOutput(&contents);
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
QString HtmlDocExtractor::getClassOrNamespaceMemberDescription(const QString &html,
|
QString HtmlDocExtractor::getClassOrNamespaceMemberDescription(const QString &html,
|
||||||
const QString &startMark,
|
const QString &startMark,
|
||||||
const QString &endMark) const
|
const QString &endMark) const
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ public:
|
|||||||
QString getFunctionDescription(const QString &html,
|
QString getFunctionDescription(const QString &html,
|
||||||
const QString &mark,
|
const QString &mark,
|
||||||
const bool mainOverload = true) const;
|
const bool mainOverload = true) const;
|
||||||
QString getQMLItemDescription(const QString &html, const QString &mark) const;
|
QString getQmlComponentDescription(const QString &html, const QString &mark) const;
|
||||||
|
QString getQmlPropertyDescription(const QString &html, const QString &mark) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getClassOrNamespaceMemberDescription(const QString &html,
|
QString getClassOrNamespaceMemberDescription(const QString &html,
|
||||||
|
|||||||
@@ -109,25 +109,29 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
|
|||||||
if (!qmlEditor)
|
if (!qmlEditor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!matchDiagnosticMessage(qmlEditor, pos)) {
|
if (matchDiagnosticMessage(qmlEditor, pos))
|
||||||
const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
|
return;
|
||||||
if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QList<AST::Node *> astPath = semanticInfo.astPath(pos);
|
const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
|
||||||
if (astPath.isEmpty())
|
if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const Document::Ptr qmlDocument = semanticInfo.document;
|
QList<AST::Node *> astPath = semanticInfo.astPath(pos);
|
||||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
|
if (astPath.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!matchColorItem(lookupContext, qmlDocument, astPath, pos)) {
|
const Document::Ptr qmlDocument = semanticInfo.document;
|
||||||
handleOrdinaryMatch(lookupContext, semanticInfo.nodeUnderCursor(pos));
|
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
|
||||||
const QString &helpId = qmlHelpId(toolTip());
|
|
||||||
if (!helpId.isEmpty())
|
if (matchColorItem(lookupContext, qmlDocument, astPath, pos))
|
||||||
setLastHelpItemIdentified(TextEditor::HelpItem(helpId, TextEditor::HelpItem::QML));
|
return;
|
||||||
}
|
|
||||||
}
|
AST::Node *node = semanticInfo.nodeUnderCursor(pos);
|
||||||
|
handleOrdinaryMatch(lookupContext, node);
|
||||||
|
|
||||||
|
TextEditor::HelpItem helpItem = qmlHelpItem(lookupContext, node);
|
||||||
|
if (!helpItem.helpId().isEmpty())
|
||||||
|
setLastHelpItemIdentified(helpItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HoverHandler::matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditor *qmlEditor, int pos)
|
bool HoverHandler::matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditor *qmlEditor, int pos)
|
||||||
@@ -236,19 +240,15 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
|
if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
|
||||||
bool found = false;
|
|
||||||
Interpreter::PrototypeIterator iter(objectValue, context);
|
Interpreter::PrototypeIterator iter(objectValue, context);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
const Interpreter::ObjectValue *prototype = iter.next();
|
const Interpreter::ObjectValue *prototype = iter.next();
|
||||||
const QString className = prototype->className();
|
const QString className = prototype->className();
|
||||||
|
|
||||||
if (! className.isEmpty()) {
|
if (! className.isEmpty()) {
|
||||||
found = !qmlHelpId(className).isEmpty();
|
setToolTip(className);
|
||||||
if (toolTip().isEmpty() || found)
|
|
||||||
setToolTip(className);
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (const Interpreter::QmlEnumValue *enumValue =
|
} else if (const Interpreter::QmlEnumValue *enumValue =
|
||||||
dynamic_cast<const Interpreter::QmlEnumValue *>(value)) {
|
dynamic_cast<const Interpreter::QmlEnumValue *>(value)) {
|
||||||
@@ -262,10 +262,74 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HoverHandler::qmlHelpId(const QString &itemName) const
|
// if node refers to a property, its name and defining object are returned - otherwise zero
|
||||||
|
static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookupContext,
|
||||||
|
AST::Node *node, QString *name)
|
||||||
{
|
{
|
||||||
QString helpId(QLatin1String("QML.") + itemName);
|
const Interpreter::ObjectValue *owningObject = 0;
|
||||||
if (!Core::HelpManager::instance()->linksForIdentifier(helpId).isEmpty())
|
if (AST::IdentifierExpression *identExp = AST::cast<AST::IdentifierExpression *>(node)) {
|
||||||
return helpId;
|
if (!identExp->name)
|
||||||
return QString();
|
return 0;
|
||||||
|
*name = identExp->name->asString();
|
||||||
|
lookupContext->context()->lookup(*name, &owningObject);
|
||||||
|
} else if (AST::FieldMemberExpression *fme = AST::cast<AST::FieldMemberExpression *>(node)) {
|
||||||
|
if (!fme->base || !fme->name)
|
||||||
|
return 0;
|
||||||
|
*name = fme->name->asString();
|
||||||
|
const Interpreter::Value *base = lookupContext->evaluate(fme->base);
|
||||||
|
if (!base)
|
||||||
|
return 0;
|
||||||
|
owningObject = base->asObjectValue();
|
||||||
|
if (owningObject)
|
||||||
|
owningObject->lookupMember(*name, lookupContext->context(), &owningObject);
|
||||||
|
} else if (AST::UiQualifiedId *qid = AST::cast<AST::UiQualifiedId *>(node)) {
|
||||||
|
if (!qid->name)
|
||||||
|
return 0;
|
||||||
|
*name = qid->name->asString();
|
||||||
|
const Interpreter::Value *value = lookupContext->context()->lookup(*name, &owningObject);
|
||||||
|
for (AST::UiQualifiedId *it = qid->next; it; it = it->next) {
|
||||||
|
if (!value)
|
||||||
|
return 0;
|
||||||
|
const Interpreter::ObjectValue *next = value->asObjectValue();
|
||||||
|
if (!next || !it->name)
|
||||||
|
return 0;
|
||||||
|
*name = it->name->asString();
|
||||||
|
value = next->lookupMember(*name, lookupContext->context(), &owningObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return owningObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::HelpItem HoverHandler::qmlHelpItem(const LookupContext::Ptr &lookupContext,
|
||||||
|
AST::Node *node) const
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
if (const Interpreter::ObjectValue *scope = isMember(lookupContext, node, &name)) {
|
||||||
|
// maybe it's a type?
|
||||||
|
if (!name.isEmpty() && name.at(0).isUpper()) {
|
||||||
|
const QString maybeHelpId(QLatin1String("QML.") + name);
|
||||||
|
if (!Core::HelpManager::instance()->linksForIdentifier(maybeHelpId).isEmpty())
|
||||||
|
return TextEditor::HelpItem(maybeHelpId, name, TextEditor::HelpItem::QmlComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, it's probably a property
|
||||||
|
const Interpreter::ObjectValue *lastScope;
|
||||||
|
scope->lookupMember(name, lookupContext->context(), &lastScope);
|
||||||
|
Interpreter::PrototypeIterator iter(scope, lookupContext->context());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
const Interpreter::ObjectValue *cur = iter.next();
|
||||||
|
|
||||||
|
const QString className = cur->className();
|
||||||
|
if (!className.isEmpty()) {
|
||||||
|
const QString maybeHelpId(className + QLatin1String("::") + name);
|
||||||
|
if (!Core::HelpManager::instance()->linksForIdentifier(maybeHelpId).isEmpty())
|
||||||
|
return TextEditor::HelpItem(maybeHelpId, name, TextEditor::HelpItem::QmlProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur == lastScope)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextEditor::HelpItem();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ private:
|
|||||||
void prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
|
void prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
|
||||||
const QmlJS::Interpreter::Context *context);
|
const QmlJS::Interpreter::Context *context);
|
||||||
|
|
||||||
QString qmlHelpId(const QString &itemName) const;
|
TextEditor::HelpItem qmlHelpItem(const QmlJS::LookupContext::Ptr &lookupContext,
|
||||||
|
QmlJS::AST::Node *node) const;
|
||||||
|
|
||||||
QmlJS::ModelManagerInterface *m_modelManager;
|
QmlJS::ModelManagerInterface *m_modelManager;
|
||||||
QColor m_colorTip;
|
QColor m_colorTip;
|
||||||
|
|||||||
@@ -108,8 +108,11 @@ QString HelpItem::extractContent(bool extended) const
|
|||||||
case Macro:
|
case Macro:
|
||||||
contents = htmlExtractor.getMacroDescription(html, m_docMark);
|
contents = htmlExtractor.getMacroDescription(html, m_docMark);
|
||||||
break;
|
break;
|
||||||
case QML:
|
case QmlComponent:
|
||||||
contents = htmlExtractor.getQMLItemDescription(html, m_docMark);
|
contents = htmlExtractor.getQmlComponentDescription(html, m_docMark);
|
||||||
|
break;
|
||||||
|
case QmlProperty:
|
||||||
|
contents = htmlExtractor.getQmlPropertyDescription(html, m_docMark);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ public:
|
|||||||
Macro,
|
Macro,
|
||||||
Brief,
|
Brief,
|
||||||
Function,
|
Function,
|
||||||
QML,
|
QmlComponent,
|
||||||
|
QmlProperty,
|
||||||
Unknown
|
Unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user