зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1580334 - Hovering on the timeline should update the debugger.
Differential Revision: https://phabricator.services.mozilla.com/D46550 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d19841f79e
Коммит
f13398b88f
|
@ -168,6 +168,14 @@ DebuggerPanel.prototype = {
|
|||
return this._actions.selectSourceURL(cx, url, { line, column });
|
||||
},
|
||||
|
||||
previewPausedLocation(location) {
|
||||
return this._actions.previewPausedLocation(location);
|
||||
},
|
||||
|
||||
clearPreviewPausedLocation() {
|
||||
return this._actions.clearPreviewPausedLocation();
|
||||
},
|
||||
|
||||
async selectSource(sourceId, line, column) {
|
||||
const cx = this._selectors.getContext(this._getState());
|
||||
const location = { sourceId, line, column };
|
||||
|
|
|
@ -30,3 +30,7 @@ export { toggleSkipPausing, setSkipPausing } from "./skipPausing";
|
|||
export { toggleMapScopes } from "./mapScopes";
|
||||
export { setExpandedScope } from "./expandScopes";
|
||||
export { generateInlinePreview } from "./inlinePreview";
|
||||
export {
|
||||
previewPausedLocation,
|
||||
clearPreviewPausedLocation,
|
||||
} from "./previewPausedLocation";
|
||||
|
|
|
@ -19,6 +19,7 @@ CompiledModules(
|
|||
'mapScopes.js',
|
||||
'paused.js',
|
||||
'pauseOnExceptions.js',
|
||||
'previewPausedLocation.js',
|
||||
'resumed.js',
|
||||
'selectFrame.js',
|
||||
'skipPausing.js',
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* 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/>. */
|
||||
|
||||
// @flow
|
||||
|
||||
import { selectLocation } from "../sources";
|
||||
import { getContext, getSourceByURL } from "../../selectors";
|
||||
import type { ThunkArgs } from "../types";
|
||||
|
||||
type Location = {
|
||||
sourceUrl: string,
|
||||
column: number,
|
||||
line: number,
|
||||
};
|
||||
|
||||
export function previewPausedLocation(location: Location) {
|
||||
return ({ dispatch, getState }: ThunkArgs) => {
|
||||
const cx = getContext(getState());
|
||||
const source = getSourceByURL(getState(), location.sourceUrl);
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceLocation = { ...location, sourceId: source.id };
|
||||
dispatch(selectLocation(cx, sourceLocation));
|
||||
|
||||
dispatch({
|
||||
type: "PREVIEW_PAUSED_LOCATION",
|
||||
location: sourceLocation,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function clearPreviewPausedLocation() {
|
||||
return {
|
||||
type: "CLEAR_PREVIEW_PAUSED_LOCATION",
|
||||
};
|
||||
}
|
|
@ -5,7 +5,13 @@
|
|||
// @flow
|
||||
|
||||
import typeof SourceMaps from "devtools-source-map";
|
||||
import type { ThreadList, Thread, Context, ThreadId } from "../../types";
|
||||
import type {
|
||||
ThreadList,
|
||||
Thread,
|
||||
Context,
|
||||
ThreadId,
|
||||
SourceLocation,
|
||||
} from "../../types";
|
||||
import type { State } from "../../reducers/types";
|
||||
import type { MatchedLocations } from "../../reducers/file-search";
|
||||
import type { TreeNode } from "../../utils/sources-tree/types";
|
||||
|
@ -149,6 +155,13 @@ export type DebuggeeAction =
|
|||
+type: "SELECT_THREAD",
|
||||
+cx: Context,
|
||||
+thread: ThreadId,
|
||||
|}
|
||||
| {|
|
||||
+type: "PREVIEW_PAUSED_LOCATION",
|
||||
+location: SourceLocation,
|
||||
|}
|
||||
| {|
|
||||
+type: "CLEAR_PREVIEW_PAUSED_LOCATION",
|
||||
|};
|
||||
|
||||
export type {
|
||||
|
|
|
@ -20,12 +20,13 @@ import {
|
|||
getPauseReason,
|
||||
getSourceWithContent,
|
||||
getCurrentThread,
|
||||
getPausePreviewLocation,
|
||||
} from "../../selectors";
|
||||
|
||||
import type { Frame, Why, SourceWithContent } from "../../types";
|
||||
import type { SourceLocation, Why, SourceWithContent } from "../../types";
|
||||
|
||||
type Props = {
|
||||
frame: Frame,
|
||||
location: SourceLocation,
|
||||
why: Why,
|
||||
source: ?SourceWithContent,
|
||||
};
|
||||
|
@ -35,42 +36,40 @@ type TextClasses = {
|
|||
lineClass: string,
|
||||
};
|
||||
|
||||
function isDocumentReady(source: ?SourceWithContent, frame) {
|
||||
return (
|
||||
frame && source && source.content && hasDocument(frame.location.sourceId)
|
||||
);
|
||||
function isDocumentReady(source: ?SourceWithContent, location) {
|
||||
return location && source && source.content && hasDocument(location.sourceId);
|
||||
}
|
||||
|
||||
export class DebugLine extends PureComponent<Props> {
|
||||
debugExpression: null;
|
||||
|
||||
componentDidMount() {
|
||||
const { why, frame, source } = this.props;
|
||||
this.setDebugLine(why, frame, source);
|
||||
const { why, location, source } = this.props;
|
||||
this.setDebugLine(why, location, source);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { why, frame, source } = this.props;
|
||||
this.clearDebugLine(why, frame, source);
|
||||
const { why, location, source } = this.props;
|
||||
this.clearDebugLine(why, location, source);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const { why, frame, source } = this.props;
|
||||
const { why, location, source } = this.props;
|
||||
|
||||
startOperation();
|
||||
this.clearDebugLine(prevProps.why, prevProps.frame, prevProps.source);
|
||||
this.setDebugLine(why, frame, source);
|
||||
this.clearDebugLine(prevProps.why, prevProps.location, prevProps.source);
|
||||
this.setDebugLine(why, location, source);
|
||||
endOperation();
|
||||
}
|
||||
|
||||
setDebugLine(why: Why, frame: Frame, source: ?SourceWithContent) {
|
||||
if (!isDocumentReady(source, frame)) {
|
||||
setDebugLine(why: Why, location: SourceLocation, source: ?SourceWithContent) {
|
||||
if (!isDocumentReady(source, location)) {
|
||||
return;
|
||||
}
|
||||
const sourceId = frame.location.sourceId;
|
||||
const sourceId = location.sourceId;
|
||||
const doc = getDocument(sourceId);
|
||||
|
||||
let { line, column } = toEditorPosition(frame.location);
|
||||
let { line, column } = toEditorPosition(location);
|
||||
let { markTextClass, lineClass } = this.getTextClasses(why);
|
||||
doc.addLineClass(line, "line", lineClass);
|
||||
|
||||
|
@ -92,8 +91,12 @@ export class DebugLine extends PureComponent<Props> {
|
|||
);
|
||||
}
|
||||
|
||||
clearDebugLine(why: Why, frame: Frame, source: ?SourceWithContent) {
|
||||
if (!isDocumentReady(source, frame)) {
|
||||
clearDebugLine(
|
||||
why: Why,
|
||||
location: SourceLocation,
|
||||
source: ?SourceWithContent
|
||||
) {
|
||||
if (!isDocumentReady(source, location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,15 +104,15 @@ export class DebugLine extends PureComponent<Props> {
|
|||
this.debugExpression.clear();
|
||||
}
|
||||
|
||||
const sourceId = frame.location.sourceId;
|
||||
const { line } = toEditorPosition(frame.location);
|
||||
const sourceId = location.sourceId;
|
||||
const { line } = toEditorPosition(location);
|
||||
const doc = getDocument(sourceId);
|
||||
const { lineClass } = this.getTextClasses(why);
|
||||
doc.removeLineClass(line, "line", lineClass);
|
||||
}
|
||||
|
||||
getTextClasses(why: Why): TextClasses {
|
||||
if (isException(why)) {
|
||||
if (why && isException(why)) {
|
||||
return {
|
||||
markTextClass: "debug-expression-error",
|
||||
lineClass: "new-debug-line-error",
|
||||
|
@ -126,9 +129,12 @@ export class DebugLine extends PureComponent<Props> {
|
|||
|
||||
const mapStateToProps = state => {
|
||||
const frame = getVisibleSelectedFrame(state);
|
||||
const previewLocation = getPausePreviewLocation(state);
|
||||
const location = previewLocation || (frame && frame.location);
|
||||
return {
|
||||
frame,
|
||||
source: frame && getSourceWithContent(state, frame.location.sourceId),
|
||||
location,
|
||||
source: location && getSourceWithContent(state, location.sourceId),
|
||||
why: getPauseReason(state, getCurrentThread(state)),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -41,13 +41,11 @@ function generateDefaults(editor, overrides) {
|
|||
};
|
||||
}
|
||||
|
||||
function createFrame(line) {
|
||||
function createLocation(line) {
|
||||
return {
|
||||
location: {
|
||||
sourceId: "foo",
|
||||
line,
|
||||
column: 2,
|
||||
},
|
||||
sourceId: "foo",
|
||||
line,
|
||||
column: 2,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,9 +78,9 @@ describe("DebugLine Component", () => {
|
|||
},
|
||||
});
|
||||
const line = 2;
|
||||
const frame = createFrame(line);
|
||||
const location = createLocation(line);
|
||||
|
||||
component.setProps({ ...props, frame });
|
||||
component.setProps({ ...props, location });
|
||||
|
||||
expect(doc.removeLineClass.mock.calls).toEqual([]);
|
||||
expect(doc.addLineClass.mock.calls).toEqual([
|
||||
|
@ -107,10 +105,10 @@ describe("DebugLine Component", () => {
|
|||
const firstLine = 2;
|
||||
const secondLine = 2;
|
||||
|
||||
component.setProps({ ...props, frame: createFrame(firstLine) });
|
||||
component.setProps({ ...props, location: createLocation(firstLine) });
|
||||
component.setProps({
|
||||
...props,
|
||||
frame: createFrame(secondLine),
|
||||
frame: createLocation(secondLine),
|
||||
});
|
||||
|
||||
expect(doc.removeLineClass.mock.calls).toEqual([
|
||||
|
@ -143,9 +141,9 @@ describe("DebugLine Component", () => {
|
|||
it("should not set the debug line", () => {
|
||||
const { component, props, doc } = render({ frame: null });
|
||||
const line = 2;
|
||||
const frame = createFrame(line);
|
||||
const location = createLocation(line);
|
||||
|
||||
component.setProps({ ...props, frame });
|
||||
component.setProps({ ...props, location });
|
||||
expect(doc.removeLineClass).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
// @flow
|
||||
/* eslint complexity: ["error", 30]*/
|
||||
/* eslint complexity: ["error", 35]*/
|
||||
|
||||
/**
|
||||
* Pause reducer
|
||||
|
@ -29,6 +29,7 @@ import type {
|
|||
Context,
|
||||
ThreadContext,
|
||||
Previews,
|
||||
SourceLocation,
|
||||
} from "../types";
|
||||
|
||||
export type Command =
|
||||
|
@ -96,6 +97,7 @@ export type PauseState = {
|
|||
mapScopes: boolean,
|
||||
shouldPauseOnExceptions: boolean,
|
||||
shouldPauseOnCaughtExceptions: boolean,
|
||||
previewLocation: ?SourceLocation,
|
||||
};
|
||||
|
||||
function createPauseState(thread: ThreadId = "UnknownThread") {
|
||||
|
@ -109,6 +111,7 @@ function createPauseState(thread: ThreadId = "UnknownThread") {
|
|||
isPaused: false,
|
||||
pauseCounter: 0,
|
||||
},
|
||||
previewLocation: null,
|
||||
threads: {},
|
||||
canRewind: false,
|
||||
skipPausing: prefs.skipPausing,
|
||||
|
@ -191,6 +194,7 @@ function update(
|
|||
|
||||
state = {
|
||||
...state,
|
||||
previewLocation: null,
|
||||
threadcx: {
|
||||
...state.threadcx,
|
||||
pauseCounter: state.threadcx.pauseCounter + 1,
|
||||
|
@ -207,6 +211,14 @@ function update(
|
|||
});
|
||||
}
|
||||
|
||||
case "PREVIEW_PAUSED_LOCATION": {
|
||||
return { ...state, previewLocation: action.location };
|
||||
}
|
||||
|
||||
case "CLEAR_PREVIEW_PAUSED_LOCATION": {
|
||||
return { ...state, previewLocation: null };
|
||||
}
|
||||
|
||||
case "MAP_FRAMES": {
|
||||
const { selectedFrameId, frames } = action;
|
||||
return updateThreadState({ frames, selectedFrameId });
|
||||
|
@ -677,4 +689,8 @@ export function getLastExpandedScopes(state: State, thread: ThreadId) {
|
|||
return getThreadPauseState(state.pause, thread).lastExpandedScopes;
|
||||
}
|
||||
|
||||
export function getPausePreviewLocation(state: State) {
|
||||
return state.pause.previewLocation;
|
||||
}
|
||||
|
||||
export default update;
|
||||
|
|
|
@ -101,6 +101,13 @@ function sameLocation(m1, m2) {
|
|||
);
|
||||
}
|
||||
|
||||
function getMessageLocation(message) {
|
||||
const {
|
||||
frame: { source, line, column },
|
||||
} = message;
|
||||
return { sourceUrl: source, line, column };
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* The player has 4 valid states
|
||||
|
@ -341,11 +348,6 @@ class WebReplayPlayer extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
async clearPreviewLocation() {
|
||||
const dbg = await this.toolbox.loadTool("jsdebugger");
|
||||
dbg.clearPreviewPausedLocation();
|
||||
}
|
||||
|
||||
unhighlightConsoleMessage() {
|
||||
if (this.hoveredMessage) {
|
||||
this.hoveredMessage.classList.remove("highlight");
|
||||
|
@ -374,9 +376,20 @@ class WebReplayPlayer extends Component {
|
|||
}
|
||||
|
||||
onMessageMouseEnter(message) {
|
||||
this.previewLocation(message);
|
||||
this.showMessage(message);
|
||||
}
|
||||
|
||||
async previewLocation(closestMessage) {
|
||||
const dbg = await this.toolbox.loadTool("jsdebugger");
|
||||
dbg.previewPausedLocation(getMessageLocation(closestMessage));
|
||||
}
|
||||
|
||||
async clearPreviewLocation() {
|
||||
const dbg = await this.toolbox.loadTool("jsdebugger");
|
||||
dbg.clearPreviewPausedLocation();
|
||||
}
|
||||
|
||||
onProgressBarClick(e) {
|
||||
if (!e.altKey) {
|
||||
return;
|
||||
|
@ -403,6 +416,7 @@ class WebReplayPlayer extends Component {
|
|||
|
||||
onPlayerMouseLeave() {
|
||||
this.unhighlightConsoleMessage();
|
||||
this.clearPreviewLocation();
|
||||
return this.threadFront.paintCurrentPoint();
|
||||
}
|
||||
|
||||
|
@ -614,7 +628,7 @@ class WebReplayPlayer extends Component {
|
|||
e.stopPropagation();
|
||||
this.seek(message.executionPoint);
|
||||
},
|
||||
onMouseEnter: () => this.onMessageMouseEnter(message.executionPoint),
|
||||
onMouseEnter: () => this.onMessageMouseEnter(message),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче