summaryrefslogtreecommitdiff
path: root/src/plugins/debugger/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/debugger/qml')
-rw-r--r--src/plugins/debugger/qml/interactiveinterpreter.cpp90
-rw-r--r--src/plugins/debugger/qml/interactiveinterpreter.h (renamed from src/plugins/debugger/qml/scriptconsole.h)67
-rw-r--r--src/plugins/debugger/qml/qml.pri14
-rw-r--r--src/plugins/debugger/qml/qmladapter.cpp33
-rw-r--r--src/plugins/debugger/qml/qmladapter.h8
-rw-r--r--src/plugins/debugger/qml/qmldebuggerclient.h4
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp113
-rw-r--r--src/plugins/debugger/qml/qmlengine.h6
-rw-r--r--src/plugins/debugger/qml/qmljsscriptconsole.cpp556
-rw-r--r--src/plugins/debugger/qml/qmljsscriptconsole.h130
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclient.cpp1988
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclient.h50
-rw-r--r--src/plugins/debugger/qml/qmlv8debuggerclientconstants.h121
-rw-r--r--src/plugins/debugger/qml/qscriptdebuggerclient.cpp6
-rw-r--r--src/plugins/debugger/qml/qscriptdebuggerclient.h7
-rw-r--r--src/plugins/debugger/qml/scriptconsole.cpp241
16 files changed, 2599 insertions, 835 deletions
diff --git a/src/plugins/debugger/qml/interactiveinterpreter.cpp b/src/plugins/debugger/qml/interactiveinterpreter.cpp
new file mode 100644
index 0000000000..2f43649ad0
--- /dev/null
+++ b/src/plugins/debugger/qml/interactiveinterpreter.cpp
@@ -0,0 +1,90 @@
+/**************************************************************************
+**
+** 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.
+**
+**************************************************************************/
+
+#include "interactiveinterpreter.h"
+
+namespace Debugger {
+namespace Internal {
+
+bool InteractiveInterpreter::canEvaluate()
+{
+ int yyaction = 0;
+ int yytoken = -1;
+ int yytos = -1;
+
+ setCode(m_code, 1);
+ m_tokens.append(T_FEED_JS_PROGRAM);
+
+ do {
+ if (++yytos == m_stateStack.size())
+ m_stateStack.resize(m_stateStack.size() * 2);
+
+ m_stateStack[yytos] = yyaction;
+
+again:
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
+ if (m_tokens.isEmpty())
+ yytoken = lex();
+ else
+ yytoken = m_tokens.takeFirst();
+ }
+
+ yyaction = t_action(yyaction, yytoken);
+ if (yyaction > 0) {
+ if (yyaction == ACCEPT_STATE) {
+ --yytos;
+ return true;
+ }
+ yytoken = -1;
+ } else if (yyaction < 0) {
+ const int ruleno = -yyaction - 1;
+ yytos -= rhs[ruleno];
+ yyaction = nt_action(m_stateStack[yytos], lhs[ruleno] - TERMINAL_COUNT);
+ }
+ } while (yyaction);
+
+ const int errorState = m_stateStack[yytos];
+ if (t_action(errorState, T_AUTOMATIC_SEMICOLON) && canInsertAutomaticSemicolon(yytoken)) {
+ yyaction = errorState;
+ m_tokens.prepend(yytoken);
+ yytoken = T_SEMICOLON;
+ goto again;
+ }
+
+ if (yytoken != EOF_SYMBOL)
+ return true;
+
+ return false;
+}
+
+}
+}
diff --git a/src/plugins/debugger/qml/scriptconsole.h b/src/plugins/debugger/qml/interactiveinterpreter.h
index 058b62e8bf..57962ab62a 100644
--- a/src/plugins/debugger/qml/scriptconsole.h
+++ b/src/plugins/debugger/qml/interactiveinterpreter.h
@@ -4,7 +4,7 @@
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
@@ -26,61 +26,46 @@
** 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 qt-info@nokia.com.
+** Nokia at info@qt.nokia.com.
**
**************************************************************************/
-#ifndef QMLJSSCRIPTCONSOLE_H
-#define QMLJSSCRIPTCONSOLE_H
+#ifndef INTERACTIVEINTERPRETER_H
+#define INTERACTIVEINTERPRETER_H
-#include <QtGui/QWidget>
-#include <QtGui/QToolButton>
-#include <QtGui/QPlainTextEdit>
+#include <qmljs/parser/qmljslexer_p.h>
+#include <qmljs/parser/qmljsengine_p.h>
-#include <utils/fancylineedit.h>
-
-namespace QmlJSEditor {
-class Highlighter;
-}
+#include <QtCore/QVector>
+#include <QtCore/QString>
+#include <QtCore/QList>
namespace Debugger {
namespace Internal {
-class ScriptConsole : public QWidget
+class InteractiveInterpreter: QmlJS::Lexer
{
- Q_OBJECT
public:
- ScriptConsole(QWidget *parent = 0);
-
-public slots:
- void appendResult(const QString &result);
-signals:
- void expressionEntered(const QString &expr);
-
-protected slots:
- void clearTextEditor();
- void executeExpression();
+ InteractiveInterpreter()
+ : Lexer(&m_engine),
+ m_stateStack(128)
+ {
-protected:
- bool eventFilter(QObject *obj, QEvent *event);
- void setFontSettings();
- void clear();
+ }
-// QToolButton *m_clearButton;
- QPlainTextEdit *m_textEdit;
- Utils::FancyLineEdit *m_lineEdit;
- QString m_prompt;
- QString m_expr;
- QString m_lastExpr;
+ void clearText() { m_code.clear(); }
+ void appendText(const QString &text) { m_code += text; }
- QString m_title;
- QmlJSEditor::Highlighter *m_highlighter;
+ QString code() const { return m_code; }
+ bool canEvaluate();
+private:
+ QmlJS::Engine m_engine;
+ QVector<int> m_stateStack;
+ QList<int> m_tokens;
+ QString m_code;
};
-
}
-} //end namespaces
-
-
-#endif
+}
+#endif // INTERACTIVEINTERPRETER_H
diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri
index 396f247a9b..a34c120add 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 \
@@ -8,15 +6,19 @@ HEADERS += \
$$PWD/qmldebuggerclient.h \
$$PWD/qmljsprivateapi.h \
$$PWD/qmlcppengine.h \
- $$PWD/scriptconsole.h \
+ $$PWD/qmljsscriptconsole.h \
$$PWD/qscriptdebuggerclient.h \
- $$PWD/qmlv8debuggerclient.h
+ $$PWD/qmlv8debuggerclient.h \
+ $$PWD/interactiveinterpreter.h \
+ $$PWD/qmlv8debuggerclientconstants.h
SOURCES += \
$$PWD/qmlengine.cpp \
$$PWD/qmladapter.cpp \
$$PWD/qmldebuggerclient.cpp \
$$PWD/qmlcppengine.cpp \
- $$PWD/scriptconsole.cpp \
+ $$PWD/qmljsscriptconsole.cpp \
$$PWD/qscriptdebuggerclient.cpp \
- $$PWD/qmlv8debuggerclient.cpp
+ $$PWD/qmlv8debuggerclient.cpp \
+ $$PWD/interactiveinterpreter.cpp
+
diff --git a/src/plugins/debugger/qml/qmladapter.cpp b/src/plugins/debugger/qml/qmladapter.cpp
index 99d5d69583..81c8eeca47 100644
--- a/src/plugins/debugger/qml/qmladapter.cpp
+++ b/src/plugins/debugger/qml/qmladapter.cpp
@@ -54,7 +54,9 @@ public:
explicit QmlAdapterPrivate(DebuggerEngine *engine)
: m_engine(engine)
, m_qmlClient(0)
+ , m_engineDebugClient(0)
, m_conn(0)
+ , m_currentSelectedDebugId(-1)
{
m_connectionTimer.setInterval(4000);
m_connectionTimer.setSingleShot(true);
@@ -62,9 +64,12 @@ public:
QWeakPointer<DebuggerEngine> m_engine;
QmlDebuggerClient *m_qmlClient;
+ QmlJsDebugClient::QDeclarativeEngineDebug *m_engineDebugClient;
QTimer m_connectionTimer;
QDeclarativeDebugConnection *m_conn;
QHash<QString, QmlDebuggerClient*> debugClients;
+ int m_currentSelectedDebugId;
+ QString m_currentSelectedDebugName;
};
} // namespace Internal
@@ -272,6 +277,34 @@ QHash<QString, Internal::QmlDebuggerClient*> QmlAdapter::debuggerClients()
{
return d->debugClients;
}
+
+QmlJsDebugClient::QDeclarativeEngineDebug *QmlAdapter::engineDebugClient() const
+{
+ return d->m_engineDebugClient;
+}
+
+void QmlAdapter::setEngineDebugClient(QmlJsDebugClient::QDeclarativeEngineDebug *client)
+{
+ d->m_engineDebugClient = client;
+}
+
+int QmlAdapter::currentSelectedDebugId() const
+{
+ return d->m_currentSelectedDebugId;
+}
+
+QString QmlAdapter::currentSelectedDisplayName() const
+{
+ return d->m_currentSelectedDebugName;
+}
+
+void QmlAdapter::setCurrentSelectedDebugInfo(int currentDebugId, const QString &displayName)
+{
+ d->m_currentSelectedDebugId = currentDebugId;
+ d->m_currentSelectedDebugName = displayName;
+ emit selectionChanged();
+}
+
void QmlAdapter::logServiceStatusChange(const QString &service,
QDeclarativeDebugClient::Status newStatus)
{
diff --git a/src/plugins/debugger/qml/qmladapter.h b/src/plugins/debugger/qml/qmladapter.h
index c19994796a..10750f009c 100644
--- a/src/plugins/debugger/qml/qmladapter.h
+++ b/src/plugins/debugger/qml/qmladapter.h
@@ -73,6 +73,13 @@ public:
Internal::QmlDebuggerClient *activeDebuggerClient();
QHash<QString, Internal::QmlDebuggerClient*> debuggerClients();
+ QmlJsDebugClient::QDeclarativeEngineDebug *engineDebugClient() const;
+ void setEngineDebugClient(QmlJsDebugClient::QDeclarativeEngineDebug *client);
+
+ int currentSelectedDebugId() const;
+ QString currentSelectedDisplayName() const;
+ void setCurrentSelectedDebugInfo(int debugId, const QString &displayName = QString());
+
public slots:
void logServiceStatusChange(const QString &service, QDeclarativeDebugClient::Status newStatus);
void logServiceActivity(const QString &service, const QString &logMessage);
@@ -83,6 +90,7 @@ signals:
void connectionStartupFailed();
void connectionError(QAbstractSocket::SocketError socketError);
void serviceConnectionError(const QString serviceName);
+ void selectionChanged();
private slots:
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
diff --git a/src/plugins/debugger/qml/qmldebuggerclient.h b/src/plugins/debugger/qml/qmldebuggerclient.h
index 521df7ed79..e190ce3a78 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 cafd726c77..826e4c81c5 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -52,6 +52,7 @@
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/applicationlauncher.h>
+#include <qmljsdebugclient/qdeclarativeoutputparser.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
@@ -100,6 +101,7 @@ private:
ApplicationLauncher m_applicationLauncher;
Utils::FileInProjectFinder fileFinder;
QTimer m_noDebugOutputTimer;
+ QmlJsDebugClient::QDeclarativeOutputParser m_outputParser;
};
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
@@ -144,6 +146,14 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters,
&d->m_noDebugOutputTimer,
SLOT(start()));
+ d->m_outputParser.setNoOutputText(ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput());
+ connect(&d->m_outputParser, SIGNAL(waitingForConnectionMessage()),
+ this, SLOT(beginConnection()));
+ connect(&d->m_outputParser, SIGNAL(noOutputMessage()),
+ this, SLOT(beginConnection()));
+ connect(&d->m_outputParser, SIGNAL(errorMessage(QString)),
+ this, SLOT(wrongSetupMessageBox(QString)));
+
// Only wait 8 seconds for the 'Waiting for connection' on application ouput, then just try to connect
// (application output might be redirected / blocked)
d->m_noDebugOutputTimer.setSingleShot(true);
@@ -258,6 +268,28 @@ void QmlEngine::retryMessageBoxFinished(int result)
}
}
+void QmlEngine::wrongSetupMessageBox(const QString &errorMessage)
+{
+ d->m_noDebugOutputTimer.stop();
+ notifyEngineRunFailed();
+
+ Core::ICore * const core = Core::ICore::instance();
+ QMessageBox *infoBox = new QMessageBox(core->mainWindow());
+ infoBox->setIcon(QMessageBox::Critical);
+ infoBox->setWindowTitle(tr("Qt Creator"));
+ //: %1 is detailed error message
+ infoBox->setText(tr("Could not connect to the in-process QML debugger:\n%1")
+ .arg(errorMessage));
+ infoBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
+ infoBox->setDefaultButton(QMessageBox::Ok);
+ infoBox->setModal(true);
+
+ connect(infoBox, SIGNAL(finished(int)),
+ this, SLOT(wrongSetupMessageBoxFinished(int)));
+
+ infoBox->show();
+}
+
void QmlEngine::connectionError(QAbstractSocket::SocketError socketError)
{
if (socketError == QAbstractSocket::RemoteHostClosedError)
@@ -280,63 +312,9 @@ bool QmlEngine::canDisplayTooltip() const
return state() == InferiorRunOk || state() == InferiorStopOk;
}
-void QmlEngine::filterApplicationMessage(const QString &msg, int /*channel*/)
+void QmlEngine::filterApplicationMessage(const QString &output, int /*channel*/)
{
- static const QString qddserver = QLatin1String("QDeclarativeDebugServer: ");
- static const QString cannotRetrieveDebuggingOutput = ApplicationLauncher::msgWinCannotRetrieveDebuggingOutput();
-
- const int index = msg.indexOf(qddserver);
- if (index != -1) {
- // we're actually getting debug output
- d->m_noDebugOutputTimer.stop();
-
- QString status = msg;
- status.remove(0, index + qddserver.length()); // chop of 'QDeclarativeDebugServer: '
-
- static QString waitingForConnection = QLatin1String("Waiting for connection ");
- static QString unableToListen = QLatin1String("Unable to listen ");
- static QString debuggingNotEnabled = QLatin1String("Ignoring \"-qmljsdebugger=");
- static QString debuggingNotEnabled2 = QLatin1String("Ignoring\"-qmljsdebugger="); // There is (was?) a bug in one of the error strings - safest to handle both
- static QString connectionEstablished = QLatin1String("Connection established");
-
- QString errorMessage;
- if (status.startsWith(waitingForConnection)) {
- beginConnection();
- } else if (status.startsWith(unableToListen)) {
- //: Error message shown after 'Could not connect ... debugger:"
- errorMessage = tr("The port seems to be in use.");
- } else if (status.startsWith(debuggingNotEnabled) || status.startsWith(debuggingNotEnabled2)) {
- //: Error message shown after 'Could not connect ... debugger:"
- errorMessage = tr("The application is not set up for QML/JS debugging.");
- } else if (status.startsWith(connectionEstablished)) {
- // nothing to do
- } else {
- qWarning() << "Unknown QDeclarativeDebugServer status message: " << status;
- }
-
- if (!errorMessage.isEmpty()) {
- notifyEngineRunFailed();
-
- Core::ICore * const core = Core::ICore::instance();
- QMessageBox *infoBox = new QMessageBox(core->mainWindow());
- infoBox->setIcon(QMessageBox::Critical);
- infoBox->setWindowTitle(tr("Qt Creator"));
- //: %1 is detailed error message
- infoBox->setText(tr("Could not connect to the in-process QML debugger:\n%1")
- .arg(errorMessage));
- infoBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
- infoBox->setDefaultButton(QMessageBox::Ok);
- infoBox->setModal(true);
-
- connect(infoBox, SIGNAL(finished(int)),
- this, SLOT(wrongSetupMessageBoxFinished(int)));
-
- infoBox->show();
- }
- } else if (msg.contains(cannotRetrieveDebuggingOutput)) {
- // we won't get debugging output, so just try to connect ...
- beginConnection();
- }
+ d->m_outputParser.processOutput(output);
}
void QmlEngine::showMessage(const QString &msg, int channel, int timeout) const
@@ -638,10 +616,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();
}
}
}
@@ -689,7 +667,7 @@ void QmlEngine::requestModuleSymbols(const QString &moduleName)
bool QmlEngine::setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor *editor, const DebuggerToolTipContext &ctx)
{
- // This is processed by QML inspector, which has dependencies to
+ // This is processed by QML inspector, which has dependencies to
// the qml js editor. Makes life easier.
emit tooltipRequested(mousePos, editor, ctx.position);
return true;
@@ -724,7 +702,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)) {
@@ -768,12 +746,10 @@ unsigned QmlEngine::debuggerCapabilities() const
QString QmlEngine::toFileInProject(const QUrl &fileUrl)
{
- if (startParameters().startMode != AttachToQmlPort) {
- if (d->fileFinder.projectDirectory().isEmpty()) {
- d->fileFinder.setProjectDirectory(startParameters().projectSourceDirectory);
- d->fileFinder.setProjectFiles(startParameters().projectSourceFiles);
- }
- }
+ // make sure file finder is properly initialized
+ d->fileFinder.setProjectDirectory(startParameters().projectSourceDirectory);
+ d->fileFinder.setProjectFiles(startParameters().projectSourceFiles);
+ d->fileFinder.setSysroot(startParameters().sysroot);
return d->fileFinder.findFile(fileUrl);
}
@@ -826,6 +802,11 @@ void QmlEngine::logMessage(LogDirection direction, const QString &message)
showMessage(msg, LogDebug);
}
+QmlAdapter *QmlEngine::adapter() const
+{
+ return &d->m_adapter;
+}
+
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
DebuggerEngine *masterEngine)
{
diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h
index 2b77d8575b..226792e085 100644
--- a/src/plugins/debugger/qml/qmlengine.h
+++ b/src/plugins/debugger/qml/qmlengine.h
@@ -40,6 +40,9 @@
#include <QtNetwork/QAbstractSocket>
namespace Debugger {
+
+class QmlAdapter;
+
namespace Internal {
class QmlEnginePrivate;
@@ -71,11 +74,14 @@ public:
void logMessage(LogDirection direction, const QString &str);
+ QmlAdapter *adapter() const;
+
public slots:
void disconnected();
private slots:
void retryMessageBoxFinished(int result);
+ void wrongSetupMessageBox(const QString &errorMessage);
void wrongSetupMessageBoxFinished(int result);
private:
diff --git a/src/plugins/debugger/qml/qmljsscriptconsole.cpp b/src/plugins/debugger/qml/qmljsscriptconsole.cpp
new file mode 100644
index 0000000000..5e28b5eb7e
--- /dev/null
+++ b/src/plugins/debugger/qml/qmljsscriptconsole.cpp
@@ -0,0 +1,556 @@
+/**************************************************************************
+**
+** 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.
+**
+**************************************************************************/
+
+#include "qmljsscriptconsole.h"
+#include "interactiveinterpreter.h"
+#include "qmladapter.h"
+#include "debuggerstringutils.h"
+
+#include <texteditor/fontsettings.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <utils/statuslabel.h>
+
+#include <QtGui/QMenu>
+#include <QtGui/QTextBlock>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QToolButton>
+
+namespace Debugger {
+namespace Internal {
+
+class QmlJSScriptConsolePrivate
+{
+public:
+ QmlJSScriptConsolePrivate()
+ : prompt(_("> ")),
+ startOfEditableArea(-1),
+ lastKnownPosition(0),
+ inferiorStopped(false)
+ {
+ resetCache();
+ }
+
+ void resetCache();
+ void appendToHistory(const QString &script);
+ bool canEvaluateScript(const QString &script);
+
+ QWeakPointer<QmlAdapter> adapter;
+
+ QString prompt;
+ int startOfEditableArea;
+ int lastKnownPosition;
+
+ QStringList scriptHistory;
+ int scriptHistoryIndex;
+
+ InteractiveInterpreter interpreter;
+
+ bool inferiorStopped;
+ QList<QTextEdit::ExtraSelection> selections;
+};
+
+void QmlJSScriptConsolePrivate::resetCache()
+{
+ scriptHistory.clear();
+ scriptHistory.append(QString());
+ scriptHistoryIndex = scriptHistory.count();
+
+ selections.clear();
+}
+
+void QmlJSScriptConsolePrivate::appendToHistory(const QString &script)
+{
+ scriptHistoryIndex = scriptHistory.count();
+ scriptHistory.replace(scriptHistoryIndex - 1,script);
+ scriptHistory.append(QString());
+ scriptHistoryIndex = scriptHistory.count();
+}
+
+bool QmlJSScriptConsolePrivate::canEvaluateScript(const QString &script)
+{
+ interpreter.clearText();
+ interpreter.appendText(script);
+ return interpreter.canEvaluate();
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// QmlJSScriptConsoleWidget
+//
+///////////////////////////////////////////////////////////////////////
+
+QmlJSScriptConsoleWidget::QmlJSScriptConsoleWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ vbox->setMargin(0);
+ vbox->setSpacing(0);
+
+ QWidget *statusbarContainer = new QWidget;
+
+ QHBoxLayout *hbox = new QHBoxLayout(statusbarContainer);
+ hbox->setMargin(0);
+ hbox->setSpacing(0);
+
+ //Clear Button
+ QToolButton *clearButton = new QToolButton;
+ QAction *clearAction = new QAction(tr("Clear Console"), this);
+ clearAction->setIcon(QIcon(_(Core::Constants::ICON_CLEAN_PANE)));
+
+ clearButton->setDefaultAction(clearAction);
+
+ //Status Label
+ m_statusLabel = new Utils::StatusLabel;
+
+ hbox->addWidget(m_statusLabel, 20, Qt::AlignLeft);
+ hbox->addWidget(clearButton, 0, Qt::AlignRight);
+
+ m_console = new QmlJSScriptConsole;
+ connect(m_console, SIGNAL(evaluateExpression(QString)), this,
+ SIGNAL(evaluateExpression(QString)));
+ connect(m_console, SIGNAL(updateStatusMessage(const QString &, int)), m_statusLabel,
+ SLOT(showStatusMessage(const QString &, int)));
+ connect(clearAction, SIGNAL(triggered()), m_console, SLOT(clear()));
+ vbox->addWidget(statusbarContainer);
+ vbox->addWidget(m_console);
+
+}
+
+void QmlJSScriptConsoleWidget::setQmlAdapter(QmlAdapter *adapter)
+{
+ m_console->setQmlAdapter(adapter);
+}
+
+void QmlJSScriptConsoleWidget::setInferiorStopped(bool inferiorStopped)
+{
+ m_console->setInferiorStopped(inferiorStopped);
+}
+
+void QmlJSScriptConsoleWidget::appendResult(const QString &result)
+{
+ m_console->appendResult(result);
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// QmlJSScriptConsole
+//
+///////////////////////////////////////////////////////////////////////
+
+QmlJSScriptConsole::QmlJSScriptConsole(QWidget *parent)
+ : QPlainTextEdit(parent),
+ d(new QmlJSScriptConsolePrivate())
+{
+ connect(this, SIGNAL(cursorPositionChanged()), SLOT(onCursorPositionChanged()));
+
+ setFrameStyle(QFrame::NoFrame);
+ setUndoRedoEnabled(false);
+ setBackgroundVisible(false);
+ const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings();
+ setFont(fs.font());
+
+ displayPrompt();
+}
+
+QmlJSScriptConsole::~QmlJSScriptConsole()
+{
+ delete d;
+}
+
+void QmlJSScriptConsole::setPrompt(const QString &prompt)
+{
+ d->prompt = prompt;
+}
+
+QString QmlJSScriptConsole::prompt() const
+{
+ return d->prompt;
+}
+
+void QmlJSScriptConsole::setInferiorStopped(bool inferiorStopped)
+{
+ d->inferiorStopped = inferiorStopped;
+ onSelectionChanged();
+}
+
+void QmlJSScriptConsole::setQmlAdapter(QmlAdapter *adapter)
+{
+ d->adapter = adapter;
+ clear();
+}
+
+void QmlJSScriptConsole::appendResult(const QString &result)
+{
+ QString currentScript = getCurrentScript();
+ d->appendToHistory(currentScript);
+
+ QTextCursor cur = textCursor();
+ cur.movePosition(QTextCursor::End);
+ cur.insertText(_("\n"));
+ cur.insertText(result);
+ cur.movePosition(QTextCursor::EndOfLine);
+ cur.insertText(_("\n"));
+ setTextCursor(cur);
+ displayPrompt();
+
+ QTextEdit::ExtraSelection sel;
+
+ QTextCharFormat resultFormat;
+ resultFormat.setForeground(QBrush(QColor(Qt::darkGray)));
+
+ QTextCursor c(document()->findBlockByNumber(cur.blockNumber()-1));
+ c.movePosition(QTextCursor::StartOfBlock);
+ c.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
+
+ sel.format = resultFormat;
+ sel.cursor = c;
+
+ d->selections.append(sel);
+
+ setExtraSelections(d->selections);
+}
+
+void QmlJSScriptConsole::clear()
+{
+ d->resetCache();
+
+ QPlainTextEdit::clear();
+ displayPrompt();
+}
+
+void QmlJSScriptConsole::onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State state)
+{
+ QDeclarativeDebugExpressionQuery *query = qobject_cast<QDeclarativeDebugExpressionQuery *>(sender());
+
+ if (query && state != QDeclarativeDebugQuery::Error) {
+ QString result(query->result().toString());
+ if (result == _("<undefined>") && d->inferiorStopped) {
+ //don't give up. check if we can still evaluate using javascript engine
+ emit evaluateExpression(getCurrentScript());
+ } else {
+ appendResult(result);
+ }
+ } else {
+ QPlainTextEdit::appendPlainText(QString());
+ moveCursor(QTextCursor::EndOfLine);
+ }
+ delete query;
+}
+
+void QmlJSScriptConsole::onSelectionChanged()
+{
+ if (!d->adapter.isNull()) {
+ QString status;
+ if (!d->inferiorStopped) {
+ status.append(tr("Current Selected Object: "));
+ status.append(d->adapter.data()->currentSelectedDisplayName());
+ }
+ emit updateStatusMessage(status, 0);
+ }
+}
+
+void QmlJSScriptConsole::keyPressEvent(QKeyEvent *e)
+{
+ bool keyConsumed = false;
+ switch (e->key()) {
+
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if (isEditableArea()) {
+ handleReturnKey();
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_Backspace: {
+ QTextCursor cursor = textCursor();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ if ((hasSelection && selectionStart < d->startOfEditableArea)
+ || (!hasSelection && selectionStart == d->startOfEditableArea)) {
+ keyConsumed = true;
+ }
+ break;
+ }
+
+ case Qt::Key_Delete:
+ if (textCursor().selectionStart() < d->startOfEditableArea) {
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ keyConsumed = true;
+ break;
+
+ case Qt::Key_Left:
+ if (textCursor().position() == d->startOfEditableArea) {
+ keyConsumed = true;
+ } else if (e->modifiers() & Qt::ControlModifier && isEditableArea()) {
+ handleHomeKey();
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_Up:
+ if (isEditableArea()) {
+ handleUpKey();
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_Down:
+ if (isEditableArea()) {
+ handleDownKey();
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_Home:
+ if (isEditableArea()) {
+ handleHomeKey();
+ keyConsumed = true;
+ }
+ break;
+
+ case Qt::Key_C:
+ case Qt::Key_Insert: {
+ //Fair to assume that for any selection beyond startOfEditableArea
+ //only copy function is allowed.
+ QTextCursor cursor = textCursor();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ if (hasSelection && selectionStart < d->startOfEditableArea) {
+ if (!(e->modifiers() & Qt::ControlModifier))
+ keyConsumed = true;
+ }
+ break;
+ }
+
+ default: {
+ QTextCursor cursor = textCursor();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ if (hasSelection && selectionStart < d->startOfEditableArea) {
+ keyConsumed = true;
+ }
+ break;
+ }
+ }
+
+ if (!keyConsumed)
+ QPlainTextEdit::keyPressEvent(e);
+}
+
+void QmlJSScriptConsole::contextMenuEvent(QContextMenuEvent *event)
+{
+ QTextCursor cursor = textCursor();
+ Qt::TextInteractionFlags flags = textInteractionFlags();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ bool canBeEdited = true;
+ if (hasSelection && selectionStart < d->startOfEditableArea) {
+ canBeEdited = false;
+ }
+
+ QMenu *menu = new QMenu();
+ QAction *a;
+
+ if ((flags & Qt::TextEditable) && canBeEdited) {
+ a = menu->addAction(tr("Cut"), this, SLOT(cut()));
+ a->setEnabled(cursor.hasSelection());
+ }
+
+ a = menu->addAction(tr("Copy"), this, SLOT(copy()));
+ a->setEnabled(cursor.hasSelection());
+
+ if ((flags & Qt::TextEditable) && canBeEdited) {
+ a = menu->addAction(tr("Paste"), this, SLOT(paste()));
+ a->setEnabled(canPaste());
+ }
+
+ menu->addSeparator();
+ a = menu->addAction(tr("Select All"), this, SLOT(selectAll()));
+ a->setEnabled(!document()->isEmpty());
+
+ menu->addSeparator();
+ menu->addAction(tr("Clear"), this, SLOT(clear()));
+
+ menu->exec(event->globalPos());
+
+ delete menu;
+}
+
+void QmlJSScriptConsole::mouseReleaseEvent(QMouseEvent *e)
+{
+ QPlainTextEdit::mouseReleaseEvent(e);
+ QTextCursor cursor = textCursor();
+ if (e->button() == Qt::LeftButton && !cursor.hasSelection() && !isEditableArea()) {
+ cursor.setPosition(d->lastKnownPosition);
+ setTextCursor(cursor);
+ }
+}
+
+void QmlJSScriptConsole::onCursorPositionChanged()
+{
+ if (!isEditableArea()) {
+ setTextInteractionFlags(Qt::TextSelectableByMouse);
+ } else {
+ d->lastKnownPosition = textCursor().position();
+ setTextInteractionFlags(Qt::TextEditorInteraction);
+ }
+}
+
+void QmlJSScriptConsole::displayPrompt()
+{
+ d->startOfEditableArea = textCursor().position() + d->prompt.length();
+ QTextCursor cur = textCursor();
+ cur.insertText(d->prompt);
+ cur.movePosition(QTextCursor::EndOfWord);
+ setTextCursor(cur);
+}
+
+void QmlJSScriptConsole::handleReturnKey()
+{
+ QString currentScript = getCurrentScript();
+ bool scriptEvaluated = false;
+
+ //Check if string is only white spaces
+ if (currentScript.trimmed().isEmpty()) {
+ QTextCursor cur = textCursor();
+ cur.movePosition(QTextCursor::EndOfLine);
+ cur.insertText(_("\n"));
+ setTextCursor(cur);
+ displayPrompt();
+ scriptEvaluated = true;
+ }
+
+ if (!scriptEvaluated) {
+ //check if it can be evaluated
+ if (d->canEvaluateScript(currentScript)) {
+
+ //Select the engine for evaluation based on
+ //inferior state
+ if (!d->inferiorStopped) {
+ if (!d->adapter.isNull()) {
+ QDeclarativeEngineDebug *engineDebug = d->adapter.data()->engineDebugClient();
+ int id = d->adapter.data()->currentSelectedDebugId();
+ if (engineDebug && id != -1) {
+ QDeclarativeDebugExpressionQuery *query =
+ engineDebug->queryExpressionResult(id, currentScript, this);
+ connect(query, SIGNAL(stateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)),
+ this, SLOT(onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State)));
+ scriptEvaluated = true;
+ }
+ }
+ }
+
+ if (!scriptEvaluated) {
+ emit evaluateExpression(currentScript);
+ scriptEvaluated = true;
+ }
+ }
+ }
+ if (!scriptEvaluated) {
+ QPlainTextEdit::appendPlainText(QString());
+ moveCursor(QTextCursor::EndOfLine);
+ }
+
+}
+
+void QmlJSScriptConsole::handleUpKey()
+{
+ //get the current script and update in script history
+ QString currentScript = getCurrentScript();
+ d->scriptHistory.replace(d->scriptHistoryIndex - 1,currentScript);
+
+ if (d->scriptHistoryIndex > 1)
+ d->scriptHistoryIndex--;
+
+ replaceCurrentScript(d->scriptHistory.at(d->scriptHistoryIndex - 1));
+}
+
+void QmlJSScriptConsole::handleDownKey()
+{
+ //get the current script and update in script history
+ QString currentScript = getCurrentScript();
+ d->scriptHistory.replace(d->scriptHistoryIndex - 1,currentScript);
+
+ if (d->scriptHistoryIndex < d->scriptHistory.count())
+ d->scriptHistoryIndex++;
+
+ replaceCurrentScript(d->scriptHistory.at(d->scriptHistoryIndex - 1));
+}
+
+void QmlJSScriptConsole::handleHomeKey()
+{
+ QTextCursor cursor = textCursor();
+ cursor.setPosition(d->startOfEditableArea);
+ setTextCursor(cursor);
+}
+
+QString QmlJSScriptConsole::getCurrentScript() const
+{
+ QTextCursor cursor = textCursor();
+ cursor.setPosition(d->startOfEditableArea);
+ while (cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor)) ;
+ QString script = cursor.selectedText();
+ cursor.clearSelection();
+ //remove trailing white space
+ int end = script.size() - 1;
+ while (end > 0 && script[end].isSpace())
+ end--;
+ return script.left(end + 1);
+}
+
+void QmlJSScriptConsole::replaceCurrentScript(const QString &script)
+{
+ QTextCursor cursor = textCursor();
+ cursor.setPosition(d->startOfEditableArea);
+ while (cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor)) ;
+ cursor.deleteChar();
+ cursor.insertText(script);
+ setTextCursor(cursor);
+}
+
+bool QmlJSScriptConsole::isEditableArea() const
+{
+ return textCursor().position() >= d->startOfEditableArea;
+}
+
+} //Internal
+} //Debugger
diff --git a/src/plugins/debugger/qml/qmljsscriptconsole.h b/src/plugins/debugger/qml/qmljsscriptconsole.h
new file mode 100644
index 0000000000..5240112309
--- /dev/null
+++ b/src/plugins/debugger/qml/qmljsscriptconsole.h
@@ -0,0 +1,130 @@
+/**************************************************************************
+**
+** 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 QMLJSSCRIPTCONSOLE_H
+#define QMLJSSCRIPTCONSOLE_H
+
+#include <qmljsdebugclient/qdeclarativeenginedebug.h>
+#include <QtGui/QPlainTextEdit>
+
+namespace Utils {
+class StatusLabel;
+}
+
+namespace Debugger {
+
+class QmlAdapter;
+
+namespace Internal {
+
+class QmlJSScriptConsolePrivate;
+class QmlJSScriptConsole;
+
+class QmlJSScriptConsoleWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ QmlJSScriptConsoleWidget(QWidget *parent = 0);
+
+ void setQmlAdapter(QmlAdapter *adapter);
+ void setInferiorStopped(bool inferiorStopped);
+
+public slots:
+ void appendResult(const QString &result);
+
+signals:
+ void evaluateExpression(const QString &expr);
+
+private:
+ QmlJSScriptConsole *m_console;
+ Utils::StatusLabel *m_statusLabel;
+
+};
+
+class QmlJSScriptConsole : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ explicit QmlJSScriptConsole(QWidget *parent = 0);
+ ~QmlJSScriptConsole();
+
+ inline void setTitle(const QString &title)
+ { setDocumentTitle(title); }
+
+ inline QString title() const
+ { return documentTitle(); }
+
+ void setPrompt(const QString &prompt);
+ QString prompt() const;
+
+ void setInferiorStopped(bool inferiorStopped);
+
+ void setQmlAdapter(QmlAdapter *adapter);
+
+ void appendResult(const QString &result);
+
+public slots:
+ void clear();
+ void onStateChanged(QmlJsDebugClient::QDeclarativeDebugQuery::State);
+ void onSelectionChanged();
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+signals:
+ void evaluateExpression(const QString &expr);
+ void updateStatusMessage(const QString &message, int timeoutMS);
+
+private slots:
+ void onCursorPositionChanged();
+
+private:
+ void displayPrompt();
+ void handleReturnKey();
+ void handleUpKey();
+ void handleDownKey();
+ void handleHomeKey();
+ QString getCurrentScript() const;
+ void replaceCurrentScript(const QString &script);
+ bool isEditableArea() const;
+
+private:
+ QmlJSScriptConsolePrivate *d;
+};
+
+} //Internal
+} //Debugger
+
+#endif
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
index 0be6a496fe..9e0caac222 100644
--- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
+++ b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
@@ -31,281 +31,898 @@
**************************************************************************/
#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>
#include <QtGui/QTextBlock>
#include <QtCore/QVariant>
+#include <QtCore/QStack>
+#include <QtCore/QQueue>
#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 << '\n'
+#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),
- engine(0)
+ explicit QmlV8DebuggerClientPrivate(QmlV8DebuggerClient *q) :
+ q(q),
+ sequence(-1),
+ engine(0),
+ debugServiceState(QmlV8DebuggerClient::RunningState),
+ requestListBreakpoints(false),
+ requestBacktrace(true)
{
+ 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);
+ void clearCache();
+
+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;
+
+ QScriptValue parser;
+ QScriptValue stringifier;
+
+ //State Information
+ QmlV8DebuggerClient::V8DebugServiceStates debugServiceState;
+ int currentFrameIndex;
+ QStringList watchedExpressions;
+
+ //Flags
+ bool requestListBreakpoints;
+ bool requestBacktrace;
+
+ //Cache
+ QHash<int, QByteArray> localsAndWatchers;
+ QHash<int, QString> evaluatingWatches;
+ QStack<QString> watchesToEvaluate;
+ QStack<int> currentFrameScopes;
+ QList<WatchData> localDataList;
+ QVariant refsVal;
+ QHash<int, QString> evaluatingExpression;
+ QQueue<QByteArray> requestQueue;
+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->resetDebugger();
+
+ // { "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)
+{
+ // { "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)
{
- continueDebugging(Out);
+ // { "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 QmlV8DebuggerClient::executeNext()
+void QmlV8DebuggerClientPrivate::setExceptionBreak(QmlV8DebuggerClient::Exceptions type,
+ bool enabled)
{
- continueDebugging(Next);
+ // { "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::executeStepI()
+void QmlV8DebuggerClientPrivate::listBreakpoints()
{
- continueDebugging(In);
+ // { "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::continueInferior()
+void QmlV8DebuggerClientPrivate::v8flags(const QString flags)
+{
+ // { "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 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)
{
- QByteArray request;
+ // { "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));
+ }
- JsonInputStream(request) << '{' << INITIALPARAMS ;
- JsonInputStream(request) << ',' << "command" << ':' << "connect";
+ return objectData;
+}
- JsonInputStream(request) << '}';
+void QmlV8DebuggerClientPrivate::clearCache()
+{
+ localsAndWatchers.clear();
+ evaluatingWatches.clear();
+ watchesToEvaluate.clear();
+ currentFrameScopes.clear();
+ localDataList.clear();
+ refsVal.clear();
+}
- sendMessage(packMessage(request));
+QByteArray QmlV8DebuggerClientPrivate::packMessage(const QByteArray &message)
+{
+ SDEBUG(message);
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ QByteArray cmd = V8DEBUG;
+ rs << cmd << message;
+ return reply;
+}
+
+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))
+{
+ resetDebugger();
+}
+
+QmlV8DebuggerClient::~QmlV8DebuggerClient()
+{
+ delete d;
+}
+
+void QmlV8DebuggerClient::startSession()
+{
+ resetDebugger();
+ d->debugServiceState = QmlV8DebuggerClient::RunningState;
+ d->connect();
}
void QmlV8DebuggerClient::endSession()
{
- clearExceptionSelection();
+ d->disconnect();
+}
- QByteArray request;
+void QmlV8DebuggerClient::executeStep()
+{
+ d->continueDebugging(In);
+}
- JsonInputStream(request) << '{' << INITIALPARAMS ;
- JsonInputStream(request) << ',' << "command" << ':' << "disconnect";
+void QmlV8DebuggerClient::executeStepOut()
+{
+ d->continueDebugging(Out);
+}
- JsonInputStream(request) << '}';
+void QmlV8DebuggerClient::executeNext()
+{
+ d->continueDebugging(Next);
+}
+
+void QmlV8DebuggerClient::executeStepI()
+{
+ d->continueDebugging(In);
+}
+
+void QmlV8DebuggerClient::continueInferior()
+{
+ d->continueDebugging(Continue);
+}
- sendMessage(packMessage(request));
+void QmlV8DebuggerClient::interruptInferior()
+{
+ d->interrupt();
}
void QmlV8DebuggerClient::activateFrame(int index)
{
- setLocals(index);
+ d->backtrace(index);
}
bool QmlV8DebuggerClient::acceptsBreakpoint(const BreakpointModelId &id)
@@ -323,57 +940,38 @@ void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &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);
- }
-
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)
@@ -382,107 +980,90 @@ void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id)
const BreakpointParameters &params = handler->breakpointData(id);
if (params.type == BreakpointAtJavaScriptThrow) {
- return breakOnException(AllExceptions, params.enabled);
+ d->setExceptionBreak(AllExceptions, params.enabled);
}
+
+ int breakpoint = d->breakpoints.value(id);
+ d->changeBreakpoint(breakpoint, params.enabled, QString(params.condition),
+ params.ignoreCount);
+
+ BreakpointResponse br = handler->response(id);
+ br.enabled = params.enabled;
+ br.condition = params.condition;
+ br.ignoreCount = params.ignoreCount;
+ handler->setResponse(id, br);
}
-void QmlV8DebuggerClient::updateBreakpoints()
+void QmlV8DebuggerClient::synchronizeBreakpoints()
{
+ //NOT USED
}
void QmlV8DebuggerClient::assignValueInDebugger(const QByteArray /*expr*/, const quint64 &/*id*/,
- const QString &/*property*/, const QString &/*value*/)
+ const QString &property, const QString &value)
{
- //TODO::
+ StackHandler *stackHandler = d->engine->stackHandler();
+ QString expression = QString(_("%1 = %2;")).arg(property).arg(value);
+ if (stackHandler->isContentsValid()) {
+ d->evaluate(expression, false, false, stackHandler->currentIndex());
+ }
}
-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()) {
+ QString exp(data.exp);
+ if (!d->watchedExpressions.contains(exp)) {
+ //Push new expression to the stack
+ d->watchesToEvaluate.push(exp);
+ }
+ }
}
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());
+ d->evaluatingExpression.insert(d->sequence, command);
+ } 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*/)
+void QmlV8DebuggerClient::synchronizeWatchers(const QStringList &watchers)
{
- //TODO:: send watchers list
+ SDEBUG(watchers);
+ //Cache the watched expression List
+ d->watchedExpressions = watchers;
+ //Evaluate new expressions one at a time.
+ if (!d->watchesToEvaluate.isEmpty()) {
+ StackHandler *stackHandler = d->engine->stackHandler();
+ const QString exp = d->watchesToEvaluate.pop();
+ if (stackHandler->isContentsValid()) {
+ d->evaluate(exp, false, false, stackHandler->currentIndex());
+ } else {
+ d->evaluate(exp);
+ }
+ d->evaluatingWatches.insert(d->sequence, exp);
+ }
}
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));
+ if (d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ if (!d->localsAndWatchers.contains(objectId)) {
+ d->lookup(QList<int>() << objectId);
+ d->localsAndWatchers.insert(objectId, iname);
+ }
+ }
}
-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 +1072,801 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data)
QByteArray command;
ds >> command;
- if (command == "V8DEBUG") {
+ if (command == V8DEBUG) {
QByteArray response;
ds >> response;
+ QString responseString(response);
+
+ SDEBUG(responseString);
- JsonValue value(response);
- const QString type = value.findChild("type").toVariant().toString();
+ const QVariantMap resp = d->parser.call(QScriptValue(),
+ QScriptValueList() <<
+ QScriptValue(responseString)).toVariant().toMap();
+ bool isV8Running = resp.value(_("running")).toBool();
+ const QString type(resp.value(_(TYPE)).toString());
- if (type == "response") {
+ if (type == _("response")) {
- 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;
+ 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());
+
+ if (debugCommand == _(CONNECT)) {
+ //debugging session started
+
+ } else if (debugCommand == _(DISCONNECT)) {
+ //debugging session ended
+
+ } else if (debugCommand == _(CONTINEDEBUGGING)) {
+ d->requestBacktrace = true;
- } else if (debugCommand == "lookup") {
- expandLocal(response);
+ } else if (debugCommand == _(BACKTRACE)) {
+ if (success && d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ updateStack(resp.value(_(BODY)), resp.value(_(REFS)));
+ }
+
+ } else if (debugCommand == _(LOOKUP)) {
+ if (success && d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ expandLocalsAndWatchers(resp.value(_(BODY)), resp.value(_(REFS)));
+ }
- } 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 == _(EVALUATE)) {
+ int seq = resp.value(_("request_seq")).toInt();
+ if (success) {
+ d->requestBacktrace = true;
+ updateEvaluationResult(seq, success, resp.value(_(BODY)), resp.value(_(REFS)));
+ } else {
+ QVariantMap map;
+ map.insert(_(TYPE), QVariant(_("string")));
+ map.insert(_(VALUE), resp.value(_("message")));
+ updateEvaluationResult(seq, success, QVariant(map), QVariant());
+ }
- //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 == _(LISTBREAKPOINTS)) {
+ if (success && d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ updateBreakpoints(resp.value(_(BODY)));
}
- } else if (debugCommand == "evaluate") {
- setExpression(response);
+ } 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 && d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ 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 == "listbreakpoints") {
- updateBreakpoints(response);
- backtrace();
+ } else if (debugCommand == _(SCOPE)) {
+ if (success && d->debugServiceState != QmlV8DebuggerClient::RunningState) {
+ const QVariant body = resp.value(_(BODY)).toMap().value(_("object"));
+ const QVariant refs = resp.value(_(REFS));
+ updateScope(body, refs);
+ }
+ } 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 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();
- }
- }
- }
-}
+ if (!isV8Running
+ && d->debugServiceState == QmlV8DebuggerClient::ProcessingRequestState)
+ d->debugServiceState = QmlV8DebuggerClient::WaitingForRequestState;
-void QmlV8DebuggerClient::setStackFrames(const QByteArray &message)
-{
- d->frames = message;
- JsonValue response(message);
+ } else if (type == _(EVENT)) {
+ const QString eventType(resp.value(_(EVENT)).toString());
- JsonValue refs = response.findChild("refs");
- JsonValue body = response.findChild("body");
+ if (eventType == _("break")) {
+ if (d->engine->state() == InferiorRunOk)
+ d->engine->inferiorSpontaneousStop();
+ isV8Running = false;
- int totalFrames = body.findChild("totalFrames").toVariant().toInt();
- JsonValue stackFrames = body.findChild("frames");
+ } else if (eventType == _("exception")) {
+ const QVariantMap body = resp.value(_(BODY)).toMap();
+ int lineNumber = body.value(_("sourceLine")).toInt() + 1;
- StackFrames ideStackFrames;
- for (int i = 0; i != totalFrames; ++i) {
+ const QVariantMap script = body.value(_("script")).toMap();
+ QUrl fileUrl(script.value(_(NAME)).toString());
+ QString filePath = d->engine->toFileInProject(fileUrl);
- JsonValue stackFrame = stackFrames.childAt(i);
+ const QVariantMap exception = body.value(_("exception")).toMap();
+ QString errorMessage = exception.value(_("text")).toString();
- StackFrame frame;
+ highlightExceptionCode(lineNumber, filePath, errorMessage);
- int frameIndex = stackFrame.findChild("index").toVariant().toInt();
- frame.level = frameIndex;
+ if (d->engine->state() == InferiorRunOk)
+ d->engine->inferiorSpontaneousStop();
+ isV8Running = false;
+ d->requestBacktrace = true;
- frame.line = stackFrame.findChild("line").toVariant().toInt() + 1;
+ } else if (eventType == _("afterCompile")) {
+ d->requestListBreakpoints = true;
+ }
+
+ //Sometimes we do not get event type!
+ //This is most probably due to a wrong eval expression.
+ //Redirect output to console.
+ if (eventType.isEmpty()) {
+ bool success = resp.value(_("success")).toBool();
+ QVariantMap map;
+ map.insert(_(TYPE), QVariant(_("string")));
+ map.insert(_(VALUE), resp.value(_("message")));
+ //Since there is no sequence value, best estimate is
+ //last sequence value
+ updateEvaluationResult(d->sequence, success, QVariant(map), QVariant());
+ if (!isV8Running
+ && d->debugServiceState == QmlV8DebuggerClient::ProcessingRequestState)
+ d->debugServiceState = QmlV8DebuggerClient::WaitingForRequestState;
+ }
+
+ if (!isV8Running
+ && d->debugServiceState == QmlV8DebuggerClient::RunningState)
+ d->debugServiceState = QmlV8DebuggerClient::WaitingForRequestState;
+ }
+
+ if (isV8Running) {
+ resetDebugger();
+ d->debugServiceState = QmlV8DebuggerClient::RunningState;
+
+ } else {
+ if (d->requestListBreakpoints) {
+ d->listBreakpoints();
+ d->requestListBreakpoints = false;
+ }
+
+ if (d->requestBacktrace) {
+ d->backtrace(d->currentFrameIndex);
+ d->requestBacktrace = false;
+ }
+
+ if (d->debugServiceState == QmlV8DebuggerClient::WaitingForRequestState
+ && !d->requestQueue.isEmpty()) {
+ QmlDebuggerClient::sendMessage(d->requestQueue.dequeue());
+ d->debugServiceState = QmlV8DebuggerClient::ProcessingRequestState;
+ }
- 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();
+ } else {
+ //DO NOTHING
+ }
+ SDEBUG(QString(_("State: %1")).arg(d->debugServiceState));
+}
+
+void QmlV8DebuggerClient::sendMessage(const QByteArray &msg)
+{
+ if (d->debugServiceState == QmlV8DebuggerClient::RunningState) {
+ QmlDebuggerClient::sendMessage(msg);
+ } else if (d->debugServiceState == QmlV8DebuggerClient::WaitingForRequestState) {
+ QmlDebuggerClient::sendMessage(msg);
+ d->debugServiceState = QmlV8DebuggerClient::ProcessingRequestState;
+ } else {
+ d->requestQueue.enqueue(msg);
+ }
+
+}
+
+void QmlV8DebuggerClient::updateStack(const QVariant &bodyVal, const QVariant &refsVal)
+{
+ // { "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
+ // }
+
+ const QVariantMap body = bodyVal.toMap();
+ const QVariantList frames = body.value(_("frames")).toList();
+
+ int fromFrameIndex = body.value(_("fromFrame")).toInt();
+
+
+ if (0 == fromFrameIndex) {
+ StackFrames stackFrames;
+ foreach (const QVariant &frame, frames) {
+ stackFrames << createStackFrame(frame, refsVal);
}
- ideStackFrames << frame;
+ d->engine->stackHandler()->setFrames(stackFrames);
}
- d->engine->stackHandler()->setFrames(ideStackFrames);
+ if (d->currentFrameIndex != fromFrameIndex) {
+ StackHandler *stackHandler = d->engine->stackHandler();
+ stackHandler->setCurrentIndex(fromFrameIndex);
+ d->engine->gotoLocation(stackHandler->currentFrame());
+ d->currentFrameIndex = fromFrameIndex;
+ }
- if (!ideStackFrames.isEmpty()) {
- setLocals(0);
- d->engine->gotoLocation(ideStackFrames.value(0));
+ //Update all Locals visible in current scope
+ //Traverse the scope chain and store the local properties
+ //in a list and show them in the Locals Window.
+ const QVariantMap currentFrame = frames.value(0).toMap();
+ d->clearCache();
+ d->refsVal = refsVal;
+ //Set "this" variable
+ {
+ WatchData data;
+ data.exp = QByteArray("this");
+ data.name = QString(data.exp);
+ data.iname = QByteArray("local.") + data.exp;
+ QVariantMap receiver = currentFrame.value(_("receiver")).toMap();
+ if (receiver.contains(_(REF))) {
+ receiver = valueFromRef(receiver.value(_(REF)).toInt(), refsVal).toMap();
+ }
+ data.id = receiver.value(_("handle")).toInt();
+ QmlV8ObjectData receiverData = d->extractData(QVariant(receiver));
+ data.type = receiverData.type;
+ data.value = receiverData.value.toString();
+ data.setHasChildren(receiverData.properties.toList().count());
+ d->localDataList << data;
}
- if (d->handleException) {
- handleException();
+ const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
+ foreach (const QVariant &scope, currentFrameScopes) {
+ //Do not query for global types (0)
+ //Showing global properties increases clutter.
+ if (scope.toMap().value(_("type")).toInt() == 0)
+ continue;
+ d->currentFrameScopes.push(scope.toMap().value(_("index")).toInt());
+ }
+ if (!d->currentFrameScopes.isEmpty()) {
+ d->scope(d->currentFrameScopes.pop(), d->currentFrameIndex);
+ } else {
+ updateLocalsAndWatchers();
}
}
-void QmlV8DebuggerClient::setLocals(int frameIndex)
+StackFrame QmlV8DebuggerClient::createStackFrame(const QVariant &bodyVal, const QVariant &refsVal)
{
- JsonValue response(d->frames);
+ // { "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();
- JsonValue refs = response.findChild("refs");
- JsonValue body = response.findChild("body");
+ 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();
- int totalFrames = body.findChild("totalFrames").toVariant().toInt();
- JsonValue stackFrames = body.findChild("frames");
+ QVariantMap receiver = body.value(_("receiver")).toMap();
+ if (receiver.contains(_(REF))) {
+ receiver = valueFromRef(receiver.value(_(REF)).toInt(), refsVal).toMap();
+ }
+ stackFrame.to = d->extractData(QVariant(receiver)).value.toString();
+ stackFrame.line = body.value(_("line")).toInt() + 1;
- for (int i = 0; i != totalFrames; ++i) {
+ return stackFrame;
+}
- 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 = QString(data.exp);
+ data.iname = QByteArray("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);
+ QmlV8ObjectData objectData = d->extractData(QVariant(localData));
+ data.type = objectData.type;
+ data.value = objectData.value.toString();
- WatchData data;
- data.exp = local.findChild("name").toVariant().toByteArray();
- //Check for v8 specific local
- if (data.exp.startsWith("."))
- continue;
+ data.setHasChildren(objectData.properties.toList().count());
- 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();
+ localDataList << data;
+ }
- if (data.type == "object") {
- data.hasChildren = true;
- data.value = val.findChild("className").toVariant().toByteArray();
+ d->engine->watchHandler()->insertBulkData(localDataList);
- } else if (data.type == "function" || data.type == "undefined") {
- data.hasChildren = false;
- data.value = val.findChild("text").toVariant().toByteArray();
+}
- } else {
- data.hasChildren = false;
- data.value = val.findChild("value").toVariant().toByteArray();
- }
+void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &refsVal)
+{
+// { "seq" : <number>,
+// "type" : "response",
+// "request_seq" : <number>,
+// "command" : "scope",
+// "body" : { "index" : <index of this scope in the scope chain. Index 0 is the top scope
+// and the global scope will always have the highest index for a
+// frame>,
+// "frameIndex" : <index of the frame>,
+// "type" : <type of the scope:
+// 0: Global
+// 1: Local
+// 2: With
+// 3: Closure
+// 4: Catch >,
+// "object" : <the scope object defining the content of the scope.
+// For local and closure scopes this is transient objects,
+// which has a negative handle value>
+// }
+// "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();
+ }
- data.id = val.findChild("handle").toVariant().toInt();
+ const QVariantList properties = bodyMap.value(_("properties")).toList();
- d->engine->watchHandler()->insertData(data);
+ foreach (const QVariant &property, properties) {
+ QVariantMap localData = property.toMap();
+ WatchData data;
+ data.exp = localData.value(_(NAME)).toByteArray();
+ //Check for v8 specific local data
+ if (data.exp.startsWith(".") || data.exp.isEmpty())
+ continue;
- if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
- expandObject(data.iname, data.id);
+ data.name = QString(data.exp);
+ data.iname = QByteArray("local.") + data.exp;
+
+ int handle = localData.value(_(REF)).toInt();
+ localData = valueFromRef(handle, d->refsVal).toMap();
+ if (localData.isEmpty()) {
+ //Fetch Data asynchronously and insert later
+ // see expandLocalsAndWatchers()
+ if (!d->localsAndWatchers.contains(handle)) {
+ d->lookup(QList<int>() << handle);
+ d->localsAndWatchers.insert(handle, data.exp);
}
+
+ } else {
+ data.id = localData.value(_(HANDLE)).toInt();
+
+ QmlV8ObjectData objectData = d->extractData(QVariant(localData));
+ data.type = objectData.type;
+ data.value = objectData.value.toString();
+
+ data.setHasChildren(objectData.properties.toList().count());
+
+ d->localDataList << data;
}
+ }
- d->engine->watchHandler()->endCycle();
+ if (!d->currentFrameScopes.isEmpty()) {
+ d->scope(d->currentFrameScopes.pop(), d->currentFrameIndex);
+ } else {
+ updateLocalsAndWatchers();
}
}
-void QmlV8DebuggerClient::expandLocal(const QByteArray &message)
+void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
+ const QVariant &refsVal)
{
- JsonValue response(message);
+ // { "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();
+ }
+
+ QmlV8ObjectData body = d->extractData(QVariant(bodyMap));
+
+ if (d->evaluatingExpression.contains(sequence)) {
+ d->evaluatingExpression.take(sequence);
+ //Console
+ d->engine->showMessage(body.value.toString(), ScriptConsoleOutput);
+
+ } else if (d->evaluatingWatches.contains(sequence)) {
+ d->requestBacktrace = false;
+ QString exp = d->evaluatingWatches.take(sequence);
+ QByteArray iname = d->engine->watchHandler()->watcherName(exp.toLatin1());
+ SDEBUG(QString(iname));
+ WatchData data;
+ data.exp = exp.toLatin1();
+ data.name = exp;
+ data.iname = iname;
+ data.id = bodyMap.value(_(HANDLE)).toInt();
+ if (success) {
+ data.type = body.type;
+ data.value = body.value.toString();
+ } else {
+ //Do not set type since it is unkown
+ data.setError(body.value.toString());
+ }
+
+ //TODO:: Fix expanding watched objects/expressions
+// const QVariantList properties = body.properties.toList();
+// data.setHasChildren(properties.count());
+
+ //Insert the newly evaluated expression to the Watchers Window
+ d->engine->watchHandler()->beginCycle(false);
+ d->engine->watchHandler()->insertData(data);
+ d->engine->watchHandler()->endCycle();
+
+ //Check if there are more expressions to be evaluated
+ //Evaluate one at a time.
+ if (!d->watchesToEvaluate.isEmpty()) {
+ StackHandler *stackHandler = d->engine->stackHandler();
+ const QString exp = d->watchesToEvaluate.pop();
+ if (stackHandler->isContentsValid()) {
+ d->evaluate(exp, false, false, stackHandler->currentIndex());
+ } else {
+ d->evaluate(exp);
+ }
+ d->evaluatingWatches.insert(d->sequence, exp);
+
+ }
+
+
+ // foreach (const QVariant &property, properties) {
+ // QVariantMap propertyData = property.toMap();
+ // WatchData data;
+ // data.exp = propertyData.value(_(NAME)).toByteArray();
- JsonValue refs = response.findChild("refs");
- JsonValue body = response.findChild("body");
- JsonValue details = body.childAt(0);
+ // //Check for v8 specific local data
+ // if (data.exp.startsWith(".") || data.exp.isEmpty())
+ // continue;
- int id = QString(details.name()).toInt();
- QByteArray prepend = d->locals.take(id);
+ // data.name = data.exp;
+ // data.iname = prepend + '.' + data.exp;
+ // propertyData = valueFromRef(propertyData.value(_(REF)).toInt(),
+ // refsVal).toMap();
+ // data.id = propertyData.value(_(HANDLE)).toInt();
- JsonValue properties = details.findChild("properties");
- int propertiesCount = properties.childCount();
+ // QmlV8ObjectData objectData = d->extractData(QVariant(propertyData));
+ // data.type = objectData.type;
+ // data.value = objectData.value.toString();
- for (int k = 0; k != propertiesCount; ++k) {
- JsonValue property = properties.childAt(k);
- setPropertyValue(refs,property,prepend);
+ // data.setHasChildren(objectData.properties.toList().count());
+ // d->engine->watchHandler()->insertData(data);
+ // }
}
}
-void QmlV8DebuggerClient::setExpression(const QByteArray &message)
+void QmlV8DebuggerClient::updateBreakpoints(const QVariant &bodyVal)
{
- JsonValue response(message);
- JsonValue body = response.findChild("body");
+ // { "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();
+
+ foreach (const QVariant &breakpoint, breakpoints) {
+ const QVariantMap breakpointData = breakpoint.toMap();
+
+ int index = breakpointData.value(_("number")).toInt();
+ BreakpointModelId id = d->breakpoints.key(index);
+ BreakpointResponse br = handler->response(id);
- int seq = response.findChild("request_seq").toVariant().toInt();
+ 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();
- //Console
- if (!d->watches.contains(seq)) {
- d->engine->showMessage(body.findChild("text").toVariant().toString(), ScriptConsoleOutput);
- return;
+ handler->setResponse(id, br);
+ }
}
+}
- //TODO: For watch point
+QVariant QmlV8DebuggerClient::valueFromRef(int handle, const QVariant &refsVal)
+{
+ 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;
+ }
+ }
+ return variant;
}
-void QmlV8DebuggerClient::updateBreakpoints(const QByteArray &message)
+void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const QVariant &refsVal)
{
- JsonValue response(message);
+ // { "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();
+
+ QList<WatchData> watchDataList;
+ QStringList handlesList = body.keys();
+ foreach (const QString &handle, handlesList) {
+ QmlV8ObjectData bodyObjectData = d->extractData(
+ body.value(handle));
+ QByteArray prepend = d->localsAndWatchers.take(handle.toInt());
+
+
+ if (prepend.isEmpty())
+ return;
+
+ if (bodyObjectData.properties.isValid()) {
+ //Could be an object or function
+ const WatchData *parent = d->engine->watchHandler()->findItem(prepend);
+ const QVariantList properties = bodyObjectData.properties.toList();
+ 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 && parent->type == "object") {
+ if (parent->value == _("Array"))
+ data.exp = parent->exp + QByteArray("[") + data.name.toLatin1() + QByteArray("]");
+ else if (parent->value == _("Object"))
+ data.exp = parent->exp + QByteArray(".") + data.name.toLatin1();
+ } else {
+ data.exp = data.name.toLatin1();
+ }
- JsonValue body = response.findChild("body");
+ if (prepend.startsWith("local."))
+ data.iname = prepend + '.' + data.name.toLatin1();
+ if (prepend.startsWith("watch."))
+ data.iname = prepend;
+ propertyData = valueFromRef(propertyData.value(_(REF)).toInt(),
+ refsVal).toMap();
+ data.id = propertyData.value(_(HANDLE)).toInt();
- QList<JsonValue> breakpoints = body.findChild("breakpoints").children();
- BreakHandler *handler = d->engine->breakHandler();
+ QmlV8ObjectData objectData = d->extractData(QVariant(propertyData));
+ data.type = objectData.type;
+ data.value = objectData.value.toString();
- foreach (const JsonValue &bp, breakpoints) {
+ data.setHasChildren(objectData.properties.toList().count());
+ watchDataList << data;
+ }
+ } else {
+ //rest
+ WatchData data;
+ data.exp = prepend;
+ data.name = data.exp;
+ data.iname = QByteArray("local.") + data.exp;
+ data.id = handle.toInt();
- int bpIndex = bp.findChild("number").toVariant().toInt();
- BreakpointModelId id = d->breakpoints.key(bpIndex);
- BreakpointResponse br = handler->response(id);
+ data.type = bodyObjectData.type;
+ data.value = bodyObjectData.value.toString();
- if (!br.pending)
- continue;
+ data.setHasChildren(bodyObjectData.properties.toList().count());
- br.hitCount = bp.findChild("hit_count").toVariant().toInt();
-
- 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);
+ watchDataList << data;
}
}
+
+ d->engine->watchHandler()->beginCycle(false);
+ d->engine->watchHandler()->insertBulkData(watchDataList);
+ d->engine->watchHandler()->endCycle();
+ d->localDataList << watchDataList;
}
-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();
+ EditorManager *editorManager = EditorManager::instance();
+ QList<IEditor *> openedEditors = editorManager->openedEditors();
- if (data.type == "object") {
- data.hasChildren = true;
- data.value = val.findChild("className").toVariant().toByteArray();
+ // set up the format for the errors
+ QTextCharFormat errorFormat;
+ errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ errorFormat.setUnderlineColor(Qt::red);
- } else if (data.type == "function") {
- data.hasChildren = false;
- data.value = val.findChild("text").toVariant().toByteArray();
+ foreach (IEditor *editor, openedEditors) {
+ if (editor->file()->fileName() == filePath) {
+ TextEditor::BaseTextEditorWidget *ed = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
+ if (!ed)
+ continue;
- } else {
- data.hasChildren = false;
- data.value = val.findChild("value").toVariant().toByteArray();
- }
+ QList<QTextEdit::ExtraSelection> selections;
+ QTextEdit::ExtraSelection sel;
+ sel.format = errorFormat;
+ QTextCursor c(ed->document()->findBlockByNumber(lineNumber - 1));
+ 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;
- data.id = val.findChild("handle").toVariant().toInt();
+ sel.format.setToolTip(errorMessage);
- d->engine->watchHandler()->insertData(data);
+ selections.append(sel);
+ ed->setExtraSelections(TextEditor::BaseTextEditorWidget::DebuggerExceptionSelection, selections);
- if (d->engine->watchHandler()->expandedINames().contains(data.iname)) {
- expandObject(data.iname, data.id);
+ QString message = QString(_("%1: %2: %3")).arg(filePath).arg(lineNumber)
+ .arg(errorMessage);
+ d->engine->showMessage(message, ScriptConsoleOutput);
+ }
}
}
-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::resetDebugger()
{
- d->engine = engine;
+ clearExceptionSelection();
+ d->currentFrameIndex = -1;
+ SDEBUG(QString(_("State: %1")).arg(d->debugServiceState));
+}
+
+void QmlV8DebuggerClient::updateLocalsAndWatchers()
+{
+ d->engine->watchHandler()->beginCycle();
+ d->engine->watchHandler()->insertBulkData(d->localDataList);
+ d->engine->watchHandler()->endCycle();
+
+ //Push all Watched expressions to a stack.
+ //Evaluate the expressions one at a time
+ //and append the evaluated result to the watchers
+ //window (see updateEvaluationResult())
+ foreach (const QString &expr, d->watchedExpressions)
+ d->watchesToEvaluate.push(expr);
+
+ if (!d->watchesToEvaluate.isEmpty()) {
+ StackHandler *stackHandler = d->engine->stackHandler();
+ const QString exp = d->watchesToEvaluate.pop();
+ if (stackHandler->isContentsValid()) {
+ d->evaluate(exp, false, false, stackHandler->currentIndex());
+ } else {
+ d->evaluate(exp);
+ }
+ d->evaluatingWatches.insert(d->sequence, exp);
+ }
}
} // Internal
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.h b/src/plugins/debugger/qml/qmlv8debuggerclient.h
index 806ec3b06e..a5ac30aa82 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 {
@@ -63,6 +61,13 @@ class QmlV8DebuggerClient : public QmlDebuggerClient
Next
};
+ enum V8DebugServiceStates
+ {
+ RunningState,
+ WaitingForRequestState,
+ ProcessingRequestState
+ };
+
public:
explicit QmlV8DebuggerClient(QmlJsDebugClient::QDeclarativeDebugConnection *client);
~QmlV8DebuggerClient();
@@ -84,12 +89,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 +103,31 @@ public:
void setEngine(QmlEngine *engine);
-signals:
- void notifyDebuggerStopped();
-
protected:
void messageReceived(const QByteArray &data);
+ void sendMessage(const QByteArray &msg);
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 updateScope(const QVariant &localsVal, const QVariant &refsVal);
+
+ void updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
+ const QVariant &refsVal);
+ void updateBreakpoints(const QVariant &bodyVal);
+
+ QVariant valueFromRef(int handle, const QVariant &refsVal);
+
+ void expandLocalsAndWatchers(const QVariant &bodyVal, const QVariant &refsVal);
+
+ void highlightExceptionCode(int lineNumber, const QString &filePath,
+ const QString &errorMessage);
void clearExceptionSelection();
- void continueDebugging(StepAction type);
+ void resetDebugger();
+
+ void updateLocalsAndWatchers();
private:
QmlV8DebuggerClientPrivate *d;
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclientconstants.h b/src/plugins/debugger/qml/qmlv8debuggerclientconstants.h
new file mode 100644
index 0000000000..40a39ddcde
--- /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 0cf2a165d1..584b891a0d 100644
--- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
+++ b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
@@ -249,7 +249,7 @@ void QScriptDebuggerClient::changeBreakpoint(const BreakpointModelId &id)
handler->setResponse(id, br);
}
-void QScriptDebuggerClient::updateBreakpoints()
+void QScriptDebuggerClient::synchronizeBreakpoints()
{
QByteArray reply;
QDataStream rs(&reply, QIODevice::WriteOnly);
@@ -270,13 +270,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 698e0ac2f6..fe8b539db2 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);
diff --git a/src/plugins/debugger/qml/scriptconsole.cpp b/src/plugins/debugger/qml/scriptconsole.cpp
deleted file mode 100644
index 124d3aa2ae..0000000000
--- a/src/plugins/debugger/qml/scriptconsole.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@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 qt-info@nokia.com.
-**
-**************************************************************************/
-
-#include "scriptconsole.h"
-
-#include <QtCore/QDebug>
-#include <QtGui/QVBoxLayout>
-#include <QtGui/QDockWidget>
-#include <qmljseditor/qmljshighlighter.h>
-#include <utils/styledbar.h>
-#include <utils/filterlineedit.h>
-#include <texteditor/fontsettings.h>
-#include <texteditor/texteditorconstants.h>
-#include <texteditor/texteditorsettings.h>
-
-namespace Debugger {
-namespace Internal {
-
-ScriptConsole::ScriptConsole(QWidget *parent)
- : QWidget(parent),
- m_textEdit(new QPlainTextEdit),
- m_lineEdit(0)
-{
-
-// m_prompt = QLatin1String(">");
-
- QVBoxLayout *layout = new QVBoxLayout(this);
- layout->setMargin(0);
- layout->setSpacing(0);
- layout->addWidget(m_textEdit);
- m_textEdit->setFrameStyle(QFrame::NoFrame);
-
- //updateTitle();
-
- /*m_highlighter = new QmlJSEditor::Highlighter(m_textEdit->document());
- m_highlighter->setParent(m_textEdit->document());*/
-
- Utils::StyledBar *bar = new Utils::StyledBar;
- m_lineEdit = new Utils::FilterLineEdit;
-
- m_lineEdit->setPlaceholderText(tr("<Type expression to evaluate>"));
- m_lineEdit->setToolTip(tr("Write and evaluate QtScript expressions."));
-
- /*m_clearButton = new QToolButton();
- m_clearButton->setToolTip(tr("Clear Output"));
- m_clearButton->setIcon(QIcon(Core::Constants::ICON_CLEAN_PANE));
- connect(m_clearButton, SIGNAL(clicked()), this, SLOT(clearTextEditor()));*/
- //connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(changeContextHelpId(QString)));
-
- connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression()));
- QHBoxLayout *hbox = new QHBoxLayout(bar);
- hbox->setMargin(1);
- hbox->setSpacing(1);
- hbox->addWidget(m_lineEdit);
- //hbox->addWidget(m_clearButton);
- layout->addWidget(bar);
-
- m_textEdit->setReadOnly(true);
- m_lineEdit->installEventFilter(this);
-
- setFontSettings();
-}
-
-
-void ScriptConsole::setFontSettings()
-{
- const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings();
- static QVector<QString> categories;
- if (categories.isEmpty()) {
- categories << QLatin1String(TextEditor::Constants::C_NUMBER)
- << QLatin1String(TextEditor::Constants::C_STRING)
- << QLatin1String(TextEditor::Constants::C_TYPE)
- << QLatin1String(TextEditor::Constants::C_KEYWORD)
- << QLatin1String(TextEditor::Constants::C_LABEL)
- << QLatin1String(TextEditor::Constants::C_COMMENT)
- << QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE);
- }
-
- const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
-/* m_highlighter->setFormats(formats);
- m_highlighter->rehighlight();*/
- m_textEdit->setFont(fs.font());
- m_lineEdit->setFont(fs.font());
-}
-
-
-void ScriptConsole::clear()
-{
- clearTextEditor();
-
- if (m_lineEdit)
- m_lineEdit->clear();
-// appendPrompt();
-}
-
-void ScriptConsole::clearTextEditor()
-{
- m_textEdit->clear();
- m_textEdit->appendPlainText(tr("Script Console\n"));
-}
-
-
-/*void ExpressionQueryWidget::updateTitle()
-{
- if (m_currObject.debugId() < 0) {
- m_title = tr("Expression queries");
- } else {
- QString desc = QLatin1String("<")
- + m_currObject.className() + QLatin1String(": ")
- + (m_currObject.name().isEmpty() ? QLatin1String("<unnamed>") : m_currObject.name())
- + QLatin1String(">");
- m_title = tr("Expression queries (using context for %1)" , "Selected object").arg(desc);
- }
-}*/
-/*
-void ExpressionQueryWidget::appendPrompt()
-{
- m_textEdit->moveCursor(QTextCursor::End);
-
- if (m_mode == SeparateEntryMode) {
- m_textEdit->insertPlainText("\n");
- } else {
- m_textEdit->appendPlainText(m_prompt);
- }
-}
-*/
-
-
-
-bool ScriptConsole::eventFilter(QObject* obj, QEvent* event)
-{
- if (obj == m_textEdit) {
- switch (event->type()) {
- case QEvent::KeyPress:
- {
- QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
- int key = keyEvent->key();
- if (key == Qt::Key_Return || key == Qt::Key_Enter) {
- executeExpression();
- return true;
- } else if (key == Qt::Key_Backspace) {
- // ensure m_expr doesn't contain backspace characters
- QTextCursor cursor = m_textEdit->textCursor();
- bool atLastLine = !(cursor.block().next().isValid());
- if (!atLastLine)
- return true;
- if (cursor.positionInBlock() <= m_prompt.count())
- return true;
- cursor.deletePreviousChar();
- m_expr = cursor.block().text().mid(m_prompt.count());
- return true;
- } else {
- m_textEdit->moveCursor(QTextCursor::End);
- m_expr += keyEvent->text();
- }
- break;
- }
- case QEvent::FocusIn:
- //checkCurrentContext();
- m_textEdit->moveCursor(QTextCursor::End);
- break;
- default:
- break;
- }
- } else if (obj == m_lineEdit) {
- switch (event->type()) {
- case QEvent::KeyPress:
- {
- QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
- int key = keyEvent->key();
- if (key == Qt::Key_Up && m_lineEdit->text() != m_lastExpr) {
- m_expr = m_lineEdit->text();
- if (!m_lastExpr.isEmpty())
- m_lineEdit->setText(m_lastExpr);
- } else if (key == Qt::Key_Down) {
- m_lineEdit->setText(m_expr);
- }
- break;
- }
- case QEvent::FocusIn:
- // checkCurrentContext();
- break;
- default:
- break;
- }
- }
- return QWidget::eventFilter(obj, event);
-}
-
-void ScriptConsole::executeExpression()
-{
- m_expr = m_lineEdit->text().trimmed();
- m_expr = m_expr.trimmed();
- if (!m_expr.isEmpty()) {
- emit expressionEntered(m_expr);
- m_lastExpr = m_expr;
- if (m_lineEdit)
- m_lineEdit->clear();
- }
-}
-
-void ScriptConsole::appendResult(const QString& result)
-{
- m_textEdit->moveCursor(QTextCursor::End);
- m_textEdit->insertPlainText(m_expr + " : ");
- m_textEdit->insertPlainText(result);
- m_textEdit->insertPlainText("\n");
- m_expr.clear();
-}
-
-}
-}