From f3c047a33c84ac5ba24cbaf594f04ba95977cb97 Mon Sep 17 00:00:00 2001 From: Aurindam Jana <aurindam.jana@nokia.com> Date: Wed, 26 Oct 2011 10:02:37 +0200 Subject: [PATCH] QmlV8DebuggerClient: Refactored code Change List: a) Refactored code: Shifted JSON message creation to QmlV8DebuggerClientPrivate. b) QScriptEngine is used for JSON instead of JsonValue and JsonInputStream. c) Locals Window displays all variables accessible in the current context. Change-Id: I82e73f6c57482408f5fc501c908aa96297d3d754 Reviewed-by: Kai Koehne <kai.koehne@nokia.com> --- src/libs/symbianutils/symbianutils.pri | 2 +- src/libs/symbianutils/symbianutils.pro | 2 +- src/plugins/debugger/qml/qml.pri | 5 +- src/plugins/debugger/qml/qmldebuggerclient.h | 4 +- src/plugins/debugger/qml/qmlengine.cpp | 6 +- .../debugger/qml/qmlv8debuggerclient.cpp | 1698 ++++++++++++----- .../debugger/qml/qmlv8debuggerclient.h | 39 +- .../qml/qmlv8debuggerclientconstants.h | 121 ++ .../debugger/qml/qscriptdebuggerclient.cpp | 6 +- .../debugger/qml/qscriptdebuggerclient.h | 7 +- 10 files changed, 1392 insertions(+), 498 deletions(-) create mode 100644 src/plugins/debugger/qml/qmlv8debuggerclientconstants.h diff --git a/src/libs/symbianutils/symbianutils.pri b/src/libs/symbianutils/symbianutils.pri index 978aabebdb4..e6b59799fde 100644 --- a/src/libs/symbianutils/symbianutils.pri +++ b/src/libs/symbianutils/symbianutils.pri @@ -1,2 +1,2 @@ -INCLUDEPATH *= $$PWD/../../shared/symbianutils +INCLUDEPATH *= $$PWD/../../shared/symbianutils $$PWD/../../shared/json LIBS *= -l$$qtLibraryName(symbianutils) diff --git a/src/libs/symbianutils/symbianutils.pro b/src/libs/symbianutils/symbianutils.pro index 3ae094e9d7a..ed2ff004eb8 100644 --- a/src/libs/symbianutils/symbianutils.pro +++ b/src/libs/symbianutils/symbianutils.pro @@ -1,6 +1,6 @@ TEMPLATE = lib CONFIG+=dll TARGET = symbianutils -DEFINES += SYMBIANUTILS_BUILD_LIB +DEFINES += SYMBIANUTILS_BUILD_LIB JSON_BUILD_LIB include(../../qtcreatorlibrary.pri) include(../../shared/symbianutils/symbianutils.pri) diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri index c70ce3ea11e..a34c120add6 100644 --- a/src/plugins/debugger/qml/qml.pri +++ b/src/plugins/debugger/qml/qml.pri @@ -1,6 +1,4 @@ include($$PWD/../../../libs/qmljsdebugclient/qmljsdebugclient.pri) -include($$PWD/../../../shared/json/json.pri) -DEFINES += JSON_INCLUDE_PRI HEADERS += \ $$PWD/qmlengine.h \ @@ -11,7 +9,8 @@ HEADERS += \ $$PWD/qmljsscriptconsole.h \ $$PWD/qscriptdebuggerclient.h \ $$PWD/qmlv8debuggerclient.h \ - $$PWD/interactiveinterpreter.h + $$PWD/interactiveinterpreter.h \ + $$PWD/qmlv8debuggerclientconstants.h SOURCES += \ $$PWD/qmlengine.cpp \ diff --git a/src/plugins/debugger/qml/qmldebuggerclient.h b/src/plugins/debugger/qml/qmldebuggerclient.h index 26fd33c53aa..2333e9ac87c 100644 --- a/src/plugins/debugger/qml/qmldebuggerclient.h +++ b/src/plugins/debugger/qml/qmldebuggerclient.h @@ -69,12 +69,12 @@ public: virtual void insertBreakpoint(const BreakpointModelId &id) = 0; virtual void removeBreakpoint(const BreakpointModelId &id) = 0; virtual void changeBreakpoint(const BreakpointModelId &id) = 0; - virtual void updateBreakpoints() = 0; + virtual void synchronizeBreakpoints() = 0; virtual void assignValueInDebugger(const QByteArray expr, const quint64 &id, const QString &property, const QString &value) = 0; - virtual void updateWatchData(const WatchData *data) = 0; + virtual void updateWatchData(const WatchData &data) = 0; virtual void executeDebuggerCommand(const QString &command) = 0; virtual void synchronizeWatchers(const QStringList &watchers) = 0; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 9023f002341..6bfb054c9c3 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -629,10 +629,10 @@ void QmlEngine::attemptBreakpointSynchronization() DebuggerEngine::attemptBreakpointSynchronization(); if (d->m_adapter.activeDebuggerClient()) { - d->m_adapter.activeDebuggerClient()->updateBreakpoints(); + d->m_adapter.activeDebuggerClient()->synchronizeBreakpoints(); } else { foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) { - client->updateBreakpoints(); + client->synchronizeBreakpoints(); } } } @@ -715,7 +715,7 @@ void QmlEngine::updateWatchData(const WatchData &data, if (data.isValueNeeded()) { logMessage(LogSend, QString("%1 %2 %3").arg(QString("EXEC"), QString(data.iname), QString(data.name))); - d->m_adapter.activeDebuggerClient()->updateWatchData(&data); + d->m_adapter.activeDebuggerClient()->updateWatchData(data); } if (data.isChildrenNeeded() && watchHandler()->isExpandedIName(data.iname)) { diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp index 33d4353d414..8dc6182714b 100644 --- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp +++ b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp @@ -31,19 +31,16 @@ **************************************************************************/ #include "qmlv8debuggerclient.h" +#include "qmlv8debuggerclientconstants.h" +#include "debuggerstringutils.h" -#include "watchdata.h" #include "watchhandler.h" #include "breakpoint.h" #include "breakhandler.h" -#include "debuggerconstants.h" #include "qmlengine.h" #include "stackhandler.h" -#include "debuggercore.h" -#include <extensionsystem/pluginmanager.h> #include <utils/qtcassert.h> - #include <coreplugin/editormanager/editormanager.h> #include <texteditor/basetexteditor.h> @@ -51,261 +48,859 @@ #include <QtCore/QVariant> #include <QtCore/QFileInfo> #include <QtGui/QTextDocument> -#include <QtGui/QMessageBox> +#include <QtScript/QScriptEngine> +#include <QtScript/QScriptValue> -#define INITIALPARAMS "seq" << ':' << ++d->sequence << ',' << "type" << ':' << "request" +#define DEBUG_QML 0 +#if DEBUG_QML +# define SDEBUG(s) qDebug() << s +#else +# define SDEBUG(s) +#endif using namespace Core; -using namespace Json; namespace Debugger { namespace Internal { -struct ExceptionInfo -{ - int sourceLine; - QString filePath; - QString errorMessage; +typedef QPair<QByteArray, QByteArray> WatchDataPair; + +struct QmlV8ObjectData { + QByteArray type; + QVariant value; + QVariant properties; }; class QmlV8DebuggerClientPrivate { public: - explicit QmlV8DebuggerClientPrivate(QmlV8DebuggerClient *) : - handleException(false), - sequence(0), - ping(0), + explicit QmlV8DebuggerClientPrivate(QmlV8DebuggerClient *q) : + q(q), + sequence(-1), engine(0) { + q->reset(); + parser = m_scriptEngine.evaluate(_("JSON.parse")); + stringifier = m_scriptEngine.evaluate(_("JSON.stringify")); } - bool handleException; + void connect(); + void disconnect(); + + void interrupt(); + void continueDebugging(QmlV8DebuggerClient::StepAction stepAction, int stepCount = 1); + + void evaluate(const QString expr, bool global = false, bool disableBreak = false, + int frame = -1, bool addContext = false); + void lookup(const QList<int> handles, bool includeSource = false); + void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false); + void frame(int number = -1); + void scope(int number = -1, int frameNumber = -1); + void scopes(int frameNumber = -1); + void scripts(int types = 4, const QList<int> ids = QList<int>(), + bool includeSource = false, const QVariant filter = QVariant()); + void source(int frame = -1, int fromLine = -1, int toLine = -1); + + void setBreakpoint(const QString type, const QString target, int line = -1, + int column = -1, bool enabled = true, + const QString condition = QString(), int ignoreCount = -1); + void changeBreakpoint(int breakpoint, bool enabled = true, + const QString condition = QString(), int ignoreCount = -1); + void clearBreakpoint(int breakpoint); + void setExceptionBreak(QmlV8DebuggerClient::Exceptions type, bool enabled = false); + void listBreakpoints(); + + void v8flags(const QString flags); + void version(); + //void profile(ProfileCommand command); //NOT SUPPORTED + void gc(); + + QmlV8ObjectData extractData(const QVariant &data); + +private: + QByteArray packMessage(const QByteArray &message); + QScriptValue initObject(); + +public: + QmlV8DebuggerClient *q; + int sequence; - int ping; QmlEngine *engine; - QHash<BreakpointModelId,int> breakpoints; - QHash<int,BreakpointModelId> breakpointsSync; - QHash<int,QByteArray> locals; - QHash<int,QByteArray> watches; - QByteArray frames; - QScopedPointer<ExceptionInfo> exceptionInfo; + QHash<BreakpointModelId, int> breakpoints; + QHash<int, BreakpointModelId> breakpointsSync; + QHash<int, QByteArray> locals; + QHash<int, WatchDataPair> watches; + + QScriptValue parser; + QScriptValue stringifier; + + int currentFrameIndex; + bool updateCurrentStackFrameIndex; +private: + QScriptEngine m_scriptEngine; }; -QmlV8DebuggerClient::QmlV8DebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection* client) - : QmlDebuggerClient(client, QLatin1String("V8Debugger")), - d(new QmlV8DebuggerClientPrivate(this)) +/////////////////////////////////////////////////////////////////////// +// +// QmlV8DebuggerClientPrivate +// +/////////////////////////////////////////////////////////////////////// + +void QmlV8DebuggerClientPrivate::connect() { + // { "seq" : <number>, + // "type" : "request", + // "command" : "connect", + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(CONNECT))); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -QmlV8DebuggerClient::~QmlV8DebuggerClient() +void QmlV8DebuggerClientPrivate::disconnect() { - delete d; + // { "seq" : <number>, + // "type" : "request", + // "command" : "disconnect", + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(DISCONNECT))); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -QByteArray QmlV8DebuggerClient::packMessage(const QByteArray &message) +void QmlV8DebuggerClientPrivate::interrupt() { - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - QByteArray cmd = "V8DEBUG"; - rs << cmd << message; - return reply; + // { "seq" : <number>, + // "type" : "request", + // "command" : "interrupt", + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(INTERRUPT))); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::breakOnException(Exceptions exceptionsType, bool enabled) +void QmlV8DebuggerClientPrivate::continueDebugging(QmlV8DebuggerClient::StepAction action, + int count) { - //TODO: Have to deal with NoExceptions - QByteArray request; - - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "setexceptionbreak"; + //First reset + q->reset(); + + // { "seq" : <number>, + // "type" : "request", + // "command" : "continue", + // "arguments" : { "stepaction" : <"in", "next" or "out">, + // "stepcount" : <number of steps (default 1)> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(CONTINEDEBUGGING))); + + if (action != QmlV8DebuggerClient::Continue) { + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + switch (action) { + case QmlV8DebuggerClient::In: + args.setProperty(_(STEPACTION), QScriptValue(_(IN))); + break; + case QmlV8DebuggerClient::Out: + args.setProperty(_(STEPACTION), QScriptValue(_(OUT))); + break; + case QmlV8DebuggerClient::Next: + args.setProperty(_(STEPACTION), QScriptValue(_(NEXT))); + break; + default:break; + } + if (count != 1) + args.setProperty(_(STEPCOUNT), QScriptValue(count)); + jsonVal.setProperty(_(ARGUMENTS), args); - JsonInputStream(request) << ',' << "arguments" << ':'; - if (exceptionsType == AllExceptions) - JsonInputStream(request) << '{' << "type" << ':' << "all"; - else if (exceptionsType == UncaughtExceptions) - JsonInputStream(request) << '{' << "type" << ':' << "uncaught"; + } + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} - JsonInputStream(request) << ',' << "enabled" << ':' << enabled; - JsonInputStream(request) << '}'; +void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global, + bool disableBreak, int frame, + bool addContext) +{ + updateCurrentStackFrameIndex = false; + + // { "seq" : <number>, + // "type" : "request", + // "command" : "evaluate", + // "arguments" : { "expression" : <expression to evaluate>, + // "frame" : <number>, + // "global" : <boolean>, + // "disable_break" : <boolean>, + // "additional_context" : [ + // { "name" : <name1>, "handle" : <handle1> }, + // { "name" : <name2>, "handle" : <handle2> }, + // ... + // ] + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(EVALUATE))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + args.setProperty(_(EXPRESSION), QScriptValue(expr)); + + if (frame != -1) + args.setProperty(_(FRAME), QScriptValue(frame)); + + if (global) + args.setProperty(_(GLOBAL), QScriptValue(global)); + + if (disableBreak) + args.setProperty(_(DISABLE_BREAK), QScriptValue(disableBreak)); + + if (addContext) { + QAbstractItemModel *localsModel = engine->localsModel(); + int rowCount = localsModel->rowCount(); + + QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY )); + while (rowCount) { + QModelIndex index = localsModel->index(--rowCount, 0); + const WatchData *data = engine->watchHandler()->watchData(LocalsWatch, index); + QScriptValue ctxt = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + ctxt.setProperty(_(NAME), QScriptValue(data->name)); + ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id))); + + ctxtList.setProperty(rowCount, ctxt); + } - JsonInputStream(request) << '}'; + args.setProperty(_(ADDITIONAL_CONTEXT), QScriptValue(ctxtList)); + } + jsonVal.setProperty(_(ARGUMENTS), args); - sendMessage(packMessage(request)); + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::storeExceptionInformation(const QByteArray &message) +void QmlV8DebuggerClientPrivate::lookup(QList<int> handles, bool includeSource) { - JsonValue response(message); + // { "seq" : <number>, + // "type" : "request", + // "command" : "lookup", + // "arguments" : { "handles" : <array of handles>, + // "includeSource" : <boolean indicating whether + // the source will be included when + // script objects are returned>, + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(LOOKUP))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + QScriptValue array = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY)); + int index = 0; + foreach (int handle, handles) { + array.setProperty(index++, QScriptValue(handle)); + } + args.setProperty(_(HANDLES), array); + + if (includeSource) + args.setProperty(_(INCLUDESOURCE), QScriptValue(includeSource)); - JsonValue body = response.findChild("body"); + jsonVal.setProperty(_(ARGUMENTS), args); - d->exceptionInfo.reset(new ExceptionInfo); - d->exceptionInfo->sourceLine = body.findChild("sourceLine").toVariant().toInt(); - QUrl fileUrl(body.findChild("script").findChild("name").toVariant().toString()); - d->exceptionInfo->filePath = d->engine->toFileInProject(fileUrl); - d->exceptionInfo->errorMessage = body.findChild("exception").findChild("text").toVariant().toString(); + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::handleException() +void QmlV8DebuggerClientPrivate::backtrace(int fromFrame, int toFrame, bool bottom) { - EditorManager *editorManager = EditorManager::instance(); - QList<IEditor *> openedEditors = editorManager->openedEditors(); + // { "seq" : <number>, + // "type" : "request", + // "command" : "backtrace", + // "arguments" : { "fromFrame" : <number> + // "toFrame" : <number> + // "bottom" : <boolean, set to true if the bottom of the + // stack is requested> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(BACKTRACE))); - // set up the format for the errors - QTextCharFormat errorFormat; - errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); - errorFormat.setUnderlineColor(Qt::red); + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); - foreach (IEditor *editor, openedEditors) { - if (editor->file()->fileName() == d->exceptionInfo->filePath) { - TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget()); - if (!ed) - continue; + if (fromFrame != -1) + args.setProperty(_(FROMFRAME), QScriptValue(fromFrame)); - QList<QTextEdit::ExtraSelection> selections; - QTextEdit::ExtraSelection sel; - sel.format = errorFormat; - QTextCursor c(ed->document()->findBlockByNumber(d->exceptionInfo->sourceLine)); - const QString text = c.block().text(); - for (int i = 0; i < text.size(); ++i) { - if (! text.at(i).isSpace()) { - c.setPosition(c.position() + i); - break; - } - } - c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); - sel.cursor = c; + if (toFrame != -1) + args.setProperty(_(TOFRAME), QScriptValue(toFrame)); - sel.format.setToolTip(d->exceptionInfo->errorMessage); + if (bottom) + args.setProperty(_(BOTTOM), QScriptValue(bottom)); - selections.append(sel); - ed->setExtraSelections(TextEditor::BaseTextEditorWidget::DebuggerExceptionSelection, selections); + jsonVal.setProperty(_(ARGUMENTS), args); - d->engine->showMessage(d->exceptionInfo->errorMessage, ScriptConsoleOutput); - } + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} + +void QmlV8DebuggerClientPrivate::frame(int number) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "frame", + // "arguments" : { "number" : <frame number> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(FRAME))); + + if (number != -1) { + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + args.setProperty(_(NUMBER), QScriptValue(number)); + + jsonVal.setProperty(_(ARGUMENTS), args); } - //Delete the info even if the code hasnt been highlighted - d->exceptionInfo.reset(); + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::clearExceptionSelection() +void QmlV8DebuggerClientPrivate::scope(int number, int frameNumber) { - //Check if break was due to exception - if (d->handleException) { - EditorManager *editorManager = EditorManager::instance(); - QList<IEditor *> openedEditors = editorManager->openedEditors(); - QList<QTextEdit::ExtraSelection> selections; + // { "seq" : <number>, + // "type" : "request", + // "command" : "scope", + // "arguments" : { "number" : <scope number> + // "frameNumber" : <frame number, optional uses selected + // frame if missing> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(SCOPE))); + + if (number != -1) { + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + args.setProperty(_(NUMBER), QScriptValue(number)); + + if (frameNumber != -1) + args.setProperty(_(FRAMENUMBER), QScriptValue(frameNumber)); + + jsonVal.setProperty(_(ARGUMENTS), args); + } - foreach (IEditor *editor, openedEditors) { - TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget()); - if (!ed) - continue; + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} - ed->setExtraSelections(TextEditor::BaseTextEditorWidget::DebuggerExceptionSelection, selections); +void QmlV8DebuggerClientPrivate::scopes(int frameNumber) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "scopes", + // "arguments" : { "frameNumber" : <frame number, optional uses selected + // frame if missing> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(SCOPES))); + + if (frameNumber != -1) { + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + args.setProperty(_(FRAMENUMBER), QScriptValue(frameNumber)); + + jsonVal.setProperty(_(ARGUMENTS), args); + } + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} + +void QmlV8DebuggerClientPrivate::scripts(int types, const QList<int> ids, bool includeSource, + const QVariant /*filter*/) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "scripts", + // "arguments" : { "types" : <types of scripts to retrieve + // set bit 0 for native scripts + // set bit 1 for extension scripts + // set bit 2 for normal scripts + // (default is 4 for normal scripts)> + // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned> + // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned> + // "filter" : <string or number: filter string or script id. + // If a number is specified, then only the script with the same number as its script id will be retrieved. + // If a string is specified, then only scripts whose names contain the filter string will be retrieved.> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(SCRIPTS))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + args.setProperty(_(TYPES), QScriptValue(types)); + + if (ids.count()) { + QScriptValue array = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY)); + int index = 0; + foreach (int id, ids) { + array.setProperty(index++, QScriptValue(id)); } - d->handleException = false; + args.setProperty(_(IDS), array); } + + if (includeSource) + args.setProperty(_(INCLUDESOURCE), QScriptValue(includeSource)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::continueDebugging(StepAction type) +void QmlV8DebuggerClientPrivate::source(int frame, int fromLine, int toLine) { - clearExceptionSelection(); + // { "seq" : <number>, + // "type" : "request", + // "command" : "source", + // "arguments" : { "frame" : <frame number (default selected frame)> + // "fromLine" : <from line within the source default is line 0> + // "toLine" : <to line within the source this line is not included in + // the result default is the number of lines in the script> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(SOURCE))); - QByteArray request; + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "continue"; + if (frame != -1) + args.setProperty(_(FRAME), QScriptValue(frame)); - if (type != Continue) { - JsonInputStream(request) << ',' << "arguments" << ':'; + if (fromLine != -1) + args.setProperty(_(FROMLINE), QScriptValue(fromLine)); - switch (type) { - case In: JsonInputStream(request) << '{' << "stepaction" << ':' << "in"; - break; - case Out: JsonInputStream(request) << '{' << "stepaction" << ':' << "out"; - break; - case Next: JsonInputStream(request) << '{' << "stepaction" << ':' << "next"; - break; - default:break; - } + if (toLine != -1) + args.setProperty(_(TOLINE), QScriptValue(toLine)); - JsonInputStream(request) << '}'; - } + jsonVal.setProperty(_(ARGUMENTS), args); - JsonInputStream(request) << '}'; + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} - sendMessage(packMessage(request)); +void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString target, + int line, int column, bool enabled, + const QString condition, int ignoreCount) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "setbreakpoint", + // "arguments" : { "type" : <"function" or "script" or "scriptId" or "scriptRegExp"> + // "target" : <function expression or script identification> + // "line" : <line in script or function> + // "column" : <character position within the line> + // "enabled" : <initial enabled state. True or false, default is true> + // "condition" : <string with break point condition> + // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(SETBREAKPOINT))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + args.setProperty(_(TYPE), QScriptValue(type)); + args.setProperty(_(TARGET), QScriptValue(target)); + + if (line != -1) + args.setProperty(_(LINE), QScriptValue(line)); + + if (column != -1) + args.setProperty(_(COLUMN), QScriptValue(column)); + + args.setProperty(_(ENABLED), QScriptValue(enabled)); + + if (!condition.isEmpty()) + args.setProperty(_(CONDITION), QScriptValue(condition)); + + if (ignoreCount != -1) + args.setProperty(_(IGNORECOUNT), QScriptValue(ignoreCount)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::executeStep() +void QmlV8DebuggerClientPrivate::changeBreakpoint(int breakpoint, bool enabled, + const QString condition, int ignoreCount) { - continueDebugging(In); + // { "seq" : <number>, + // "type" : "request", + // "command" : "changebreakpoint", + // "arguments" : { "breakpoint" : <number of the break point to clear> + // "enabled" : <initial enabled state. True or false, + // default is true> + // "condition" : <string with break point condition> + // "ignoreCount" : <number specifying the number of break point hits } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(CHANGEBREAKPOINT))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + args.setProperty(_(BREAKPOINT), QScriptValue(breakpoint)); + + args.setProperty(_(ENABLED), QScriptValue(enabled)); + + if (!condition.isEmpty()) + args.setProperty(_(CONDITION), QScriptValue(condition)); + + if (ignoreCount != -1) + args.setProperty(_(IGNORECOUNT), QScriptValue(ignoreCount)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::executeStepOut() +void QmlV8DebuggerClientPrivate::clearBreakpoint(int breakpoint) +{ + // { "seq" : <number>, + // "type" : "request", + // "command" : "clearbreakpoint", + // "arguments" : { "breakpoint" : <number of the break point to clear> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(CLEARBREAKPOINT))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + args.setProperty(_(BREAKPOINT), QScriptValue(breakpoint)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +} + +void QmlV8DebuggerClientPrivate::setExceptionBreak(QmlV8DebuggerClient::Exceptions type, + bool enabled) { - continueDebugging(Out); + // { "seq" : <number>, + // "type" : "request", + // "command" : "setexceptionbreak", + // "arguments" : { "type" : <string: "all", or "uncaught">, + // "enabled" : <optional bool: enables the break type if true> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(SETEXCEPTIONBREAK))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + if (type == QmlV8DebuggerClient::AllExceptions) + args.setProperty(_(TYPE), QScriptValue(_(ALL))); + //Not Supported + // else if (type == QmlV8DebuggerClient::UncaughtExceptions) + // args.setProperty(_(TYPE),QScriptValue(_(UNCAUGHT))); + + if (enabled) + args.setProperty(_(ENABLED), QScriptValue(enabled)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::executeNext() +void QmlV8DebuggerClientPrivate::listBreakpoints() { - continueDebugging(Next); + // { "seq" : <number>, + // "type" : "request", + // "command" : "listbreakpoints", + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(LISTBREAKPOINTS))); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::executeStepI() +void QmlV8DebuggerClientPrivate::v8flags(const QString flags) { - continueDebugging(In); + // { "seq" : <number>, + // "type" : "request", + // "command" : "v8flags", + // "arguments" : { "flags" : <string: a sequence of v8 flags just like + // those used on the command line> + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(V8FLAGS))); + + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + + args.setProperty(_(FLAGS), QScriptValue(flags)); + + jsonVal.setProperty(_(ARGUMENTS), args); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::continueInferior() +void QmlV8DebuggerClientPrivate::version() { - continueDebugging(Continue); + // { "seq" : <number>, + // "type" : "request", + // "command" : "version", + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), QScriptValue(_(VERSION))); + + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::interruptInferior() +//void QmlV8DebuggerClientPrivate::profile(ProfileCommand command) +//{ +//// { "seq" : <number>, +//// "type" : "request", +//// "command" : "profile", +//// "arguments" : { "command" : "resume" or "pause" } +//// } +// QScriptValue jsonVal = initObject(); +// jsonVal.setProperty(_(COMMAND), QScriptValue(_(PROFILE))); + +// QScriptValue args = m_parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); + +// if (command == Resume) +// args.setProperty(_(COMMAND), QScriptValue(_(RESUME))); +// else +// args.setProperty(_(COMMAND), QScriptValue(_(PAUSE))); + +// args.setProperty(_("modules"), QScriptValue(1)); +// jsonVal.setProperty(_(ARGUMENTS), args); + +// const QScriptValue jsonMessage = m_stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); +// q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); +//} + +void QmlV8DebuggerClientPrivate::gc() { - QByteArray request; + // { "seq" : <number>, + // "type" : "request", + // "command" : "gc", + // "arguments" : { "type" : <string: "all">, + // } + // } + QScriptValue jsonVal = initObject(); + jsonVal.setProperty(_(COMMAND), + QScriptValue(_(GARBAGECOLLECTOR))); - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "interrupt"; + QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT))); - JsonInputStream(request) << '}'; + args.setProperty(_(TYPE), QScriptValue(_(ALL))); - sendMessage(packMessage(request)); + jsonVal.setProperty(_(ARGUMENTS), args); + const QScriptValue jsonMessage = stringifier.call(QScriptValue(), QScriptValueList() << jsonVal); + q->sendMessage(packMessage(jsonMessage.toString().toUtf8())); } -void QmlV8DebuggerClient::startSession() +QmlV8ObjectData QmlV8DebuggerClientPrivate::extractData(const QVariant &data) +{ + // { "handle" : <handle>, + // "type" : <"undefined", "null", "boolean", "number", "string", "object", "function" or "frame"> + // } + + // {"handle":<handle>,"type":"undefined"} + + // {"handle":<handle>,"type":"null"} + + // { "handle":<handle>, + // "type" : <"boolean", "number" or "string"> + // "value" : <JSON encoded value> + // } + + // {"handle":7,"type":"boolean","value":true} + + // {"handle":8,"type":"number","value":42} + + // { "handle" : <handle>, + // "type" : "object", + // "className" : <Class name, ECMA-262 property [[Class]]>, + // "constructorFunction" : {"ref":<handle>}, + // "protoObject" : {"ref":<handle>}, + // "prototypeObject" : {"ref":<handle>}, + // "properties" : [ {"name" : <name>, + // "ref" : <handle> + // }, + // ... + // ] + // } + + // { "handle" : <handle>, + // "type" : "function", + // "className" : "Function", + // "constructorFunction" : {"ref":<handle>}, + // "protoObject" : {"ref":<handle>}, + // "prototypeObject" : {"ref":<handle>}, + // "name" : <function name>, + // "inferredName" : <inferred function name for anonymous functions> + // "source" : <function source>, + // "script" : <reference to function script>, + // "scriptId" : <id of function script>, + // "position" : <function begin position in script>, + // "line" : <function begin source line in script>, + // "column" : <function begin source column in script>, + // "properties" : [ {"name" : <name>, + // "ref" : <handle> + // }, + // ... + // ] + // } + + QmlV8ObjectData objectData; + const QVariantMap dataMap = data.toMap(); + QString type = dataMap.value(_(TYPE)).toString(); + + if (type == _("undefined")) { + objectData.type = QByteArray("undefined"); + objectData.value = QVariant(_("undefined")); + + } else if (type == _("null")) { + objectData.type = QByteArray("null"); + objectData.value= QVariant(_("null")); + + } else if (type == _("boolean")) { + objectData.type = QByteArray("boolean"); + objectData.value = dataMap.value(_(VALUE)); + + } else if (type == _("number")) { + objectData.type = QByteArray("number"); + objectData.value = dataMap.value(_(VALUE)); + + } else if (type == _("string")) { + objectData.type = QByteArray("string"); + objectData.value = dataMap.value(_(VALUE)); + + } else if (type == _("object")) { + objectData.type = QByteArray("object"); + objectData.value = dataMap.value(_("className")); + objectData.properties = dataMap.value(_("properties")); + + } else if (type == _("function")) { + objectData.type = QByteArray("function"); + objectData.value = dataMap.value(_(NAME)); + objectData.properties = dataMap.value(_("properties")); + + } else if (type == _("script")) { + objectData.type = QByteArray("script"); + objectData.value = dataMap.value(_(NAME)); + } + + return objectData; +} + +QByteArray QmlV8DebuggerClientPrivate::packMessage(const QByteArray &message) { - QByteArray request; + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + QByteArray cmd = V8DEBUG; + rs << cmd << message; + SDEBUG(QString(message)); + return reply; +} - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "connect"; +QScriptValue QmlV8DebuggerClientPrivate::initObject() +{ + QScriptValue jsonVal = parser.call(QScriptValue(), + QScriptValueList() << QScriptValue(_(OBJECT))); + jsonVal.setProperty(_(SEQ), QScriptValue(++sequence)); + jsonVal.setProperty(_(TYPE), _(REQUEST)); + return jsonVal; +} + +/////////////////////////////////////////////////////////////////////// +// +// QmlV8DebuggerClient +// +/////////////////////////////////////////////////////////////////////// + +QmlV8DebuggerClient::QmlV8DebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client) + : QmlDebuggerClient(client, QLatin1String("V8Debugger")), + d(new QmlV8DebuggerClientPrivate(this)) +{ +} - JsonInputStream(request) << '}'; +QmlV8DebuggerClient::~QmlV8DebuggerClient() +{ + delete d; +} - sendMessage(packMessage(request)); +void QmlV8DebuggerClient::startSession() +{ + d->connect(); } void QmlV8DebuggerClient::endSession() { - clearExceptionSelection(); + d->disconnect(); +} + +void QmlV8DebuggerClient::executeStep() +{ + + d->continueDebugging(In); +} + +void QmlV8DebuggerClient::executeStepOut() +{ + + d->continueDebugging(Out); +} - QByteArray request; +void QmlV8DebuggerClient::executeNext() +{ - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "disconnect"; + d->continueDebugging(Next); +} - JsonInputStream(request) << '}'; +void QmlV8DebuggerClient::executeStepI() +{ + + d->continueDebugging(In); +} + +void QmlV8DebuggerClient::continueInferior() +{ - sendMessage(packMessage(request)); + d->continueDebugging(Continue); +} + +void QmlV8DebuggerClient::interruptInferior() +{ + + + d->interrupt(); } void QmlV8DebuggerClient::activateFrame(int index) { - setLocals(index); + + d->backtrace(index); } bool QmlV8DebuggerClient::acceptsBreakpoint(const BreakpointModelId &id) @@ -318,76 +913,64 @@ bool QmlV8DebuggerClient::acceptsBreakpoint(const BreakpointModelId &id) void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id) { + + BreakHandler *handler = d->engine->breakHandler(); const BreakpointParameters ¶ms = handler->breakpointData(id); if (params.type == BreakpointAtJavaScriptThrow) { handler->notifyBreakpointInsertOk(id); - return breakOnException(AllExceptions, params.enabled); - } + d->setExceptionBreak(AllExceptions, params.enabled); - QByteArray request; + } else if (params.type == BreakpointByFileAndLine) { + d->setBreakpoint(QString(_(SCRIPT)), QFileInfo(params.fileName).fileName(), + params.lineNumber - 1, -1, params.enabled, + QString(params.condition), params.ignoreCount); - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "setbreakpoint"; - JsonInputStream(request) << ',' << "arguments" << ':' << '{'; - if (params.type == BreakpointByFileAndLine) { - JsonInputStream(request) << "type" << ':' << "script"; - JsonInputStream(request) << ',' << "target" << ':' << QFileInfo(params.fileName).fileName().toUtf8(); - JsonInputStream(request) << ',' << "line" << ':' << params.lineNumber - 1; } else if (params.type == BreakpointByFunction) { - JsonInputStream(request) << "type" << ':' << "function"; - JsonInputStream(request) << ',' << "target" << ':' << params.functionName.toUtf8(); + d->setBreakpoint(QString(_(FUNCTION)), params.functionName, + -1, -1, params.enabled, QString(params.condition), + params.ignoreCount); + } else if (params.type == BreakpointOnQmlSignalHandler) { - JsonInputStream(request) << "type" << ':' << "event"; - JsonInputStream(request) << ',' << "target" << ':' << params.functionName.toUtf8(); + d->setBreakpoint(QString(_(EVENT)), params.functionName, + -1, -1, params.enabled); } - JsonInputStream(request) << ',' << "enabled" << ':' << params.enabled; - - JsonInputStream(request) << '}'; - JsonInputStream(request) << '}'; - d->breakpointsSync.insert(d->sequence,id); - sendMessage(packMessage(request)); + d->breakpointsSync.insert(d->sequence, id); } void QmlV8DebuggerClient::removeBreakpoint(const BreakpointModelId &id) { - BreakHandler *handler = d->engine->breakHandler(); - if (handler->breakpointData(id).type == BreakpointAtJavaScriptThrow) { - return breakOnException(AllExceptions, false); - } + + BreakHandler *handler = d->engine->breakHandler(); int breakpoint = d->breakpoints.value(id); d->breakpoints.remove(id); - QByteArray request; - - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "clearbreakpoint"; - - JsonInputStream(request) << ',' << "arguments" << ':'; - JsonInputStream(request) << '{' << "breakpoint" << ':' << breakpoint; - JsonInputStream(request) << '}'; - - JsonInputStream(request) << '}'; - - sendMessage(packMessage(request)); + if (handler->breakpointData(id).type == BreakpointAtJavaScriptThrow) { + d->setExceptionBreak(AllExceptions); + } else { + d->clearBreakpoint(breakpoint); + } } void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id) { + + BreakHandler *handler = d->engine->breakHandler(); const BreakpointParameters ¶ms = handler->breakpointData(id); if (params.type == BreakpointAtJavaScriptThrow) { - return breakOnException(AllExceptions, params.enabled); + d->setExceptionBreak(AllExceptions, params.enabled); } } -void QmlV8DebuggerClient::updateBreakpoints() +void QmlV8DebuggerClient::synchronizeBreakpoints() { + //NOT USED } void QmlV8DebuggerClient::assignValueInDebugger(const QByteArray /*expr*/, const quint64 &/*id*/, @@ -396,93 +979,56 @@ void QmlV8DebuggerClient::assignValueInDebugger(const QByteArray /*expr*/, const //TODO:: } -void QmlV8DebuggerClient::updateWatchData(const WatchData *data) +void QmlV8DebuggerClient::updateWatchData(const WatchData &data) { - if (!data->iname.startsWith("watch.")) - return; - - QByteArray request; - - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "evaluate"; - - JsonInputStream(request) << ',' << "arguments" << ':'; - JsonInputStream(request) << '{' << "expression" << ':' << data->exp; - JsonInputStream(request) << ',' << "frame" << ':' << d->engine->stackHandler()->currentFrame().level; - JsonInputStream(request) << '}'; - - JsonInputStream(request) << '}'; - - d->watches.insert(d->sequence,data->iname); - - sendMessage(packMessage(request)); - + if (data.isWatcher()) { + WatchDataPair pair(data.iname, data.exp); + if (d->watches.key(pair)) { + WatchData data1 = data; + data1.setAllUnneeded(); + // data1.setValue(_("<unavailable>")); + // data1.setHasChildren(false); + d->engine->watchHandler()->insertData(data1); + } else { + StackHandler *stackHandler = d->engine->stackHandler(); + if (stackHandler->isContentsValid()) + d->evaluate(data.exp, false, false, stackHandler->currentIndex()); + else + d->evaluate(data.exp); + d->watches.insert(d->sequence, pair); + } + } } void QmlV8DebuggerClient::executeDebuggerCommand(const QString &command) { - QByteArray request; - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "evaluate"; - - JsonInputStream(request) << ',' << "arguments" << ':'; - JsonInputStream(request) << '{' << "expression" << ':' << command; - JsonInputStream(request) << ',' << "global" << ':' << true; - JsonInputStream(request) << '}'; - - JsonInputStream(request) << '}'; - - sendMessage(packMessage(request)); + StackHandler *stackHandler = d->engine->stackHandler(); + if (stackHandler->isContentsValid()) { + d->evaluate(command, false, false, stackHandler->currentIndex()); + } else { + //Currently cannot evaluate if not in a javascript break + d->engine->showMessage(_("Request Was Unsuccessful"), ScriptConsoleOutput); + // d->evaluate(command); + } } void QmlV8DebuggerClient::synchronizeWatchers(const QStringList &/*watchers*/) { - //TODO:: send watchers list + //TODO:: } void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId) { - d->locals.insert(objectId,iname); - QList<int> ids; - ids.append(objectId); - - QByteArray request; - - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "lookup"; - - JsonInputStream(request) << ',' << "arguments" << ':'; - JsonInputStream(request) << '{' << "handles" << ':' << ids; - JsonInputStream(request) << '}'; - - JsonInputStream(request) << '}'; - - sendMessage(packMessage(request)); - -} - -void QmlV8DebuggerClient::listBreakpoints() -{ - QByteArray request; - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "listbreakpoints"; - JsonInputStream(request) << '}'; - - sendMessage(packMessage(request)); + d->locals.insertMulti(objectId, iname); + d->lookup(QList<int>() << objectId); } -void QmlV8DebuggerClient::backtrace() +void QmlV8DebuggerClient::setEngine(QmlEngine *engine) { - QByteArray request; - - JsonInputStream(request) << '{' << INITIALPARAMS ; - JsonInputStream(request) << ',' << "command" << ':' << "backtrace"; - JsonInputStream(request) << '}'; - - sendMessage(packMessage(request)); + d->engine = engine; } void QmlV8DebuggerClient::messageReceived(const QByteArray &data) @@ -491,292 +1037,528 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data) QByteArray command; ds >> command; - if (command == "V8DEBUG") { + if (command == V8DEBUG) { QByteArray response; ds >> response; + QString responseString(response); - JsonValue value(response); - const QString type = value.findChild("type").toVariant().toString(); + SDEBUG(responseString); - if (type == "response") { + const QVariantMap resp = d->parser.call(QScriptValue(), + QScriptValueList() << + QScriptValue(responseString)).toVariant().toMap(); + const QString type(resp.value(_(TYPE)).toString()); - if (!value.findChild("success").toVariant().toBool()) { - //TODO:: have to handle this case for each command - d->engine->logMessage(QmlEngine::LogReceive, QString("V8 Response Error: %1").arg(QString(value.toString(true,2)))); - return; + if (type == _("response")) { + + bool success = resp.value(_("success")).toBool(); + if (!success) { + SDEBUG("Request was unsuccessful"); + d->engine->logMessage(QmlEngine::LogReceive, + QString(_("V8 Response Error: %1")).arg( + resp.value(_("message")).toString())); } - const QString debugCommand(value.findChild("command").toVariant().toString()); - if (debugCommand == "backtrace") { - setStackFrames(response); + const QString debugCommand(resp.value(_(COMMAND)).toString()); - } else if (debugCommand == "lookup") { - expandLocal(response); + if (debugCommand == _(CONNECT)) { + //debugging session started - } else if (debugCommand == "setbreakpoint") { - int sequence = value.findChild("request_seq").toVariant().toInt(); - int breakpoint = value.findChild("body").findChild("breakpoint").toVariant().toInt(); - BreakpointModelId id = d->breakpointsSync.take(sequence); - d->breakpoints.insert(id,breakpoint); + } else if (debugCommand == _(DISCONNECT)) { + //debugging session ended - //If this is an event breakpoint then set state = BreakpointInsertOk - const QString breakpointType = value.findChild("body").findChild("type").toVariant().toString(); - if (breakpointType == "event") { - d->engine->breakHandler()->notifyBreakpointInsertOk(id); + } else if (debugCommand == _(BACKTRACE)) { + if (success) { + updateStack(resp.value(_(BODY)), resp.value(_(REFS))); } - } else if (debugCommand == "evaluate") { - setExpression(response); + } else if (debugCommand == _(LOOKUP)) { + expandLocal(resp.value(_(BODY)), resp.value(_(REFS))); - } else if (debugCommand == "listbreakpoints") { - updateBreakpoints(response); - backtrace(); + } else if (debugCommand == _(EVALUATE)) { + if (success) { + int seq = resp.value(_("request_seq")).toInt(); + updateEvaluationResult(seq, resp.value(_(BODY)), resp.value(_(REFS))); + } else { + d->engine->showMessage(resp.value(_("message")).toString(), ScriptConsoleOutput); + } + } else if (debugCommand == _(LISTBREAKPOINTS)) { + updateBreakpoints(resp.value(_(BODY))); + + } else if (debugCommand == _(SETBREAKPOINT)) { + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "setbreakpoint", + // "body" : { "type" : <"function" or "script"> + // "breakpoint" : <break point number of the new break point> + // } + // "running" : <is the VM running after sending this response> + // "success" : true + // } + + int seq = resp.value(_("request_seq")).toInt(); + const QVariantMap breakpointData = resp.value(_(BODY)).toMap(); + int index = breakpointData.value(_("breakpoint")).toInt(); + + BreakpointModelId id = d->breakpointsSync.take(seq); + d->breakpoints.insert(id, index); + + d->engine->breakHandler()->notifyBreakpointInsertOk(id); + + + } else if (debugCommand == _(CHANGEBREAKPOINT)) { + // DO NOTHING + + } else if (debugCommand == _(CLEARBREAKPOINT)) { + // DO NOTHING + + } else if (debugCommand == _(SETEXCEPTIONBREAK)) { + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "setexceptionbreak", + // “body†: { "type" : <string: "all" or "uncaught" corresponding to the request.>, + // "enabled" : <bool: true if the break type is currently enabled as a result of the request> + // } + // "running" : true + // "success" : true + // } + //TODO:: + + } else if (debugCommand == _(FRAME)) { + if (success) { + const QVariant body = resp.value(_(BODY)); + const QVariant refs = resp.value(_(REFS)); + const QVariant locals = body.toMap().value(_("locals")); + StackFrame frame = createStackFrame(body, refs); + updateLocals(locals, refs); + d->engine->stackHandler()->setCurrentIndex(frame.level); + } + + } else if (debugCommand == _(SCOPE)) { + } else if (debugCommand == _(SCOPES)) { + } else if (debugCommand == _(SOURCE)) { + } else if (debugCommand == _(SCRIPTS)) { + } else if (debugCommand == _(VERSION)) { + } else if (debugCommand == _(V8FLAGS)) { + } else if (debugCommand == _(GARBAGECOLLECTOR)) { } else { - d->engine->logMessage(QmlEngine::LogReceive, value.toString(true,2)); + // DO NOTHING } + } else if (type == _(EVENT)) { + const QString eventType(resp.value(_(EVENT)).toString()); + + if (eventType == _("break")) { + //DO NOTHING + } else if (eventType == _("exception")) { + const QVariantMap body = resp.value(_(BODY)).toMap(); + int lineNumber = body.value(_("sourceLine")).toInt() + 1; - } else if (type == "event") { - const QString event(value.findChild("event").toVariant().toString()); - - if (event == "break") { - d->engine->inferiorSpontaneousStop(); - listBreakpoints(); - } else if (event == "exception") { - d->handleException = true; - d->engine->inferiorSpontaneousStop(); - storeExceptionInformation(response); - backtrace(); + const QVariantMap script = body.value(_("script")).toMap(); + QUrl fileUrl(script.value(_(NAME)).toString()); + QString filePath = d->engine->toFileInProject(fileUrl); + + const QVariantMap exception = body.value(_("exception")).toMap(); + QString errorMessage = exception.value(_("text")).toString(); + + highlightExceptionCode(lineNumber, filePath, errorMessage); } } + + if (resp.value(_("running")).toBool()) { + //DO NOTHING + } else { + d->engine->inferiorSpontaneousStop(); + d->listBreakpoints(); + d->backtrace(d->currentFrameIndex); + } + } else { + //DO NOTHING } + } -void QmlV8DebuggerClient::setStackFrames(const QByteArray &message) +void QmlV8DebuggerClient::updateStack(const QVariant &bodyVal, const QVariant &refsVal) { - d->frames = message; - JsonValue response(message); - - JsonValue refs = response.findChild("refs"); - JsonValue body = response.findChild("body"); - - int totalFrames = body.findChild("totalFrames").toVariant().toInt(); - JsonValue stackFrames = body.findChild("frames"); - - StackFrames ideStackFrames; - for (int i = 0; i != totalFrames; ++i) { + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "backtrace", + // "body" : { "fromFrame" : <number> + // "toFrame" : <number> + // "totalFrames" : <number> + // "frames" : <array of frames - see frame request for details> + // } + // "running" : <is the VM running after sending this response> + // "success" : true + // } + + StackFrames stackFrames; + const QVariantMap body = bodyVal.toMap(); + const QVariantList frames = body.value(_("frames")).toList(); + + d->engine->watchHandler()->beginCycle(); + foreach (const QVariant &frame, frames) { + stackFrames << createStackFrame(frame, refsVal); + } + d->engine->watchHandler()->endCycle(); - JsonValue stackFrame = stackFrames.childAt(i); + d->currentFrameIndex = body.value(_("fromFrame")).toInt(); - StackFrame frame; + if (!d->currentFrameIndex ) { + d->engine->stackHandler()->setFrames(stackFrames); + } - int frameIndex = stackFrame.findChild("index").toVariant().toInt(); - frame.level = frameIndex; + if (d->updateCurrentStackFrameIndex) { + d->engine->stackHandler()->setCurrentIndex(d->currentFrameIndex); + d->engine->gotoLocation(stackFrames.value(d->currentFrameIndex)); + } - frame.line = stackFrame.findChild("line").toVariant().toInt() + 1; + d->updateCurrentStackFrameIndex = true; - int index = indexInRef(refs,stackFrame.findChild("func").findChild("ref").toVariant().toInt()); - if (index != -1) { - JsonValue func = refs.childAt(index); - frame.function = func.findChild("name").toVariant().toString(); - } +} - index = indexInRef(refs,stackFrame.findChild("script").findChild("ref").toVariant().toInt()); - if (index != -1) { - JsonValue script = refs.childAt(index); - frame.file = d->engine->toFileInProject(script.findChild("name").toVariant().toString()); - frame.usable = QFileInfo(frame.file).isReadable(); - } - ideStackFrames << frame; +StackFrame QmlV8DebuggerClient::createStackFrame(const QVariant &bodyVal, const QVariant &refsVal) +{ + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "frame", + // "body" : { "index" : <frame number>, + // "receiver" : <frame receiver>, + // "func" : <function invoked>, + // "script" : <script for the function>, + // "constructCall" : <boolean indicating whether the function was called as constructor>, + // "debuggerFrame" : <boolean indicating whether this is an internal debugger frame>, + // "arguments" : [ { name: <name of the argument - missing of anonymous argument>, + // value: <value of the argument> + // }, + // ... <the array contains all the arguments> + // ], + // "locals" : [ { name: <name of the local variable>, + // value: <value of the local variable> + // }, + // ... <the array contains all the locals> + // ], + // "position" : <source position>, + // "line" : <source line>, + // "column" : <source column within the line>, + // "sourceLineText" : <text for current source line>, + // "scopes" : [ <array of scopes, see scope request below for format> ], + + // } + // "running" : <is the VM running after sending this response> + // "success" : true + // } + + const QVariantMap body = bodyVal.toMap(); + + StackFrame stackFrame; + stackFrame.level = body.value(_("index")).toInt(); + + QVariantMap func = body.value(_("func")).toMap(); + if (func.contains(_(REF))) { + func = valueFromRef(func.value(_(REF)).toInt(), refsVal).toMap(); } + stackFrame.function = d->extractData(QVariant(func)).value.toString(); - d->engine->stackHandler()->setFrames(ideStackFrames); - - if (!ideStackFrames.isEmpty()) { - setLocals(0); - d->engine->gotoLocation(ideStackFrames.value(0)); + QVariantMap file = body.value(_("script")).toMap(); + if (file.contains(_(REF))) { + file = valueFromRef(file.value(_(REF)).toInt(), refsVal).toMap(); } + stackFrame.file = d->engine->toFileInProject(d->extractData(QVariant(file)).value.toString()); + stackFrame.usable = QFileInfo(stackFrame.file).isReadable(); - if (d->handleException) { - handleException(); + QVariantMap receiver = body.value(_("receiver")).toMap(); + if (receiver.contains(_(REF))) { + receiver = valueFromRef(receiver.value(_(REF)).toInt(), refsVal).toMap(); } -} - -void QmlV8DebuggerClient::setLocals(int frameIndex) -{ - JsonValue response(d->frames); + stackFrame.to = d->extractData(QVariant(receiver)).value.toString(); - JsonValue refs = response.findChild("refs"); - JsonValue body = response.findChild("body"); + stackFrame.line = body.value(_("line")).toInt() + 1; - int totalFrames = body.findChild("totalFrames").toVariant().toInt(); - JsonValue stackFrames = body.findChild("frames"); + const QVariant locals = body.value(_("locals")); + updateLocals(locals, refsVal); + return stackFrame; +} - for (int i = 0; i != totalFrames; ++i) { - - JsonValue stackFrame = stackFrames.childAt(i); - int index = stackFrame.findChild("index").toVariant().toInt(); - if (index != frameIndex) +void QmlV8DebuggerClient::updateLocals(const QVariant &localsVal, const QVariant &refsVal) +{ + //Add Locals + const QVariantList locals = localsVal.toList(); + QList<WatchData> localDataList; + foreach (const QVariant &localValue, locals) { + QVariantMap localData = localValue.toMap(); + WatchData data; + data.exp = localData.value(_(NAME)).toByteArray(); + //Check for v8 specific local data + if (data.exp.startsWith(".") || data.exp.isEmpty()) continue; - JsonValue locals = stackFrame.findChild("locals"); + data.name = data.exp; + data.iname = "local." + data.exp; - d->engine->watchHandler()->beginCycle(); + localData = valueFromRef(localData.value(_(VALUE)).toMap() + .value(_(REF)).toInt(), refsVal).toMap(); + data.id = localData.value(_(HANDLE)).toInt(); - int localsCount = locals.childCount(); - for (int j = 0; j != localsCount; ++j) { - JsonValue local = locals.childAt(j); - - WatchData data; - data.exp = local.findChild("name").toVariant().toByteArray(); - //Check for v8 specific local - if (data.exp.startsWith(".")) - continue; + QmlV8ObjectData objectData = d->extractData(QVariant(localData)); + data.type = objectData.type; + data.value = objectData.value.toString(); - data.name = data.exp; - data.iname = "local." + data.exp; - JsonValue val = refs.childAt(indexInRef(refs,local.findChild("value").findChild("ref").toVariant().toInt())); - data.type = val.findChild("type").toVariant().toByteArray(); + data.setHasChildren(objectData.properties.toList().count()); - if (data.type == "object") { - data.hasChildren = true; - data.value = val.findChild("className").toVariant().toByteArray(); + localDataList << data; + } - } else if (data.type == "function" || data.type == "undefined") { - data.hasChildren = false; - data.value = val.findChild("text").toVariant().toByteArray(); + d->engine->watchHandler()->insertBulkData(localDataList); - } else { - data.hasChildren = false; - data.value = val.findChild("value").toVariant().toByteArray(); - } +} - data.id = val.findChild("handle").toVariant().toInt(); +void QmlV8DebuggerClient::updateEvaluationResult(int sequence, const QVariant &bodyVal, + const QVariant &refsVal) +{ + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "evaluate", + // "body" : ... + // "running" : <is the VM running after sending this response> + // "success" : true + // } + QVariantMap bodyMap = bodyVal.toMap(); + if (bodyMap.contains(_(REF))) { + bodyMap = valueFromRef(bodyMap.value(_(REF)).toInt(), + refsVal).toMap(); + } - d->engine->watchHandler()->insertData(data); + QmlV8ObjectData body = d->extractData(QVariant(bodyMap)); - if (d->engine->watchHandler()->expandedINames().contains(data.iname)) { - expandObject(data.iname, data.id); - } - } + if (!d->watches.contains(sequence)) { + //Console + d->engine->showMessage(body.value.toString(), ScriptConsoleOutput); - d->engine->watchHandler()->endCycle(); + } else { + WatchDataPair pair = d->watches.value(sequence); + QByteArray iname = pair.first; + QByteArray exp = pair.second; + WatchData data; + data.exp = exp; + data.name = data.exp; + data.iname = iname; + data.id = bodyMap.value(_(HANDLE)).toInt(); + data.type = body.type; + data.value = body.value.toString(); + + const QVariantList properties = body.properties.toList(); + data.setHasChildren(properties.count()); + // data.setAllUnneeded(); + // data.setValueNeeded(); + d->engine->watchHandler()->insertData(data); + + // foreach (const QVariant &property, properties) { + // QVariantMap propertyData = property.toMap(); + // WatchData data; + // data.exp = propertyData.value(_(NAME)).toByteArray(); + + // //Check for v8 specific local data + // if (data.exp.startsWith(".") || data.exp.isEmpty()) + // continue; + + // data.name = data.exp; + // data.iname = prepend + '.' + data.exp; + // propertyData = valueFromRef(propertyData.value(_(REF)).toInt(), + // refsVal).toMap(); + // data.id = propertyData.value(_(HANDLE)).toInt(); + + // QmlV8ObjectData objectData = d->extractData(QVariant(propertyData)); + // data.type = objectData.type; + // data.value = objectData.value.toString(); + + // data.setHasChildren(objectData.properties.toList().count()); + // d->engine->watchHandler()->insertData(data); + // } } } -void QmlV8DebuggerClient::expandLocal(const QByteArray &message) +void QmlV8DebuggerClient::updateBreakpoints(const QVariant &bodyVal) { - JsonValue response(message); + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "listbreakpoints", + // "body" : { "breakpoints": [ { "type" : <string: "scriptId" or "scriptName".>, + // "script_id" : <int: script id. Only defined if type is scriptId.>, + // "script_name" : <string: script name. Only defined if type is scriptName.>, + // "number" : <int: breakpoint number. Starts from 1.>, + // "line" : <int: line number of this breakpoint. Starts from 0.>, + // "column" : <int: column number of this breakpoint. Starts from 0.>, + // "groupId" : <int: group id of this breakpoint.>, + // "hit_count" : <int: number of times this breakpoint has been hit. Starts from 0.>, + // "active" : <bool: true if this breakpoint is enabled.>, + // "ignoreCount" : <int: remaining number of times to ignore breakpoint. Starts from 0.>, + // "actual_locations" : <actual locations of the breakpoint.>, + // } + // ], + // "breakOnExceptions" : <true if break on all exceptions is enabled>, + // "breakOnUncaughtExceptions" : <true if break on uncaught exceptions is enabled> + // } + // "running" : <is the VM running after sending this response> + // "success" : true + // } + + const QVariantMap body = bodyVal.toMap(); + const QVariantList breakpoints = body.value(_("breakpoints")).toList(); + BreakHandler *handler = d->engine->breakHandler(); - JsonValue refs = response.findChild("refs"); - JsonValue body = response.findChild("body"); - JsonValue details = body.childAt(0); + foreach (const QVariant &breakpoint, breakpoints) { + const QVariantMap breakpointData = breakpoint.toMap(); - int id = QString(details.name()).toInt(); - QByteArray prepend = d->locals.take(id); + int index = breakpointData.value(_("number")).toInt(); + BreakpointModelId id = d->breakpoints.key(index); + BreakpointResponse br = handler->response(id); - JsonValue properties = details.findChild("properties"); - int propertiesCount = properties.childCount(); + const QVariantList actualLocations = breakpointData.value(_("actual_locations")).toList(); + foreach (const QVariant &location, actualLocations) { + const QVariantMap locationData = location.toMap(); + br.lineNumber = locationData.value(_("line")).toInt() + 1;; + br.enabled = breakpointData.value(_("active")).toBool(); + br.hitCount = breakpointData.value(_("hit_count")).toInt(); + br.ignoreCount = breakpointData.value(_("ignoreCount")).toInt(); - for (int k = 0; k != propertiesCount; ++k) { - JsonValue property = properties.childAt(k); - setPropertyValue(refs,property,prepend); + handler->setResponse(id, br); + } } } -void QmlV8DebuggerClient::setExpression(const QByteArray &message) +QVariant QmlV8DebuggerClient::valueFromRef(int handle, const QVariant &refsVal) { - JsonValue response(message); - JsonValue body = response.findChild("body"); - - int seq = response.findChild("request_seq").toVariant().toInt(); - - //Console - if (!d->watches.contains(seq)) { - d->engine->showMessage(body.findChild("text").toVariant().toString(), ScriptConsoleOutput); - return; + QVariant variant; + const QVariantList refs = refsVal.toList(); + foreach (const QVariant &ref, refs) { + const QVariantMap refData = ref.toMap(); + if (refData.value(_(HANDLE)).toInt() == handle) { + variant = refData; + break; + } } - - //TODO: For watch point + return variant; } -void QmlV8DebuggerClient::updateBreakpoints(const QByteArray &message) +void QmlV8DebuggerClient::expandLocal(const QVariant &bodyVal, const QVariant &refsVal) { - JsonValue response(message); - - JsonValue body = response.findChild("body"); - - QList<JsonValue> breakpoints = body.findChild("breakpoints").children(); - BreakHandler *handler = d->engine->breakHandler(); - - foreach (const JsonValue &bp, breakpoints) { - - int bpIndex = bp.findChild("number").toVariant().toInt(); - BreakpointModelId id = d->breakpoints.key(bpIndex); - BreakpointResponse br = handler->response(id); - - if (!br.pending) + // { "seq" : <number>, + // "type" : "response", + // "request_seq" : <number>, + // "command" : "lookup", + // "body" : <array of serialized objects indexed using their handle> + // "running" : <is the VM running after sending this response> + // "success" : true + // } + const QVariantMap body = bodyVal.toMap(); + + int handle = body.keys().value(0).toInt(); + QByteArray prepend = d->locals.take(handle); + const WatchData *parent = d->engine->watchHandler()->findItem(prepend); + QmlV8ObjectData bodyObjectData = d->extractData( + body.value(body.keys().value(0))); + + const QVariantList properties = bodyObjectData.properties.toList(); + + QList<WatchData> children; + foreach (const QVariant &property, properties) { + QVariantMap propertyData = property.toMap(); + WatchData data; + data.name = propertyData.value(_(NAME)).toString(); + + //Check for v8 specific local data + if (data.name.startsWith(".") || data.name.isEmpty()) continue; + if (parent->type == "object") { + if (parent->value == _("Array")) + data.exp = parent->exp + '[' + data.name.toUtf8() + ']'; + else if (parent->value == _("Object")) + data.exp = parent->exp + '.' + data.name.toUtf8(); + } + data.iname = prepend + '.' + data.name.toUtf8(); + propertyData = valueFromRef(propertyData.value(_(REF)).toInt(), + refsVal).toMap(); + data.id = propertyData.value(_(HANDLE)).toInt(); - br.hitCount = bp.findChild("hit_count").toVariant().toInt(); + QmlV8ObjectData objectData = d->extractData(QVariant(propertyData)); + data.type = objectData.type; + data.value = objectData.value.toString(); - QList<JsonValue> actualLocations = bp.findChild("actual_locations").children(); - foreach (const JsonValue &location, actualLocations) { - int line = location.findChild("line").toVariant().toInt() + 1; //Add the offset - br.lineNumber = line; - br.correctedLineNumber = line; - handler->setResponse(id,br); - handler->notifyBreakpointInsertOk(id); - } + data.setHasChildren(objectData.properties.toList().count()); + children << data; } + d->engine->watchHandler()->insertBulkData(children); } -void QmlV8DebuggerClient::setPropertyValue(const JsonValue &refs, const JsonValue &property, const QByteArray &prepend) +void QmlV8DebuggerClient::highlightExceptionCode(int lineNumber, + const QString &filePath, + const QString &errorMessage) { - WatchData data; - data.exp = property.findChild("name").toVariant().toByteArray(); - data.name = data.exp; - data.iname = prepend + '.' + data.exp; - JsonValue val = refs.childAt(indexInRef(refs,property.findChild("ref").toVariant().toInt())); - data.type = val.findChild("type").toVariant().toByteArray(); - - if (data.type == "object") { - data.hasChildren = true; - data.value = val.findChild("className").toVariant().toByteArray(); + EditorManager *editorManager = EditorManager::instance(); + QList<IEditor *> openedEditors = editorManager->openedEditors(); - } else if (data.type == "function") { - data.hasChildren = false; - data.value = val.findChild("text").toVariant().toByteArray(); + // set up the format for the errors + QTextCharFormat errorFormat; + errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + errorFormat.setUnderlineColor(Qt::red); - } else { - data.hasChildren = false; - data.value = val.findChild("value").toVariant().toByteArray(); - } + foreach (IEditor *editor, openedEditors) { + if (editor->file()->fileName() == filePath) { + TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget()); + if (!ed) + continue; - data.id = val.findChild("handle").toVariant().toInt(); + QList<QTextEdit::ExtraSelection> selections; + QTextEdit::ExtraSelection sel; + sel.format = errorFormat; + QTextCursor c(ed->document()->findBlockByNumber(lineNumber)); + const QString text = c.block().text(); + for (int i = 0; i < text.size(); ++i) { + if (! text.at(i).isSpace()) { + c.setPosition(c.position() + i); + break; + } + } + c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + sel.cursor = c; - d->engine->watchHandler()->insertData(data); + sel.format.setToolTip(errorMessage); - if (d->engine->watchHandler()->expandedINames().contains(data.iname)) { - expandObject(data.iname, data.id); + selections.append(sel); + ed->setExtraSelections(TextEditor::BaseTextEditorWidget::DebuggerExceptionSelection, selections); + } } } -int QmlV8DebuggerClient::indexInRef(const JsonValue &refs, int refIndex) +void QmlV8DebuggerClient::clearExceptionSelection() { - for (int i = 0; i != refs.childCount(); ++i) { - JsonValue ref = refs.childAt(i); - int index = ref.findChild("handle").toVariant().toInt(); - if (index == refIndex) - return i; + EditorManager *editorManager = EditorManager::instance(); + QList<IEditor *> openedEditors = editorManager->openedEditors(); + QList<QTextEdit::ExtraSelection> selections; + + foreach (IEditor *editor, openedEditors) { + TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget()); + if (!ed) + continue; + + ed->setExtraSelections(TextEditor::BaseTextEditorWidget::DebuggerExceptionSelection, selections); } - return -1; + } -void QmlV8DebuggerClient::setEngine(QmlEngine *engine) +void QmlV8DebuggerClient::reset() { - d->engine = engine; + clearExceptionSelection(); + d->currentFrameIndex = 0; + d->updateCurrentStackFrameIndex = true; } } // Internal diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.h b/src/plugins/debugger/qml/qmlv8debuggerclient.h index 8c0c5cc13a5..830151232dc 100644 --- a/src/plugins/debugger/qml/qmlv8debuggerclient.h +++ b/src/plugins/debugger/qml/qmlv8debuggerclient.h @@ -36,8 +36,6 @@ #include "qmldebuggerclient.h" #include "stackframe.h" #include "watchdata.h" -#include "qmlengine.h" -#include "json.h" namespace Debugger { namespace Internal { @@ -84,12 +82,12 @@ public: void insertBreakpoint(const BreakpointModelId &id); void removeBreakpoint(const BreakpointModelId &id); void changeBreakpoint(const BreakpointModelId &id); - void updateBreakpoints(); + void synchronizeBreakpoints(); void assignValueInDebugger(const QByteArray expr, const quint64 &id, const QString &property, const QString &value); - void updateWatchData(const WatchData *data); + void updateWatchData(const WatchData &data); void executeDebuggerCommand(const QString &command); void synchronizeWatchers(const QStringList &watchers); @@ -98,30 +96,27 @@ public: void setEngine(QmlEngine *engine); -signals: - void notifyDebuggerStopped(); - protected: void messageReceived(const QByteArray &data); private: - void listBreakpoints(); - void backtrace(); - void setStackFrames(const QByteArray &message); - void setLocals(int frameIndex); - void setExpression(const QByteArray &message); - void updateBreakpoints(const QByteArray &message); - void expandLocal(const QByteArray &message); - void setPropertyValue(const Json::JsonValue &refs, const Json::JsonValue &property, const QByteArray &prepend); - int indexInRef(const Json::JsonValue &refs, int refIndex); - QByteArray packMessage(const QByteArray &message); - - void breakOnException(Exceptions exceptionsType, bool enabled); - void storeExceptionInformation(const QByteArray &message); - void handleException(); + void updateStack(const QVariant &bodyVal, const QVariant &refsVal); + StackFrame createStackFrame(const QVariant &bodyVal, const QVariant &refsVal); + void updateLocals(const QVariant &localsVal, const QVariant &refsVal); + + void updateEvaluationResult(int sequence, const QVariant &bodyVal, + const QVariant &refsVal); + void updateBreakpoints(const QVariant &bodyVal); + + QVariant valueFromRef(int handle, const QVariant &refsVal); + + void expandLocal(const QVariant &bodyVal, const QVariant &refsVal); + + void highlightExceptionCode(int lineNumber, const QString &filePath, + const QString &errorMessage); void clearExceptionSelection(); - void continueDebugging(StepAction type); + void reset(); private: QmlV8DebuggerClientPrivate *d; diff --git a/src/plugins/debugger/qml/qmlv8debuggerclientconstants.h b/src/plugins/debugger/qml/qmlv8debuggerclientconstants.h new file mode 100644 index 00000000000..40a39ddcde5 --- /dev/null +++ b/src/plugins/debugger/qml/qmlv8debuggerclientconstants.h @@ -0,0 +1,121 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#ifndef QMLV8DEBUGGERCLIENTCONSTANTS_H +#define QMLV8DEBUGGERCLIENTCONSTANTS_H + +namespace Debugger { +namespace Internal { + +const char V8DEBUG[] = "V8DEBUG"; +const char SEQ[] = "seq"; +const char TYPE[] = "type"; +const char COMMAND[] = "command"; +const char ARGUMENTS[] = "arguments"; +const char STEPACTION[] = "stepaction"; +const char STEPCOUNT[] = "stepcount"; +const char EXPRESSION[] = "expression"; +const char FRAME[] = "frame"; +const char GLOBAL[] = "global"; +const char DISABLE_BREAK[] = "disable_break"; +const char ADDITIONAL_CONTEXT[] = "additional_context"; +const char HANDLES[] = "handles"; +const char INCLUDESOURCE[] = "includeSource"; +const char FROMFRAME[] = "fromFrame"; +const char TOFRAME[] = "toFrame"; +const char BOTTOM[] = "bottom"; +const char NUMBER[] = "number"; +const char FRAMENUMBER[] = "frameNumber"; +const char TYPES[] = "types"; +const char IDS[] = "ids"; +const char FILTER[] = "filter"; +const char FROMLINE[] = "fromLine"; +const char TOLINE[] = "toLine"; +const char TARGET[] = "target"; +const char LINE[] = "line"; +const char COLUMN[] = "column"; +const char ENABLED[] = "enabled"; +const char CONDITION[] = "condition"; +const char IGNORECOUNT[] = "ignoreCount"; +const char BREAKPOINT[] = "breakpoint"; +const char FLAGS[] = "flags"; + +const char CONTINEDEBUGGING[] = "continue"; +const char EVALUATE[] = "evaluate"; +const char LOOKUP[] = "lookup"; +const char BACKTRACE[] = "backtrace"; +const char SCOPE[] = "scope"; +const char SCOPES[] = "scopes"; +const char SCRIPTS[] = "scripts"; +const char SOURCE[] = "source"; +const char SETBREAKPOINT[] = "setbreakpoint"; +const char CHANGEBREAKPOINT[] = "changebreakpoint"; +const char CLEARBREAKPOINT[] = "clearbreakpoint"; +const char SETEXCEPTIONBREAK[] = "setexceptionbreak"; +const char V8FLAGS[] = "v8flags"; +const char VERSION[] = "version"; +const char DISCONNECT[] = "disconnect"; +const char LISTBREAKPOINTS[] = "listbreakpoints"; +const char GARBAGECOLLECTOR[] = "gc"; +//const char PROFILE[] = "profile"; + +const char CONNECT[] = "connect"; +const char INTERRUPT[] = "interrupt"; + +const char REQUEST[] = "request"; +const char IN[] = "in"; +const char NEXT[] = "next"; +const char OUT[] = "out"; + +const char FUNCTION[] = "function"; +const char SCRIPT[] = "script"; +const char EVENT[] = "event"; + +const char ALL[] = "all"; +const char UNCAUGHT[] = "uncaught"; + +//const char PAUSE[] = "pause"; +//const char RESUME[] = "resume"; + +const char HANDLE[] = "handle"; +const char REF[] = "ref"; +const char REFS[] = "refs"; +const char BODY[] = "body"; +const char NAME[] = "name"; +const char VALUE[] = "value"; + +const char OBJECT[] = "{}"; +const char ARRAY[] = "[]"; + +} //Internal +} //Debugger +#endif // QMLV8DEBUGGERCLIENTCONSTANTS_H diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp index 12710c44d10..aad0ffea864 100644 --- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp +++ b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp @@ -240,7 +240,7 @@ void QScriptDebuggerClient::changeBreakpoint(const BreakpointModelId &/*id*/) { } -void QScriptDebuggerClient::updateBreakpoints() +void QScriptDebuggerClient::synchronizeBreakpoints() { QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); @@ -261,13 +261,13 @@ void QScriptDebuggerClient::assignValueInDebugger(const QByteArray expr, const q sendMessage(reply); } -void QScriptDebuggerClient::updateWatchData(const WatchData *data) +void QScriptDebuggerClient::updateWatchData(const WatchData &data) { QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); QByteArray cmd = "EXEC"; rs << cmd; - rs << data->iname << data->name; + rs << data.iname << data.name; sendMessage(reply); } diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.h b/src/plugins/debugger/qml/qscriptdebuggerclient.h index bd57ef60470..691fa2c829f 100644 --- a/src/plugins/debugger/qml/qscriptdebuggerclient.h +++ b/src/plugins/debugger/qml/qscriptdebuggerclient.h @@ -67,12 +67,12 @@ public: void insertBreakpoint(const BreakpointModelId &id); void removeBreakpoint(const BreakpointModelId &id); void changeBreakpoint(const BreakpointModelId &id); - void updateBreakpoints(); + void synchronizeBreakpoints(); void assignValueInDebugger(const QByteArray expr, const quint64 &id, const QString &property, const QString &value); - void updateWatchData(const WatchData *data); + void updateWatchData(const WatchData &data); void executeDebuggerCommand(const QString &command); void synchronizeWatchers(const QStringList &watchers); @@ -81,9 +81,6 @@ public: void setEngine(QmlEngine *engine); -signals: - void notifyDebuggerStopped(); - protected: void messageReceived(const QByteArray &data); -- GitLab