diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index 58264a34a097..d1101d7e2c31 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,9 +1,9 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 104 +Version 105 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-103...release-104 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-104...release-105 Packages: - babel-plugin-transform-es2015-modules-commonjs @6.26.2 diff --git a/devtools/client/debugger/new/dist/debugger.css b/devtools/client/debugger/new/dist/debugger.css index 7aa5af9b1cbc..91b951ed3eec 100644 --- a/devtools/client/debugger/new/dist/debugger.css +++ b/devtools/client/debugger/new/dist/debugger.css @@ -276,6 +276,22 @@ button.jump-definition { background-color: var(--theme-highlight-blue); } +/******************************************************************************/ +/* Invoke getter button */ + +button.invoke-getter { + mask: url("resource://devtools/client/shared/components/reps/images/input.svg") no-repeat; + display: inline-block; + background-color: var(--comment-node-color); + height: 12px; + vertical-align:bottom; + border:none; +} + +.invoke-getter:hover { + background-color: var(--theme-highlight-blue); +} + /******************************************************************************/ /* "more…" ellipsis */ .more-ellipsis { @@ -337,24 +353,29 @@ button.jump-definition { cursor: default; } -.tree-node img.arrow { - mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - mask-size: 100%; +.tree-node button.arrow { + background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; + background-size:contain; + background-position:center center; width: 9px; height: 9px; + border:0; + padding:0; margin-inline-start: 1px; margin-inline-end: 4px; - background-color: var(--theme-splitter-color, #9B9B9B); transform: rotate(-90deg); + transform-origin: center center; transition: transform 0.125s ease; align-self: center; + -moz-context-properties: fill; + fill: var(--theme-splitter-color, #9B9B9B); } -html[dir="rtl"] .tree-node img.arrow { +html[dir="rtl"] .tree-node button.arrow { transform: rotate(90deg); } -.tree-node img.arrow.expanded.expanded { +.tree-node button.arrow.expanded.expanded { transform: rotate(0deg); } @@ -363,8 +384,8 @@ html[dir="rtl"] .tree-node img.arrow { background-color: var(--theme-selection-background, #0a84ff); } -.tree-node.focused img.arrow { - background-color: currentColor; +.tree-node.focused button.arrow { + fill: currentColor; } /* 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 @@ -404,7 +425,7 @@ html[dir="rtl"] .tree-node img.arrow { color: var(--theme-comment); } -.object-inspector .tree-node img.arrow { +.object-inspector .tree-node .arrow { display: inline-block; vertical-align: middle; } @@ -2665,7 +2686,7 @@ menuseparator { .call-site { position: relative; - border-bottom: 2px solid lightgrey; + display: inline; cursor: pointer; } @@ -2680,20 +2701,8 @@ menuseparator { height: 12px; } -.call-site-bp { - position: relative; - border-bottom: 2px solid #aed3ef; - cursor: pointer; -} - -.call-site-bp::before { - content: ""; - mask: url("resource://devtools/client/debugger/new/images/column-marker.svg") no-repeat 100% 100%; - mask-size: contain; - display: inline-block; - background-color: var(--blue-55); - width: 9px; - height: 12px; +.call-site.active::before { + opacity: 1; } .theme-dark .call-site { @@ -2950,7 +2959,8 @@ html[dir="rtl"] .editor-mount { color: var(--theme-comment); } -.debug-expression { +.debug-expression, +.new-debug-line .call-site { background-color: var(--debug-expression-background); } @@ -3612,7 +3622,7 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line { margin-inline-start: 4px; } -:root.theme-dark .annotation-logo svg path { +:root.theme-dark .annotation-logo:not(.angular) svg path { fill: var(--theme-highlight-blue); } /* This Source Code Form is subject to the terms of the Mozilla Public diff --git a/devtools/client/debugger/new/dist/parser-worker.js b/devtools/client/debugger/new/dist/parser-worker.js index 8c88edba5ebe..4def7a2f61e7 100644 --- a/devtools/client/debugger/new/dist/parser-worker.js +++ b/devtools/client/debugger/new/dist/parser-worker.js @@ -1015,6 +1015,7 @@ exports.isVariable = isVariable; exports.isComputedExpression = isComputedExpression; exports.getMemberExpression = getMemberExpression; exports.getVariables = getVariables; +exports.getPatternIdentifiers = getPatternIdentifiers; exports.isTopLevel = isTopLevel; var _types = __webpack_require__(2268); @@ -1164,14 +1165,15 @@ function getVariables(dec) { return []; } - // NOTE: it's possible that an element is empty + // NOTE: it's possible that an element is empty or has several variables // e.g. const [, a] = arr + // e.g. const [{a, b }] = 2 return dec.id.elements.filter(element => element).map(element => { return { - name: t.isAssignmentPattern(element) ? element.left.name : element.name || element.argument.name, + name: t.isAssignmentPattern(element) ? element.left.name : element.name || element.argument && element.argument.name, location: element.loc }; - }); + }).filter(({ name }) => name); } return [{ @@ -1180,6 +1182,36 @@ function getVariables(dec) { }]; } +function getPatternIdentifiers(pattern) { + let items = []; + if (t.isObjectPattern(pattern)) { + items = pattern.properties.map(({ value }) => value); + } + + if (t.isArrayPattern(pattern)) { + items = pattern.elements; + } + + return getIdentifiers(items); +} + +function getIdentifiers(items) { + let ids = []; + items.forEach(function (item) { + if (t.isObjectPattern(item) || t.isArrayPattern(item)) { + ids = ids.concat(getPatternIdentifiers(item)); + } else if (t.isIdentifier(item)) { + const { start, end } = item.loc; + ids.push({ + name: item.name, + expression: item.name, + location: { start, end } + }); + } + }); + return ids; +} + // Top Level checks the number of "body" nodes in the ancestor chain // if the node is top-level, then it shoul only have one body. function isTopLevel(ancestors) { @@ -1450,7 +1482,7 @@ function extractSymbol(path, symbols) { }); } - if (t.isIdentifier(path) && !t.isGenericTypeAnnotation(path.parent)) { + if (t.isIdentifier(path) && !t.isGenericTypeAnnotation(path.parent) && !t.isObjectProperty(path.parent) && !t.isArrayPattern(path.parent)) { let { start, end } = path.node.loc; // We want to include function params, but exclude the function name @@ -1490,25 +1522,11 @@ function extractSymbol(path, symbols) { if (t.isVariableDeclarator(path)) { const nodeId = path.node.id; - if (t.isArrayPattern(nodeId)) { - return; - } - - const properties = nodeId.properties && t.objectPattern(nodeId.properties) ? nodeId.properties : [{ - value: { name: nodeId.name }, - loc: path.node.loc - }]; - - properties.forEach(function (property) { - const { start, end } = property.loc; - symbols.identifiers.push({ - name: property.value.name, - expression: property.value.name, - location: { start, end } - }); - }); + const ids = (0, _helpers.getPatternIdentifiers)(nodeId); + symbols.identifiers = [...symbols.identifiers, ...ids]; } } + /* eslint-enable complexity */ function extractSymbols(sourceId) { diff --git a/devtools/client/debugger/new/dist/vendors.css b/devtools/client/debugger/new/dist/vendors.css index 404c74ce1e9c..e9e5a9f16879 100644 --- a/devtools/client/debugger/new/dist/vendors.css +++ b/devtools/client/debugger/new/dist/vendors.css @@ -54,24 +54,29 @@ cursor: default; } -.tree-node img.arrow { - mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - mask-size: 100%; +.tree-node button.arrow { + background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; + background-size:contain; + background-position:center center; width: 9px; height: 9px; + border:0; + padding:0; margin-inline-start: 1px; margin-inline-end: 4px; - background-color: var(--theme-splitter-color, #9B9B9B); transform: rotate(-90deg); + transform-origin: center center; transition: transform 0.125s ease; align-self: center; + -moz-context-properties: fill; + fill: var(--theme-splitter-color, #9B9B9B); } -html[dir="rtl"] .tree-node img.arrow { +html[dir="rtl"] .tree-node button.arrow { transform: rotate(90deg); } -.tree-node img.arrow.expanded.expanded { +.tree-node button.arrow.expanded.expanded { transform: rotate(0deg); } @@ -80,8 +85,8 @@ html[dir="rtl"] .tree-node img.arrow { background-color: var(--theme-selection-background, #0a84ff); } -.tree-node.focused img.arrow { - background-color: currentColor; +.tree-node.focused button.arrow { + fill: currentColor; } /* vim:set ts=2 sw=2 sts=2 et: */ /* This Source Code Form is subject to the terms of the Mozilla Public diff --git a/devtools/client/debugger/new/dist/vendors.js b/devtools/client/debugger/new/dist/vendors.js index 4cf389e3bc05..97ef104453bd 100644 --- a/devtools/client/debugger/new/dist/vendors.js +++ b/devtools/client/debugger/new/dist/vendors.js @@ -4622,7 +4622,7 @@ module.exports = "" +module.exports = "" /***/ }), @@ -4678,7 +4678,7 @@ module.exports = "" +module.exports = "" /***/ }), @@ -6012,7 +6012,7 @@ class ArrowExpander extends Component { if (expanded) { classNames.push("expanded"); } - return _reactDomFactories2.default.img({ + return _reactDomFactories2.default.button({ className: classNames.join(" ") }); } diff --git a/devtools/client/debugger/new/images/moz.build b/devtools/client/debugger/new/images/moz.build index fa9791a08037..551d68c287bd 100644 --- a/devtools/client/debugger/new/images/moz.build +++ b/devtools/client/debugger/new/images/moz.build @@ -21,7 +21,6 @@ DevToolsModules( 'folder.svg', 'help.svg', 'javascript.svg', - 'next.svg', 'pause.svg', 'prettyPrint.svg', 'react.svg', diff --git a/devtools/client/debugger/new/images/next.svg b/devtools/client/debugger/new/images/next.svg deleted file mode 100644 index fb66d5b3f7ff..000000000000 --- a/devtools/client/debugger/new/images/next.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/devtools/client/debugger/new/src/actions/ui.js b/devtools/client/debugger/new/src/actions/ui.js index c73208c7701a..ac225452fb61 100644 --- a/devtools/client/debugger/new/src/actions/ui.js +++ b/devtools/client/debugger/new/src/actions/ui.js @@ -14,7 +14,7 @@ import { } from "../selectors"; import { selectSource } from "../actions/sources/select"; import type { ThunkArgs, panelPositionType } from "./types"; -import { getEditor } from "../utils/editor"; +import { getEditor, getLocationsInViewport } from "../utils/editor"; import { searchContents } from "./file-search"; import type { @@ -201,6 +201,13 @@ export function setProjectDirectoryRoot(newRoot: string) { }; } +export function updateViewport() { + return { + type: "SET_VIEWPORT", + viewport: getLocationsInViewport(getEditor()) + }; +} + export function setOrientation(orientation: OrientationType) { return { type: "SET_ORIENTATION", orientation }; } diff --git a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js new file mode 100644 index 000000000000..e55aa7912fe6 --- /dev/null +++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js @@ -0,0 +1,80 @@ +/* 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 . */ + +// @flow +import { PureComponent } from "react"; +import classnames from "classnames"; +import { getDocument } from "../../utils/editor"; + +// eslint-disable-next-line max-len +import type { ColumnBreakpoint as ColumnBreakpointType } from "../../selectors/visibleColumnBreakpoints"; + +type Bookmark = { + clear: Function +}; + +type Props = { + callSite: Object, + editor: Object, + source: Object, + enabled: boolean, + toggleBreakpoint: (number, number) => void, + columnBreakpoint: ColumnBreakpointType +}; + +const breakpointImg = document.createElement("div"); +function makeBookmark(isActive, { onClick }) { + const bp = breakpointImg.cloneNode(true); + bp.className = classnames("call-site", { + active: isActive + }); + bp.onclick = onClick; + return bp; +} + +export default class CallSite extends PureComponent { + addCallSite: Function; + bookmark: ?Bookmark; + + addCallSite = (nextProps: ?Props) => { + const { columnBreakpoint, source } = nextProps || this.props; + const sourceId = source.id; + const { line, column } = columnBreakpoint.location; + const widget = makeBookmark(columnBreakpoint.enabled, { + onClick: this.toggleBreakpoint + }); + const doc = getDocument(sourceId); + this.bookmark = doc.setBookmark({ line: line - 1, ch: column }, { widget }); + }; + + clearCallSite = () => { + if (this.bookmark) { + this.bookmark.clear(); + this.bookmark = null; + } + }; + + toggleBreakpoint = () => { + const { columnBreakpoint, toggleBreakpoint } = this.props; + const { line, column } = columnBreakpoint.location; + toggleBreakpoint(line, column); + }; + + componentDidMount() { + this.addCallSite(); + } + + componentWillUnmount() { + this.clearCallSite(); + } + + componentDidUpdate() { + this.clearCallSite(); + this.addCallSite(); + } + + render() { + return null; + } +} diff --git a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.js b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.js new file mode 100644 index 000000000000..75603744da24 --- /dev/null +++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.js @@ -0,0 +1,67 @@ +/* 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 . */ + +import React, { Component } from "react"; +import { connect } from "react-redux"; + +import ColumnBreakpoint from "./ColumnBreakpoint"; +import "./ColumnBreakpoints.css"; + +import { getSelectedSource, visibleColumnBreakpoints } from "../../selectors"; +import { makeLocationId } from "../../utils/breakpoint"; +import actions from "../../actions"; + +import type { Source } from "../../types"; +// eslint-disable-next-line max-len +import type { ColumnBreakpoint as ColumnBreakpointType } from "../../selectors/visibleColumnBreakpoints"; + +class ColumnBreakpoints extends Component { + props: { + editor: Object, + selectedSource: Source, + columnBreakpoints: ColumnBreakpointType[] + }; + + render() { + const { + editor, + columnBreakpoints, + selectedSource, + toggleBreakpoint + } = this.props; + + if (!selectedSource || selectedSource.isBlackBoxed) { + return null; + } + + let breakpoints; + editor.codeMirror.operation(() => { + breakpoints = columnBreakpoints.map(breakpoint => ( + + )); + }); + return
{breakpoints}
; + } +} + +const mapStateToProps = state => { + return { + selectedSource: getSelectedSource(state), + columnBreakpoints: visibleColumnBreakpoints(state) + }; +}; + +const { toggleBreakpoint } = actions; +const mapDispatchToProps = { toggleBreakpoint }; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ColumnBreakpoints); diff --git a/devtools/client/debugger/new/src/components/Editor/Tabs.js b/devtools/client/debugger/new/src/components/Editor/Tabs.js index 2537b71c141a..cfbacf56c5ef 100644 --- a/devtools/client/debugger/new/src/components/Editor/Tabs.js +++ b/devtools/client/debugger/new/src/components/Editor/Tabs.js @@ -76,12 +76,16 @@ class Tabs extends PureComponent { componentDidMount() { window.requestIdleCallback(this.updateHiddenTabs); window.addEventListener("resize", this.onResize); - window.document.querySelector(".editor-pane").addEventListener("resizeend", this.onResize); + window.document + .querySelector(".editor-pane") + .addEventListener("resizeend", this.onResize); } componentWillUnmount() { window.removeEventListener("resize", this.onResize); - window.document.querySelector(".editor-pane").removeEventListener("resizeend", this.onResize); + window.document + .querySelector(".editor-pane") + .removeEventListener("resizeend", this.onResize); } /* diff --git a/devtools/client/debugger/new/src/components/Editor/index.js b/devtools/client/debugger/new/src/components/Editor/index.js index d7cc4e296098..45be88063eb5 100644 --- a/devtools/client/debugger/new/src/components/Editor/index.js +++ b/devtools/client/debugger/new/src/components/Editor/index.js @@ -9,6 +9,8 @@ import React, { PureComponent } from "react"; import ReactDOM from "react-dom"; import { connect } from "react-redux"; import classnames from "classnames"; +import { debounce } from "lodash"; + import { isLoaded } from "../../utils/source"; import { isFirefox } from "devtools-environment"; import { features } from "../../utils/prefs"; @@ -30,7 +32,7 @@ import SearchBar from "./SearchBar"; import HighlightLines from "./HighlightLines"; import Preview from "./Preview"; import Breakpoints from "./Breakpoints"; -import CallSites from "./CallSites"; +import ColumnBreakpoints from "./ColumnBreakpoints"; import DebugLine from "./DebugLine"; import HighlightLine from "./HighlightLine"; import EmptyLines from "./EmptyLines"; @@ -91,7 +93,8 @@ export type Props = { toggleBreakpointsAtLine: (?number) => void, addOrToggleDisabledBreakpoint: (?number) => void, jumpToMappedLocation: any => void, - traverseResults: (boolean, Object) => void + traverseResults: (boolean, Object) => void, + updateViewport: void => void }; type State = { @@ -157,6 +160,7 @@ class Editor extends PureComponent { codeMirrorWrapper.addEventListener("keydown", e => this.onKeyDown(e)); codeMirrorWrapper.addEventListener("click", e => this.onClick(e)); codeMirrorWrapper.addEventListener("mouseover", onMouseOver(codeMirror)); + codeMirror.on("scroll", this.onEditorScroll); const toggleFoldMarkerVisibility = e => { if (node instanceof HTMLElement) { @@ -277,6 +281,8 @@ class Editor extends PureComponent { this.toggleConditionalPanel(line); }; + onEditorScroll = debounce(this.props.updateViewport, 200); + onKeyDown(e: KeyboardEvent) { const { codeMirror } = this.state.editor; const { key, target } = e; @@ -548,7 +554,9 @@ class Editor extends PureComponent { - {features.columnBreakpoints ? : null} + {features.columnBreakpoints ? ( + + ) : null} ); } @@ -607,6 +615,7 @@ export default connect( toggleBreakpointsAtLine: actions.toggleBreakpointsAtLine, addOrToggleDisabledBreakpoint: actions.addOrToggleDisabledBreakpoint, jumpToMappedLocation: actions.jumpToMappedLocation, - traverseResults: actions.traverseResults + traverseResults: actions.traverseResults, + updateViewport: actions.updateViewport } )(Editor); diff --git a/devtools/client/debugger/new/src/components/Editor/moz.build b/devtools/client/debugger/new/src/components/Editor/moz.build index 19d406fa2e17..f8107c90fa91 100644 --- a/devtools/client/debugger/new/src/components/Editor/moz.build +++ b/devtools/client/debugger/new/src/components/Editor/moz.build @@ -10,8 +10,8 @@ DIRS += [ DebuggerModules( 'Breakpoint.js', 'Breakpoints.js', - 'CallSite.js', - 'CallSites.js', + 'ColumnBreakpoint.js', + 'ColumnBreakpoints.js', 'ConditionalPanel.js', 'DebugLine.js', 'EditorMenu.js', diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js index 39fc811e3144..b4b6d9b92e2e 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js @@ -15,7 +15,7 @@ import BreakpointHeading from "./BreakpointHeading"; import actions from "../../../actions"; import { getDisplayPath } from "../../../utils/source"; -import { makeLocationId } from "../../../utils/breakpoint"; +import { makeLocationId, sortBreakpoints } from "../../../utils/breakpoint"; import { getSelectedSource, getBreakpointSources } from "../../../selectors"; @@ -79,6 +79,8 @@ class Breakpoints extends Component { return [ ...breakpointSources.map(({ source, breakpoints, i }) => { const path = getDisplayPath(source, sources); + const sortedBreakpoints = sortBreakpoints(breakpoints); + return [ { path={path} key={source.url} />, - ...breakpoints.map(breakpoint => ( + ...sortedBreakpoints.map(breakpoint => ( . */ + +import { groupBy, hasIn } from "lodash"; +import { createSelector } from "reselect"; + +import { getViewport } from "../selectors"; +import { getVisibleBreakpoints } from "./visibleBreakpoints"; +import { getVisiblePausePoints } from "./visiblePausePoints"; + +import type { Location } from "../types"; + +export type ColumnBreakpoint = {| + +location: Location, + +enabled: boolean +|}; + +function contains(location, range) { + return ( + location.line >= range.start.line && + location.line <= range.end.line && + location.column >= range.start.column && + location.column <= range.end.column + ); +} + +function groupBreakpoints(breakpoints) { + const map = groupBy(breakpoints, ({ location }) => location.line); + for (const line in map) { + map[line] = groupBy(map[line], ({ location }) => location.column); + } + + return map; +} + +function isEnabled(location, breakpointMap) { + const { line, column } = location; + return hasIn(breakpointMap, [line, column]); +} + +export function formatColumnBreakpoints(columnBreakpoints) { + console.log( + "Column Breakpoints\n\n", + columnBreakpoints + .map( + ({ location, enabled }) => + `(${location.line}, ${location.column}) ${enabled}` + ) + .join("\n") + ); +} + +export function getColumnBreakpoints(pausePoints, breakpoints, viewport) { + if (!pausePoints) { + return []; + } + + const breakpointMap = groupBreakpoints(breakpoints); + const columnBreakpoints = pausePoints + .filter(({ types }) => types.break) + .filter(({ location }) => breakpointMap[location.line]) + .filter(({ location }) => viewport && contains(location, viewport)); + + return columnBreakpoints.map(({ location }) => ({ + location, + enabled: isEnabled(location, breakpointMap) + })); +} + +export const visibleColumnBreakpoints = createSelector( + getVisiblePausePoints, + getVisibleBreakpoints, + getViewport, + getColumnBreakpoints +); diff --git a/devtools/client/debugger/new/src/selectors/visiblePausePoints.js b/devtools/client/debugger/new/src/selectors/visiblePausePoints.js new file mode 100644 index 000000000000..7d332c85da88 --- /dev/null +++ b/devtools/client/debugger/new/src/selectors/visiblePausePoints.js @@ -0,0 +1,17 @@ +/* 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 . */ + +import { getSelectedSource } from "../reducers/sources"; +import { getPausePoints } from "../reducers/ast"; +import { convertToList } from "../utils/pause/pausePoints"; + +export function getVisiblePausePoints(state) { + const source = getSelectedSource(state); + if (!source) { + return null; + } + + const pausePoints = getPausePoints(state, source.id); + return convertToList(pausePoints); +} diff --git a/devtools/client/debugger/new/src/utils/breakpoint/index.js b/devtools/client/debugger/new/src/utils/breakpoint/index.js index bbed30c1b545..79b234e41509 100644 --- a/devtools/client/debugger/new/src/utils/breakpoint/index.js +++ b/devtools/client/debugger/new/src/utils/breakpoint/index.js @@ -4,12 +4,15 @@ // @flow +import { sortBy } from "lodash"; + import { getBreakpoint } from "../../selectors"; import assert from "../assert"; import { features } from "../prefs"; export { getASTLocation, findScopeByName } from "./astBreakpointLocation"; +import type { FormattedBreakpoint } from "../../selectors/breakpointSources"; import type { Location, PendingLocation, @@ -179,3 +182,20 @@ export function createPendingBreakpoint(bp: Breakpoint) { generatedLocation: pendingGeneratedLocation }; } + +export function sortBreakpoints(breakpoints: FormattedBreakpoint[]) { + breakpoints = breakpoints.map(bp => ({ + ...bp, + selectedLocation: { + ...bp.selectedLocation, + // If a breakpoint has an undefined column, we must provide a 0 value + // or the breakpoint will display after all explicit column numbers + column: bp.selectedLocation.column || 0 + } + })); + + return sortBy(breakpoints, [ + "selectedLocation.line", + "selectedLocation.column" + ]); +} diff --git a/devtools/client/debugger/new/src/utils/dbg.js b/devtools/client/debugger/new/src/utils/dbg.js index bedcad7e5d32..e6c0f05cb20c 100644 --- a/devtools/client/debugger/new/src/utils/dbg.js +++ b/devtools/client/debugger/new/src/utils/dbg.js @@ -54,6 +54,14 @@ function _formatPausePoints(dbg: Object, url: string) { console.log(formatPausePoints(source.text, pausePoints)); } +function _formatColumnBreapoints(dbg: Object) { + console.log( + dbg.selectors.formatColumnBreakpoints( + dbg.selectors.visibleColumnBreakpoints() + ) + ); +} + export function setupHelper(obj: Object) { const selectors = bindSelectors(obj); const dbg: Object = { @@ -72,7 +80,8 @@ export function setupHelper(obj: Object) { sendPacket: (packet, cbk) => sendPacket(dbg, packet, cbk) }, formatters: { - pausePoints: url => _formatPausePoints(dbg, url) + pausePoints: url => _formatPausePoints(dbg, url), + visibleColumnBreakpoints: () => _formatColumnBreapoints(dbg) }, _telemetry: { events: {} diff --git a/devtools/client/debugger/new/src/utils/editor/index.js b/devtools/client/debugger/new/src/utils/editor/index.js index 5acdaea8a76b..d6a8bd811865 100644 --- a/devtools/client/debugger/new/src/utils/editor/index.js +++ b/devtools/client/debugger/new/src/utils/editor/index.js @@ -158,6 +158,34 @@ function isVisible(codeMirror: any, top: number, left: number) { return inXView && inYView; } +export function getLocationsInViewport(_editor: any) { + // Get scroll position + const charWidth = _editor.codeMirror.defaultCharWidth(); + const scrollArea = _editor.codeMirror.getScrollInfo(); + const { scrollLeft } = _editor.codeMirror.doc; + const rect = _editor.codeMirror.getWrapperElement().getBoundingClientRect(); + const topVisibleLine = _editor.codeMirror.lineAtHeight(rect.top, "window"); + const bottomVisibleLine = _editor.codeMirror.lineAtHeight( + rect.bottom, + "window" + ); + + const leftColumn = Math.floor(scrollLeft > 0 ? scrollLeft / charWidth : 0); + const rightPosition = scrollLeft + (scrollArea.clientWidth - 30); + const rightCharacter = Math.floor(rightPosition / charWidth); + + return { + start: { + line: topVisibleLine, + column: leftColumn + }, + end: { + line: bottomVisibleLine, + column: rightCharacter + } + }; +} + export function markText(_editor: any, className, { start, end }: EditorRange) { return _editor.codeMirror.markText( { ch: start.column, line: start.line }, diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js index 2829db2e0407..a9bc68e8c99d 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js @@ -33,38 +33,46 @@ add_task(async function() { await addBreakpoint(dbg, "simple1", 5); await addBreakpoint(dbg, "simple1", 6); - openFirstBreakpointContextMenu(dbg) + openFirstBreakpointContextMenu(dbg); // select "Disable Others" + let dispatched = waitForDispatch(dbg, "DISABLE_BREAKPOINT", 3); selectMenuItem(dbg, 7); await waitForState(dbg, state => dbg.selectors.getBreakpointsList(state) .every(bp => (bp.location.line !== 1) === bp.disabled) ); + await dispatched; ok("breakpoint at 1 is the only enabled breakpoint"); - openFirstBreakpointContextMenu(dbg) + openFirstBreakpointContextMenu(dbg); // select "Disable All" + dispatched = waitForDispatch(dbg, "DISABLE_ALL_BREAKPOINTS"); selectMenuItem(dbg, 9); await waitForState(dbg, state => dbg.selectors.getBreakpointsList(state).every(bp => bp.disabled) ); - ok("all breakpoints are disabled") + await dispatched; + ok("all breakpoints are disabled"); - openFirstBreakpointContextMenu(dbg) + openFirstBreakpointContextMenu(dbg); // select "Enable Others" + dispatched = waitForDispatch(dbg, "ENABLE_BREAKPOINT", 3); selectMenuItem(dbg, 3); await waitForState(dbg, state => dbg.selectors.getBreakpointsList(state) .every(bp => (bp.location.line === 1) === bp.disabled) ); + await dispatched; ok("all breakpoints except line 1 are enabled"); - openFirstBreakpointContextMenu(dbg) + openFirstBreakpointContextMenu(dbg); // select "Remove Others" + dispatched = waitForDispatch(dbg, "REMOVE_BREAKPOINT", 3); selectMenuItem(dbg, 6); await waitForState(dbg, state => dbg.selectors.getBreakpointsList(state).length === 1 && dbg.selectors.getBreakpointsList(state)[0].location.line === 1 ); + await dispatched; ok("remaining breakpoint should be on line 1"); }); diff --git a/devtools/client/debugger/new/test/mochitest/helpers.js b/devtools/client/debugger/new/test/mochitest/helpers.js index 1b1a95873463..6009dbf23cde 100644 --- a/devtools/client/debugger/new/test/mochitest/helpers.js +++ b/devtools/client/debugger/new/test/mochitest/helpers.js @@ -341,7 +341,7 @@ function assertDebugLine(dbg, line) { const markedSpans = lineInfo.handle.markedSpans; if (markedSpans && markedSpans.length > 0) { const classMatch = markedSpans.filter( - span => span.marker.className.includes("debug-expression") + span => span.marker.className && span.marker.className.includes("debug-expression") ).length > 0; ok( diff --git a/devtools/client/shared/components/reps/images/input.svg b/devtools/client/shared/components/reps/images/input.svg new file mode 100644 index 000000000000..830b651e9e02 --- /dev/null +++ b/devtools/client/shared/components/reps/images/input.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/devtools/client/shared/components/reps/images/moz.build b/devtools/client/shared/components/reps/images/moz.build index 180e133adf7b..4cc1ee9e94a0 100644 --- a/devtools/client/shared/components/reps/images/moz.build +++ b/devtools/client/shared/components/reps/images/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + 'input.svg', 'jump-definition.svg', 'open-inspector.svg', ) diff --git a/devtools/client/shared/components/reps/reps.css b/devtools/client/shared/components/reps/reps.css index 52f698b9f2ac..ce0b4ae153cc 100644 --- a/devtools/client/shared/components/reps/reps.css +++ b/devtools/client/shared/components/reps/reps.css @@ -276,6 +276,22 @@ button.jump-definition { background-color: var(--theme-highlight-blue); } +/******************************************************************************/ +/* Invoke getter button */ + +button.invoke-getter { + mask: url("resource://devtools/client/shared/components/reps/images/input.svg") no-repeat; + display: inline-block; + background-color: var(--comment-node-color); + height: 12px; + vertical-align:bottom; + border:none; +} + +.invoke-getter:hover { + background-color: var(--theme-highlight-blue); +} + /******************************************************************************/ /* "more…" ellipsis */ .more-ellipsis { @@ -337,24 +353,29 @@ button.jump-definition { cursor: default; } -.tree-node img.arrow { - mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - mask-size: 100%; +.tree-node button.arrow { + background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; + background-size:contain; + background-position:center center; width: 9px; height: 9px; + border:0; + padding:0; margin-inline-start: 1px; margin-inline-end: 4px; - background-color: var(--theme-splitter-color, #9B9B9B); transform: rotate(-90deg); + transform-origin: center center; transition: transform 0.125s ease; align-self: center; + -moz-context-properties: fill; + fill: var(--theme-splitter-color, #9B9B9B); } -html[dir="rtl"] .tree-node img.arrow { +html[dir="rtl"] .tree-node button.arrow { transform: rotate(90deg); } -.tree-node img.arrow.expanded.expanded { +.tree-node button.arrow.expanded.expanded { transform: rotate(0deg); } @@ -363,8 +384,8 @@ html[dir="rtl"] .tree-node img.arrow { background-color: var(--theme-selection-background, #0a84ff); } -.tree-node.focused img.arrow { - background-color: currentColor; +.tree-node.focused button.arrow { + fill: currentColor; } /* 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 @@ -404,7 +425,7 @@ html[dir="rtl"] .tree-node img.arrow { color: var(--theme-comment); } -.object-inspector .tree-node img.arrow { +.object-inspector .tree-node .arrow { display: inline-block; vertical-align: middle; } diff --git a/devtools/client/shared/components/reps/reps.js b/devtools/client/shared/components/reps/reps.js index 86ce7479a4db..b0313801c8dc 100644 --- a/devtools/client/shared/components/reps/reps.js +++ b/devtools/client/shared/components/reps/reps.js @@ -3771,7 +3771,7 @@ class ArrowExpander extends Component { if (expanded) { classNames.push("expanded"); } - return _reactDomFactories2.default.img({ + return _reactDomFactories2.default.button({ className: classNames.join(" ") }); } @@ -4993,6 +4993,8 @@ module.exports = { "use strict"; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + /* 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 . */ @@ -5014,18 +5016,40 @@ Accessor.propTypes = { }; function Accessor(props) { - const { object } = props; + const { object, evaluation, onInvokeGetterButtonClick } = props; + + if (evaluation) { + const { Rep, Grip } = __webpack_require__(3647); + return span({ + className: "objectBox objectBox-accessor objectTitle" + }, Rep(_extends({}, props, { + object: evaluation.getterValue, + mode: props.mode || MODE.TINY, + defaultRep: Grip + }))); + } + + if (hasGetter(object) && onInvokeGetterButtonClick) { + return dom.button({ + className: "invoke-getter", + title: "Invoke getter", + onClick: event => { + onInvokeGetterButtonClick(); + event.stopPropagation(); + } + }); + } const accessors = []; if (hasGetter(object)) { accessors.push("Getter"); } + if (hasSetter(object)) { accessors.push("Setter"); } - const title = accessors.join(" & "); - return span({ className: "objectBox objectBox-accessor objectTitle" }, title); + return span({ className: "objectBox objectBox-accessor objectTitle" }, accessors.join(" & ")); } function hasGetter(object) { diff --git a/devtools/client/shared/vendor/WASMPARSER_UPGRADING b/devtools/client/shared/vendor/WASMPARSER_UPGRADING index 88caa491899d..59db3a8cd2d1 100644 --- a/devtools/client/shared/vendor/WASMPARSER_UPGRADING +++ b/devtools/client/shared/vendor/WASMPARSER_UPGRADING @@ -1,13 +1,13 @@ # wasmparser version -Current vesion is: 0.6.1 +Current vesion is: 0.6.2 # Upgrade process 1. Pull latest release from npm and extract WasmDis.js and WasmParser.js, e.g. ``` -curl https://registry.npmjs.org/wasmparser/-/wasmparser-0.6.1.tgz | tar -x --strip-components 2 package/dist/{WasmDis,WasmParser}.js +curl https://registry.npmjs.org/wasmparser/-/wasmparser-0.6.2.tgz | tar -x --strip-components 2 package/dist/{WasmDis,WasmParser}.js ``` 2. Remove reference to source maps (last line) diff --git a/devtools/client/shared/vendor/WasmDis.js b/devtools/client/shared/vendor/WasmDis.js index e84b2b975769..82574b2724cb 100644 --- a/devtools/client/shared/vendor/WasmDis.js +++ b/devtools/client/shared/vendor/WasmDis.js @@ -631,7 +631,7 @@ var WasmDisassembler = /** @class */ (function () { this.appendBuffer(" " + operator.literal.toString()); break; case 66 /* i64_const */: - this.appendBuffer(" " + operator.literal.toDouble()); + this.appendBuffer(" " + operator.literal.toString()); break; case 67 /* f32_const */: this.appendBuffer(" " + formatFloat32(operator.literal)); diff --git a/devtools/client/shared/vendor/WasmParser.js b/devtools/client/shared/vendor/WasmParser.js index 5852ede7c4b2..71b9afc11fce 100644 --- a/devtools/client/shared/vendor/WasmParser.js +++ b/devtools/client/shared/vendor/WasmParser.js @@ -414,6 +414,36 @@ var Int64 = /** @class */ (function () { } return sum; }; + Int64.prototype.toString = function () { + var low = (this._data[0] | (this._data[1] << 8) | (this._data[2] << 16) | (this._data[3] << 24)) >>> 0; + var high = (this._data[4] | (this._data[5] << 8) | (this._data[6] << 16) | (this._data[7] << 24)) >>> 0; + if (low === 0 && high === 0) { + return '0'; + } + var sign = false; + if (high >> 31) { + high = 4294967296 - high; + if (low > 0) { + high--; + low = 4294967296 - low; + } + sign = true; + } + var buf = []; + while (high > 0) { + var t = ((high % 10) * 4294967296) + low; + high = Math.floor(high / 10); + buf.unshift((t % 10).toString()); + low = Math.floor(t / 10); + } + while (low > 0) { + buf.unshift((low % 10).toString()); + low = Math.floor(low / 10); + } + if (sign) + buf.unshift('-'); + return buf.join(''); + }; Object.defineProperty(Int64.prototype, "data", { get: function () { return this._data;