← Commit history

0.9.256: reveal_library plugin method (0.9.2): left-open editor shows the library's FULL list via tree-node select, no text filter (generic names like UI lost the fuzzy match)

Colby Knox ·84ee39d6d2 ·1mo ago ·parent 8d17d87
5 files changed +83−12
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.255\ No newline at end of file+0.9.256\ No newline at end of file
adom-bridge-kicad-manifest.json+5−5
@@ -1,15 +1,15 @@ {   "manifest_version": 1,   "name": "kicad",-  "version": "0.9.255",-  "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.255/adom-bridge-kicad-v0.9.255.zip",-  "sha256": "e89d3bd81e3dbefe12826b0a1c8b0881bd279eb48af1a5a950526ae4826e824f",-  "size": 453653,+  "version": "0.9.256",+  "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.256/adom-bridge-kicad-v0.9.256.zip",+  "sha256": "c9b5d8ee2c4433a81d8e412b276d561232d2383e829866d1388d9add71a0884f",+  "size": 454370,   "verbPrefixes": [     "kicad_"   ],   "healthEndpoint": "/status",-  "released_at": "2026-08-27T21:14:23Z",+  "released_at": "2026-08-27T21:16:40Z",   "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png",   "languages": [     "Python",
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "kicad",   "displayName": "KiCad EDA",-  "version": "0.9.255",+  "version": "0.9.256",   "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.",   "homepage": "https://wiki.adom.inc/adom/adom-bridge",   "author": "Adom Inc.",
handlers/install_library_bundle.py+6−4
@@ -109,14 +109,16 @@ def _capture_proof(kicad_info: dict, args: dict, lib_name: str, first_symbol: st                     pass         else:             result["editorLeftOpen"] = True-            # Loosen the tree filter to just the LIBRARY name so the user sees-            # the whole list, not only the photographed part.+            # Show the FULL list: clear the tree filter and select/expand the+            # library node by name (plugin 0.9.2 reveal_library; a text filter+            # made generic names like 'UI' lose a fuzzy match to other libs).             try:                 from handlers.bridge_client import _resolve_plugin, call as _plugin_call                 info, err = _resolve_plugin("eeschema")                 if info and err is None:-                    _plugin_call(info["port"], "select_and_load_symbol",-                                 {"symbolName": lib_name, "libraryName": lib_name}, timeout=15.0)+                    rev = _plugin_call(info["port"], "reveal_library",+                                       {"libraryName": lib_name}, timeout=20.0)+                    result["libraryRevealed"] = bool((rev or {}).get("found"))             except Exception:                 pass     except Exception as e:
plugin_payload/adom_bridge.py+70−1
@@ -60,7 +60,7 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path from typing import Any, Callable, Optional -__version__ = "0.9.1"+__version__ = "0.9.2"  # Exe-name -> port offset. The KiCad bridge in adom-desktop knows this # table too. New exes get appended; never renumber existing entries or@@ -1948,6 +1948,62 @@ def _ui_navigate_symbol(symbol_name: str) -> dict:     return _ui_navigate_in_editor("symbol", symbol_name)  +def _ui_reveal_library(editor_kind: str, library_name: str) -> dict:+    """Select + expand the LIBRARY node by name with NO text filter. A filter+    string competes globally (a generic library name like 'UI' loses a fuzzy+    match to Arduino_* items), so the reveal works on the tree model instead:+    walk the top-level (library) items, match the label, expand and select."""+    try:+        import wx  # type: ignore[import-not-found]+        import wx.dataview  # type: ignore[import-not-found]+    except ImportError:+        return {"found": False, "error": "wx not loaded"}+    needle = f"{editor_kind} editor".lower()+    target = None+    for win in wx.GetTopLevelWindows():+        try:+            title = win.GetTitle() if hasattr(win, "GetTitle") else ""+        except Exception:  # pylint: disable=broad-except+            title = ""+        if needle in title.lower():+            target = win+            break+    if target is None:+        return {"found": False, "error": f"no '{editor_kind} editor' frame is open"}+    dvc = _find_dataview_ctrl_recursive(target)+    if dvc is None:+        return {"found": False, "error": "no library tree control found"}+    try:+        model = dvc.GetModel()+        root = wx.dataview.DataViewItem()+        kids = wx.dataview.DataViewItemArray()+        model.GetChildren(root, kids)+    except Exception as e:  # pylint: disable=broad-except+        return {"found": False, "error": f"tree walk failed: {e}"}+    want = (library_name or "").strip().lower()+    hit = None+    labels = []+    for i in range(len(kids)):+        try:+            label = str(model.GetValue(kids[i], 0) or "")+        except Exception:  # pylint: disable=broad-except+            label = ""+        labels.append(label)+        if label.strip().lower() == want or label.split(" ")[0].strip().lower() == want:+            hit = kids[i]+            break+    if hit is None:+        return {"found": False, "error": "library not in tree", "libraries": labels[:40]}+    try:+        dvc.UnselectAll()+        dvc.Expand(hit)+        dvc.Select(hit)+        dvc.EnsureVisible(hit)+    except Exception:  # pylint: disable=broad-except+        pass+    return {"found": True, "revealed": library_name, "frameTitle": target.GetTitle()}++ def _ui_navigate_footprint(footprint_name: str) -> dict:     return _ui_navigate_in_editor("footprint", footprint_name) @@ -3050,6 +3106,19 @@ def _dispatch(method: str, params: dict) -> Any:     # useSendInput:true escalates from wx.PostEvent (safe, may not     # propagate) to real Win32 SendInput (reliable, briefly steals     # foreground). Always pair with verify_loaded for confirmation.+    if method == "reveal_library":+        # Show the user their new library's FULL list: clear the tree filter+        # (hop 1; the repopulate debounces on the UI thread), then select and+        # expand the library node by NAME on the model (hop 2) - no text+        # filter, so generic names never lose a fuzzy match to other libs.+        _lib = params.get("libraryName") or params.get("name") or ""+        if not _lib:+            raise ValueError("reveal_library requires params.libraryName")+        _editor = params.get("editor") or "symbol"+        import time as _t+        _call_on_ui_thread(lambda: _ui_navigate_in_editor(_editor, ""))+        _t.sleep(0.8)+        return _call_on_ui_thread(lambda: _ui_reveal_library(_editor, _lib))     if method == "select_and_load_symbol":         name = params.get("symbolName") or params.get("name") or ""         use_si = bool(params.get("useSendInput"))