Bug 1605331 - Watch expressions should be evaluated in the right context. r=nchevobbe
☠☠ backed out by 222228bd896a ☠ ☠
authorJason Laster <jlaster@mozilla.com>
Fri, 03 Apr 2020 22:23:11 +0000
changeset 522098 185a33dcfa94b9c37b3514846487bc7b7554f306
parent 522097 4ee309f18e609d6321ff7b5ae23101f72e113181
child 522099 98a9c8ceeaa0ea7c3eff6b75cd98fbbb3e98e0f6
push id112011
push userjlaster@mozilla.com
push dateFri, 03 Apr 2020 23:16:21 +0000
treeherderautoland@185a33dcfa94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1605331
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1605331 - Watch expressions should be evaluated in the right context. r=nchevobbe Differential Revision: https://phabricator.services.mozilla.com/D67701
devtools/client/debugger/panel.js
devtools/client/framework/toolbox.js
devtools/client/shared/redux/moz.build
devtools/client/shared/redux/subscriber.js
--- a/devtools/client/debugger/panel.js
+++ b/devtools/client/debugger/panel.js
@@ -1,38 +1,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
+
 loader.lazyRequireGetter(
   this,
   "openContentLink",
   "devtools/client/shared/link",
   true
 );
 loader.lazyRequireGetter(
   this,
   "features",
   "devtools/client/debugger/src/utils/prefs",
   true
 );
+loader.lazyRequireGetter(
+  this,
+  "registerStoreObserver",
+  "devtools/client/shared/redux/subscriber",
+  true
+);
 
 const DBG_STRINGS_URI = "devtools/client/locales/debugger.properties";
 const L10N = new LocalizationHelper(DBG_STRINGS_URI);
 
-function registerStoreObserver(store, subscriber) {
-  let oldState = store.getState();
-  store.subscribe(() => {
-    const state = store.getState();
-    subscriber(state, oldState);
-    oldState = state;
-  });
-}
-
 async function getNodeFront(gripOrFront, toolbox) {
   // Given a NodeFront
   if ("actorID" in gripOrFront) {
     return new Promise(resolve => resolve(gripOrFront));
   }
 
   const inspectorFront = await toolbox.target.getFront("inspector");
   return inspectorFront.getNodeFrontFromNodeGrip(gripOrFront);
@@ -87,17 +85,17 @@ class DebuggerPanel {
     const currentThreadActorID = getCurrentThread(state);
     if (
       currentThreadActorID &&
       currentThreadActorID !== getCurrentThread(oldState)
     ) {
       const threadFront = this.toolbox.target.client.getFrontByID(
         currentThreadActorID
       );
-      this.toolbox.selectTarget(threadFront?.targetFront?.actorID);
+      this.toolbox.selectTarget(threadFront?.targetFront.actorID);
     }
   }
 
   getVarsForTests() {
     return {
       store: this._store,
       selectors: this._selectors,
       actions: this._actions,
@@ -198,42 +196,46 @@ class DebuggerPanel {
   }
 
   selectSourceURL(url, line, column) {
     const cx = this._selectors.getContext(this._getState());
     return this._actions.selectSourceURL(cx, url, { line, column });
   }
 
   async selectWorker(workerTargetFront) {
-    const threadId = workerTargetFront.threadFront.actorID;
+    const threadActorID = workerTargetFront.threadFront.actorID;
     const isThreadAvailable = this._selectors
       .getThreads(this._getState())
-      .find(x => x.actor === threadId);
+      .find(x => x.actor === threadActorID);
 
     if (!features.windowlessServiceWorkers) {
       console.error(
         "Selecting a worker needs the pref debugger.features.windowless-service-workers set to true"
       );
       return;
     }
 
     if (!isThreadAvailable) {
-      console.error(`Worker ${threadId} is not available for debugging`);
+      console.error(`Worker ${threadActorID} is not available for debugging`);
       return;
     }
 
     // select worker's thread
-    const cx = this._selectors.getContext(this._getState());
-    this._actions.selectThread(cx, threadId);
+    this.selectThread(threadActorID);
 
     // select worker's source
     const source = this.getSourceByURL(workerTargetFront._url);
     await this.selectSource(source.id, 1, 1);
   }
 
+  selectThread(actorID) {
+    const cx = this._selectors.getContext(this._getState());
+    this._actions.selectThread(cx, actorID);
+  }
+
   previewPausedLocation(location) {
     return this._actions.previewPausedLocation(location);
   }
 
   clearPreviewPausedLocation() {
     return this._actions.clearPreviewPausedLocation();
   }
 
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -44,16 +44,22 @@ const { BrowserLoader } = ChromeUtils.im
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper(
   "devtools/client/locales/toolbox.properties"
 );
 
 loader.lazyRequireGetter(
   this,
+  "registerStoreObserver",
+  "devtools/client/shared/redux/subscriber",
+  true
+);
+loader.lazyRequireGetter(
+  this,
   "createToolboxStore",
   "devtools/client/framework/store",
   true
 );
 loader.lazyRequireGetter(
   this,
   "registerWalkerListeners",
   "devtools/client/framework/actions/index",
@@ -397,16 +403,17 @@ Toolbox.prototype = {
     }
 
     return this._nodePicker;
   },
 
   get store() {
     if (!this._store) {
       this._store = createToolboxStore();
+      registerStoreObserver(this._store, this._onToolboxStateChange.bind(this));
     }
     return this._store;
   },
 
   get currentToolId() {
     return this._currentToolId;
   },
 
@@ -612,30 +619,42 @@ Toolbox.prototype = {
   },
 
   /**
    * Set a given target as selected (which may impact the console evaluation context selector).
    *
    * @param {String} targetActorID: The actorID of the target we want to select.
    */
   selectTarget(targetActorID) {
-    this.store.dispatch(selectTarget(targetActorID));
+    if (this.getSelectedTargetFront()?.actorID !== targetActorID) {
+      this.store.dispatch(selectTarget(targetActorID));
+    }
   },
 
   /**
    * @returns {ThreadFront|null} The selected thread front, or null if there is none.
    */
   getSelectedTargetFront: function() {
     const selectedTarget = getSelectedTarget(this.store.getState());
     if (!selectedTarget) {
       return null;
     }
+
     return this.target.client.getFrontByID(selectedTarget.actorID);
   },
 
+  _onToolboxStateChange(state, oldState) {
+    if (getSelectedTarget(state) !== getSelectedTarget(oldState)) {
+      const dbg = this.getPanel("jsdebugger");
+      dbg?.selectThread(
+        getSelectedTarget(state)?._targetFront.threadFront.actorID
+      );
+    }
+  },
+
   _onPausedState: function(packet, threadFront) {
     // Suppress interrupted events by default because the thread is
     // paused/resumed a lot for various actions.
     if (packet.why.type === "interrupted") {
       return;
     }
 
     this.highlightTool("jsdebugger");
--- a/devtools/client/shared/redux/moz.build
+++ b/devtools/client/shared/redux/moz.build
@@ -6,10 +6,11 @@
 
 DIRS += [
     'middleware',
 ]
 
 DevToolsModules(
     'create-store.js',
     'non-react-subscriber.js',
+    'subscriber.js',
     'visibility-handler-connect.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/redux/subscriber.js
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+"use strict";
+
+function registerStoreObserver(store, subscriber) {
+  let oldState = store.getState();
+  store.subscribe(() => {
+    const state = store.getState();
+    subscriber(state, oldState);
+    oldState = state;
+  });
+}
+
+exports.registerStoreObserver = registerStoreObserver;