feat: libs 0002 spike — kicadLibs provider stub + lib-table seeding; bump kicad
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa9d613f50
commit
7e454104aa
3 changed files with 135 additions and 2 deletions
2
kicad
2
kicad
|
|
@ -1 +1 @@
|
||||||
Subproject commit 693c513293e8706c0c9d2a0304ea098cfd391864
|
Subproject commit 378b502e27bb84d2135464691abbfe5dc74661e3
|
||||||
|
|
@ -5,6 +5,10 @@ import {
|
||||||
TOOL_ARGV0,
|
TOOL_ARGV0,
|
||||||
TOOL_NEEDS_CONFIG_SEED,
|
TOOL_NEEDS_CONFIG_SEED,
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
|
import {
|
||||||
|
installSpikeLibsProvider,
|
||||||
|
SPIKE_LIB_TABLE_ROW,
|
||||||
|
} from "./libs/spike-provider";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boot a KiCad tool directly in the main React document — no iframe.
|
* Boot a KiCad tool directly in the main React document — no iframe.
|
||||||
|
|
@ -88,6 +92,9 @@ async function doBoot(opts: BootOptions): Promise<void> {
|
||||||
// mismatches the viewport, breaking the whole AUI layout (toolbars/panels).
|
// mismatches the viewport, breaking the whole AUI layout (toolbars/panels).
|
||||||
(w as unknown as { mainWindow: HTMLElement }).mainWindow = container;
|
(w as unknown as { mainWindow: HTMLElement }).mainWindow = container;
|
||||||
|
|
||||||
|
// libs 0002 spike: must exist before any plugin call can suspend on it.
|
||||||
|
installSpikeLibsProvider(log);
|
||||||
|
|
||||||
onStatus("Downloading…");
|
onStatus("Downloading…");
|
||||||
|
|
||||||
// Prefetch images.tar.gz in parallel with the (much larger) wasm download —
|
// Prefetch images.tar.gz in parallel with the (much larger) wasm download —
|
||||||
|
|
@ -174,9 +181,11 @@ async function doBoot(opts: BootOptions): Promise<void> {
|
||||||
2,
|
2,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
// libs 0002 spike: one remote lib row; the PCBJAM plugin resolves it
|
||||||
|
// through window.kicadLibs (installed in doBoot).
|
||||||
writeIfAbsent(
|
writeIfAbsent(
|
||||||
`${KICAD_CONFIG_DIR}/sym-lib-table`,
|
`${KICAD_CONFIG_DIR}/sym-lib-table`,
|
||||||
"(sym_lib_table\n (version 7)\n)\n",
|
`(sym_lib_table\n (version 7)\n${SPIKE_LIB_TABLE_ROW}\n)\n`,
|
||||||
);
|
);
|
||||||
writeIfAbsent(
|
writeIfAbsent(
|
||||||
`${KICAD_CONFIG_DIR}/fp-lib-table`,
|
`${KICAD_CONFIG_DIR}/fp-lib-table`,
|
||||||
|
|
|
||||||
124
web/standalone/src/wasm/libs/spike-provider.ts
Normal file
124
web/standalone/src/wasm/libs/spike-provider.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
/**
|
||||||
|
* libs 0002 spike: a static JS-side library provider.
|
||||||
|
*
|
||||||
|
* The kicad fork's SCH_IO_PCBJAM_LIB plugin (lib-table type "PCBJAM") calls
|
||||||
|
* `globalThis.kicadLibs.request(op, lib, arg)` through an Asyncify suspension
|
||||||
|
* (EM_ASYNC_JS) and blocks the C++ stack until the returned promise resolves:
|
||||||
|
*
|
||||||
|
* request("list", "pcbjam://spike", "") -> JSON {"symbols": [...]}
|
||||||
|
* request("get", "pcbjam://spike", "R") -> full kicad_symbol_lib s-expr
|
||||||
|
* document holding that symbol
|
||||||
|
*
|
||||||
|
* This stub serves two handcrafted symbols from memory — no server. An
|
||||||
|
* artificial delay (`?libdelay=1500` in the URL) exercises the reentrancy
|
||||||
|
* question: the tab must stay alive while C++ is suspended mid-fetch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const SPIKE_LIB_NICKNAME = "pcbjam-spike";
|
||||||
|
export const SPIKE_LIB_URI = "pcbjam://spike";
|
||||||
|
|
||||||
|
/** sym-lib-table row seeded at boot (see boot.ts seedKicadConfig). */
|
||||||
|
export const SPIKE_LIB_TABLE_ROW = ` (lib (name "${SPIKE_LIB_NICKNAME}")(type "PCBJAM")(uri "${SPIKE_LIB_URI}")(options "")(descr "pcbjam libs 0002 spike"))`;
|
||||||
|
|
||||||
|
const wrapLib = (symbolBody: string) =>
|
||||||
|
`(kicad_symbol_lib (version 20241209) (generator "pcbjam") (generator_version "0.1")
|
||||||
|
${symbolBody}
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SYMBOLS: Record<string, string> = {
|
||||||
|
R: ` (symbol "R" (pin_numbers hide) (pin_names (offset 0)) (exclude_from_sim no) (in_bom yes) (on_board yes)
|
||||||
|
(property "Reference" "R" (at 2.032 0 90) (effects (font (size 1.27 1.27))))
|
||||||
|
(property "Value" "R" (at 0 0 90) (effects (font (size 1.27 1.27))))
|
||||||
|
(property "Footprint" "" (at -1.778 0 90) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "Datasheet" "~" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "Description" "Resistor (pcbjam spike)" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "ki_keywords" "R res resistor" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(symbol "R_0_1"
|
||||||
|
(rectangle (start -1.016 -2.54) (end 1.016 2.54) (stroke (width 0.254) (type default)) (fill (type none)))
|
||||||
|
)
|
||||||
|
(symbol "R_1_1"
|
||||||
|
(pin passive line (at 0 3.81 270) (length 1.27)
|
||||||
|
(name "~" (effects (font (size 1.27 1.27)))) (number "1" (effects (font (size 1.27 1.27)))))
|
||||||
|
(pin passive line (at 0 -3.81 90) (length 1.27)
|
||||||
|
(name "~" (effects (font (size 1.27 1.27)))) (number "2" (effects (font (size 1.27 1.27)))))
|
||||||
|
)
|
||||||
|
)`,
|
||||||
|
C: ` (symbol "C" (pin_numbers hide) (pin_names (offset 0.254)) (exclude_from_sim no) (in_bom yes) (on_board yes)
|
||||||
|
(property "Reference" "C" (at 0.635 2.54 0) (effects (font (size 1.27 1.27)) (justify left)))
|
||||||
|
(property "Value" "C" (at 0.635 -2.54 0) (effects (font (size 1.27 1.27)) (justify left)))
|
||||||
|
(property "Footprint" "" (at 0.9652 -3.81 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "Datasheet" "~" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "Description" "Capacitor (pcbjam spike)" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(property "ki_keywords" "cap capacitor" (at 0 0 0) (effects (font (size 1.27 1.27)) hide))
|
||||||
|
(symbol "C_0_1"
|
||||||
|
(polyline (pts (xy -2.032 -0.762) (xy 2.032 -0.762)) (stroke (width 0.508) (type default)) (fill (type none)))
|
||||||
|
(polyline (pts (xy -2.032 0.762) (xy 2.032 0.762)) (stroke (width 0.508) (type default)) (fill (type none)))
|
||||||
|
)
|
||||||
|
(symbol "C_1_1"
|
||||||
|
(pin passive line (at 0 3.81 270) (length 2.794)
|
||||||
|
(name "~" (effects (font (size 1.27 1.27)))) (number "1" (effects (font (size 1.27 1.27)))))
|
||||||
|
(pin passive line (at 0 -3.81 90) (length 2.794)
|
||||||
|
(name "~" (effects (font (size 1.27 1.27)))) (number "2" (effects (font (size 1.27 1.27)))))
|
||||||
|
)
|
||||||
|
)`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type KicadLibsRequest = (
|
||||||
|
op: string,
|
||||||
|
lib: string,
|
||||||
|
arg: string,
|
||||||
|
) => Promise<string | null>;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
kicadLibs?: { request: KicadLibsRequest };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function artificialDelayMs(): number {
|
||||||
|
const raw = new URLSearchParams(window.location.search).get("libdelay");
|
||||||
|
const n = raw ? Number(raw) : 0;
|
||||||
|
return Number.isFinite(n) && n > 0 ? n : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KiCad's lib-table path handling normalizes URIs as if they were file paths:
|
||||||
|
* "pcbjam://spike" arrives as "/pcbjam:/spike" or even
|
||||||
|
* "<project-dir>/pcbjam:/spike" (made absolute against the cwd). Recover the
|
||||||
|
* lib id after the "pcbjam:" marker. Finding for 0003: give the real plugin a
|
||||||
|
* path shape that survives normalization, or normalize C++-side.
|
||||||
|
*/
|
||||||
|
function libIdFromMangledUri(lib: string): string | null {
|
||||||
|
const m = lib.match(/pcbjam:\/*(.+)$/);
|
||||||
|
return m ? m[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function installSpikeLibsProvider(log: (msg: string) => void): void {
|
||||||
|
if (window.kicadLibs) return;
|
||||||
|
|
||||||
|
const delay = artificialDelayMs();
|
||||||
|
|
||||||
|
const request: KicadLibsRequest = async (op, lib, arg) => {
|
||||||
|
log(`[libs] request op=${op} lib=${lib} arg=${arg} (delay=${delay}ms)`);
|
||||||
|
|
||||||
|
if (libIdFromMangledUri(lib) !== "spike") return null;
|
||||||
|
if (delay) await sleep(delay);
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case "list":
|
||||||
|
return JSON.stringify({ symbols: Object.keys(SYMBOLS) });
|
||||||
|
case "get": {
|
||||||
|
const body = SYMBOLS[arg];
|
||||||
|
return body ? wrapLib(body) : null;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.kicadLibs = { request };
|
||||||
|
log(`[libs] spike provider installed (${SPIKE_LIB_URI})`);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue