2026-07-02 14:48:11 +02:00
|
|
|
/*
|
|
|
|
|
* Embind dispatcher for the merged kicad_editor WASM image (editor-unification Part 2).
|
|
|
|
|
*
|
|
|
|
|
* The pcbnew and eeschema binding TUs each implement the collab bridge for their own
|
|
|
|
|
* frame and, standalone, register the SAME JS-facing names. In the merged image both
|
|
|
|
|
* TUs are compiled with -DKICAD_MERGED_EMBIND, which
|
|
|
|
|
* - compiles out their duplicate frame-agnostic definitions (kicadOpenFile,
|
|
|
|
|
* extern "C" kicadCollabOnSave) — the single definitions live HERE, and
|
|
|
|
|
* - compiles out their shared-name EMSCRIPTEN_BINDINGS registrations — registered
|
|
|
|
|
* once HERE, dispatching to the renamed per-editor entries (pcbCollab… and
|
|
|
|
|
* schCollab…) on whichever editor frame is live. Per-editor unique names
|
|
|
|
|
* (kicadSaveBoard, kicadSaveSchematic, kicadCollabTestItemBlob, Board_…) keep
|
|
|
|
|
* flowing from the per-editor blocks unchanged.
|
|
|
|
|
*
|
|
|
|
|
* With the one-frame-per-page-load model exactly one of pcbEditorActive() /
|
|
|
|
|
* schEditorActive() is true — the same dynamic_cast probe every per-editor entry
|
|
|
|
|
* already starts with. JS-facing names and signatures are IDENTICAL to the standalone
|
|
|
|
|
* bundles, so the web app and tests need no per-bundle API differences.
|
|
|
|
|
*
|
|
|
|
|
* Deliberately header-light: no pcbnew/eeschema headers (avoids mixing both include
|
|
|
|
|
* roots in one TU); only the generic KIWAY_PLAYER surface + the extern declarations.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
|
#include <emscripten.h>
|
|
|
|
|
#include <emscripten/bind.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <wx/app.h>
|
|
|
|
|
#include <wx/string.h>
|
|
|
|
|
#include <wx/window.h>
|
|
|
|
|
#include <kiway.h>
|
|
|
|
|
#include <kiway_player.h>
|
|
|
|
|
|
|
|
|
|
using namespace emscripten;
|
|
|
|
|
|
|
|
|
|
// Per-editor entry points and frame probes — defined (with external linkage) in
|
|
|
|
|
// pcbnew_embind.cpp / eeschema_embind.cpp.
|
|
|
|
|
bool pcbEditorActive();
|
|
|
|
|
void pcbCollabApply( std::string aJson );
|
|
|
|
|
void pcbCollabApplyItems( std::string aJson );
|
|
|
|
|
std::string pcbCollabSnapshot();
|
|
|
|
|
std::string pcbCollabSnapshotItems();
|
|
|
|
|
std::string pcbCollabTestMoveFirst( int aDx, int aDy );
|
|
|
|
|
std::string pcbCollabGetPos( std::string aId );
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
bool pcbCollabTestRemoveItem( std::string aId );
|
|
|
|
|
bool pcbCollabTestRotateItem( std::string aId, double aDeg );
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
bool schEditorActive();
|
|
|
|
|
void schCollabApply( std::string aJson );
|
|
|
|
|
void schCollabApplyItems( std::string aJson );
|
|
|
|
|
std::string schCollabSnapshot();
|
|
|
|
|
std::string schCollabSnapshotItems();
|
|
|
|
|
std::string schCollabTestMoveFirst( int aDx, int aDy );
|
|
|
|
|
std::string schCollabGetPos( std::string aId );
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
bool schCollabTestRemoveItem( std::string aId );
|
|
|
|
|
bool schCollabTestRotateItem( std::string aId, double aDeg );
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Programmatically open a project file in the running editor frame, without UI
|
|
|
|
|
// automation. Frame-agnostic (any KIWAY_PLAYER); byte-identical to the definition the
|
|
|
|
|
// standalone bundles compile from their own binding TU.
|
|
|
|
|
static bool kicadOpenFile( std::string path )
|
|
|
|
|
{
|
|
|
|
|
KIWAY_PLAYER* frame =
|
|
|
|
|
wxTheApp ? static_cast<KIWAY_PLAYER*>( wxTheApp->GetTopWindow() ) : nullptr;
|
|
|
|
|
|
|
|
|
|
if( !frame )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if( wxWindow* blocking = frame->Kiway().GetBlockingDialog() )
|
|
|
|
|
blocking->Close( true );
|
|
|
|
|
|
|
|
|
|
return frame->OpenProjectFiles(
|
|
|
|
|
std::vector<wxString>( 1, wxString::FromUTF8( path.c_str() ) ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// C++ → JS save notification. Called from BOTH fork save chokepoints
|
|
|
|
|
// (PCB_EDIT_FRAME::SavePcbFile and SCH_EDIT_FRAME::saveSchematicFile) — one shared
|
|
|
|
|
// definition serves the merged image. No-op without a JS listener.
|
|
|
|
|
extern "C" void kicadCollabOnSave( const char* aPath )
|
|
|
|
|
{
|
|
|
|
|
EM_ASM( {
|
|
|
|
|
if( window.kicadCollab && window.kicadCollab.onSave )
|
|
|
|
|
window.kicadCollab.onSave( UTF8ToString( $0 ) );
|
|
|
|
|
}, aPath );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dispatch shims: route each shared JS name to the live editor's implementation.
|
|
|
|
|
// The sch path is the fallback arm so a JS call with NO frame up behaves like the
|
|
|
|
|
// standalone bundles (the per-editor impls no-op / return empty on a null frame).
|
|
|
|
|
static void collabApply( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabApply( aJson ) : schCollabApply( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void collabApplyItems( std::string aJson )
|
|
|
|
|
{
|
|
|
|
|
pcbEditorActive() ? pcbCollabApplyItems( aJson ) : schCollabApplyItems( aJson );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabSnapshot()
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabSnapshot() : schCollabSnapshot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabSnapshotItems()
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabSnapshotItems() : schCollabSnapshotItems();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabTestMoveFirst( int aDx, int aDy )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestMoveFirst( aDx, aDy )
|
|
|
|
|
: schCollabTestMoveFirst( aDx, aDy );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string collabGetPos( std::string aId )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabGetPos( aId ) : schCollabGetPos( aId );
|
|
|
|
|
}
|
|
|
|
|
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
static bool collabTestRemoveItem( std::string aId )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestRemoveItem( aId ) : schCollabTestRemoveItem( aId );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool collabTestRotateItem( std::string aId, double aDeg )
|
|
|
|
|
{
|
|
|
|
|
return pcbEditorActive() ? pcbCollabTestRotateItem( aId, aDeg )
|
|
|
|
|
: schCollabTestRotateItem( aId, aDeg );
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-02 14:48:11 +02:00
|
|
|
|
|
|
|
|
EMSCRIPTEN_BINDINGS(kicad_editor) {
|
|
|
|
|
// Programmatic file open (preferred over UI automation from the web app).
|
|
|
|
|
function("kicadOpenFile", &kicadOpenFile);
|
|
|
|
|
|
|
|
|
|
// Yjs collaborative bridge entry points — same JS contract as the standalone
|
|
|
|
|
// bundles, dispatched on the active editor frame.
|
|
|
|
|
function("kicadCollabApply", &collabApply);
|
|
|
|
|
function("kicadCollabSnapshot", &collabSnapshot);
|
|
|
|
|
function("kicadCollabApplyItems", &collabApplyItems);
|
|
|
|
|
function("kicadCollabSnapshotItems", &collabSnapshotItems);
|
|
|
|
|
function("kicadCollabTestMoveFirst", &collabTestMoveFirst);
|
|
|
|
|
function("kicadCollabGetPos", &collabGetPos);
|
test(ysync): repro tests for review bugs 01-07 + v2 items-wire e2e port (miss 11)
The 2026-07-02 sync review (docs/features/ysync-review, ysync-review branch)
found 7 bugs and that the two-tab e2e only exercised the DEAD legacy scalar
wire. This lands plan doc 15 in full; results + empirical findings in doc 16.
- tests/collab/browser-entry-v2.ts (+build.mjs): the PRODUCTION v2 stack
bundled for e2e (connectKicadDoc + attachKicadCollab, kdoc_* keys), with
in-page renderActiveDoc/singleSeedRender/driftReport helpers and yjs forced
to ONE copy (the two web pnpm workspaces otherwise bundle two
instanceof-incompatible instances).
- tests/kicad/ysync-two-tab.spec.ts: pl_editor green baseline (A↔B edits,
ITEM-level drift silence) + divergent-uuid adopt; bug-01 pcb/ee fresh-room
repros (Chromium-only: two kicad_editor tabs exceed Firefox's per-process
wasm budget); bug-06 concurrent-seed race; bug-03 Y-half.
- tests/kicad/ysync-repros-{pcbnew,eeschema}.spec.ts: bugs 02/03/05 + the
bug-04 matrix (anchor-centred fp rotation, pad resize, endpoint drag,
symbol rotation, Value-field edit), each with green landed-preconditions;
the "local move emits" controls double as headless-emit probes — GREEN on
both tools, so every emit-dependent repro is a live test.fail.
- wasm/bindings: 7 local-edit test hooks via real commits
(CallAfter+COROUTINE) — TestRemoveItem/TestRotateItem (both tools,
dispatched in the merged image), TestSetPadSize/TestMoveEndpoint (pcbnew),
TestSetFieldText (eeschema).
- web/standalone ysync-repros.test.ts: bug-01 units (C++-faithful fake gating
emit on ensureBridge) + bug-07a/b (stale DOWN hook, real sheet-manager gap).
- web/pcbjam-shared bump: bug-03/06 unit repros.
Convention: every repro asserts the CORRECT behavior and is expected-fail
(test.fail/it.fails) naming its bug doc; a fix flips it to "unexpected pass",
forcing marker removal — the repro becomes the regression test. Every
expected failure verified (JSON reporter) to fail at its documented assert.
Suite state: 39 passed / 0 failed / 0 flaky / 5 skipped (2 firefox guards,
2 pre-existing legacy two-tab skips, 1 pre-existing roundtrip fixme).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPfrVhfYgPPgtawjSssZfn
2026-07-03 12:43:35 +02:00
|
|
|
// ysync-review repro hooks (shared names; per-editor-only hooks — pad size,
|
|
|
|
|
// endpoint, field text — flow from the per-editor blocks unchanged).
|
|
|
|
|
function("kicadCollabTestRemoveItem", &collabTestRemoveItem);
|
|
|
|
|
function("kicadCollabTestRotateItem", &collabTestRotateItem);
|
2026-07-02 14:48:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // __EMSCRIPTEN__
|