Initial work on global completion for QML/JS files.

This commit is contained in:
Roberto Raggi
2010-01-24 17:33:07 +01:00
parent feab07de81
commit b4a901aa1e

View File

@@ -202,11 +202,11 @@ class SearchPropertyDefinitions: protected AST::Visitor
QList<AST::UiPublicMember *> _properties;
public:
QList<AST::UiPublicMember *> operator()(AST::Node *node)
QList<AST::UiPublicMember *> operator()(Document::Ptr doc)
{
_properties.clear();
if (node)
node->accept(this);
if (doc && doc->qmlProgram())
doc->qmlProgram()->accept(this);
return _properties;
}
@@ -669,78 +669,18 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
m_completions.clear();
QmlJS::Document::Ptr qmlDocument = edit->qmlDocument();
// qDebug() << "*** document:" << qmlDocument;
if (qmlDocument.isNull())
return -1;
const QmlJS::Snapshot &snapshot = m_modelManager->snapshot();
if (! qmlDocument->qmlProgram()) {
qmlDocument = snapshot.value(qmlDocument->fileName());
if (! qmlDocument)
return -1;
}
qmlDocument = snapshot.value(qmlDocument->fileName());
const QFileInfo currentFileInfo(qmlDocument->fileName());
const QString currentFilePath = currentFileInfo.absolutePath();
const QIcon typeIcon = iconForColor(Qt::yellow);
const QIcon symbolIcon = iconForColor(Qt::darkCyan);
QChar completionOperator;
if (m_startPosition > 0)
completionOperator = editor->characterAt(m_startPosition - 1);
if (completionOperator.isSpace() || completionOperator.isNull()) {
// Add the visible components to the completion box.
foreach (QmlJS::Document::Ptr doc, snapshot) {
const QFileInfo fileInfo(doc->fileName());
if (fileInfo.suffix() != QLatin1String("qml"))
continue;
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME includ `imported' components
continue;
const QString typeName = fileInfo.baseName();
if (typeName.isEmpty())
continue;
if (typeName.at(0).isUpper()) {
TextEditor::CompletionItem item(this);
item.text = typeName;
item.icon = typeIcon;
m_completions.append(item);
}
}
// Add the visible IDs to the completion box
const QIcon idIcon = iconForColor(Qt::darkGray);
QStringList ids = qmlDocument->ids().keys();
foreach (const QString &id, ids) {
if (id.isEmpty())
continue;
TextEditor::CompletionItem item(this);
item.text = id;
item.icon = idIcon;
m_completions.append(item);
}
}
if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
ExpressionUnderCursor expressionUnderCursor;
QTextCursor tc = edit->textCursor();
tc.setPosition(m_startPosition - 1);
const QString expression = expressionUnderCursor(tc);
//qDebug() << "expression:" << expression;
QmlJS::Document::Ptr exprDoc = QmlJS::Document::create(QLatin1String("<expression>"));
exprDoc->setSource(expression);
exprDoc->parseExpression();
if (exprDoc->ast()) {
Interpreter::Engine interp;
if (qmlDocument && qmlDocument->qmlProgram()) {
@@ -777,23 +717,85 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
}
}
QChar completionOperator;
if (m_startPosition > 0)
completionOperator = editor->characterAt(m_startPosition - 1);
if (completionOperator.isSpace() || completionOperator.isNull()) {
// Add the visible components to the completion box.
foreach (QmlJS::Document::Ptr doc, snapshot) {
const QFileInfo fileInfo(doc->fileName());
if (fileInfo.suffix() != QLatin1String("qml"))
continue;
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME includ `imported' components
continue;
const QString typeName = fileInfo.baseName();
if (typeName.isEmpty())
continue;
if (typeName.at(0).isUpper()) {
TextEditor::CompletionItem item(this);
item.text = typeName;
item.icon = typeIcon;
m_completions.append(item);
}
}
// ### set up the current scope chain.
const Interpreter::ObjectValue *scope = interp.globalObject();
EnumerateProperties enumerateProperties;
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(scope));
while (it.hasNext()) {
it.next();
TextEditor::CompletionItem item(this);
item.text = it.key();
item.icon = symbolIcon;
m_completions.append(item);
}
}
else if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
ExpressionUnderCursor expressionUnderCursor;
QTextCursor tc = edit->textCursor();
tc.setPosition(m_startPosition - 1);
const QString expression = expressionUnderCursor(tc);
//qDebug() << "expression:" << expression;
QmlJS::Document::Ptr exprDoc = Document::create(QLatin1String("<expression>"));
exprDoc->setSource(expression);
exprDoc->parseExpression();
if (exprDoc->ast()) {
Evaluate evaluate(&interp);
// ### set up the scope chain
SearchPropertyDefinitions searchPropertyDefinitions;
const QList<AST::UiPublicMember *> properties = searchPropertyDefinitions(qmlDocument->ast());
const QList<AST::UiPublicMember *> properties = searchPropertyDefinitions(qmlDocument);
foreach (AST::UiPublicMember *prop, properties) {
if (prop->name && prop->memberType && prop->memberType->asString() == QLatin1String("string")) {
interp.globalObject()->setProperty(prop->name->asString(), interp.stringValue());
}
if (! (prop->name && prop->memberType))
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()));
//qDebug() << "type:" << interp.typeId(value);
const QIcon symbolIcon = iconForColor(Qt::darkCyan);
if (value && completionOperator == QLatin1Char('.')) { // member completion
EnumerateProperties enumerateProperties;
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(value));
@@ -805,7 +807,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
item.icon = symbolIcon;
m_completions.append(item);
}
} else if (value && completionOperator == QLatin1Char('(')) {
} else if (value && completionOperator == QLatin1Char('(')) { // function completion
if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
QString functionName = expression;
int indexOfDot = expression.lastIndexOf(QLatin1Char('.'));
@@ -816,10 +818,11 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
if (!m_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.
}
}