summaryrefslogtreecommitdiffstats
path: root/src/scripttools
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-06-12 15:05:27 (GMT)
committerKent Hansen <khansen@trolltech.com>2009-06-12 15:06:08 (GMT)
commita25548dd9a6ad08961df56a97b6b5189d465f251 (patch)
tree986f1e0118f510c9ad4a71defab4c37080783c00 /src/scripttools
parent4d0cc0b9600f8530bb0e8712b4bb109d1810c4a7 (diff)
downloadQt-a25548dd9a6ad08961df56a97b6b5189d465f251.zip
Qt-a25548dd9a6ad08961df56a97b6b5189d465f251.tar.gz
Qt-a25548dd9a6ad08961df56a97b6b5189d465f251.tar.bz2
make debugger console's auto-completion asynchronous
Needed for remote debugging.
Diffstat (limited to 'src/scripttools')
-rw-r--r--src/scripttools/debugging/qscriptcompletiontask.cpp204
-rw-r--r--src/scripttools/debugging/qscriptcompletiontask_p.h9
-rw-r--r--src/scripttools/debugging/qscriptdebugger.cpp2
-rw-r--r--src/scripttools/debugging/qscriptdebuggercommand.cpp9
-rw-r--r--src/scripttools/debugging/qscriptdebuggercommand_p.h2
-rw-r--r--src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp67
-rw-r--r--src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend.cpp5
-rw-r--r--src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend_p.h1
8 files changed, 196 insertions, 103 deletions
diff --git a/src/scripttools/debugging/qscriptcompletiontask.cpp b/src/scripttools/debugging/qscriptcompletiontask.cpp
index 9554681..e2034f3 100644
--- a/src/scripttools/debugging/qscriptcompletiontask.cpp
+++ b/src/scripttools/debugging/qscriptcompletiontask.cpp
@@ -44,12 +44,10 @@
#include "qscriptdebuggerconsole_p.h"
#include "qscriptdebuggerconsolecommand_p.h"
#include "qscriptdebuggerconsolecommandmanager_p.h"
-
-#include "qscriptenginedebuggerfrontend_p.h" // ### kill
-#include "qscriptdebuggerbackend_p.h" // ### kill
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptvalueiterator.h>
+#include "qscriptdebuggercommandschedulerjob_p.h"
+#include "qscriptdebuggercommandschedulerfrontend_p.h"
+#include "qscriptdebuggerjobschedulerinterface_p.h"
+#include "qscriptdebuggerresponse_p.h"
#include "private/qobject_p.h"
@@ -67,11 +65,13 @@ public:
~QScriptCompletionTaskPrivate();
void completeScriptExpression();
+ void emitFinished();
QString contents;
int cursorPosition;
int frameIndex;
- QScriptDebuggerFrontend *frontend;
+ QScriptDebuggerCommandSchedulerInterface *commandScheduler;
+ QScriptDebuggerJobSchedulerInterface *jobScheduler;
QScriptDebuggerConsole *console;
};
@@ -83,28 +83,33 @@ QScriptCompletionTaskPrivate::~QScriptCompletionTaskPrivate()
{
}
-QScriptCompletionTask::QScriptCompletionTask(
- const QString &contents, int cursorPosition,
- int frameIndex, QScriptDebuggerFrontend *frontend,
- QScriptDebuggerConsole *console,
- QObject *parent)
- : QScriptCompletionTaskInterface(
- *new QScriptCompletionTaskPrivate, parent)
+class QScriptCompleteExpressionJob : public QScriptDebuggerCommandSchedulerJob
{
- Q_D(QScriptCompletionTask);
- d->contents = contents;
- d->cursorPosition = cursorPosition;
- if ((frameIndex == -1) && console)
- d->frameIndex = console->currentFrameIndex();
- else
- d->frameIndex = frameIndex;
- d->frontend = frontend;
- d->console = console;
-}
+public:
+ QScriptCompleteExpressionJob(int frameIndex, const QStringList &path,
+ QScriptCompletionTaskPrivate *task,
+ QScriptDebuggerCommandSchedulerInterface *scheduler)
+ : QScriptDebuggerCommandSchedulerJob(scheduler),
+ m_frameIndex(frameIndex), m_path(path), m_task(task)
+ {}
-QScriptCompletionTask::~QScriptCompletionTask()
-{
-}
+ void start()
+ {
+ QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
+ frontend.scheduleGetCompletions(m_frameIndex, m_path);
+ }
+ void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
+ {
+ m_task->results = response.result().toStringList();
+ m_task->emitFinished();
+ finish();
+ }
+
+private:
+ int m_frameIndex;
+ QStringList m_path;
+ QScriptCompletionTaskPrivate *m_task;
+};
namespace {
@@ -122,11 +127,43 @@ static bool isPrefixOf(const QString &prefix, const QString &what)
} // namespace
+class QScriptCompleteScriptsJob : public QScriptDebuggerCommandSchedulerJob
+{
+public:
+ QScriptCompleteScriptsJob(const QString &prefix, QScriptCompletionTaskPrivate *task,
+ QScriptDebuggerCommandSchedulerInterface *scheduler)
+ : QScriptDebuggerCommandSchedulerJob(scheduler),
+ m_prefix(prefix), m_task(task)
+ {}
+
+ void start()
+ {
+ QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
+ frontend.scheduleGetScripts();
+ }
+ void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
+ {
+ QScriptScriptMap scripts = response.resultAsScripts();
+ QScriptScriptMap::const_iterator it;
+ for (it = scripts.constBegin(); it != scripts.constEnd(); ++it) {
+ QString fileName = it.value().fileName();
+ if (isPrefixOf(m_prefix, fileName))
+ m_task->results.append(fileName);
+ }
+ m_task->emitFinished();
+ finish();
+ }
+private:
+ QString m_prefix;
+ QScriptCompletionTaskPrivate *m_task;
+};
+
void QScriptCompletionTaskPrivate::completeScriptExpression()
{
int pos = cursorPosition;
if ((pos > 0) && contents.at(pos-1).isNumber()) {
// completion of numbers is pointless
+ emitFinished();
return;
}
@@ -148,65 +185,41 @@ void QScriptCompletionTaskPrivate::completeScriptExpression()
path.prepend(contents.mid(pos, pos2 - pos));
}
- // ### super-cheating for now; have to use the async API
- QScriptEngineDebuggerFrontend *edf = static_cast<QScriptEngineDebuggerFrontend*>(frontend);
- QScriptDebuggerBackend *backend = edf->backend();
- QScriptContext *ctx = backend->context(frameIndex);
- QScriptValueList objects;
- QString prefix = path.last();
- QSet<QString> matches;
- if (path.size() > 1) {
- const QString &topLevelIdent = path.at(0);
- QScriptValue obj;
- if (topLevelIdent == QLatin1String("this")) {
- obj = ctx->thisObject();
- } else {
- QScriptValueList scopeChain;
- scopeChain = ctx->scopeChain();
- for (int i = 0; i < scopeChain.size(); ++i) {
- QScriptValue oo = scopeChain.at(i).property(topLevelIdent);
- if (oo.isObject()) {
- obj = oo;
- break;
- }
- }
- }
- for (int i = 1; obj.isObject() && (i < path.size()-1); ++i)
- obj = obj.property(path.at(i));
- if (obj.isValid())
- objects.append(obj);
- } else {
- objects << ctx->scopeChain();
- QStringList keywords;
- keywords.append(QString::fromLatin1("this"));
- keywords.append(QString::fromLatin1("true"));
- keywords.append(QString::fromLatin1("false"));
- keywords.append(QString::fromLatin1("null"));
- for (int i = 0; i < keywords.size(); ++i) {
- const QString &kwd = keywords.at(i);
- if (isPrefixOf(prefix, kwd))
- matches.insert(kwd);
- }
- }
+ length = path.last().length();
+ type = QScriptCompletionTask::ScriptIdentifierCompletion;
- for (int i = 0; i < objects.size(); ++i) {
- QScriptValue obj = objects.at(i);
- while (obj.isObject()) {
- QScriptValueIterator it(obj);
- while (it.hasNext()) {
- it.next();
- QString propertyName = it.name();
- if (isPrefixOf(prefix, propertyName))
- matches.insert(propertyName);
- }
- obj = obj.prototype();
- }
- }
- results = matches.toList();
- qStableSort(results);
+ QScriptDebuggerJob *job = new QScriptCompleteExpressionJob(frameIndex, path, this, commandScheduler);
+ jobScheduler->scheduleJob(job);
+}
- length = prefix.length();
- type = QScriptCompletionTask::ScriptIdentifierCompletion;
+void QScriptCompletionTaskPrivate::emitFinished()
+{
+ emit q_func()->finished();
+}
+
+QScriptCompletionTask::QScriptCompletionTask(
+ const QString &contents, int cursorPosition, int frameIndex,
+ QScriptDebuggerCommandSchedulerInterface *commandScheduler,
+ QScriptDebuggerJobSchedulerInterface *jobScheduler,
+ QScriptDebuggerConsole *console,
+ QObject *parent)
+ : QScriptCompletionTaskInterface(
+ *new QScriptCompletionTaskPrivate, parent)
+{
+ Q_D(QScriptCompletionTask);
+ d->contents = contents;
+ d->cursorPosition = cursorPosition;
+ if ((frameIndex == -1) && console)
+ d->frameIndex = console->currentFrameIndex();
+ else
+ d->frameIndex = frameIndex;
+ d->commandScheduler = commandScheduler;
+ d->jobScheduler = jobScheduler;
+ d->console = console;
+}
+
+QScriptCompletionTask::~QScriptCompletionTask()
+{
}
void QScriptCompletionTask::start()
@@ -223,7 +236,6 @@ void QScriptCompletionTask::start()
if ((d->cursorPosition >= cmdIndex) && (d->cursorPosition <= (cmdIndex+len))) {
// editing command --> get command completions
d->results = d->console->commandManager()->completions(prefix);
- qStableSort(d->results);
d->position = cmdRx.pos(1);
d->length = prefix.length();
d->type = CommandNameCompletion;
@@ -259,38 +271,34 @@ void QScriptCompletionTask::start()
if (argType == QLatin1String("command-or-group-name")) {
d->results = d->console->commandManager()->completions(arg);
} else if (argType == QLatin1String("script-filename")) {
- // ### super-cheating for now; have to use the async API
- QScriptEngineDebuggerFrontend *edf = static_cast<QScriptEngineDebuggerFrontend*>(d->frontend);
- QScriptDebuggerBackend *backend = edf->backend();
- QScriptScriptMap scripts = backend->scripts();
- QScriptScriptMap::const_iterator it;
- for (it = scripts.constBegin(); it != scripts.constEnd(); ++it) {
- QString fileName = it.value().fileName();
- if (isPrefixOf(arg, fileName))
- d->results.append(fileName);
- }
+ d->position = pos;
+ d->length = arg.length();
+ d->type = CommandArgumentCompletion;
+ QScriptDebuggerJob *job = new QScriptCompleteScriptsJob(arg, d, d->commandScheduler);
+ d->jobScheduler->scheduleJob(job);
} else if (argType == QLatin1String("subcommand-name")) {
for (int i = 0; i < cmd->subCommands().size(); ++i) {
QString name = cmd->subCommands().at(i);
if (isPrefixOf(arg, name))
d->results.append(name);
}
+ qStableSort(d->results);
} else if (argType == QLatin1String("script")) {
d->completeScriptExpression();
+ } else {
+ emit finished();
}
if ((d->type == NoCompletion) && !d->results.isEmpty()) {
- qStableSort(d->results);
d->position = pos;
d->length = arg.length();
d->type = CommandArgumentCompletion;
+ emit finished();
}
}
- emit finished();
}
} else {
// assume it's an eval expression
d->completeScriptExpression();
- emit finished();
}
}
diff --git a/src/scripttools/debugging/qscriptcompletiontask_p.h b/src/scripttools/debugging/qscriptcompletiontask_p.h
index dd82250..0055959 100644
--- a/src/scripttools/debugging/qscriptcompletiontask_p.h
+++ b/src/scripttools/debugging/qscriptcompletiontask_p.h
@@ -60,7 +60,8 @@
QT_BEGIN_NAMESPACE
-class QScriptDebuggerFrontend;
+class QScriptDebuggerCommandSchedulerInterface;
+class QScriptDebuggerJobSchedulerInterface;
class QScriptDebuggerConsole;
class QScriptCompletionTaskPrivate;
@@ -70,9 +71,9 @@ class Q_AUTOTEST_EXPORT QScriptCompletionTask
Q_OBJECT
public:
QScriptCompletionTask(
- const QString &contents, int cursorPosition,
- int frameIndex,
- QScriptDebuggerFrontend *frontend,
+ const QString &contents, int cursorPosition, int frameIndex,
+ QScriptDebuggerCommandSchedulerInterface *commandScheduler,
+ QScriptDebuggerJobSchedulerInterface *jobScheduler,
QScriptDebuggerConsole *console,
QObject *parent = 0);
~QScriptCompletionTask();
diff --git a/src/scripttools/debugging/qscriptdebugger.cpp b/src/scripttools/debugging/qscriptdebugger.cpp
index d83a1d0..5626a4b 100644
--- a/src/scripttools/debugging/qscriptdebugger.cpp
+++ b/src/scripttools/debugging/qscriptdebugger.cpp
@@ -695,7 +695,7 @@ QScriptCompletionTaskInterface *QScriptDebuggerPrivate::createCompletionTask(
const QString &contents, int cursorPosition, int frameIndex, int options)
{
return new QScriptCompletionTask(
- contents, cursorPosition, frameIndex, frontend,
+ contents, cursorPosition, frameIndex, this, this,
(options & QScriptCompletionProviderInterface::ConsoleCommandCompletion) ? console : 0);
}
diff --git a/src/scripttools/debugging/qscriptdebuggercommand.cpp b/src/scripttools/debugging/qscriptdebuggercommand.cpp
index 3ceb0d5..fc9b96a 100644
--- a/src/scripttools/debugging/qscriptdebuggercommand.cpp
+++ b/src/scripttools/debugging/qscriptdebuggercommand.cpp
@@ -568,6 +568,15 @@ QScriptDebuggerCommand QScriptDebuggerCommand::getPropertyExpressionValue(
return cmd;
}
+QScriptDebuggerCommand QScriptDebuggerCommand::getCompletions(
+ int contextIndex, const QStringList &path)
+{
+ QScriptDebuggerCommand cmd(GetCompletions);
+ cmd.setContextIndex(contextIndex);
+ cmd.setAttribute(UserAttribute, path);
+ return cmd;
+}
+
QScriptDebuggerCommand QScriptDebuggerCommand::newScriptObjectSnapshotCommand()
{
QScriptDebuggerCommand cmd(NewScriptObjectSnapshot);
diff --git a/src/scripttools/debugging/qscriptdebuggercommand_p.h b/src/scripttools/debugging/qscriptdebuggercommand_p.h
index 6cfdec5..7ba4b6f 100644
--- a/src/scripttools/debugging/qscriptdebuggercommand_p.h
+++ b/src/scripttools/debugging/qscriptdebuggercommand_p.h
@@ -107,6 +107,7 @@ public:
GetScopeChain,
ContextsCheckpoint,
GetPropertyExpressionValue,
+ GetCompletions,
NewScriptObjectSnapshot,
ScriptObjectSnapshotCapture,
@@ -232,6 +233,7 @@ public:
static QScriptDebuggerCommand contextsCheckpoint();
static QScriptDebuggerCommand getPropertyExpressionValue(int contextIndex, int lineNumber,
const QStringList &path);
+ static QScriptDebuggerCommand getCompletions(int contextIndex, const QStringList &path);
static QScriptDebuggerCommand newScriptObjectSnapshotCommand();
static QScriptDebuggerCommand scriptObjectSnapshotCaptureCommand(int id, const QScriptDebuggerValue &object);
diff --git a/src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp b/src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp
index ce9aa03..afac2e7 100644
--- a/src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp
+++ b/src/scripttools/debugging/qscriptdebuggercommandexecutor.cpp
@@ -101,6 +101,12 @@ QScriptDebuggerCommandExecutor::~QScriptDebuggerCommandExecutor()
delete d_ptr;
}
+static bool isPrefixOf(const QString &prefix, const QString &what)
+{
+ return ((what.length() > prefix.length())
+ && what.startsWith(prefix));
+}
+
/*!
Applies the given \a command to the given \a backend.
*/
@@ -337,6 +343,67 @@ QScriptDebuggerResponse QScriptDebuggerCommandExecutor::execute(
}
} break;
+ case QScriptDebuggerCommand::GetCompletions: {
+ QScriptContext *ctx = backend->context(command.contextIndex());
+ QVariant attr = command.attribute(QScriptDebuggerCommand::UserAttribute);
+ QStringList path = attr.toStringList();
+ if (!ctx || path.isEmpty())
+ break;
+ QScriptValueList objects;
+ QString prefix = path.last();
+ QSet<QString> matches;
+ if (path.size() > 1) {
+ const QString &topLevelIdent = path.at(0);
+ QScriptValue obj;
+ if (topLevelIdent == QLatin1String("this")) {
+ obj = ctx->thisObject();
+ } else {
+ QScriptValueList scopeChain;
+ scopeChain = ctx->scopeChain();
+ for (int i = 0; i < scopeChain.size(); ++i) {
+ QScriptValue oo = scopeChain.at(i).property(topLevelIdent);
+ if (oo.isObject()) {
+ obj = oo;
+ break;
+ }
+ }
+ }
+ for (int i = 1; obj.isObject() && (i < path.size()-1); ++i)
+ obj = obj.property(path.at(i));
+ if (obj.isValid())
+ objects.append(obj);
+ } else {
+ objects << ctx->scopeChain();
+ QStringList keywords;
+ keywords.append(QString::fromLatin1("this"));
+ keywords.append(QString::fromLatin1("true"));
+ keywords.append(QString::fromLatin1("false"));
+ keywords.append(QString::fromLatin1("null"));
+ for (int i = 0; i < keywords.size(); ++i) {
+ const QString &kwd = keywords.at(i);
+ if (isPrefixOf(prefix, kwd))
+ matches.insert(kwd);
+ }
+ }
+
+ for (int i = 0; i < objects.size(); ++i) {
+ QScriptValue obj = objects.at(i);
+ while (obj.isObject()) {
+ QScriptValueIterator it(obj);
+ while (it.hasNext()) {
+ it.next();
+ QString propertyName = it.name();
+ if (isPrefixOf(prefix, propertyName))
+ matches.insert(propertyName);
+ }
+ obj = obj.prototype();
+ }
+ }
+ QStringList matchesList = matches.toList();
+ qStableSort(matchesList);
+ response.setResult(matchesList);
+ } break;
+
case QScriptDebuggerCommand::NewScriptObjectSnapshot: {
int id = backend->newScriptObjectSnapshot();
response.setResult(id);
diff --git a/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend.cpp b/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend.cpp
index a181711..83e634e 100644
--- a/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend.cpp
+++ b/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend.cpp
@@ -257,6 +257,11 @@ int QScriptDebuggerCommandSchedulerFrontend::scheduleGetPropertyExpressionValue(
return scheduleCommand(QScriptDebuggerCommand::getPropertyExpressionValue(contextIndex, lineNumber, path));
}
+int QScriptDebuggerCommandSchedulerFrontend::scheduleGetCompletions(int contextIndex, const QStringList &path)
+{
+ return scheduleCommand(QScriptDebuggerCommand::getCompletions(contextIndex, path));
+}
+
int QScriptDebuggerCommandSchedulerFrontend::scheduleEvaluate(int contextIndex,
const QString &program,
const QString &fileName,
diff --git a/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend_p.h b/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend_p.h
index ff9c570..9a1a36d 100644
--- a/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend_p.h
+++ b/src/scripttools/debugging/qscriptdebuggercommandschedulerfrontend_p.h
@@ -111,6 +111,7 @@ public:
int scheduleContextsCheckpoint();
int scheduleGetPropertyExpressionValue(int contextIndex, int lineNumber,
const QStringList &path);
+ int scheduleGetCompletions(int contextIndex, const QStringList &path);
// iteration
int scheduleNewScriptValueIterator(const QScriptDebuggerValue &object);