forked from qt-creator/qt-creator
Initial work on global completion for QML/JS files.
This commit is contained in:
@@ -202,11 +202,11 @@ class SearchPropertyDefinitions: protected AST::Visitor
|
|||||||
QList<AST::UiPublicMember *> _properties;
|
QList<AST::UiPublicMember *> _properties;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QList<AST::UiPublicMember *> operator()(AST::Node *node)
|
QList<AST::UiPublicMember *> operator()(Document::Ptr doc)
|
||||||
{
|
{
|
||||||
_properties.clear();
|
_properties.clear();
|
||||||
if (node)
|
if (doc && doc->qmlProgram())
|
||||||
node->accept(this);
|
doc->qmlProgram()->accept(this);
|
||||||
return _properties;
|
return _properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,23 +669,53 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
m_completions.clear();
|
m_completions.clear();
|
||||||
|
|
||||||
QmlJS::Document::Ptr qmlDocument = edit->qmlDocument();
|
QmlJS::Document::Ptr qmlDocument = edit->qmlDocument();
|
||||||
// qDebug() << "*** document:" << qmlDocument;
|
|
||||||
if (qmlDocument.isNull())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const QmlJS::Snapshot &snapshot = m_modelManager->snapshot();
|
const QmlJS::Snapshot &snapshot = m_modelManager->snapshot();
|
||||||
|
|
||||||
if (! qmlDocument->qmlProgram()) {
|
if (! qmlDocument)
|
||||||
qmlDocument = snapshot.value(qmlDocument->fileName());
|
qmlDocument = snapshot.value(qmlDocument->fileName());
|
||||||
|
|
||||||
if (! qmlDocument)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QFileInfo currentFileInfo(qmlDocument->fileName());
|
const QFileInfo currentFileInfo(qmlDocument->fileName());
|
||||||
const QString currentFilePath = currentFileInfo.absolutePath();
|
const QString currentFilePath = currentFileInfo.absolutePath();
|
||||||
|
|
||||||
const QIcon typeIcon = iconForColor(Qt::yellow);
|
const QIcon typeIcon = iconForColor(Qt::yellow);
|
||||||
|
const QIcon symbolIcon = iconForColor(Qt::darkCyan);
|
||||||
|
|
||||||
|
Interpreter::Engine interp;
|
||||||
|
|
||||||
|
if (qmlDocument && qmlDocument->qmlProgram()) {
|
||||||
|
const Interpreter::ObjectValue *parentItem = 0;
|
||||||
|
parentItem = interp.newQmlObject(QLatin1String("Item")); // ### TODO: find the parent item.
|
||||||
|
interp.globalObject()->setProperty(QLatin1String("parent"), parentItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Document::Ptr doc, snapshot) {
|
||||||
|
const QFileInfo fileInfo(doc->fileName());
|
||||||
|
|
||||||
|
if (fileInfo.suffix() != QLatin1String("qml"))
|
||||||
|
continue;
|
||||||
|
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME include `imported' components
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString typeName = fileInfo.baseName();
|
||||||
|
if (typeName.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QMapIterator<QString, IdSymbol *> it(doc->ids());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
|
||||||
|
if (IdSymbol *symbol = it.value()) {
|
||||||
|
const QString id = it.key();
|
||||||
|
|
||||||
|
if (symbol->parentNode()) {
|
||||||
|
const QString component = symbol->parentNode()->name();
|
||||||
|
if (const Interpreter::ObjectValue *object = interp.newQmlObject(component))
|
||||||
|
interp.globalObject()->setProperty(id, object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QChar completionOperator;
|
QChar completionOperator;
|
||||||
if (m_startPosition > 0)
|
if (m_startPosition > 0)
|
||||||
@@ -713,21 +743,22 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the visible IDs to the completion box
|
// ### set up the current scope chain.
|
||||||
const QIcon idIcon = iconForColor(Qt::darkGray);
|
const Interpreter::ObjectValue *scope = interp.globalObject();
|
||||||
QStringList ids = qmlDocument->ids().keys();
|
|
||||||
foreach (const QString &id, ids) {
|
EnumerateProperties enumerateProperties;
|
||||||
if (id.isEmpty())
|
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(scope));
|
||||||
continue;
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
|
||||||
TextEditor::CompletionItem item(this);
|
TextEditor::CompletionItem item(this);
|
||||||
item.text = id;
|
item.text = it.key();
|
||||||
item.icon = idIcon;
|
item.icon = symbolIcon;
|
||||||
m_completions.append(item);
|
m_completions.append(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
|
else if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
|
||||||
ExpressionUnderCursor expressionUnderCursor;
|
ExpressionUnderCursor expressionUnderCursor;
|
||||||
|
|
||||||
QTextCursor tc = edit->textCursor();
|
QTextCursor tc = edit->textCursor();
|
||||||
@@ -736,64 +767,35 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
const QString expression = expressionUnderCursor(tc);
|
const QString expression = expressionUnderCursor(tc);
|
||||||
//qDebug() << "expression:" << expression;
|
//qDebug() << "expression:" << expression;
|
||||||
|
|
||||||
QmlJS::Document::Ptr exprDoc = QmlJS::Document::create(QLatin1String("<expression>"));
|
QmlJS::Document::Ptr exprDoc = Document::create(QLatin1String("<expression>"));
|
||||||
exprDoc->setSource(expression);
|
exprDoc->setSource(expression);
|
||||||
exprDoc->parseExpression();
|
exprDoc->parseExpression();
|
||||||
|
|
||||||
if (exprDoc->ast()) {
|
if (exprDoc->ast()) {
|
||||||
Interpreter::Engine interp;
|
|
||||||
|
|
||||||
if (qmlDocument && qmlDocument->qmlProgram()) {
|
|
||||||
const Interpreter::ObjectValue *parentItem = 0;
|
|
||||||
parentItem = interp.newQmlObject(QLatin1String("Item")); // ### TODO: find the parent item.
|
|
||||||
interp.globalObject()->setProperty(QLatin1String("parent"), parentItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Document::Ptr doc, snapshot) {
|
|
||||||
const QFileInfo fileInfo(doc->fileName());
|
|
||||||
|
|
||||||
if (fileInfo.suffix() != QLatin1String("qml"))
|
|
||||||
continue;
|
|
||||||
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME include `imported' components
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const QString typeName = fileInfo.baseName();
|
|
||||||
if (typeName.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QMapIterator<QString, IdSymbol *> it(doc->ids());
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
|
|
||||||
if (IdSymbol *symbol = it.value()) {
|
|
||||||
const QString id = it.key();
|
|
||||||
|
|
||||||
if (symbol->parentNode()) {
|
|
||||||
const QString component = symbol->parentNode()->name();
|
|
||||||
if (const Interpreter::ObjectValue *object = interp.newQmlObject(component))
|
|
||||||
interp.globalObject()->setProperty(id, object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Evaluate evaluate(&interp);
|
Evaluate evaluate(&interp);
|
||||||
// ### set up the scope chain
|
// ### set up the scope chain
|
||||||
|
|
||||||
SearchPropertyDefinitions searchPropertyDefinitions;
|
SearchPropertyDefinitions searchPropertyDefinitions;
|
||||||
|
|
||||||
const QList<AST::UiPublicMember *> properties = searchPropertyDefinitions(qmlDocument->ast());
|
const QList<AST::UiPublicMember *> properties = searchPropertyDefinitions(qmlDocument);
|
||||||
foreach (AST::UiPublicMember *prop, properties) {
|
foreach (AST::UiPublicMember *prop, properties) {
|
||||||
if (prop->name && prop->memberType && prop->memberType->asString() == QLatin1String("string")) {
|
if (! (prop->name && prop->memberType))
|
||||||
interp.globalObject()->setProperty(prop->name->asString(), interp.stringValue());
|
continue;
|
||||||
}
|
|
||||||
|
const QString propName = prop->name->asString();
|
||||||
|
const QString propType = prop->memberType->asString();
|
||||||
|
|
||||||
|
if (propType == QLatin1String("string"))
|
||||||
|
interp.globalObject()->setProperty(propName, interp.stringValue());
|
||||||
|
else if (propType == QLatin1String("bool"))
|
||||||
|
interp.globalObject()->setProperty(propName, interp.booleanValue());
|
||||||
|
else if (propType == QLatin1String("int") || propType == QLatin1String("real"))
|
||||||
|
interp.globalObject()->setProperty(propName, interp.numberValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->ast()));
|
const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->ast()));
|
||||||
//qDebug() << "type:" << interp.typeId(value);
|
//qDebug() << "type:" << interp.typeId(value);
|
||||||
|
|
||||||
const QIcon symbolIcon = iconForColor(Qt::darkCyan);
|
|
||||||
|
|
||||||
if (value && completionOperator == QLatin1Char('.')) { // member completion
|
if (value && completionOperator == QLatin1Char('.')) { // member completion
|
||||||
EnumerateProperties enumerateProperties;
|
EnumerateProperties enumerateProperties;
|
||||||
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(value));
|
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(value));
|
||||||
@@ -805,7 +807,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
item.icon = symbolIcon;
|
item.icon = symbolIcon;
|
||||||
m_completions.append(item);
|
m_completions.append(item);
|
||||||
}
|
}
|
||||||
} else if (value && completionOperator == QLatin1Char('(')) {
|
} else if (value && completionOperator == QLatin1Char('(')) { // function completion
|
||||||
if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
|
if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
|
||||||
QString functionName = expression;
|
QString functionName = expression;
|
||||||
int indexOfDot = expression.lastIndexOf(QLatin1Char('.'));
|
int indexOfDot = expression.lastIndexOf(QLatin1Char('.'));
|
||||||
@@ -816,10 +818,11 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
|||||||
if (!m_functionArgumentWidget)
|
if (!m_functionArgumentWidget)
|
||||||
m_functionArgumentWidget = new QmlJSEditor::Internal::FunctionArgumentWidget;
|
m_functionArgumentWidget = new QmlJSEditor::Internal::FunctionArgumentWidget;
|
||||||
|
|
||||||
m_functionArgumentWidget->showFunctionHint(functionName.trimmed(), f->argumentCount(), m_startPosition);
|
m_functionArgumentWidget->showFunctionHint(functionName.trimmed(), f->argumentCount(),
|
||||||
|
m_startPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1; // We always return -1 when completing function prototypes.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user