make sure draw logic works with multiple repls

This commit is contained in:
Felix Roos 2024-06-01 15:41:55 +02:00
parent 827993a8c9
commit 375c68775c
7 changed files with 20 additions and 16 deletions

View File

@ -154,9 +154,9 @@ export class StrudelMirror {
this.prebaked = prebake(); this.prebaked = prebake();
autodraw && this.drawFirstFrame(); autodraw && this.drawFirstFrame();
this.repl = repl({ this.repl = repl({
...replOptions, ...replOptions,
id,
onToggle: (started) => { onToggle: (started) => {
replOptions?.onToggle?.(started); replOptions?.onToggle?.(started);
if (started) { if (started) {
@ -171,11 +171,11 @@ export class StrudelMirror {
} else { } else {
this.drawer.stop(); this.drawer.stop();
updateMiniLocations(this.editor, []); updateMiniLocations(this.editor, []);
cleanupDraw(false); cleanupDraw(false, id);
} }
}, },
beforeEval: async () => { beforeEval: async () => {
cleanupDraw(); cleanupDraw(true, id);
this.painters = []; this.painters = [];
const self = this; const self = this;
// this is similar to repl.mjs > injectPatternMethods // this is similar to repl.mjs > injectPatternMethods

View File

@ -37,11 +37,11 @@ function safeEval(str, options = {}) {
return Function(body)(); return Function(body)();
} }
export const evaluate = async (code, transpiler) => { export const evaluate = async (code, transpiler, transpilerOptions) => {
let meta = {}; let meta = {};
if (transpiler) { if (transpiler) {
// transform syntactically correct js code to semantically usable code // transform syntactically correct js code to semantically usable code
const transpiled = transpiler(code); const transpiled = transpiler(code, transpilerOptions);
code = transpiled.output; code = transpiled.output;
meta = transpiled; meta = transpiled;
} }

View File

@ -19,6 +19,7 @@ export function repl({
sync = false, sync = false,
setInterval, setInterval,
clearInterval, clearInterval,
id,
}) { }) {
const state = { const state = {
schedulerError: undefined, schedulerError: undefined,
@ -32,6 +33,10 @@ export function repl({
started: false, started: false,
}; };
const transpilerOptions = {
id,
};
const updateState = (update) => { const updateState = (update) => {
Object.assign(state, update); Object.assign(state, update);
state.isDirty = state.code !== state.activeCode; state.isDirty = state.code !== state.activeCode;
@ -139,9 +144,10 @@ export function repl({
try { try {
updateState({ code, pending: true }); updateState({ code, pending: true });
await injectPatternMethods(); await injectPatternMethods();
setTime(() => scheduler.now()); // TODO: refactor?
await beforeEval?.({ code }); await beforeEval?.({ code });
shouldHush && hush(); shouldHush && hush();
let { pattern, meta } = await _evaluate(code, transpiler); let { pattern, meta } = await _evaluate(code, transpiler, transpilerOptions);
if (Object.keys(pPatterns).length) { if (Object.keys(pPatterns).length) {
pattern = stack(...Object.values(pPatterns)); pattern = stack(...Object.values(pPatterns));
} }

View File

@ -36,8 +36,8 @@ function stopAnimationFrame(id) {
delete animationFrames[id]; delete animationFrames[id];
} }
} }
function stopAllAnimations() { function stopAllAnimations(replID) {
Object.keys(animationFrames).forEach((id) => stopAnimationFrame(id)); Object.keys(animationFrames).forEach((id) => (!replID || id.startsWith(replID)) && stopAnimationFrame(id));
} }
let memory = {}; let memory = {};
@ -72,13 +72,10 @@ Pattern.prototype.draw = function (fn, options) {
return this; return this;
}; };
export const cleanupDraw = (clearScreen = true) => { export const cleanupDraw = (clearScreen = true, id) => {
const ctx = getDrawContext(); const ctx = getDrawContext();
clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width); clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width);
stopAllAnimations(); stopAllAnimations(id);
if (window.strudelScheduler) {
clearInterval(window.strudelScheduler);
}
}; };
Pattern.prototype.onPaint = function () { Pattern.prototype.onPaint = function () {

View File

@ -266,7 +266,7 @@ export function getDrawOptions(drawTime, options = {}) {
let [lookbehind, lookahead] = drawTime; let [lookbehind, lookahead] = drawTime;
lookbehind = Math.abs(lookbehind); lookbehind = Math.abs(lookbehind);
const cycles = lookahead + lookbehind; const cycles = lookahead + lookbehind;
const playhead = lookbehind / cycles; const playhead = cycles !== 0 ? lookbehind / cycles : 0;
return { fold: 1, ...options, cycles, playhead }; return { fold: 1, ...options, cycles, playhead };
} }

View File

@ -69,6 +69,7 @@ export function transpiler(input, options = {}) {
to: node.end, to: node.end,
index, index,
type, type,
id: options.id,
}; };
emitWidgets && widgets.push(widgetConfig); emitWidgets && widgets.push(widgetConfig);
return this.replace(widgetWithLocation(node, widgetConfig)); return this.replace(widgetWithLocation(node, widgetConfig));
@ -162,7 +163,7 @@ export function getWidgetID(widgetConfig) {
// that means, if we use the index index of line position as id, less garbage is generated // that means, if we use the index index of line position as id, less garbage is generated
// return `widget_${widgetConfig.to}`; // more gargabe // return `widget_${widgetConfig.to}`; // more gargabe
//return `widget_${widgetConfig.index}_${widgetConfig.to}`; // also more garbage //return `widget_${widgetConfig.index}_${widgetConfig.to}`; // also more garbage
return `widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage return `${widgetConfig.id || ''}_widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage
} }
function widgetWithLocation(node, widgetConfig) { function widgetWithLocation(node, widgetConfig) {

View File

@ -34,7 +34,7 @@ export function MiniRepl({
const canvasId = useMemo(() => `canvas-${id}`, [id]); const canvasId = useMemo(() => `canvas-${id}`, [id]);
const shouldDraw = !!punchcard || !!claviature; const shouldDraw = !!punchcard || !!claviature;
const shouldShowCanvas = !!punchcard; const shouldShowCanvas = !!punchcard;
const drawTime = punchcard ? [0, 4] : [0, 0]; const drawTime = punchcard ? [0, 4] : [-2, 2];
const [activeNotes, setActiveNotes] = useState([]); const [activeNotes, setActiveNotes] = useState([]);
const init = useCallback(({ code, shouldDraw }) => { const init = useCallback(({ code, shouldDraw }) => {