Rebrand Pinscope to Periscope across product and codebase.
Rename the core package to periscopex, update UI/docs/Docker/deploy defaults to periscope.michelebigi.it, and keep legacy version/storage key aliases so existing projects keep working. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""Periscope KiCad 9/10 action plugin — load periscope-findings.json and focus.
|
||||
|
||||
Install: copy this ``plugins/kicad`` folder into the KiCad scripting plugins
|
||||
directory (Preferences → Plugins), or symlink it.
|
||||
|
||||
Pan-and-zoom uses pcbnew.FocusOnItem for layout findings. Schematic focus
|
||||
uses the IPC/kipy API when present; otherwise the plugin selects by uuid
|
||||
text so you can paste into the sheet named in the finding.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class PeriscopeAction:
|
||||
def defaults(self) -> None:
|
||||
self.name = "Periscope findings"
|
||||
self.category = "Periscope"
|
||||
self.description = "Jump to a Periscope finding on the schematic or board"
|
||||
self.show_toolbar_button = True
|
||||
|
||||
def Run(self) -> None:
|
||||
import wx
|
||||
|
||||
from .focus import find_bridge_file, focus_target, load_bridge
|
||||
|
||||
board_path = _board_path()
|
||||
start = Path(board_path) if board_path else Path.cwd()
|
||||
bridge_path = find_bridge_file(start)
|
||||
if bridge_path is None:
|
||||
wx.MessageBox(
|
||||
"No periscope-findings.json next to the project. "
|
||||
"Run Periscope and copy that file beside the .kicad_pro.",
|
||||
"Periscope",
|
||||
wx.OK | wx.ICON_INFORMATION,
|
||||
)
|
||||
return
|
||||
try:
|
||||
payload = load_bridge(bridge_path)
|
||||
except (OSError, ValueError) as exc:
|
||||
wx.MessageBox(str(exc), "Periscope", wx.OK | wx.ICON_ERROR)
|
||||
return
|
||||
findings = list(payload.get("findings") or [])
|
||||
if not findings:
|
||||
wx.MessageBox("The bridge file has no findings.", "Periscope", wx.OK)
|
||||
return
|
||||
dlg = wx.SingleChoiceDialog(
|
||||
None,
|
||||
"Select a finding",
|
||||
"Periscope",
|
||||
[_label(f) for f in findings],
|
||||
)
|
||||
if dlg.ShowModal() != wx.ID_OK:
|
||||
dlg.Destroy()
|
||||
return
|
||||
idx = dlg.GetSelection()
|
||||
dlg.Destroy()
|
||||
if idx < 0 or idx >= len(findings):
|
||||
return
|
||||
target = focus_target(findings[idx])
|
||||
if not _try_focus(target):
|
||||
wx.MessageBox(
|
||||
f"Focus {target['kind']} {target['ref']}\n"
|
||||
f"sheet={target['sheet']}\nuuid={target['uuid']}",
|
||||
"Periscope",
|
||||
wx.OK | wx.ICON_INFORMATION,
|
||||
)
|
||||
|
||||
|
||||
def _label(f: dict) -> str:
|
||||
sev = str(f.get("severity") or "").upper()
|
||||
ref = f.get("ref") or "?"
|
||||
msg = str(f.get("message") or "")
|
||||
if len(msg) > 80:
|
||||
msg = msg[:77] + "..."
|
||||
return f"{sev} {ref}: {msg}"
|
||||
|
||||
|
||||
def _board_path() -> str:
|
||||
try:
|
||||
import pcbnew
|
||||
board = pcbnew.GetBoard()
|
||||
if board:
|
||||
return board.GetFileName() or ""
|
||||
except ImportError:
|
||||
pass
|
||||
return ""
|
||||
|
||||
|
||||
def _try_focus(target: dict) -> bool:
|
||||
ref = target.get("ref") or ""
|
||||
uuid = target.get("uuid") or ""
|
||||
if target.get("kind") == "pcb":
|
||||
try:
|
||||
import pcbnew
|
||||
board = pcbnew.GetBoard()
|
||||
if board is None:
|
||||
return False
|
||||
fp = board.FindFootprintByReference(ref) if ref else None
|
||||
if fp is None:
|
||||
return False
|
||||
pcbnew.FocusOnItem(fp)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
try:
|
||||
from kipy import KiCad
|
||||
from kipy.common_types import DocumentType
|
||||
kicad = KiCad()
|
||||
docs = kicad.get_open_documents(DocumentType.SCH)
|
||||
if not docs:
|
||||
return False
|
||||
# Best-effort: selection by uuid is editor-version specific.
|
||||
_ = (uuid, docs)
|
||||
return False
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
import pcbnew
|
||||
|
||||
class PeriscopePcbnewPlugin(pcbnew.ActionPlugin, PeriscopeAction):
|
||||
pass
|
||||
|
||||
PeriscopePcbnewPlugin().register()
|
||||
except ImportError:
|
||||
pass
|
||||
Reference in New Issue
Block a user