feat: live lib edit — cmd+s accelerators, editing-context overlay, lib-set realtime (libs 0015)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0166YJapMpPB8Ab7wT8Nx51t
This commit is contained in:
Gergő Törcsvári 2026-08-19 13:47:13 +02:00
commit aeacadf603
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
11 changed files with 312 additions and 7 deletions

View file

@ -2104,6 +2104,9 @@ EMSCRIPTEN_BINDINGS(eeschema) {
function("kicadCollabTestClearSelection", &schCollabTestClearSelection);
// Library reload after a remote (synced) lib edit — r2-idb-sync realtime.
function("kicadLibsReload", &pcbjam_libs::reloadLibrary PCBJAM_PARKER_POLICY);
// Runtime lib-table row insert + load (a new team library appeared
// mid-session; the lib set is otherwise frozen at boot).
function("kicadLibsAddEntry", &pcbjam_libs::addLibraryEntry PCBJAM_PARKER_POLICY);
// Placed-instance count for a library symbol (drives the "a symbol you are
// using was updated" toast after a remote lib edit).
function("kicadLibsSymbolUsage", &schLibsSymbolUsage);

View file

@ -596,6 +596,9 @@ EMSCRIPTEN_BINDINGS(kicad_editor) {
function("kicadCollabTestClearSelection", &collabTestClearSelection);
// Library reload after a remote (synced) lib edit — r2-idb-sync realtime.
function("kicadLibsReload", &pcbjam_libs::reloadLibrary PCBJAM_PARKER_POLICY);
// Runtime lib-table row insert + load (a new team library appeared
// mid-session; the lib set is otherwise frozen at boot).
function("kicadLibsAddEntry", &pcbjam_libs::addLibraryEntry PCBJAM_PARKER_POLICY);
// Placed-instance count for a library symbol (schematic sessions only —
// 0 from any other frame; drives the "symbol you are using was updated"
// toast after a remote lib edit).

View file

@ -29,6 +29,7 @@
#include <kiway.h>
#include <kiway_player.h>
#include <libraries/library_manager.h>
#include <libraries/library_table.h>
#include <mail_type.h>
#include <pgm_base.h>
@ -76,6 +77,74 @@ inline void reloadLibrary( std::string aKind, std::string aNickname )
} );
}
/**
* Add one PCBJAM lib-table row at RUNTIME and load it — the lib SET is
* otherwise frozen at boot (sym/fp-lib-table are written once in preRun).
* Used by the "a new team library appeared" flow: the JS side has already
* created the `/mnt/pcbjam/<id>` MEMFS placeholder; this inserts the row into
* the LIVE in-memory global table (the table FILE is only re-read by
* LoadGlobalTables, which would drop every adapter cache — deliberately not
* used), loads the entry through the provider bridge, and re-syncs any open
* editor tree. Idempotent: an existing nickname is a no-op.
*
* @param aKind "symbol" | "footprint" — which lib table gets the row.
* @param aNickname the lib-table row name (LibInfo.name on the JS side).
* @param aUri the virtual mount uri ("/mnt/pcbjam/<libId>").
*/
inline void addLibraryEntry( std::string aKind, std::string aNickname, std::string aUri )
{
KIWAY_PLAYER* top =
wxTheApp ? dynamic_cast<KIWAY_PLAYER*>( wxTheApp->GetTopWindow() ) : nullptr;
if( !top )
return;
const bool fp = aKind == "footprint";
const wxString nick = wxString::FromUTF8( aNickname.c_str() );
const wxString uri = wxString::FromUTF8( aUri.c_str() );
pcbjam_collab::runOnCoroutine( top, [top, fp, nick, uri]()
{
LIBRARY_MANAGER& mgr = Pgm().GetLibraryManager();
const LIBRARY_TABLE_TYPE type =
fp ? LIBRARY_TABLE_TYPE::FOOTPRINT : LIBRARY_TABLE_TYPE::SYMBOL;
if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter = mgr.Adapter( type ); adapter )
{
LIBRARY_TABLE* table = ( *adapter )->GlobalTable();
if( !table )
return;
// Idempotent-cheap: a nickname that already has a row is done —
// content refresh is kicadLibsReload's job, and doing it here
// would let a re-announce trigger a pointless re-fat-load.
if( table->HasRow( nick ) )
return;
LIBRARY_TABLE_ROW& row = table->InsertRow();
row.SetNickname( nick );
row.SetURI( uri );
row.SetType( fp ? wxS( "PCBJAM_FP" ) : wxS( "PCBJAM" ) );
}
else
{
return;
}
// Bring the new row to LOADED through the JS provider bridge (GetRow
// walks the table on a cache miss, so the inserted row is found).
mgr.LoadLibraryEntry( type, nick );
// Open editor frames re-sync their tree; the nickname payload forces
// the named node's rebuild past the pinned-modify-hash gate (same
// reasoning as reloadLibrary above).
std::string payload( nick.utf8_str() );
top->Kiway().ExpressMail( fp ? FRAME_FOOTPRINT_EDITOR : FRAME_SCH_SYMBOL_EDITOR,
MAIL_RELOAD_LIB, payload );
} );
}
} // namespace pcbjam_libs
#endif // __EMSCRIPTEN__

View file

@ -2451,6 +2451,9 @@ EMSCRIPTEN_BINDINGS(pcbnew) {
function("kicadCollabTestClearSelection", &pcbCollabTestClearSelection);
// Library reload after a remote (synced) lib edit — r2-idb-sync realtime.
function("kicadLibsReload", &pcbjam_libs::reloadLibrary PCBJAM_PARKER_POLICY);
// Runtime lib-table row insert + load (a new team library appeared
// mid-session; the lib set is otherwise frozen at boot).
function("kicadLibsAddEntry", &pcbjam_libs::addLibraryEntry PCBJAM_PARKER_POLICY);
#endif // !KICAD_MERGED_EMBIND
}
#endif