Enable script debugging
Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 6 files). Show all
Unified · Split
| @@ -17,12 +17,18 @@ · 16 unmodified lines | |||
| 17 | #include <QtCore/QFileInfo> | 17 | #include <QtCore/QFileInfo> |
| 18 | #include <QtCore/QTimer> | 18 | #include <QtCore/QTimer> |
| 19 | #include <QtCore/QThread> | 19 | #include <QtCore/QThread> |
| 20 | #include <QtCore/QRegularExpression> | ||
| 21 | |||
| 22 | #include <QtWidgets/QMainWindow> | ||
| 23 | #include <QtWidgets/QApplication> | ||
| 24 | |||
| 20 | #include <QtNetwork/QNetworkRequest> | 25 | #include <QtNetwork/QNetworkRequest> |
| 21 | #include <QtNetwork/QNetworkReply> | 26 | #include <QtNetwork/QNetworkReply> |
| 22 | #include <QtScript/QScriptEngine> | 27 | |
| 23 | #include <QtScript/QScriptValue> | 28 | #include <QtScript/QScriptValue> |
| 24 | #include <QtScript/QScriptValueIterator> | 29 | #include <QtScript/QScriptValueIterator> |
| 25 | #include <QtCore/QStringList> | 30 | |
| 31 | #include <QtScriptTools/QScriptEngineDebugger> | ||
| 26 | 32 | ||
| 27 | #include <AudioConstants.h> | 33 | #include <AudioConstants.h> |
| 28 | #include <AudioEffectOptions.h> | 34 | #include <AudioEffectOptions.h> |
| @@ -34,6 +40,7 @@ · 5 unmodified lines | |||
| 34 | #include <NodeList.h> | 40 | #include <NodeList.h> |
| 35 | #include <udt/PacketHeaders.h> | 41 | #include <udt/PacketHeaders.h> |
| 36 | #include <UUID.h> | 42 | #include <UUID.h> |
| 43 | #include <ui/Menu.h> | ||
| 37 | 44 | ||
| 38 | #include <controllers/ScriptingInterface.h> | 45 | #include <controllers/ScriptingInterface.h> |
| 39 | #include <AnimationObject.h> | 46 | #include <AnimationObject.h> |
| @@ -169,6 +176,93 @@ void ScriptEngine::disconnectNonEssentialSignals() { · 129 unmodified lines | |||
| 169 | } | 176 | } |
| 170 | } | 177 | } |
| 171 | 178 | ||
| 179 | void ScriptEngine::runDebuggable() { | ||
| 180 | static QMenuBar* menuBar { nullptr }; | ||
| 181 | static QMenu* scriptDebugMenu { nullptr }; | ||
| 182 | static size_t scriptMenuCount { 0 }; | ||
| 183 | if (!scriptDebugMenu) { | ||
| 184 | for (auto window : qApp->topLevelWidgets()) { | ||
| 185 | auto mainWindow = qobject_cast<QMainWindow*>(window); | ||
| 186 | if (mainWindow) { | ||
| 187 | menuBar = mainWindow->menuBar(); | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | if (menuBar) { | ||
| 192 | scriptDebugMenu = menuBar->addMenu("Script Debug"); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | init(); | ||
| 197 | _isRunning = true; | ||
| 198 | _debuggable = true; | ||
| 199 | _debugger = new QScriptEngineDebugger(this); | ||
| 200 | _debugger->attachTo(this); | ||
| 201 | |||
| 202 | QMenu* parentMenu = scriptDebugMenu; | ||
| 203 | QMenu* scriptMenu { nullptr }; | ||
| 204 | if (parentMenu) { | ||
| 205 | ++scriptMenuCount; | ||
| 206 | scriptMenu = parentMenu->addMenu(_fileNameString); | ||
| 207 | scriptMenu->addMenu(_debugger->createStandardMenu(qApp->activeWindow())); | ||
| 208 | } else { | ||
| 209 | qWarning() << "Unable to add script debug menu"; | ||
| 210 | } | ||
| 211 | |||
| 212 | QScriptValue result = evaluate(_scriptContents, _fileNameString); | ||
| 213 | |||
| 214 | _lastUpdate = usecTimestampNow(); | ||
| 215 | QTimer* timer = new QTimer(this); | ||
| 216 | connect(this, &ScriptEngine::finished, [this, timer, parentMenu, scriptMenu] { | ||
| 217 | if (scriptMenu) { | ||
| 218 | parentMenu->removeAction(scriptMenu->menuAction()); | ||
| 219 | --scriptMenuCount; | ||
| 220 | if (0 == scriptMenuCount) { | ||
| 221 | menuBar->removeAction(scriptDebugMenu->menuAction()); | ||
| 222 | scriptDebugMenu = nullptr; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | disconnect(timer); | ||
| 226 | }); | ||
| 227 | |||
| 228 | connect(timer, &QTimer::timeout, [this, timer] { | ||
| 229 | if (_isFinished) { | ||
| 230 | if (!_isRunning) { | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | stopAllTimers(); // make sure all our timers are stopped if the script is ending | ||
| 234 | if (_wantSignals) { | ||
| 235 | emit scriptEnding(); | ||
| 236 | emit finished(_fileNameString, this); | ||
| 237 | } | ||
| 238 | _isRunning = false; | ||
| 239 | if (_wantSignals) { | ||
| 240 | emit runningStateChanged(); | ||
| 241 | emit doneRunning(); | ||
| 242 | } | ||
| 243 | timer->deleteLater(); | ||
| 244 | return; | ||
| 245 | } | ||
| 246 | |||
| 247 | qint64 now = usecTimestampNow(); | ||
| 248 | // we check for 'now' in the past in case people set their clock back | ||
| 249 | if (_lastUpdate < now) { | ||
| 250 | float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND; | ||
| 251 | if (!_isFinished) { | ||
| 252 | if (_wantSignals) { | ||
| 253 | emit update(deltaTime); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | _lastUpdate = now; | ||
| 258 | // Debug and clear exceptions | ||
| 259 | hadUncaughtExceptions(*this, _fileNameString); | ||
| 260 | }); | ||
| 261 | |||
| 262 | timer->start(10); | ||
| 263 | } | ||
| 264 | |||
| 265 | |||
| 172 | void ScriptEngine::runInThread() { | 266 | void ScriptEngine::runInThread() { |
| 173 | Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once"); | 267 | Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once"); |
| 174 | 268 | ||
| @@ -260,6 +354,10 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { · 85 unmodified lines | |||
| 260 | // FIXME - switch this to the new model of ScriptCache callbacks | 354 | // FIXME - switch this to the new model of ScriptCache callbacks |
| 261 | void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) { | 355 | void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) { |
| 262 | _scriptContents = scriptContents; | 356 | _scriptContents = scriptContents; |
| 357 | static const QString DEBUG_FLAG("#debug"); | ||
| 358 | if (QRegularExpression(DEBUG_FLAG).match(scriptContents).hasMatch()) { | ||
| 359 | _debuggable = true; | ||
| 360 | } | ||
| 263 | if (_wantSignals) { | 361 | if (_wantSignals) { |
| 264 | emit scriptLoaded(url.toString()); | 362 | emit scriptLoaded(url.toString()); |
| 265 | } | 363 | } |
| @@ -723,7 +821,7 @@ void ScriptEngine::run() { · 457 unmodified lines | |||
| 723 | auto nodeList = DependencyManager::get<NodeList>(); | 821 | auto nodeList = DependencyManager::get<NodeList>(); |
| 724 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 822 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 725 | 823 | ||
| 726 | qint64 lastUpdate = usecTimestampNow(); | 824 | _lastUpdate = usecTimestampNow(); |
| 727 | 825 | ||
| 728 | // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine | 826 | // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine |
| 729 | while (!_isFinished) { | 827 | while (!_isFinished) { |
| @@ -771,15 +869,15 @@ void ScriptEngine::run() { · 41 unmodified lines | |||
| 771 | qint64 now = usecTimestampNow(); | 869 | qint64 now = usecTimestampNow(); |
| 772 | 870 | ||
| 773 | // we check for 'now' in the past in case people set their clock back | 871 | // we check for 'now' in the past in case people set their clock back |
| 774 | if (lastUpdate < now) { | 872 | if (_lastUpdate < now) { |
| 775 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; | 873 | float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND; |
| 776 | if (!_isFinished) { | 874 | if (!_isFinished) { |
| 777 | if (_wantSignals) { | 875 | if (_wantSignals) { |
| 778 | emit update(deltaTime); | 876 | emit update(deltaTime); |
| 779 | } | 877 | } |
| 780 | } | 878 | } |
| 781 | } | 879 | } |
| 782 | lastUpdate = now; | 880 | _lastUpdate = now; |
| 783 | 881 | ||
| 784 | // Debug and clear exceptions | 882 | // Debug and clear exceptions |
| 785 | hadUncaughtExceptions(*this, _fileNameString); | 883 | hadUncaughtExceptions(*this, _fileNameString); |