fix(web): eeschema schematic open path — Asyncify/dynCall fixes + bump submodules
- inject-dyncall-shims.sh: add a dynCallLegacy -> wasmExports fallback so embind's generic dynCall path finds the DYNCALLS=1 trampolines. Without it, an Asyncify unwind/rewind through an embind call (kicadOpenFile -> OpenProjectFiles) died with "f is not a function". - open-flow.ts: kicadOpenFile runs OpenProjectFiles under Asyncify, so its sync return is a falsy placeholder. Invoke it and poll the frame title for the load instead of trusting the return value, and never fall back to UI automation while the hook is in flight (it would re-enter the suspended Asyncify call). - .gitignore: ignore .playwright-mcp scratch. - bump kicad + wxwidgets submodules to the wasm schematic-open fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
735e5aa8e9
commit
ddd959fbc2
5 changed files with 59 additions and 12 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -60,3 +60,5 @@ wxwidgets-clean/
|
|||
output/
|
||||
*.d
|
||||
/tests/.test-port-coroutine
|
||||
.playwright-mcp
|
||||
|
||||
|
|
|
|||
2
kicad
2
kicad
|
|
@ -1 +1 @@
|
|||
Subproject commit 211ab47df18abe03af3c8c1c8cfbbe5a42520129
|
||||
Subproject commit d701b2365aeb327b9737d97b72aafa1da4d07dc2
|
||||
|
|
@ -136,6 +136,22 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# --- 3b. embind dynCall fallback (dynCallLegacy -> wasmExports) ----------------
|
||||
# embind's generic caller (getDynCaller) routes through dynCallLegacy, which only
|
||||
# reads Module["dynCall_<sig>"]. But the DYNCALLS=1 trampolines are wasm EXPORTS,
|
||||
# not Module properties, so that lookup is undefined and an Asyncify unwind/rewind
|
||||
# through an embind call (e.g. kicadOpenFile -> OpenProjectFiles) dies with
|
||||
# "f is not a function" in Asyncify.doRewind. Add a wasmExports fallback so the
|
||||
# instrumented trampoline is found and rewind survives.
|
||||
if grep -q 'embind dynCall fallback installed' "$JS_FILE"; then
|
||||
echo "dynCallLegacy fallback already present - skipping"
|
||||
elif grep -qF ' var f = Module["dynCall_" + sig];' "$JS_FILE"; then
|
||||
perl -0pi -e 's/(\Q var f = Module["dynCall_" + sig];\E)/$1\n \/\/ embind dynCall fallback installed: DYNCALLS=1 trampolines live on wasmExports, not Module.\n if (!f && typeof wasmExports !== "undefined") f = wasmExports["dynCall_" + sig];/' "$JS_FILE"
|
||||
echo "Injected dynCallLegacy wasmExports fallback"
|
||||
else
|
||||
echo "Warning: dynCallLegacy pattern not found - skipping embind dynCall fallback"
|
||||
fi
|
||||
|
||||
# --- 4. Optional diagnostics (logging only) -----------------------------------
|
||||
if [ "$SHIM_DIAGNOSTICS" = "1" ]; then
|
||||
if grep -q 'DIAG] Asyncify/fiber/modal diagnostics installed' "$JS_FILE"; then
|
||||
|
|
|
|||
|
|
@ -81,19 +81,34 @@ function pressKey(win: ToolWindow, key: string): void {
|
|||
el.dispatchEvent(new KE("keyup", init));
|
||||
}
|
||||
|
||||
function tryProgrammaticOpen(
|
||||
/** True if the build exposes the programmatic open hook. */
|
||||
function hasProgrammaticHook(win: ToolWindow): boolean {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const mod = win.Module as any;
|
||||
return !!mod && typeof mod.kicadOpenFile === "function";
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the programmatic hook. NOTE: kicadOpenFile runs OpenProjectFiles under
|
||||
* Asyncify, so the call SUSPENDS and unwinds back to JS before the load finishes
|
||||
* — its synchronous return is a falsy placeholder, not the real bool. So we fire
|
||||
* it and ignore the return; the caller polls for the loaded schematic instead.
|
||||
*/
|
||||
function invokeProgrammaticOpen(
|
||||
win: ToolWindow,
|
||||
absPath: string,
|
||||
log: (m: string) => void,
|
||||
): boolean {
|
||||
): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const mod = win.Module as any;
|
||||
if (mod && typeof mod.kicadOpenFile === "function") {
|
||||
const ok = mod.kicadOpenFile(absPath) === true;
|
||||
log(`[open] Module.kicadOpenFile(${absPath}) -> ${ok}`);
|
||||
return ok; // false → caller falls back to UI automation
|
||||
}
|
||||
return false;
|
||||
mod.kicadOpenFile(absPath);
|
||||
log(`[open] invoked Module.kicadOpenFile(${absPath}) (async; polling for load)`);
|
||||
}
|
||||
|
||||
/** Heuristic: the editor frame title drops "untitled" once a real file is open. */
|
||||
function schematicLoaded(win: ToolWindow): boolean {
|
||||
const title = win.document?.title ?? "";
|
||||
return title.length > 0 && !/untitled/i.test(title);
|
||||
}
|
||||
|
||||
export async function openFileInTool(
|
||||
|
|
@ -125,9 +140,23 @@ export async function openFileInTool(
|
|||
}
|
||||
|
||||
// Strategy 1: programmatic hook (preferred — deterministic, no UI automation).
|
||||
if (tryProgrammaticOpen(win, absPath, log)) return "programmatic";
|
||||
// Because the call is Asyncify-async we can't trust its return value; instead
|
||||
// we invoke it and poll the frame title until the schematic loads. We must NOT
|
||||
// fall back to UI automation while the hook is in flight — synthesizing input
|
||||
// would re-enter the suspended Asyncify call and corrupt it.
|
||||
if (hasProgrammaticHook(win)) {
|
||||
invokeProgrammaticOpen(win, absPath, log);
|
||||
const loaded = await waitFor(() => schematicLoaded(win), timeoutMs);
|
||||
if (loaded) {
|
||||
log(`[open] schematic loaded: ${win.document.title}`);
|
||||
return "programmatic";
|
||||
}
|
||||
log("[open] kicadOpenFile did not load the schematic within timeout");
|
||||
return "failed";
|
||||
}
|
||||
|
||||
// Strategy 2: UI automation fallback (EXPERIMENTAL, fragile).
|
||||
// Strategy 2: UI automation fallback (EXPERIMENTAL, fragile). Only when the
|
||||
// build has no programmatic hook at all.
|
||||
log("[open] no programmatic hook; using EXPERIMENTAL UI automation");
|
||||
|
||||
const fileMenu =
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 651526b80e08ed1fdfe0455925fc2fb90d8668bd
|
||||
Subproject commit ea186374a59347955c42a5acaea8148ad855f0d3
|
||||
Loading…
Reference in a new issue