Skip to content

Commit

Permalink
Merge branch 'feature-debugger'
Browse files Browse the repository at this point in the history
  • Loading branch information
spaaaacccee committed Dec 10, 2023
2 parents 587e76d + 3e1a617 commit aa30fa2
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 48 deletions.
4 changes: 3 additions & 1 deletion client/src/components/breakpoint-editor/BreakpointEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ export function BreakpointEditor({
value: c.key,
label: startCase(c.key),
}))}
value={value?.condition?.key ?? comparators?.[0]?.key}
value={value.condition?.key ?? comparators?.[0]?.key}
onChange={(v) =>
handleChange({ condition: find(comparators, { key: v }) })
}
/>
<Space />

<TextField
label="Reference"
fullWidth
Expand All @@ -77,6 +78,7 @@ export function BreakpointEditor({
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onChange={(v) => handleChange({ reference: +v.target.value })}
type="number"
disabled={!value.condition?.needsReference}
/>
<Space sx={{ px: 2 }} />
<Switch
Expand Down
15 changes: 10 additions & 5 deletions client/src/components/breakpoint-editor/BreakpointListEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { BreakpointEditor } from "./BreakpointEditor";
import { comparators } from "./comparators";
import { intrinsicProperties } from "./intrinsicProperties";
import { propertyPaths as paths } from "./propertyPaths";
import { useMemo } from "react";

type BreakpointListEditorProps = {
breakpoints?: Breakpoint[];
Expand All @@ -30,11 +31,15 @@ export function BreakpointListEditor({
);
}

const properties = _(layer?.source?.trace?.content?.events)
.flatMap(keys)
.uniq()
.filter((p) => p !== "type")
.value();
const properties = useMemo(
() =>
_(layer?.source?.trace?.content?.events)
.flatMap(keys)
.uniq()
.filter((p) => p !== "type")
.value(),
[layer?.source?.trace?.content?.events]
);

return (
<Box sx={{ overflow: "auto hidden", width: "100%" }}>
Expand Down
14 changes: 11 additions & 3 deletions client/src/components/breakpoint-editor/comparators.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { Comparator } from "slices/UIState";

import { Comparator } from "slices/UIState";

export const comparators: Comparator[] = [
{
key: "equal",
apply: (a, b) => a === b,
needsReference: true,
},
{
key: "less-than",
apply: (a, b) => a < b,
needsReference: true,
},
{
key: "greater-than",
apply: (a, b) => a > b,
needsReference: true,
},
];
{
//find a unique next value (typically for f or g value)
key: "changed",
apply: (a, b) => a != b,
},
];
11 changes: 8 additions & 3 deletions client/src/components/script-editor/ScriptEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ import { ComponentProps } from "react";

const DELAY = 2500;

export function ScriptEditor() {
const [{ code }, setUIState] = useUIState();
export function ScriptEditor({
code,
onChange,
}: {
code?: string;
onChange?: (code?: string) => void;
}) {
const theme = useTheme();
return (
<Flex height="100%" overflow="hidden">
Expand All @@ -22,7 +27,7 @@ export function ScriptEditor() {
height={height}
language="javascript"
defaultValue={code}
onChange={debounce((v) => setUIState(() => ({ code: v })), DELAY)}
onChange={debounce((v) => onChange?.(v), DELAY)}
options={{
minimap: {
enabled: false,
Expand Down
30 changes: 7 additions & 23 deletions client/src/components/script-editor/templates.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { TraceEvent } from "protocol/Trace";
import { FunctionTemplate } from "./FunctionTemplate";

import { TraceEvent } from "protocol/Trace";
import { FunctionTemplate } from "./FunctionTemplate";

export type ShouldBreak = FunctionTemplate<
[number, TraceEvent, TraceEvent[]],
[number, TraceEvent, TraceEvent[], TraceEvent, TraceEvent[]],
boolean
>;

Expand All @@ -14,29 +14,13 @@ export const shouldBreak: ShouldBreak = {
{ name: "step", type: "number" },
{ name: "event", type: "any" },
{ name: "events", type: "any" },
{ name: "parent", type: "any" },
{ name: "children", type: "any" },
],
defaultReturnValue: false,
returnType: "boolean",
};

export type ShouldRender = FunctionTemplate<
[number, TraceEvent, TraceEvent[]],
boolean
>;

export const shouldRender: ShouldRender = {
name: "shouldRender",
description: "Define which objects the renderer should display.",
params: [
{ name: "step", type: "number" },
{ name: "event", type: "any" },
{ name: "events", type: "any" },
],
defaultReturnValue: true,
returnType: "boolean",
};

export const templates = {
shouldRender,
shouldBreak,
};
};
118 changes: 110 additions & 8 deletions client/src/hooks/useBreakpoints.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { call } from "components/script-editor/call";
import { get, keyBy, toLower as lower, startCase } from "lodash";
import { get, keyBy, toLower as lower, range, startCase } from "lodash";
import memoizee from "memoizee";
import { TraceEventType } from "protocol";
import { useTreeMemo } from "pages/TreeWorker";
import { EventTree } from "pages/tree.worker";
import { TraceEvent, TraceEventType } from "protocol";
import { useMemo } from "react";
import { UploadedTrace } from "slices/UIState";
import { useLayer } from "slices/layers";
Expand All @@ -27,17 +29,40 @@ export type DebugLayerData = {
breakpoints?: Breakpoint[];
trace?: UploadedTrace;
};

type Result = {
result?: string;
error?: string;
};

export function useBreakpoints(key?: string) {
const { layer } = useLayer<DebugLayerData>(key);
const { monotonicF, monotonicG, breakpoints, code, trace } =
layer?.source ?? {};
// TODO:
const { result } = useTreeMemo(
{
trace: layer?.source?.trace?.content,
step: layer?.source?.trace?.content?.events?.length,
radius: undefined,
},
[layer]
);

return useMemo(() => {
const memo = keyBy(trace?.content?.events, "id");
const events = trace?.content?.events ?? []; // the actual trace array
const staticBreakpoints = generateStaticBreakpoints(breakpoints, events);
console.log(staticBreakpoints);
const memo = keyBy(events, "id");
const treeDict = treeToDict(result?.tree ?? []);

return memoizee((step: number) => {
const event = trace?.content?.events?.[step];
const event = events[step];
if (event) {
try {
// Check if step is in staticBreakpoints
if (staticBreakpoints[step]) {
return staticBreakpoints[step];
}
// Check monotonic f or g values
if (step) {
for (const p of [monotonicF && "f", monotonicG && "g"]) {
Expand All @@ -55,8 +80,9 @@ export function useBreakpoints(key?: string) {
reference = 0,
} of breakpoints ?? []) {
const isType = !type || type === event.type;

const match = condition?.apply?.(get(event, property), reference);
if (active && isType && match) {
if (condition?.key !== "changed" && active && isType && match) {
return {
result: `${property} ${lower(
startCase(condition?.key)
Expand All @@ -69,7 +95,9 @@ export function useBreakpoints(key?: string) {
call(code ?? "", "shouldBreak", [
step,
event,
trace?.content?.events ?? [],
events,
treeDict[step].parent,
treeDict[step].children,
])
) {
return { result: "Script editor" };
Expand All @@ -80,5 +108,79 @@ export function useBreakpoints(key?: string) {
}
return { result: "" };
});
}, [code, trace?.content, breakpoints, monotonicF, monotonicG]);
}, [
code,
trace?.content?.events,
breakpoints,
monotonicF,
monotonicG,
result,
]);
}
function generateStaticBreakpoints(
breakpoints: Breakpoint[] | undefined,
traces: TraceEvent[]
) {
function findBreakPoints(
traces: TraceEvent[],
property: keyof TraceEvent,
type: string,
condition: Comparator
) {
const array: number[] = [];
let bool = true;
const dict: { [index: number]: Result } = {};
// Loop through traces array
for (const i of range(traces.length)) {
const isType = !type || type === traces[i].type;
if (bool && isType) {
dict[i] = { result: `${property} changed` };
array.push(i);
bool = false;
}
if (isType && traces[i].type === type) {
if (
condition?.apply?.(
traces[i][property],
traces[array[array.length - 1]][property]
)
) {
dict[i] = { result: `${property} changed` };
array.push(i);
}
}
}
return dict;
}
const combinedDictionary: { [index: number]: Result } = {};

for (const { active, condition, type = "", property = "" } of breakpoints ??
[]) {
if (active && condition?.key === "changed") {
const curDict = findBreakPoints(traces, property, type, condition);
for (const key in curDict) {
combinedDictionary[Number(key)] = curDict[key];
}
}
}

return combinedDictionary;
}
type TreeDict = {
[K in number]: EventTree;
};
function treeToDict(trees: EventTree[]) {
const dict: TreeDict = {};

nodeToDict(trees);

function nodeToDict(trees: EventTree[] = []) {
for (const tree of trees) {
for (const event of tree.events) {
dict[event.step] = tree;
}
nodeToDict(tree.children);
}
}
return dict;
}
4 changes: 2 additions & 2 deletions client/src/hooks/usePlaybackState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ export function usePlaybackState(key?: string) {
({ result, offset, error }) => {
if (!error) {
if (result) {
notify(`Breakpoint hit: ${result}`, `Step ${offset}`);
notify(`Breakpoint hit: ${result}`, `Step ${step + offset}`);
pause(offset);
} else tick(count);
} else {
notify(`${trimEnd(error, ".")}`, `Step ${offset}`);
notify(`${trimEnd(error, ".")}`, `Step ${step + offset}`);
pause();
}
}
Expand Down
16 changes: 13 additions & 3 deletions client/src/pages/DebugPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ import { useViewTreeContext } from "components/inspector/ViewTree";
import { ScriptEditor } from "components/script-editor/ScriptEditor";
import { DebugLayerData } from "hooks/useBreakpoints";
import { inferLayerName } from "layers/Layer";
import { map, set } from "lodash";
import { map, set, values } from "lodash";
import { Page } from "pages/Page";
import { produce } from "produce";
import { ReactNode, useState } from "react";
import { useLayer } from "slices/layers";
import { BreakpointListEditor } from "../components/breakpoint-editor/BreakpointListEditor";
import { makeTemplate } from "components/script-editor/makeTemplate";
import { templates } from "components/script-editor/templates";

export function DebugPage() {
const { controls, onChange, state } = useViewTreeContext();
const [tab, setTab] = useState("standard");
const { key, setKey, layers, layer, setLayer } = useLayer<DebugLayerData>();
const { monotonicF, monotonicG } = layer?.source ?? {};
const { monotonicF, monotonicG, code } = layer?.source ?? {};
function renderHeading(label: ReactNode) {
return (
<Type variant="overline" color="text.secondary">
Expand Down Expand Up @@ -91,7 +93,15 @@ export function DebugPage() {
</Box>
</TabPanel>
<TabPanel value="advanced" sx={{ p: 0, height: "100%" }}>
<ScriptEditor />
<ScriptEditor
code={code ?? makeTemplate(values(templates))}
onChange={(v) =>
layer &&
setLayer(
produce(layer, (layer) => set(layer, "source.code", v))
)
}
/>
</TabPanel>
</Box>
</Box>{" "}
Expand Down
1 change: 1 addition & 0 deletions client/src/slices/UIState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type InputState = {
export type Comparator = {
key: string;
apply: (value: number, reference: number) => boolean;
needsReference?:boolean
};

export type Breakpoint = {
Expand Down

0 comments on commit aa30fa2

Please sign in to comment.