зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1541631 - Part 8: Store breakable-line and breakpoint-position data in the source-actor store. r=jlast
Differential Revision: https://phabricator.services.mozilla.com/D42033 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c4521e96b2
Коммит
b5f7346637
|
@ -28,8 +28,8 @@ const mockCommandClient = {
|
|||
}),
|
||||
evaluateExpressions: async () => {},
|
||||
getFrameScopes: async () => {},
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
|
||||
describe("getInScopeLine", () => {
|
||||
|
|
|
@ -33,6 +33,7 @@ import {
|
|||
} from "../../utils/memoizableAction";
|
||||
import { fulfilled } from "../../utils/async-value";
|
||||
import type { ThunkArgs } from "../../actions/types";
|
||||
import { loadSourceActorBreakpointColumns } from "../source-actors";
|
||||
|
||||
async function mapLocations(
|
||||
generatedLocations: SourceLocation[],
|
||||
|
@ -113,7 +114,7 @@ async function _setBreakpointPositions(cx, sourceId, line, thunkArgs) {
|
|||
return;
|
||||
}
|
||||
|
||||
let results = {};
|
||||
const results = {};
|
||||
if (isOriginalId(sourceId)) {
|
||||
// Explicitly typing ranges is required to work around the following issue
|
||||
// https://github.com/facebook/flow/issues/5294
|
||||
|
@ -139,12 +140,22 @@ async function _setBreakpointPositions(cx, sourceId, line, thunkArgs) {
|
|||
};
|
||||
}
|
||||
|
||||
const bps = await client.getBreakpointPositions(
|
||||
getSourceActorsForSource(getState(), generatedSource.id),
|
||||
range
|
||||
const actorBps = await Promise.all(
|
||||
getSourceActorsForSource(getState(), generatedSource.id).map(actor =>
|
||||
client.getSourceActorBreakpointPositions(actor, range)
|
||||
)
|
||||
);
|
||||
for (const bpLine in bps) {
|
||||
results[bpLine] = (results[bpLine] || []).concat(bps[bpLine]);
|
||||
|
||||
for (const actorPositions of actorBps) {
|
||||
for (const rangeLine of Object.keys(actorPositions)) {
|
||||
let columns = actorPositions[parseInt(rangeLine, 10)];
|
||||
const existing = results[rangeLine];
|
||||
if (existing) {
|
||||
columns = [...new Set([...existing, ...columns])];
|
||||
}
|
||||
|
||||
results[rangeLine] = columns;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -152,10 +163,15 @@ async function _setBreakpointPositions(cx, sourceId, line, thunkArgs) {
|
|||
throw new Error("Line is required for generated sources");
|
||||
}
|
||||
|
||||
results = await client.getBreakpointPositions(
|
||||
getSourceActorsForSource(getState(), generatedSource.id),
|
||||
{ start: { line, column: 0 }, end: { line: line + 1, column: 0 } }
|
||||
const actorColumns = await Promise.all(
|
||||
getSourceActorsForSource(getState(), generatedSource.id).map(actor =>
|
||||
dispatch(loadSourceActorBreakpointColumns({ id: actor.id, line }))
|
||||
)
|
||||
);
|
||||
|
||||
for (const columns of actorColumns) {
|
||||
results[line] = (results[line] || []).concat(columns);
|
||||
}
|
||||
}
|
||||
|
||||
let positions = convertToList(results, generatedSource);
|
||||
|
|
|
@ -18,8 +18,8 @@ describe("breakpointPositions", () => {
|
|||
const fooContent = createSource("foo", "");
|
||||
|
||||
const store = createStore({
|
||||
getBreakpointPositions: async () => ({ "9": [1] }),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({ "9": [1] }),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
sourceContents: async () => fooContent,
|
||||
});
|
||||
|
||||
|
@ -63,12 +63,12 @@ describe("breakpointPositions", () => {
|
|||
let resolve = _ => {};
|
||||
let count = 0;
|
||||
const store = createStore({
|
||||
getBreakpointPositions: () =>
|
||||
getSourceActorBreakpointPositions: () =>
|
||||
new Promise(r => {
|
||||
count++;
|
||||
resolve = r;
|
||||
}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
sourceContents: async () => fooContent,
|
||||
});
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ import { mockCommandClient } from "../../tests/helpers/mockCommandClient";
|
|||
function mockClient(positionsResponse = {}) {
|
||||
return {
|
||||
...mockCommandClient,
|
||||
getBreakpointPositions: async () => positionsResponse,
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => positionsResponse,
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ const mockCommandClient = {
|
|||
}
|
||||
});
|
||||
},
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
actorID: "threadActorID",
|
||||
};
|
||||
|
||||
|
@ -176,7 +176,7 @@ describe("pause", () => {
|
|||
it("should step over when paused after an await", async () => {
|
||||
const store = createStore({
|
||||
...mockCommandClient,
|
||||
getBreakpointPositions: async () => ({ [2]: [1] }),
|
||||
getSourceActorBreakpointPositions: async () => ({ [2]: [1] }),
|
||||
});
|
||||
const { dispatch, getState } = store;
|
||||
const mockPauseInfo = createPauseInfo({
|
||||
|
|
|
@ -5,7 +5,18 @@
|
|||
// @flow
|
||||
|
||||
import type { ThunkArgs } from "./types";
|
||||
import type { SourceActor } from "../reducers/source-actors";
|
||||
import {
|
||||
getSourceActor,
|
||||
getSourceActorBreakableLines,
|
||||
getSourceActorBreakpointColumns,
|
||||
type SourceActorId,
|
||||
type SourceActor,
|
||||
} from "../reducers/source-actors";
|
||||
import {
|
||||
memoizeableAction,
|
||||
type MemoizedAction,
|
||||
} from "../utils/memoizableAction";
|
||||
import { PROMISE } from "./utils/middleware/promise";
|
||||
|
||||
export function insertSourceActor(item: SourceActor) {
|
||||
return insertSourceActors([item]);
|
||||
|
@ -30,3 +41,48 @@ export function removeSourceActors(items: Array<SourceActor>) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const loadSourceActorBreakpointColumns: MemoizedAction<
|
||||
{ id: SourceActorId, line: number },
|
||||
Array<number>
|
||||
> = memoizeableAction("loadSourceActorBreakpointColumns", {
|
||||
createKey: ({ id, line }) => `${id}:${line}`,
|
||||
getValue: ({ id, line }, { getState }) =>
|
||||
getSourceActorBreakpointColumns(getState(), id, line),
|
||||
action: async ({ id, line }, { dispatch, getState, client }) => {
|
||||
await dispatch({
|
||||
type: "SET_SOURCE_ACTOR_BREAKPOINT_COLUMNS",
|
||||
sourceId: id,
|
||||
line,
|
||||
[PROMISE]: (async () => {
|
||||
const positions = await client.getSourceActorBreakpointPositions(
|
||||
getSourceActor(getState(), id),
|
||||
{
|
||||
start: { line, column: 0 },
|
||||
end: { line: line + 1, column: 0 },
|
||||
}
|
||||
);
|
||||
|
||||
return positions[line] || [];
|
||||
})(),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const loadSourceActorBreakableLines: MemoizedAction<
|
||||
{ id: SourceActorId },
|
||||
Array<number>
|
||||
> = memoizeableAction("loadSourceActorBreakableLines", {
|
||||
createKey: args => args.id,
|
||||
getValue: ({ id }, { getState }) =>
|
||||
getSourceActorBreakableLines(getState(), id),
|
||||
action: async ({ id }, { dispatch, getState, client }) => {
|
||||
await dispatch({
|
||||
type: "SET_SOURCE_ACTOR_BREAKABLE_LINES",
|
||||
sourceId: id,
|
||||
[PROMISE]: client.getSourceActorBreakableLines(
|
||||
getSourceActor(getState(), id)
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import { setBreakpointPositions } from "../breakpoints/breakpointPositions";
|
|||
import { union } from "lodash";
|
||||
import type { Context } from "../../types";
|
||||
import type { ThunkArgs } from "../../actions/types";
|
||||
import { loadSourceActorBreakableLines } from "../source-actors";
|
||||
|
||||
function calculateBreakableLines(positions) {
|
||||
const lines = [];
|
||||
|
@ -30,11 +31,6 @@ export function setBreakableLines(cx: Context, sourceId: string) {
|
|||
setBreakpointPositions({ cx, sourceId })
|
||||
);
|
||||
breakableLines = calculateBreakableLines(positions);
|
||||
} else {
|
||||
breakableLines = await client.getBreakableLines(
|
||||
getSourceActorsForSource(getState(), sourceId)
|
||||
);
|
||||
}
|
||||
|
||||
const existingBreakableLines = getBreakableLines(getState(), sourceId);
|
||||
if (existingBreakableLines) {
|
||||
|
@ -42,10 +38,19 @@ export function setBreakableLines(cx: Context, sourceId: string) {
|
|||
}
|
||||
|
||||
dispatch({
|
||||
type: "SET_BREAKABLE_LINES",
|
||||
type: "SET_ORIGINAL_BREAKABLE_LINES",
|
||||
cx,
|
||||
sourceId,
|
||||
breakableLines,
|
||||
});
|
||||
} else {
|
||||
const actors = getSourceActorsForSource(getState(), sourceId);
|
||||
|
||||
await Promise.all(
|
||||
actors.map(actor =>
|
||||
dispatch(loadSourceActorBreakableLines({ id: actor.id }))
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("blackbox", () => {
|
|||
it("should blackbox a source", async () => {
|
||||
const store = createStore({
|
||||
blackBox: async () => true,
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
const { dispatch, getState, cx } = store;
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ describe("loadSourceText", () => {
|
|||
{
|
||||
...mockCommandClient,
|
||||
sourceContents: async () => fooGenContent,
|
||||
getBreakpointPositions: async () => ({ "1": [0] }),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({ "1": [0] }),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
},
|
||||
{},
|
||||
{
|
||||
|
@ -156,8 +156,8 @@ describe("loadSourceText", () => {
|
|||
count++;
|
||||
resolve = r;
|
||||
}),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
const id = "foo";
|
||||
|
||||
|
@ -194,8 +194,8 @@ describe("loadSourceText", () => {
|
|||
count++;
|
||||
resolve = r;
|
||||
}),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
const id = "foo";
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import readFixture from "./helpers/readFixture";
|
||||
const { getSymbols, isSymbolsLoading, getFramework } = selectors;
|
||||
|
||||
const threadFront = {
|
||||
const mockCommandClient = {
|
||||
sourceContents: async ({ source }) => ({
|
||||
source: sourceTexts[source],
|
||||
contentType: "text/javascript",
|
||||
|
@ -26,8 +26,8 @@ const threadFront = {
|
|||
evaluate: async expression => ({ result: evaluationResult[expression] }),
|
||||
evaluateExpressions: async expressions =>
|
||||
expressions.map(expression => ({ result: evaluationResult[expression] })),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
|
||||
const sourceMaps = {
|
||||
|
@ -56,7 +56,7 @@ describe("ast", () => {
|
|||
describe("setSymbols", () => {
|
||||
describe("when the source is loaded", () => {
|
||||
it("should be able to set symbols", async () => {
|
||||
const store = createStore(threadFront);
|
||||
const store = createStore(mockCommandClient);
|
||||
const { dispatch, getState, cx } = store;
|
||||
const base = await dispatch(
|
||||
actions.newGeneratedSource(makeSource("base.js"))
|
||||
|
@ -74,7 +74,7 @@ describe("ast", () => {
|
|||
|
||||
describe("when the source is not loaded", () => {
|
||||
it("should return null", async () => {
|
||||
const { getState, dispatch } = createStore(threadFront);
|
||||
const { getState, dispatch } = createStore(mockCommandClient);
|
||||
const base = await dispatch(
|
||||
actions.newGeneratedSource(makeSource("base.js"))
|
||||
);
|
||||
|
@ -86,7 +86,7 @@ describe("ast", () => {
|
|||
|
||||
describe("when there is no source", () => {
|
||||
it("should return null", async () => {
|
||||
const { getState } = createStore(threadFront);
|
||||
const { getState } = createStore(mockCommandClient);
|
||||
const baseSymbols = getSymbols(getState());
|
||||
expect(baseSymbols).toEqual(null);
|
||||
});
|
||||
|
@ -94,7 +94,7 @@ describe("ast", () => {
|
|||
|
||||
describe("frameworks", () => {
|
||||
it("should detect react components", async () => {
|
||||
const store = createStore(threadFront, {}, sourceMaps);
|
||||
const store = createStore(mockCommandClient, {}, sourceMaps);
|
||||
const { cx, dispatch, getState } = store;
|
||||
|
||||
const genSource = await dispatch(
|
||||
|
@ -113,7 +113,7 @@ describe("ast", () => {
|
|||
});
|
||||
|
||||
it("should not give false positive on non react components", async () => {
|
||||
const store = createStore(threadFront);
|
||||
const store = createStore(mockCommandClient);
|
||||
const { cx, dispatch, getState } = store;
|
||||
const base = await dispatch(
|
||||
actions.newGeneratedSource(makeSource("base.js"))
|
||||
|
|
|
@ -37,8 +37,8 @@ const mockThreadFront = {
|
|||
),
|
||||
getFrameScopes: async () => {},
|
||||
sourceContents: () => ({ source: "", contentType: "text/javascript" }),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
autocomplete: () => {
|
||||
return new Promise(resolve => {
|
||||
resolve({
|
||||
|
|
|
@ -49,6 +49,6 @@ export const mockCommandClient = {
|
|||
threadFront: async () => {},
|
||||
getFrameScopes: async () => {},
|
||||
evaluateExpressions: async () => {},
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
|
|
|
@ -27,8 +27,8 @@ const threadFront = {
|
|||
source: "function foo1() {\n const foo = 5; return foo;\n}",
|
||||
contentType: "text/javascript",
|
||||
}),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
detachWorkers: () => {},
|
||||
};
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ function mockClient(bpPos = {}) {
|
|||
return {
|
||||
...mockCommandClient,
|
||||
|
||||
getBreakpointPositions: async () => bpPos,
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => bpPos,
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ function mockThreadFront(overrides) {
|
|||
source: "",
|
||||
contentType: "text/javascript",
|
||||
}),
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
evaluateExpressions: async () => [],
|
||||
loadObjectProperties: async () => ({}),
|
||||
...overrides,
|
||||
|
|
|
@ -39,8 +39,8 @@ const sources = {
|
|||
|
||||
const threadFront = {
|
||||
sourceContents: async ({ source }) => sources[source],
|
||||
getBreakpointPositions: async () => ({}),
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakpointPositions: async () => ({}),
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
};
|
||||
|
||||
describe("project text search", () => {
|
||||
|
|
|
@ -43,7 +43,7 @@ describe("setProjectDirectoryRoot", () => {
|
|||
|
||||
it("should filter sources", async () => {
|
||||
const store = createStore({
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
const { dispatch, getState, cx } = store;
|
||||
await dispatch(actions.newGeneratedSource(makeSource("js/scopes.js")));
|
||||
|
@ -65,7 +65,7 @@ describe("setProjectDirectoryRoot", () => {
|
|||
|
||||
it("should update the child directory ", () => {
|
||||
const { dispatch, getState, cx } = createStore({
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
dispatch(actions.setProjectDirectoryRoot(cx, "example.com"));
|
||||
dispatch(actions.setProjectDirectoryRoot(cx, "example.com/foo/bar"));
|
||||
|
@ -74,7 +74,7 @@ describe("setProjectDirectoryRoot", () => {
|
|||
|
||||
it("should update the child directory when domain name is Webpack://", () => {
|
||||
const { dispatch, getState, cx } = createStore({
|
||||
getBreakableLines: async () => [],
|
||||
getSourceActorBreakableLines: async () => [],
|
||||
});
|
||||
dispatch(actions.setProjectDirectoryRoot(cx, "webpack://"));
|
||||
dispatch(actions.setProjectDirectoryRoot(cx, "webpack:///app"));
|
||||
|
|
|
@ -77,7 +77,7 @@ export type SourceAction =
|
|||
+tabs: any,
|
||||
|}
|
||||
| {|
|
||||
type: "SET_BREAKABLE_LINES",
|
||||
type: "SET_ORIGINAL_BREAKABLE_LINES",
|
||||
+cx: Context,
|
||||
breakableLines: number[],
|
||||
sourceId: string,
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
// @flow
|
||||
|
||||
import type { SourceActor } from "../../reducers/source-actors.js";
|
||||
import { type PromiseAction } from "../utils/middleware/promise";
|
||||
import type {
|
||||
SourceActorId,
|
||||
SourceActor,
|
||||
} from "../../reducers/source-actors.js";
|
||||
|
||||
export type SourceActorsInsertAction = {|
|
||||
type: "INSERT_SOURCE_ACTORS",
|
||||
|
@ -15,6 +19,25 @@ export type SourceActorsRemoveAction = {|
|
|||
items: Array<SourceActor>,
|
||||
|};
|
||||
|
||||
export type SourceActorBreakpointColumnsAction = PromiseAction<
|
||||
{|
|
||||
type: "SET_SOURCE_ACTOR_BREAKPOINT_COLUMNS",
|
||||
sourceId: SourceActorId,
|
||||
line: number,
|
||||
|},
|
||||
Array<number>
|
||||
>;
|
||||
|
||||
export type SourceActorBreakableLinesAction = PromiseAction<
|
||||
{|
|
||||
type: "SET_SOURCE_ACTOR_BREAKABLE_LINES",
|
||||
sourceId: SourceActorId,
|
||||
|},
|
||||
Array<number>
|
||||
>;
|
||||
|
||||
export type SourceActorAction =
|
||||
| SourceActorsInsertAction
|
||||
| SourceActorsRemoveAction;
|
||||
| SourceActorsRemoveAction
|
||||
| SourceActorBreakpointColumnsAction
|
||||
| SourceActorBreakableLinesAction;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import { fromPairs, toPairs } from "lodash";
|
||||
import { executeSoon } from "../../../utils/DevToolsUtils";
|
||||
|
||||
import type { ThunkArgs } from "../../types";
|
||||
|
||||
type BasePromiseAction = {|
|
||||
|
@ -30,7 +29,25 @@ export type ErrorPromiseAction = {|
|
|||
+error: any,
|
||||
|};
|
||||
|
||||
export type PromiseAction<Action, Value = any> =
|
||||
import {
|
||||
pending,
|
||||
rejected,
|
||||
fulfilled,
|
||||
type AsyncValue,
|
||||
} from "../../../utils/async-value";
|
||||
export function asyncActionAsValue<T>(
|
||||
action: PromiseAction<mixed, T>
|
||||
): AsyncValue<T> {
|
||||
if (action.status === "start") {
|
||||
return pending();
|
||||
}
|
||||
if (action.status === "error") {
|
||||
return rejected(action.error);
|
||||
}
|
||||
return fulfilled(action.value);
|
||||
}
|
||||
|
||||
export type PromiseAction<+Action, Value = any> =
|
||||
// | {| ...Action, "@@dispatch/promise": Promise<Object> |}
|
||||
| {|
|
||||
...BasePromiseAction,
|
||||
|
|
|
@ -449,33 +449,19 @@ function getMainThread() {
|
|||
return threadFront.actor;
|
||||
}
|
||||
|
||||
async function getBreakpointPositions(
|
||||
actors: Array<SourceActor>,
|
||||
range: ?Range
|
||||
): Promise<{ [string]: number[] }> {
|
||||
const sourcePositions = {};
|
||||
|
||||
for (const { thread, actor } of actors) {
|
||||
async function getSourceActorBreakpointPositions(
|
||||
{ thread, actor }: SourceActor,
|
||||
range: Range
|
||||
): Promise<{ [number]: number[] }> {
|
||||
const sourceThreadFront = lookupThreadFront(thread);
|
||||
const sourceFront = sourceThreadFront.source({ actor });
|
||||
const positions = await sourceFront.getBreakpointPositionsCompressed(range);
|
||||
|
||||
for (const line of Object.keys(positions)) {
|
||||
let columns = positions[line];
|
||||
const existing = sourcePositions[line];
|
||||
if (existing) {
|
||||
columns = [...new Set([...existing, ...columns])];
|
||||
return sourceFront.getBreakpointPositionsCompressed(range);
|
||||
}
|
||||
|
||||
sourcePositions[line] = columns;
|
||||
}
|
||||
}
|
||||
return sourcePositions;
|
||||
}
|
||||
|
||||
async function getBreakableLines(actors: Array<SourceActor>) {
|
||||
let lines = [];
|
||||
for (const { thread, actor } of actors) {
|
||||
async function getSourceActorBreakableLines({
|
||||
thread,
|
||||
actor,
|
||||
}: SourceActor): Promise<Array<number>> {
|
||||
const sourceThreadFront = lookupThreadFront(thread);
|
||||
const sourceFront = sourceThreadFront.source({ actor });
|
||||
let actorLines = [];
|
||||
|
@ -494,10 +480,7 @@ async function getBreakableLines(actors: Array<SourceActor>) {
|
|||
}
|
||||
}
|
||||
|
||||
lines = [...new Set([...lines, ...actorLines])];
|
||||
}
|
||||
|
||||
return lines;
|
||||
return actorLines;
|
||||
}
|
||||
|
||||
const clientCommands = {
|
||||
|
@ -517,8 +500,8 @@ const clientCommands = {
|
|||
breakOnNext,
|
||||
sourceContents,
|
||||
getSourceForActor,
|
||||
getBreakpointPositions,
|
||||
getBreakableLines,
|
||||
getSourceActorBreakpointPositions,
|
||||
getSourceActorBreakableLines,
|
||||
hasBreakpoint,
|
||||
setBreakpoint,
|
||||
setXHRBreakpoint,
|
||||
|
|
|
@ -6,20 +6,35 @@
|
|||
|
||||
import type { Action } from "../actions/types";
|
||||
import type { SourceId, ThreadId } from "../types";
|
||||
import {
|
||||
asSettled,
|
||||
type AsyncValue,
|
||||
type SettledValue,
|
||||
} from "../utils/async-value";
|
||||
import {
|
||||
createInitial,
|
||||
insertResources,
|
||||
updateResources,
|
||||
removeResources,
|
||||
hasResource,
|
||||
getResource,
|
||||
getMappedResource,
|
||||
makeWeakQuery,
|
||||
makeIdQuery,
|
||||
makeReduceAllQuery,
|
||||
type Resource,
|
||||
type ResourceState,
|
||||
type WeakQuery,
|
||||
type IdQuery,
|
||||
type ReduceAllQuery,
|
||||
} from "../utils/resource";
|
||||
|
||||
import { asyncActionAsValue } from "../actions/utils/middleware/promise";
|
||||
import type {
|
||||
SourceActorBreakpointColumnsAction,
|
||||
SourceActorBreakableLinesAction,
|
||||
} from "../actions/types/SourceActorAction";
|
||||
|
||||
export opaque type SourceActorId: string = string;
|
||||
export type SourceActor = {|
|
||||
+id: SourceActorId,
|
||||
|
@ -47,6 +62,12 @@ export type SourceActor = {|
|
|||
|
||||
type SourceActorResource = Resource<{
|
||||
...SourceActor,
|
||||
|
||||
// The list of breakpoint positions on each line of the file.
|
||||
breakpointPositions: Map<number, AsyncValue<Array<number>>>,
|
||||
|
||||
// The list of lines that contain breakpoints.
|
||||
breakableLines: AsyncValue<Array<number>> | null,
|
||||
}>;
|
||||
export type SourceActorsState = ResourceState<SourceActorResource>;
|
||||
export type SourceActorOuterState = { sourceActors: SourceActorsState };
|
||||
|
@ -60,7 +81,14 @@ export default function update(
|
|||
switch (action.type) {
|
||||
case "INSERT_SOURCE_ACTORS": {
|
||||
const { items } = action;
|
||||
state = insertResources(state, items);
|
||||
state = insertResources(
|
||||
state,
|
||||
items.map(item => ({
|
||||
...item,
|
||||
breakpointPositions: new Map(),
|
||||
breakableLines: null,
|
||||
}))
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "REMOVE_SOURCE_ACTORS": {
|
||||
|
@ -73,13 +101,58 @@ export default function update(
|
|||
state = initial;
|
||||
break;
|
||||
}
|
||||
|
||||
case "SET_SOURCE_ACTOR_BREAKPOINT_COLUMNS":
|
||||
state = updateBreakpointColumns(state, action);
|
||||
break;
|
||||
|
||||
case "SET_SOURCE_ACTOR_BREAKABLE_LINES":
|
||||
state = updateBreakableLines(state, action);
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export function resourceAsSourceActor(r: SourceActorResource): SourceActor {
|
||||
return r;
|
||||
function updateBreakpointColumns(
|
||||
state: SourceActorsState,
|
||||
action: SourceActorBreakpointColumnsAction
|
||||
): SourceActorsState {
|
||||
const { sourceId, line } = action;
|
||||
const value = asyncActionAsValue(action);
|
||||
|
||||
if (!hasResource(state, sourceId)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const breakpointPositions = new Map(
|
||||
getResource(state, sourceId).breakpointPositions
|
||||
);
|
||||
breakpointPositions.set(line, value);
|
||||
|
||||
return updateResources(state, [{ id: sourceId, breakpointPositions }]);
|
||||
}
|
||||
|
||||
function updateBreakableLines(
|
||||
state: SourceActorsState,
|
||||
action: SourceActorBreakableLinesAction
|
||||
): SourceActorsState {
|
||||
const value = asyncActionAsValue(action);
|
||||
const { sourceId } = action;
|
||||
|
||||
if (!hasResource(state, sourceId)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return updateResources(state, [{ id: sourceId, breakableLines: value }]);
|
||||
}
|
||||
|
||||
export function resourceAsSourceActor({
|
||||
breakpointPositions,
|
||||
breakableLines,
|
||||
...sourceActor
|
||||
}: SourceActorResource): SourceActor {
|
||||
return sourceActor;
|
||||
}
|
||||
|
||||
// Because we are using an opaque type for our source actor IDs, these
|
||||
|
@ -101,7 +174,7 @@ export function getSourceActor(
|
|||
state: SourceActorOuterState,
|
||||
id: SourceActorId
|
||||
): SourceActor {
|
||||
return getResource(state.sourceActors, id);
|
||||
return getMappedResource(state.sourceActors, id, resourceAsSourceActor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,3 +239,40 @@ export function getThreadsBySource(
|
|||
): { [SourceId]: Array<ThreadId> } {
|
||||
return queryThreadsBySourceObject(state.sourceActors);
|
||||
}
|
||||
|
||||
export function getSourceActorBreakableLines(
|
||||
state: SourceActorOuterState,
|
||||
id: SourceActorId
|
||||
): SettledValue<Array<number>> | null {
|
||||
const { breakableLines } = getResource(state.sourceActors, id);
|
||||
|
||||
return asSettled(breakableLines);
|
||||
}
|
||||
|
||||
export function getSourceActorBreakpointColumns(
|
||||
state: SourceActorOuterState,
|
||||
id: SourceActorId,
|
||||
line: number
|
||||
): SettledValue<Array<number>> | null {
|
||||
const { breakpointPositions } = getResource(state.sourceActors, id);
|
||||
|
||||
return asSettled(breakpointPositions.get(line) || null);
|
||||
}
|
||||
|
||||
export const getBreakableLinesForSourceActors: WeakQuery<
|
||||
SourceActorResource,
|
||||
Array<SourceActorId>,
|
||||
Array<number>
|
||||
> = makeWeakQuery({
|
||||
filter: (state, ids) => ids,
|
||||
map: ({ breakableLines }) => breakableLines,
|
||||
reduce: items =>
|
||||
Array.from(
|
||||
items.reduce((acc, item) => {
|
||||
if (item && item.state === "fulfilled") {
|
||||
acc = acc.concat(item.value);
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
),
|
||||
});
|
||||
|
|
|
@ -47,6 +47,7 @@ import {
|
|||
getSourceActor,
|
||||
getSourceActors,
|
||||
getThreadsBySource,
|
||||
getBreakableLinesForSourceActors,
|
||||
type SourceActorId,
|
||||
type SourceActorOuterState,
|
||||
} from "./source-actors";
|
||||
|
@ -216,7 +217,7 @@ function update(
|
|||
case "SET_PROJECT_DIRECTORY_ROOT":
|
||||
return updateProjectDirectoryRoot(state, action.url);
|
||||
|
||||
case "SET_BREAKABLE_LINES": {
|
||||
case "SET_ORIGINAL_BREAKABLE_LINES": {
|
||||
const { breakableLines, sourceId } = action;
|
||||
return {
|
||||
...state,
|
||||
|
@ -964,18 +965,34 @@ export function getBreakpointPositionsForLocation(
|
|||
return findPosition(positions, location);
|
||||
}
|
||||
|
||||
export function getBreakableLines(state: OuterState, sourceId: string) {
|
||||
export function getBreakableLines(
|
||||
state: OuterState & SourceActorOuterState,
|
||||
sourceId: string
|
||||
): ?Array<number> {
|
||||
if (!sourceId) {
|
||||
return null;
|
||||
}
|
||||
const source = getSource(state, sourceId);
|
||||
if (!source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isOriginalSource(source)) {
|
||||
return state.sources.breakableLines[sourceId];
|
||||
}
|
||||
|
||||
// We pull generated file breakable lines directly from the source actors
|
||||
// so that breakable lines can be added as new source actors on HTML loads.
|
||||
return getBreakableLinesForSourceActors(
|
||||
state.sourceActors,
|
||||
state.sources.actors[sourceId]
|
||||
);
|
||||
}
|
||||
|
||||
export const getSelectedBreakableLines: Selector<Set<number>> = createSelector(
|
||||
state => {
|
||||
const sourceId = getSelectedSourceId(state);
|
||||
return sourceId && state.sources.breakableLines[sourceId];
|
||||
return sourceId && getBreakableLines(state, sourceId);
|
||||
},
|
||||
breakableLines => new Set(breakableLines || [])
|
||||
);
|
||||
|
|
Загрузка…
Ссылка в новой задаче