← Commit history

0.9.283: Wiki #73: kicad_list_design_rules and kicad_set_design_rules consume adom/pcb-design-rules at call time (fab, layers, process; layers defaults to the board's copper count; stages <stem>.kicad_dru with backup; runs DRC with it). Wiki #62: kicad_list_symbols (bridge inventory + kicadParser), and kicad_show_library resolves an MPN/file name to the real symbol name (exact, case-insensitive, unique prefix) reporting aliasedFrom/aliasHow. Navigation trace no longer implies the filter was not applied when wx answers WM_GETTEXT with ''. kicad-bridge-dev skill records the #71 lessons.

John Lauer ·d1c2d11e2b ·1mo ago ·parent 19293f0
2 files changed +78−1
handlers/open_symbol_editor.py+64−1
@@ -513,7 +513,10 @@ def _background_navigate_win32(sym_hwnd: int, filter_text: str, verify: str,         return False     time.sleep(1.4)  # LIB_TREE search debounce runs on the UI thread (~200-500ms) + tree rebuild     trace["editTextAfterSet"] = _edit_text(edit)-    trace["steps"].append(f"WM_SETTEXT -> edit reads {trace['editTextAfterSet']!r}")+    # The read-back is unreliable: wx answers WM_GETTEXT for its own windows+    # with '' even while the box visibly holds the filter (screenshot-verified+    # 2026-09-03). Record it, but do not let '' read as "filter not applied".+    trace["steps"].append(f"WM_SETTEXT sent (read-back {trace['editTextAfterSet']!r}; wx often answers '' even when the box shows the text)")     VK_DOWN = 0x28     # Down THROUGH the filter box: KiCad forwards nav keys to the tree, which     # selects the first filtered match (verified live: Device:R row highlights).@@ -699,7 +702,67 @@ def _mac_open_symbol_editor(kicad_info: dict, args: dict) -> dict:     return {"success": True, "output": "Symbol Editor opened."}  ++def _resolve_symbol_alias(kicad_info: dict, requested: str) -> tuple[str | None, str]:+    """Map a caller's name onto a real symbol name in the Adom library.++    Exact match wins. Then case-insensitive. Then a UNIQUE prefix match in+    either direction (MPN longer than the symbol name, or the reverse). Returns+    (name, how); (None, reason) when nothing matches or the match is ambiguous.+    """+    from adom_library import _get_paths, list_symbols  # local: avoids an import cycle at load+    _table_path, lib_path = _get_paths(kicad_info)  # (sym-lib-table, Adom.kicad_sym)+    if not lib_path or not Path(lib_path).exists():+        return None, "library file not found"+    names = list_symbols(Path(lib_path)) or []+    if requested in names:+        return requested, "exact"+    low = {n.lower(): n for n in names}+    if requested.lower() in low:+        return low[requested.lower()], "case-insensitive"+    r = requested.lower()+    pref = [n for n in names if n.lower().startswith(r) or r.startswith(n.lower())]+    if len(pref) == 1:+        return pref[0], "unique prefix match"+    if len(pref) > 1:+        return None, f"ambiguous: {pref[:5]}"+    return None, "no match"++ def handle_open_symbol_editor(kicad_info: dict, args: dict) -> dict:+    """show_library / open_symbol_editor entry point.++    Wiki #62 finding 2: the file is named for the MPN but the symbol inside is+    not (CL21A226MPQNNNE.kicad_sym declares "CL21A226MPQNNN"). Resolve the+    caller's name against the library's real names BEFORE navigating and say+    so (aliasedFrom / aliasHow) on whatever the inner handler returns, instead+    of hunting for a name that does not exist and then blaming the editor.+    """+    note: dict = {}+    symbol_name = args.get("symbolName", "") or ""+    library_name = args.get("libraryName", "") or args.get("library", "") or ""+    if symbol_name and (not library_name or library_name.lower() == "adom"):+        try:+            resolved, how = _resolve_symbol_alias(kicad_info, symbol_name)+            if resolved and resolved != symbol_name:+                note = {"aliasedFrom": symbol_name, "aliasHow": how}+                args = {**args, "symbolName": resolved}+            elif not resolved and how.startswith("ambiguous"):+                note = {"aliasNote": f"'{symbol_name}' is not in the library and the prefix match is {how}"}+            elif not resolved and how == "no match":+                note = {"aliasNote": f"'{symbol_name}' is not a symbol name in the Adom library (no exact, case-insensitive or prefix match)"}+        except Exception:  # pylint: disable=broad-except+            pass+    out = _handle_open_symbol_editor_inner(kicad_info, args)+    if isinstance(out, dict) and note:+        out = {**out, **note}+        if note.get("aliasedFrom"):+            out["_hint"] = (f"Resolved '{note['aliasedFrom']}' to symbol '{args['symbolName']}' ({note['aliasHow']}). "+                            + str(out.get("_hint") or ""))+    return out+++def _handle_open_symbol_editor_inner(kicad_info: dict, args: dict) -> dict:     """Open the KiCad Symbol Editor and optionally load a specific symbol.      Args:
server.py+14
@@ -63,6 +63,8 @@ from handlers.kicad_cli_lint import (     handle_run_erc, handle_lint_board, handle_lint_schematic,     handle_lint_library, handle_format_upgrade, )+from handlers.design_rules import handle_list_design_rules, handle_set_design_rules  # wiki #73+from handlers.list_symbols import handle_list_symbols  # wiki #62 # v0.7.1+: export handlers (Gerber/PDF/SVG/STEP/BOM_CSV) via kicad-cli. The # functions have existed in handlers/export.py for a while but were never wired # into COMMAND_HANDLERS — kicad_export_gerbers/pdf/svg/step/bom_csv all returned@@ -440,6 +442,15 @@ _VERB_CATALOG = {     "place_footprint": {"summary": "Deterministically place a footprint into a board preview.", "long": False,         "hint": "Splices a footprint into a board via s-expr (no GUI); good for previews.",         "related": ["kicad_open_board", "kicad_install_footprint"], "pitfalls": ["operates on the file — close the board in KiCad first or the edit races the GUI"]},+    "list_design_rules": {"summary": "List the fabs / processes / layer counts on adom/pcb-design-rules.", "long": False,+        "hint": "kicad_list_design_rules {\"fab\":\"jlcpcb\"} (fab optional). Rows come from the wiki page at call time; InstaPCB is the house baseline.",+        "related": ["kicad_set_design_rules", "kicad_lint_board"], "pitfalls": ["needs wiki.adom.inc reachable from the desktop"]},+    "set_design_rules": {"summary": "Stage a fab's .kicad_dru next to a board and run DRC with it.", "long": False,+        "hint": "kicad_set_design_rules {\"fab\":\"adom-instapcb\",\"layers\":2,\"boardPath\":\"C:/.../x.kicad_pcb\"}. layers defaults to the board's copper count; druPath overrides the wiki file; runDrc:false to only stage.",+        "related": ["kicad_list_design_rules", "kicad_lint_board", "kicad_run_drc"], "pitfalls": ["replaces an existing <stem>.kicad_dru (backed up next to it); pass keepExisting:true to refuse instead", "an open PCB editor applies the file on its next DRC run"]},+    "list_symbols": {"summary": "Names in a registered symbol library, with KiCad's own inventory.", "long": False,+        "hint": "kicad_list_symbols {\"libraryName\":\"Adom\"} (default Adom; or libraryPath). Use a returned name as symbolName; the file name is often an MPN, not the symbol name.",+        "related": ["kicad_show_library", "kicad_adom_library_status", "kicad_lint_library"], "pitfalls": ["kicadParser.symbols is what the editor can show; symbols is the bridge's reader"]},     "run_drc": {"summary": "Run DRC on a board via kicad-cli (read-only).", "long": False,         "hint": "Absolute board path; runs kicad-cli DRC and returns violations. Doesn't need KiCad open.",         "related": ["kicad_lint_board", "kicad_open_board", "kicad_run_erc"], "pitfalls": ["needs KiCad >= 7 (kicad-cli); older installs lack it"]},@@ -931,6 +942,9 @@ COMMAND_HANDLERS = {     "find_connections": handle_find_connections,     "analyze_connections": handle_analyze_connections,     "lint_board": handle_lint_board,+    "list_design_rules": handle_list_design_rules,+    "set_design_rules": handle_set_design_rules,+    "list_symbols": handle_list_symbols,     "lint_schematic": handle_lint_schematic,     # v1.7.13+: library lint + file-format upgrade     "lint_library": handle_lint_library,