feat(libs): eeschema symbol-chooser footprint selector + preview via publish-time fp-index
The merged kicad_editor bundle made the chooser's footprint side reachable from a schematic session; this wires up the data: - boot.ts/constants.ts: every kicad_editor frame seeds BOTH sym-lib-table and fp-lib-table (+ placeholder files; a created user lib joins both lists) — the eeschema frame used to write fp-lib-table empty, leaving the selector dead. TOOL_LIB_KIND remains only the presync/primary-kind lever. - publish-libs.ts + kicad-pretty.ts: publish fp-index.json per tag — [name, uniquePadCount] per footprint (countUniquePads mirrors KiCad's GetUniquePadCount(DO_NOT_INCLUDE_NPTH)); index-only top-up mode for already-published immutable tags. - source.ts/cdn-source.ts: new bridge op "index" (source-global, dispatched before the lib-id parse) + LibsSource.getFpIndex; the CDN source fetches <tag>/fp-index.json once (404 ⇒ null ⇒ C++ default-only fallback). - dev-demo.mjs: --libs-local serves a local publish-libs layout same-origin at /libs-cdn (mirrors --models-local). - tests/web/eeschema-fp-selector.spec.ts: e2e — chooser opens in --frame=sch, selector fills from ONE index crossing, clicking a row per-item-gets the body and the cross-face GAL preview renders; adaptive for index-less sources (asserts crash-free default-only selector). Submodule bumps: kicad (index-backed filterFootprints + preview AsyncLoad fix + modal-pump crash guard), wxwidgets (modal pump logs e.stack). Doc: pcbjam-private docs/features/libs/0014-eeschema-footprint-selector.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SCWVaCRM9T847PdPwYYajX
This commit is contained in:
parent
8e99f5c5ac
commit
6fc6a64cd0
13 changed files with 492 additions and 31 deletions
|
|
@ -63,6 +63,48 @@ function findTopFootprint(src: string): [number, number] {
|
|||
* the footprint's direct children (depth 1) so a `descr`/`tags`/`model` word
|
||||
* inside a quoted string can't be mistaken for a real token.
|
||||
*/
|
||||
/**
|
||||
* Unique electrical pad count, mirroring the WASM fork's
|
||||
* `FOOTPRINT::GetUniquePadCount( DO_NOT_INCLUDE_NPTH )` (pcbnew/footprint.cpp,
|
||||
* `GetUniquePadNumbers`): count DISTINCT pad numbers, skipping pads that are
|
||||
* not on any copper layer, pads with an empty number ("mechanical" pads), and
|
||||
* NPTH pads. The symbol chooser's footprint selector filters on exactly this
|
||||
* value (`filterFootprints`, pcbnew.cpp), so the published index must agree
|
||||
* with what the editor would compute from the parsed footprint.
|
||||
*/
|
||||
export function countUniquePads(src: string): number {
|
||||
const [s, e] = findTopFootprint(src);
|
||||
const block = src.slice(s, e);
|
||||
const numbers = new Set<string>();
|
||||
|
||||
let i = block.indexOf("(", 1); // first child form
|
||||
while (i >= 0 && i < block.length) {
|
||||
const [cs, ce] = matchParen(block, i);
|
||||
const form = block.slice(cs, ce);
|
||||
|
||||
// (pad "<number>" <type> <shape> …) — number quoted (modern) or bare (old).
|
||||
const m = form.match(
|
||||
/^\(\s*pad\s+(?:"((?:[^"\\]|\\.)*)"|([^\s()"]+))\s+([a-z_]+)/,
|
||||
);
|
||||
if (m) {
|
||||
const number = m[1] !== undefined ? unescape(m[1]) : m[2]!;
|
||||
const type = m[3]!;
|
||||
// The pad's own (layers …) precedes any nested primitives, so the first
|
||||
// match is the right one. Copper = any token ending in ".Cu" ("F.Cu",
|
||||
// "B.Cu", "*.Cu", "F&B.Cu"). No layers form ⇒ count it (be permissive).
|
||||
const layers = form.match(/\(\s*layers\s+([^)]*)\)/);
|
||||
const onCopper = !layers || /\.Cu\b/.test(layers[1]!);
|
||||
if (number !== "" && type !== "np_thru_hole" && onCopper) {
|
||||
numbers.add(number);
|
||||
}
|
||||
}
|
||||
|
||||
i = block.indexOf("(", ce); // next sibling
|
||||
}
|
||||
|
||||
return numbers.size;
|
||||
}
|
||||
|
||||
export function parseFootprintFile(src: string, name: string): ParsedFootprint {
|
||||
const [s, e] = findTopFootprint(src);
|
||||
const block = src.slice(s, e);
|
||||
|
|
|
|||
Loading…
Reference in a new issue