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;
|
||||
}
|
||||
|
||||
QString HtmlDocExtractor::getQMLItemDescription(const QString &html, const QString &mark) const
|
||||
QString HtmlDocExtractor::getQmlComponentDescription(const QString &html, const QString &mark) const
|
||||
{
|
||||
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,
|
||||
const QString &startMark,
|
||||
const QString &endMark) const
|
||||
|
||||
@@ -57,7 +57,8 @@ public:
|
||||
QString getFunctionDescription(const QString &html,
|
||||
const QString &mark,
|
||||
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:
|
||||
QString getClassOrNamespaceMemberDescription(const QString &html,
|
||||
|
||||
@@ -109,25 +109,29 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
|
||||
if (!qmlEditor)
|
||||
return;
|
||||
|
||||
if (!matchDiagnosticMessage(qmlEditor, pos)) {
|
||||
const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
|
||||
if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
|
||||
return;
|
||||
if (matchDiagnosticMessage(qmlEditor, pos))
|
||||
return;
|
||||
|
||||
QList<AST::Node *> astPath = semanticInfo.astPath(pos);
|
||||
if (astPath.isEmpty())
|
||||
return;
|
||||
const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
|
||||
if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
|
||||
return;
|
||||
|
||||
const Document::Ptr qmlDocument = semanticInfo.document;
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
|
||||
QList<AST::Node *> astPath = semanticInfo.astPath(pos);
|
||||
if (astPath.isEmpty())
|
||||
return;
|
||||
|
||||
if (!matchColorItem(lookupContext, qmlDocument, astPath, pos)) {
|
||||
handleOrdinaryMatch(lookupContext, semanticInfo.nodeUnderCursor(pos));
|
||||
const QString &helpId = qmlHelpId(toolTip());
|
||||
if (!helpId.isEmpty())
|
||||
setLastHelpItemIdentified(TextEditor::HelpItem(helpId, TextEditor::HelpItem::QML));
|
||||
}
|
||||
}
|
||||
const Document::Ptr qmlDocument = semanticInfo.document;
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
|
||||
|
||||
if (matchColorItem(lookupContext, qmlDocument, astPath, pos))
|
||||
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)
|
||||
@@ -236,19 +240,15 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
|
||||
return;
|
||||
|
||||
if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
|
||||
bool found = false;
|
||||
Interpreter::PrototypeIterator iter(objectValue, context);
|
||||
while (iter.hasNext()) {
|
||||
const Interpreter::ObjectValue *prototype = iter.next();
|
||||
const QString className = prototype->className();
|
||||
|
||||
if (! className.isEmpty()) {
|
||||
found = !qmlHelpId(className).isEmpty();
|
||||
if (toolTip().isEmpty() || found)
|
||||
setToolTip(className);
|
||||
}
|
||||
if (found)
|
||||
setToolTip(className);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (const Interpreter::QmlEnumValue *enumValue =
|
||||
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);
|
||||
if (!Core::HelpManager::instance()->linksForIdentifier(helpId).isEmpty())
|
||||
return helpId;
|
||||
return QString();
|
||||
const Interpreter::ObjectValue *owningObject = 0;
|
||||
if (AST::IdentifierExpression *identExp = AST::cast<AST::IdentifierExpression *>(node)) {
|
||||
if (!identExp->name)
|
||||
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,
|
||||
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;
|
||||
QColor m_colorTip;
|
||||
|
||||
@@ -108,8 +108,11 @@ QString HelpItem::extractContent(bool extended) const
|
||||
case Macro:
|
||||
contents = htmlExtractor.getMacroDescription(html, m_docMark);
|
||||
break;
|
||||
case QML:
|
||||
contents = htmlExtractor.getQMLItemDescription(html, m_docMark);
|
||||
case QmlComponent:
|
||||
contents = htmlExtractor.getQmlComponentDescription(html, m_docMark);
|
||||
break;
|
||||
case QmlProperty:
|
||||
contents = htmlExtractor.getQmlPropertyDescription(html, m_docMark);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
Macro,
|
||||
Brief,
|
||||
Function,
|
||||
QML,
|
||||
QmlComponent,
|
||||
QmlProperty,
|
||||
Unknown
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user