Bug 1495547 - Update Debugger Frontend v91. r=dwalsh
authorJason Laster <jlaster@mozilla.com>
Mon, 01 Oct 2018 16:46:00 -0400
changeset 494988 6b9dea7e0a320af8c1aca99e46f61a660938599d
parent 494987 432a98e50d2bfab224328254266069aef1a474cc
child 494989 1192c15fc9347ccd6169dcb5bea81d7f2399e3fd
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdwalsh
bugs1495547
milestone64.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 1495547 - Update Debugger Frontend v91. r=dwalsh
devtools/client/debugger/new/README.mozilla
devtools/client/debugger/new/dist/debugger.css
devtools/client/debugger/new/dist/parser-worker.js
devtools/client/debugger/new/dist/vendors.js
devtools/client/debugger/new/src/actions/sources/prettyPrint.js
devtools/client/debugger/new/src/client/index.js
devtools/client/debugger/new/src/components/Editor/Footer.js
devtools/client/debugger/new/src/components/Editor/SearchBar.js
devtools/client/debugger/new/src/components/Editor/index.js
devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
devtools/client/debugger/new/src/reducers/tabs.js
devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
devtools/client/debugger/new/src/utils/editor/source-documents.js
devtools/client/debugger/new/src/utils/memoize.js
devtools/client/debugger/new/src/utils/moz.build
devtools/client/debugger/new/src/utils/prefs.js
devtools/client/debugger/new/src/utils/quick-open.js
devtools/client/debugger/new/src/utils/sources-tree/getDirectories.js
devtools/client/debugger/new/test/mochitest/browser_dbg-asm.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
devtools/client/shared/components/reps/reps.js
devtools/client/themes/images/debugger/disable-pausing.svg
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 90
+Version 91
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-89...release-90
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-90...release-91
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.4.1
 - react-dom @16.4.1
 - webpack @3.12.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -1798,17 +1798,17 @@ html .toggle-button.end.vertical svg {
 .source-outline-tabs {
   width: 100%;
   background: var(--theme-body-background);
   border-top: 1px solid var(--theme-splitter-color);
   display: flex;
   -moz-user-select: none;
   user-select: none;
   box-sizing: border-box;
-  height: 30px;
+  height: 29px;
   margin: 0;
   padding: 0;
 }
 
 .source-outline-tabs .tab {
   background-color: var(--theme-toolbar-background);
   border-bottom: 1px solid transparent;
   border-color: var(--theme-splitter-color);
@@ -2226,16 +2226,22 @@ menuseparator {
 :root.theme-dark .source-footer > .commands > .action {
   fill: var(--theme-body-color);
 }
 
 :root.theme-dark .source-footer > .commands > .action:hover {
   fill: var(--theme-selection-color);
 }
 
+.source-footer > .commands > div.loader {
+  vertical-align: top;
+  width: 20px;
+  margin: 0 4px;
+}
+
 .source-footer > .commands > .action > img.prettyPrint {
   mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat;
   height: 16px;
   width: 16px;
   background: var(--theme-body-color);
 }
 
 .source-footer > .commands > .action > img.blackBox {
@@ -2271,41 +2277,59 @@ menuseparator {
   text-overflow: ellipsis;
 }
 /* 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/>. */
 
 .search-bar {
   display: flex;
-  flex-direction: column;
+  border: 1px solid transparent;
+  border-top: 1px solid var(--theme-splitter-color);
+  height: var(--editor-searchbar-height);
+}
+
+.search-bar.search-bar-focused {
+  border: 1px solid var(--blue-50);
+  transition: border-color 0.2s ease-in-out;
 }
 
 .search-bar .search-field {
   padding-left: 7px;
-  height: var(--editor-searchbar-height);
+}
+
+.search-bar .search-shadow {
+  flex-grow: 1;
+}
+
+.search-bar .search-shadow.focused {
+  border-color: transparent;
+  transition: none;
+}
+
+.search-bar .search-field {
+  border-bottom: none;
+  padding-right: 0;
+  height: 100%;
 }
 
 .search-field .close-btn {
   align-self: center;
 }
 
 .search-bottom-bar * {
   -moz-user-select: none;
   user-select: none;
 }
 
 .search-bottom-bar {
   display: flex;
   flex-shrink: 0;
   justify-content: flex-end;
-  width: calc(100% - 1px);
-  height: var(--editor-second-searchbar-height);
   background-color: var(--theme-toolbar-background);
-  border-bottom: 1px solid var(--theme-splitter-color);
   padding: 0 13px;
 }
 
 .search-bottom-bar .search-modifiers {
   display: flex;
   align-items: center;
 }
 
@@ -2676,17 +2700,16 @@ menuseparator {
 /* 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/>. */
 
 .editor-wrapper {
   --debug-line-border: rgb(145, 188, 219);
   --debug-expression-background: rgba(202, 227, 255, 0.5);
   --editor-searchbar-height: 27px;
-  --editor-second-searchbar-height: 27px;
   --debug-line-error-border: rgb(255, 0, 0);
   --debug-expression-error-background: rgba(231, 116, 113, 0.3);
   --editor-header-height: 30px;
 }
 
 .theme-dark .editor-wrapper {
   --debug-expression-background: rgba(202, 227, 255, 0.3);
   --debug-line-border: #7786a2;
@@ -3681,17 +3704,17 @@ html[dir="rtl"] .breakpoints-list .break
 .accordion .arrow svg {
   fill: var(--disclosure-arrow);
 }
 /* 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/>. */
 
 .command-bar {
-  flex: 0 0 30px;
+  flex: 0 0 29px;
   border-bottom: 1px solid var(--theme-splitter-color);
   display: flex;
   overflow: hidden;
   z-index: 1;
   background-color: var(--theme-toolbar-background);
 }
 
 html[dir="rtl"] .command-bar {
@@ -4036,17 +4059,17 @@ html .welcomebox .toggle-button-end.coll
 }
 /* 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/>. */
 
 .source-header {
   border-bottom: 1px solid var(--theme-splitter-color);
   width: 100%;
-  height: 30px;
+  height: 29px;
   display: flex;
 }
 
 .source-header * {
   -moz-user-select: none;
   user-select: none;
 }
 
@@ -4160,16 +4183,17 @@ html[dir="rtl"] img.moreTabs {
 }
 
 .source-tab .filename {
   white-space: nowrap;
   text-overflow: ellipsis;
   overflow: hidden;
   padding: 0 4px;
   align-self: center;
+  margin-bottom: 2px;
 }
 
 .source-tab .filename span {
   opacity: 0.7;
   padding-left: 4px;
 }
 
 .source-tab .close-btn {
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -2590,26 +2590,18 @@ function requiresReact(callExpressions) 
 
 function extendsReactComponent(classes) {
   return classes.some(classObj => t.isIdentifier(classObj.parent, { name: "Component" }) || t.isIdentifier(classObj.parent, { name: "PureComponent" }) || t.isMemberExpression(classObj.parent, { computed: false }) && t.isIdentifier(classObj.parent, { name: "Component" }));
 }
 
 // Angular
 
 const isAngularComponent = sourceSymbols => {
-  const { memberExpressions, identifiers } = sourceSymbols;
-  return identifiesAngular(identifiers) && hasAngularExpressions(memberExpressions);
-};
-
-const identifiesAngular = identifiers => {
-  return identifiers.some(item => item.name == "angular");
-};
-
-const hasAngularExpressions = memberExpressions => {
-  return memberExpressions.some(item => item.name == "controller" || item.name == "module");
+  const { memberExpressions } = sourceSymbols;
+  return memberExpressions.some(item => item.expression == "angular.controller" || item.expression == "angular.module");
 };
 
 // Vue
 
 const isVueComponent = sourceSymbols => {
   const { identifiers } = sourceSymbols;
   return identifiers.some(identifier => identifier.name == "Vue");
 };
--- a/devtools/client/debugger/new/dist/vendors.js
+++ b/devtools/client/debugger/new/dist/vendors.js
@@ -2954,17 +2954,18 @@ const svg = {
   pug: __webpack_require__(1004),
   extjs: __webpack_require__(1043),
   mobx: __webpack_require__(1733),
   marko: __webpack_require__(1649),
   nextjs: __webpack_require__(1650),
   showSources: __webpack_require__(1044),
   showOutline: __webpack_require__(1045),
   nuxtjs: __webpack_require__(1651),
-  rxjs: __webpack_require__(1808)
+  rxjs: __webpack_require__(1808),
+  loader: __webpack_require__(3789)
 };
 
 function Svg({ name, className, onClick, "aria-label": ariaLabel }) {
   if (!svg[name]) {
     const error = `Unknown SVG: ${name}`;
     console.warn(error);
     return null;
   }
@@ -8075,16 +8076,23 @@ function formatKeyShortcut(shortcut) {
   if (isMacOS) {
     return shortcut.replace(/Shift\+/g, "\u21E7").replace(/Command\+|Cmd\+/g, "\u2318").replace(/CommandOrControl\+|CmdOrCtrl\+/g, "\u2318").replace(/Alt\+/g, "\u2325");
   }
   return shortcut.replace(/CommandOrControl\+|CmdOrCtrl\+/g, "Ctrl").replace(/Shift\+/g, "Shift");
 }
 
 /***/ }),
 
+/***/ 3789:
+/***/ (function(module, exports) {
+
+module.exports = "<!-- 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/. --><svg version=\"1.1\" id=\"loader-1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 40 40\" enable-background=\"new 0 0 40 40\" xml:space=\"preserve\"><path opacity=\"0.2\" fill=\"#000\" d=\"M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z\"></path><path fill=\"#000\" d=\"M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 C22.32,8.481,24.301,9.057,26.013,10.047z\"><animateTransform attributeType=\"xml\" attributeName=\"transform\" type=\"rotate\" from=\"0 20 20\" to=\"360 20 20\" dur=\"0.5s\" repeatCount=\"indefinite\"></animateTransform></path></svg>"
+
+/***/ }),
+
 /***/ 4:
 /***/ (function(module, exports) {
 
 module.exports = __WEBPACK_EXTERNAL_MODULE_4__;
 
 /***/ }),
 
 /***/ 52:
--- a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
+++ b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
@@ -25,16 +25,18 @@ var _source = require("../../utils/sourc
 var _loadSourceText = require("./loadSourceText");
 
 var _pause = require("../pause/index");
 
 var _sources = require("../sources/index");
 
 var _selectors = require("../../selectors/index");
 
+var _select = require("./select");
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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/>. */
 function createPrettySource(sourceId) {
   return async ({
     dispatch,
@@ -53,16 +55,17 @@ function createPrettySource(sourceId) {
       isWasm: false,
       contentType: "text/javascript",
       loadedState: "loading"
     };
     dispatch({
       type: "ADD_SOURCE",
       source: prettySource
     });
+    dispatch((0, _select.selectSource)(prettySource.id));
     const {
       code,
       mappings
     } = await (0, _prettyPrint.prettyPrint)({
       source,
       url
     });
     await sourceMaps.applySourceMap(source.id, url, code, mappings);
--- a/devtools/client/debugger/new/src/client/index.js
+++ b/devtools/client/debugger/new/src/client/index.js
@@ -28,18 +28,20 @@ function loadFromPrefs(actions) {
 
   if (pauseOnExceptions || pauseOnCaughtExceptions) {
     return actions.pauseOnExceptions(pauseOnExceptions, pauseOnCaughtExceptions);
   }
 }
 
 async function loadInitialState() {
   const pendingBreakpoints = await _prefs.asyncStore.pendingBreakpoints;
+  const tabs = await _prefs.asyncStore.tabs;
   return {
-    pendingBreakpoints
+    pendingBreakpoints,
+    tabs
   };
 }
 
 async function onConnect(connection, {
   services,
   toolboxActions
 }) {
   // NOTE: the landing page does not connect to a JS process
--- a/devtools/client/debugger/new/src/components/Editor/Footer.js
+++ b/devtools/client/debugger/new/src/components/Editor/Footer.js
@@ -11,16 +11,20 @@ var _react2 = _interopRequireDefault(_re
 var _reactRedux = require("devtools/client/shared/vendor/react-redux");
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _classnames = require("devtools/client/debugger/new/dist/vendors").vendored["classnames"];
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
+var _Svg = require("devtools/client/debugger/new/dist/vendors").vendored["Svg"];
+
+var _Svg2 = _interopRequireDefault(_Svg);
+
 var _actions = require("../../actions/index");
 
 var _actions2 = _interopRequireDefault(_actions);
 
 var _selectors = require("../../selectors/index");
 
 var _prefs = require("../../utils/prefs");
 
@@ -38,23 +42,31 @@ function _interopRequireDefault(obj) { r
  * 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/>. */
 class SourceFooter extends _react.PureComponent {
   prettyPrintButton() {
     const {
       selectedSource,
       togglePrettyPrint
     } = this.props;
-    const sourceLoaded = selectedSource && (0, _source.isLoaded)(selectedSource);
+
+    if ((0, _source.isLoading)(selectedSource) && selectedSource.isPrettyPrinted) {
+      return _react2.default.createElement("div", {
+        className: "loader"
+      }, _react2.default.createElement(_Svg2.default, {
+        name: "loader"
+      }));
+    }
 
     if (!(0, _editor.shouldShowPrettyPrint)(selectedSource)) {
       return;
     }
 
     const tooltip = L10N.getStr("sourceTabs.prettyPrint");
+    const sourceLoaded = selectedSource && (0, _source.isLoaded)(selectedSource);
     const type = "prettyPrint";
     return _react2.default.createElement("button", {
       onClick: () => togglePrettyPrint(selectedSource.id),
       className: (0, _classnames2.default)("action", type, {
         active: sourceLoaded,
         pretty: (0, _source.isPretty)(selectedSource)
       }),
       key: type,
--- a/devtools/client/debugger/new/src/components/Editor/SearchBar.js
+++ b/devtools/client/debugger/new/src/components/Editor/SearchBar.js
@@ -164,16 +164,22 @@ class SearchBar extends _react.Component
 
     this.onChange = e => {
       this.setState({
         query: e.target.value
       });
       return this.doSearch(e.target.value);
     };
 
+    this.onFocus = e => {
+      this.setState({
+        inputFocused: true
+      });
+    };
+
     this.onBlur = e => {
       this.setState({
         inputFocused: false
       });
     };
 
     this.onKeyDown = e => {
       if (e.key !== "Enter" && e.key !== "F3") {
@@ -332,24 +338,28 @@ class SearchBar extends _react.Component
       },
       searchOn
     } = this.props;
 
     if (!searchOn) {
       return _react2.default.createElement("div", null);
     }
 
+    const classes = (0, _classnames2.default)("search-bar", {
+      "search-bar-focused": this.state.inputFocused
+    });
     return _react2.default.createElement("div", {
-      className: "search-bar"
+      className: classes
     }, _react2.default.createElement(_SearchInput2.default, {
       query: this.state.query,
       count: count,
       placeholder: L10N.getStr("sourceSearch.search.placeholder2"),
       summaryMsg: this.buildSummaryMsg(),
       onChange: this.onChange,
+      onFocus: this.onFocus,
       onBlur: this.onBlur,
       showErrorEmoji: this.shouldShowErrorEmoji(),
       onKeyDown: this.onKeyDown,
       onHistoryScroll: this.onHistoryScroll,
       handleNext: e => this.traverseResults(e, false),
       handlePrev: e => this.traverseResults(e, true),
       handleClose: this.closeSearch,
       shouldFocus: this.state.inputFocused
--- a/devtools/client/debugger/new/src/components/Editor/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/index.js
@@ -95,17 +95,16 @@ var _ui = require("../../utils/ui");
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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/>. */
 // Redux actions
 const cssVars = {
   searchbarHeight: "var(--editor-searchbar-height)",
-  secondSearchbarHeight: "var(--editor-second-searchbar-height)",
   footerHeight: "var(--editor-footer-height)"
 };
 
 class Editor extends _react.PureComponent {
   constructor(props) {
     super(props);
 
     this.onToggleBreakpoint = (key, e) => {
@@ -535,17 +534,16 @@ class Editor extends _react.PureComponen
     const subtractions = [];
 
     if ((0, _editor.shouldShowFooter)(selectedSource, horizontal)) {
       subtractions.push(cssVars.footerHeight);
     }
 
     if (searchOn) {
       subtractions.push(cssVars.searchbarHeight);
-      subtractions.push(cssVars.secondSearchbarHeight);
     }
 
     return {
       height: subtractions.length === 0 ? "100%" : `calc(100% - ${subtractions.join(" - ")})`
     };
   }
 
   renderHitCounts() {
@@ -583,17 +581,16 @@ class Editor extends _react.PureComponen
     }), _react2.default.createElement(_HighlightLine2.default, null), _react2.default.createElement(_EmptyLines2.default, {
       editor: editor
     }), _react2.default.createElement(_Breakpoints2.default, {
       editor: editor
     }), _react2.default.createElement(_Preview2.default, {
       editor: editor,
       editorRef: this.$editorWrapper
     }), ";", _react2.default.createElement(_Footer2.default, {
-      editor: editor,
       horizontal: horizontal
     }), _react2.default.createElement(_HighlightLines2.default, {
       editor: editor
     }), _react2.default.createElement(_EditorMenu2.default, {
       editor: editor
     }), _react2.default.createElement(_GutterMenu2.default, {
       editor: editor
     }), _react2.default.createElement(_ConditionalPanel2.default, {
@@ -621,20 +618,20 @@ class Editor extends _react.PureComponen
     const {
       coverageOn
     } = this.props;
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)("editor-wrapper", {
         "coverage-on": coverageOn
       }),
       ref: c => this.$editorWrapper = c
-    }, this.renderSearchBar(), _react2.default.createElement("div", {
+    }, _react2.default.createElement("div", {
       className: "editor-mount devtools-monospace",
       style: this.getInlineEditorStyles()
-    }), this.renderItems());
+    }), this.renderSearchBar(), this.renderItems());
   }
 
 }
 
 Editor.contextTypes = {
   shortcuts: _propTypes2.default.object
 };
 
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
@@ -61,16 +61,26 @@ class SourcesTree extends _react.Compone
     } = this.props;
     this.state = (0, _sourcesTree.createTree)({
       projectRoot,
       debuggeeUrl,
       sources
     });
   }
 
+  componentDidMount() {
+    const {
+      selectedSource
+    } = this.props;
+
+    if (selectedSource) {
+      this.setHighlightFocusItems(selectedSource);
+    }
+  }
+
   componentWillReceiveProps(nextProps) {
     const {
       projectRoot,
       debuggeeUrl,
       sources,
       shownSource,
       selectedSource
     } = this.props;
@@ -85,43 +95,52 @@ class SourcesTree extends _react.Compone
       return this.setState((0, _sourcesTree.createTree)({
         sources: nextProps.sources,
         debuggeeUrl: nextProps.debuggeeUrl,
         projectRoot: nextProps.projectRoot
       }));
     }
 
     if (nextProps.shownSource && nextProps.shownSource != shownSource) {
-      const listItems = (0, _sourcesTree.getDirectories)(nextProps.shownSource, sourceTree);
-      return this.setState({
-        listItems
-      });
+      return this.setHighlightFocusItems(nextProps.shownSource);
     }
 
     if (nextProps.selectedSource && nextProps.selectedSource != selectedSource) {
-      const highlightItems = (0, _sourcesTree.getDirectories)(nextProps.selectedSource, sourceTree);
-      this.setState({
-        highlightItems
-      });
+      this.setHighlightFocusItems(nextProps.selectedSource);
     } // NOTE: do not run this every time a source is clicked,
     // only when a new source is added
 
 
     if (nextProps.sources != this.props.sources) {
       this.setState((0, _sourcesTree.updateTree)({
         newSources: nextProps.sources,
         prevSources: sources,
         debuggeeUrl,
         projectRoot,
         uncollapsedTree,
         sourceTree
       }));
     }
   }
 
+  setHighlightFocusItems(source) {
+    const {
+      sourceTree,
+      parentMap
+    } = this.state;
+
+    if (source) {
+      const items = (0, _sourcesTree.getDirectories)(source, parentMap, sourceTree);
+      return this.setState({
+        listItems: items,
+        highlightItems: items
+      });
+    }
+  }
+
   // NOTE: we get the source from sources because item.contents is cached
   getSource(item) {
     const source = (0, _sourcesTree.getSourceFromNode)(item);
 
     if (source) {
       return this.props.sources[source.id];
     }
 
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.js
@@ -27,57 +27,51 @@ var _text = require("../../utils/text");
 var _actions = require("../../actions/index");
 
 var _actions2 = _interopRequireDefault(_actions);
 
 var _CommandBarButton = require("../shared/Button/CommandBarButton");
 
 var _devtoolsServices = require("Services");
 
-var _devtoolsServices2 = _interopRequireDefault(_devtoolsServices);
-
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 
 /* 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 {
-  appinfo
-} = _devtoolsServices2.default;
-const isMacOS = appinfo.OS === "Darwin";
+const isMacOS = _devtoolsServices.appinfo.OS === "Darwin"; // NOTE: the "resume" command will call either the resume or breakOnNext action
+// depending on whether or not the debugger is paused or running
+
 const COMMANDS = ["resume", "stepOver", "stepIn", "stepOut"];
 const KEYS = {
   WINNT: {
     resume: "F8",
-    pause: "F8",
     stepOver: "F10",
     stepIn: "F11",
     stepOut: "Shift+F11"
   },
   Darwin: {
     resume: "Cmd+\\",
-    pause: "Cmd+\\",
     stepOver: "Cmd+'",
     stepIn: "Cmd+;",
     stepOut: "Cmd+Shift+:",
     stepOutDisplay: "Cmd+Shift+;"
   },
   Linux: {
     resume: "F8",
-    pause: "F8",
     stepOver: "F10",
     stepIn: "Ctrl+F11",
     stepOut: "Ctrl+Shift+F11"
   }
 };
 
 function getKey(action) {
-  return getKeyForOS(appinfo.OS, action);
+  return getKeyForOS(_devtoolsServices.appinfo.OS, action);
 }
 
 function getKeyForOS(os, action) {
   const osActions = KEYS[os] || KEYS.Linux;
   return osActions[action];
 }
 
 function formatKey(action) {
@@ -111,17 +105,22 @@ class CommandBar extends _react.Componen
       // as well as the Mac non-Function keys
       COMMANDS.forEach(action => shortcuts.on(getKeyForOS("WINNT", action), (_, e) => this.handleEvent(e, action)));
     }
   }
 
   handleEvent(e, action) {
     e.preventDefault();
     e.stopPropagation();
-    this.props[action]();
+
+    if (action === "resume") {
+      this.props.isPaused ? this.props.resume() : this.props.breakOnNext();
+    } else {
+      this.props[action]();
+    }
   }
 
   renderStepButtons() {
     const {
       isPaused,
       canRewind
     } = this.props;
     const className = isPaused ? "active" : "disabled";
@@ -157,17 +156,17 @@ class CommandBar extends _react.Componen
     if (_prefs.features.removeCommandBarOptions && !this.props.canRewind) {
       return;
     }
 
     if (isWaitingOnBreak) {
       return (0, _CommandBarButton.debugBtn)(null, "pause", "disabled", L10N.getStr("pausePendingButtonTooltip"), true);
     }
 
-    return (0, _CommandBarButton.debugBtn)(breakOnNext, "pause", "active", L10N.getFormatStr("pauseButtonTooltip", formatKey("pause")));
+    return (0, _CommandBarButton.debugBtn)(breakOnNext, "pause", "active", L10N.getFormatStr("pauseButtonTooltip", formatKey("resume")));
   }
 
   renderTimeTravelButtons() {
     const {
       isPaused,
       canRewind
     } = this.props;
 
--- a/devtools/client/debugger/new/src/reducers/tabs.js
+++ b/devtools/client/debugger/new/src/reducers/tabs.js
@@ -23,28 +23,32 @@ function _interopRequireDefault(obj) { r
 /* 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/>. */
 
 /**
  * Tabs reducer
  * @module reducers/tabs
  */
-function update(state = _prefs.prefs.tabs || [], action) {
+function isSimilarTab(tab, url, isOriginal) {
+  return tab.url === url && tab.isOriginal === isOriginal;
+}
+
+function update(state = [], action) {
   switch (action.type) {
     case "ADD_TAB":
     case "UPDATE_TAB":
       return updateTabList(state, action);
 
     case "MOVE_TAB":
       return moveTabInList(state, action);
 
     case "CLOSE_TAB":
     case "CLOSE_TABS":
-      _prefs.prefs.tabs = action.tabs;
+      _prefs.asyncStore.tabs = action.tabs;
       return action.tabs;
 
     default:
       return state;
   }
 }
 
 function removeSourceFromTabList(tabs, url) {
@@ -71,27 +75,27 @@ function updateTabList(tabs, {
     tabs = [{
       url,
       framework
     }, ...tabs];
   } else if (framework) {
     tabs[currentIndex].framework = framework;
   }
 
-  _prefs.prefs.tabs = tabs;
+  _prefs.asyncStore.tabs = tabs;
   return tabs;
 }
 
 function moveTabInList(tabs, {
   url,
   tabIndex: newIndex
 }) {
   const currentIndex = tabs.findIndex(tab => tab.url == url);
   tabs = (0, _lodashMove2.default)(tabs, currentIndex, newIndex);
-  _prefs.prefs.tabs = tabs;
+  _prefs.asyncStore.tabs = tabs;
   return tabs;
 }
 /**
  * Gets the next tab to select when a tab closes. Heuristics:
  * 1. if the selected tab is available, it remains selected
  * 2. if it is gone, the next available tab to the left should be active
  * 3. if the first tab is active and closed, select the second tab
  *
--- a/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
+++ b/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
@@ -8,37 +8,30 @@ exports.getVisibleBreakpoints = undefine
 var _breakpoints = require("../reducers/breakpoints");
 
 var _sources = require("../reducers/sources");
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
 
+var _memoize = require("../utils/memoize");
+
+var _memoize2 = _interopRequireDefault(_memoize);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 /* 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/>. */
 function getLocation(breakpoint, isGeneratedSource) {
   return isGeneratedSource ? breakpoint.generatedLocation || breakpoint.location : breakpoint.location;
 }
 
-function memoize(func) {
-  const store = new WeakMap();
-  return function (key, ...rest) {
-    if (store.has(key)) {
-      return store.get(key);
-    }
-
-    const value = func.apply(null, arguments);
-    store.set(key, value);
-    return value;
-  };
-}
-
-const formatBreakpoint = memoize(function (breakpoint, selectedSource) {
+const formatBreakpoint = (0, _memoize2.default)(function (breakpoint, selectedSource) {
   const {
     condition,
     loading,
     disabled,
     hidden
   } = breakpoint;
   const sourceId = selectedSource.id;
   const isGeneratedSource = (0, _devtoolsSourceMap.isGeneratedId)(sourceId);
--- a/devtools/client/debugger/new/src/utils/editor/source-documents.js
+++ b/devtools/client/debugger/new/src/utils/editor/source-documents.js
@@ -88,27 +88,29 @@ function clearEditor(editor) {
   editor.setText("");
   editor.setMode({
     name: "text"
   });
   resetLineNumberFormat(editor);
 }
 
 function showLoading(editor) {
-  if (hasDocument("loading")) {
-    return;
-  }
+  let doc = getDocument("loading");
 
-  const doc = editor.createDocument();
-  setDocument("loading", doc);
-  editor.replaceDocument(doc);
-  editor.setText(L10N.getStr("loadingText"));
-  editor.setMode({
-    name: "text"
-  });
+  if (doc) {
+    editor.replaceDocument(doc);
+  } else {
+    doc = editor.createDocument();
+    setDocument("loading", doc);
+    doc.setValue(L10N.getStr("loadingText"));
+    editor.replaceDocument(doc);
+    editor.setMode({
+      name: "text"
+    });
+  }
 }
 
 function showErrorMessage(editor, msg) {
   let error;
 
   if (msg.includes("WebAssembly binary source is not available")) {
     error = L10N.getStr("wasmIsNotAvailable");
   } else {
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/memoize.js
@@ -0,0 +1,73 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = memoize;
+
+/* 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/>. */
+function hasValue(keys, store) {
+  let currentStore = store;
+
+  for (const key of keys) {
+    if (!currentStore || !currentStore.has(key)) {
+      return false;
+    }
+
+    currentStore = currentStore.get(key);
+  }
+
+  return true;
+}
+
+function getValue(keys, store) {
+  let currentStore = store;
+
+  for (const key of keys) {
+    if (!currentStore) {
+      return null;
+    }
+
+    currentStore = currentStore.get(key);
+  }
+
+  return currentStore;
+}
+
+function setValue(keys, store, value) {
+  const keysExceptLast = keys.slice(0, -1);
+  const lastKey = keys[keys.length - 1];
+  let currentStore = store;
+
+  for (const key of keysExceptLast) {
+    if (!currentStore) {
+      return;
+    }
+
+    if (!currentStore.has(key)) {
+      currentStore.set(key, new WeakMap());
+    }
+
+    currentStore = currentStore.get(key);
+  }
+
+  if (currentStore) {
+    currentStore.set(lastKey, value);
+  }
+} // memoize with n arguments
+
+
+function memoize(func) {
+  const store = new WeakMap();
+  return function (...keys) {
+    if (hasValue(keys, store)) {
+      return getValue(keys, store);
+    }
+
+    const newValue = func.apply(null, keys);
+    setValue(keys, store, newValue);
+    return newValue;
+  };
+}
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/moz.build
+++ b/devtools/client/debugger/new/src/utils/moz.build
@@ -23,16 +23,17 @@ DevToolsModules(
     'expressions.js',
     'fromJS.js',
     'function.js',
     'indentation.js',
     'isMinified.js',
     'location.js',
     'log.js',
     'makeRecord.js',
+    'memoize.js',
     'path.js',
     'prefs.js',
     'preview.js',
     'project-search.js',
     'quick-open.js',
     'result-list.js',
     'source-maps.js',
     'source-queue.js',
--- a/devtools/client/debugger/new/src/utils/prefs.js
+++ b/devtools/client/debugger/new/src/utils/prefs.js
@@ -15,17 +15,17 @@ var _devtoolsServices2 = _interopRequire
 
 var _asyncStoreHelper = require("./asyncStoreHelper");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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 prefsSchemaVersion = "1.0.4";
+const prefsSchemaVersion = "1.0.5";
 const pref = _devtoolsServices2.default.pref;
 
 if ((0, _devtoolsEnvironment.isDevelopment)()) {
   pref("devtools.debugger.alphabetize-outline", false);
   pref("devtools.debugger.auto-pretty-print", false);
   pref("devtools.source-map.client-service.enabled", true);
   pref("devtools.debugger.pause-on-exceptions", false);
   pref("devtools.debugger.pause-on-caught-exceptions", false);
@@ -115,17 +115,18 @@ const features = exports.features = new 
   pausePoints: ["Bool", "pause-points"],
   skipPausing: ["Bool", "skip-pausing"],
   autocompleteExpression: ["Bool", "autocomplete-expressions"],
   mapExpressionBindings: ["Bool", "map-expression-bindings"],
   mapAwaitExpression: ["Bool", "map-await-expression"],
   componentPane: ["Bool", "component-pane"]
 });
 const asyncStore = exports.asyncStore = (0, _asyncStoreHelper.asyncStoreHelper)("debugger", {
-  pendingBreakpoints: ["pending-breakpoints", {}]
+  pendingBreakpoints: ["pending-breakpoints", {}],
+  tabs: ["tabs", []]
 });
 
 if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
   // clear pending Breakpoints
   prefs.pendingBreakpoints = {};
   prefs.tabs = [];
   prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/quick-open.js
+++ b/devtools/client/debugger/new/src/utils/quick-open.js
@@ -67,17 +67,17 @@ function parseLineColumn(query) {
 
 function formatSourcesForList(source, tabs) {
   const title = (0, _source.getFilename)(source);
   const subtitle = (0, _utils.endTruncateStr)(source.relativeUrl, 100);
   return {
     value: source.relativeUrl,
     title,
     subtitle,
-    icon: tabs.includes(source.url) ? "tab result-item-icon" : (0, _classnames2.default)((0, _source.getSourceClassnames)(source), "result-item-icon"),
+    icon: tabs.some(tab => tab.url == source.url) ? "tab result-item-icon" : (0, _classnames2.default)((0, _source.getSourceClassnames)(source), "result-item-icon"),
     id: source.id,
     url: source.url
   };
 }
 
 function formatSymbol(symbol) {
   return {
     id: `${symbol.name}:${symbol.location.start.line}`,
--- a/devtools/client/debugger/new/src/utils/sources-tree/getDirectories.js
+++ b/devtools/client/debugger/new/src/utils/sources-tree/getDirectories.js
@@ -1,20 +1,19 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getDirectories = getDirectories;
 
-var _utils = require("./utils");
-
 /* 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/>. */
+// import { createParentMap } from "./utils";
 function _traverse(subtree, source) {
   if (subtree.type === "source") {
     if (subtree.contents.id === source.id) {
       return subtree;
     }
 
     return null;
   }
@@ -22,33 +21,32 @@ function _traverse(subtree, source) {
   const matches = subtree.contents.map(child => _traverse(child, source));
   return matches && matches.filter(Boolean)[0];
 }
 
 function findSourceItem(sourceTree, source) {
   return _traverse(sourceTree, source);
 }
 
-function getAncestors(sourceTree, item) {
+function getAncestors(sourceTree, parentMap, item) {
   if (!item) {
     return null;
   }
 
-  const parentMap = (0, _utils.createParentMap)(sourceTree);
   const directories = [];
   directories.push(item);
 
   while (true) {
     item = parentMap.get(item);
 
     if (!item) {
       return directories;
     }
 
     directories.push(item);
   }
 }
 
-function getDirectories(source, sourceTree) {
+function getDirectories(source, parentMap, sourceTree) {
   const item = findSourceItem(sourceTree, source);
-  const ancestors = getAncestors(sourceTree, item);
+  const ancestors = getAncestors(sourceTree, parentMap, item);
   return ancestors || [sourceTree];
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-asm.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-asm.js
@@ -4,20 +4,16 @@ add_task(async function() {
 
   // After reload() we are getting getSources notifiction for old sources,
   // using the debugger statement to really stop are reloaded page.
   await waitForPaused(dbg);
   await resume(dbg);
 
   await waitForSources(dbg, "doc-asm.html", "asm.js");
 
-  // Expand nodes and make sure more sources appear.
-  is(findAllElements(dbg, "sourceNodes").length, 2);
-
-  await clickElement(dbg, "sourceDirectoryLabel", 2);
   is(findAllElements(dbg, "sourceNodes").length, 4);
 
   await selectSource(dbg, "asm.js");
 
   await addBreakpoint(dbg, "asm.js", 7);
   invokeInTab("runAsm");
 
   await waitForPaused(dbg);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // This test can be really slow on debug platforms and should be split.
-requestLongerTimeout(20);
+requestLongerTimeout(30);
 
 // Tests loading sourcemapped sources for Babel's compile output.
 
 const ACTIVE_TARGETS = new Set([
   // "webpack3",
   "webpack3-babel6",
   // "webpack3-babel7",
   // "webpack4",
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -6806,31 +6806,33 @@ const { rep: StringRep } = __webpack_req
 Accessible.propTypes = {
   object: PropTypes.object.isRequired,
   inspectIconTitle: PropTypes.string,
   nameMaxLength: PropTypes.number,
   onAccessibleClick: PropTypes.func,
   onAccessibleMouseOver: PropTypes.func,
   onAccessibleMouseOut: PropTypes.func,
   onInspectIconClick: PropTypes.func,
+  roleFirst: PropTypes.bool,
   separatorText: PropTypes.string
 };
 
 function Accessible(props) {
   const {
     object,
     inspectIconTitle,
     nameMaxLength,
     onAccessibleClick,
     onAccessibleMouseOver,
     onAccessibleMouseOut,
     onInspectIconClick,
+    roleFirst,
     separatorText
   } = props;
-  const elements = getElements(object, nameMaxLength, separatorText);
+  const elements = getElements(object, nameMaxLength, roleFirst, separatorText);
   const isInTree = object.preview && object.preview.isConnected === true;
   const baseConfig = {
     "data-link-actor-id": object.actor,
     className: "objectBox objectBox-accessible"
   };
 
   let inspectIcon;
   if (isInTree) {
@@ -6866,30 +6868,29 @@ function Accessible(props) {
         }
       });
     }
   }
 
   return span(baseConfig, ...elements, inspectIcon);
 }
 
-function getElements(grip, nameMaxLength, separatorText = ": ") {
+function getElements(grip, nameMaxLength, roleFirst = false, separatorText = ": ") {
   const { name, role } = grip.preview;
   const elements = [];
-
-  elements.push(span({ className: "accessible-role" }, role));
   if (name) {
-    elements.push(span({ className: "separator" }, separatorText), StringRep({
+    elements.push(StringRep({
       className: "accessible-name",
       object: name,
       cropLimit: nameMaxLength
-    }));
-  }
-
-  return elements;
+    }), span({ className: "separator" }, separatorText));
+  }
+
+  elements.push(span({ className: "accessible-role" }, role));
+  return roleFirst ? elements.reverse() : elements;
 }
 
 // Registration
 function supportsObject(object, noGrip = false) {
   if (noGrip === true || !isGrip(object)) {
     return false;
   }
 
--- a/devtools/client/themes/images/debugger/disable-pausing.svg
+++ b/devtools/client/themes/images/debugger/disable-pausing.svg
@@ -1,1 +1,4 @@
-<svg height="16" viewBox="0 0 15 16" width="15" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" transform="translate(0 1)"><path d="m1.5 13.5 10-13" stroke="#000" stroke-linecap="square"/><path d="m7.58013626 3-.75408823 1h-4.82604803c-.53612439 0-.77556634.12770238-.9020017.32999894-.07178403.11485445-.0979983.24068295-.0979983.27000106v4.8c0 .02931811.02621427.15514661.0979983.27000106.12643536.20229656.36587731.32999894.9020017.32999894h.30151865l-.73328118.9724077c-1.56823747-.2118785-1.56823747-1.5724077-1.56823747-1.5724077v-4.8s0-1.6 2-1.6zm3.94638894.52652517 3.4734748 3.47347483-4 4h-5.10913424l.75408823-1h3.94083241l3-3-2.6672362-2.66723627z" fill="#000" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
+<!-- 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/. -->
+<svg height="16" viewBox="0 0 15 16" width="15" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" transform="translate(0 1)"><path d="m1.5 13.5 10-13" stroke="#000" stroke-linecap="square"/><path d="m7.58013626 3-.75408823 1h-4.82604803c-.53612439 0-.77556634.12770238-.9020017.32999894-.07178403.11485445-.0979983.24068295-.0979983.27000106v4.8c0 .02931811.02621427.15514661.0979983.27000106.12643536.20229656.36587731.32999894.9020017.32999894h.30151865l-.73328118.9724077c-1.56823747-.2118785-1.56823747-1.5724077-1.56823747-1.5724077v-4.8s0-1.6 2-1.6zm3.94638894.52652517 3.4734748 3.47347483-4 4h-5.10913424l.75408823-1h3.94083241l3-3-2.6672362-2.66723627z" fill="#000" fill-rule="nonzero"/></g></svg>