87 Commits

Author SHA1 Message Date
943b808a75 BSDL: attach-bsdl command + persist the attached model
New `attach-bsdl <module> <part> <file.bsd>` command: parse via BsdlModel,
apply_bsdl() onto the part, store the path on Part::bsdl_path, report bound/
unbound. Persist a `B\t<path>` line under the part; on restore, re-parse and
re-apply each attached model (the .bsd path is persisted, not the derived
pin specs). Round-trip covered by test_bsdl_apply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:07:12 +02:00
279be513a4 BSDL: ingest libbsdl into essim and populate PinSpec from a device model
Link libbsdl dynamically (add_subdirectory ../libbsdl, overridable via
-DBSDL_DIR). New BsdlModel wraps the C ABI and reduces a parsed .bsd to
essim's pin vocabulary; apply_bsdl() binds each port to a Pin (by name, then
by physical pad) and sets its spec: direction, function (TAP role / power /
ground / signal), pad, and source = Bsdl.

This feeds the PinSpec fields from P1, so verify's existing power/ground
placement pass now lights up for BSDL-modelled parts. Covered by
test_bsdl_apply (name + pad binding, TAP roles, linkage classification).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:01:00 +02:00
86236d744d docs: document the PinSpec refactor + add a Dependencies section
DESIGN.md: Pin now carries a PinSpec (function/direction/pad/source);
expected_signal_type() is a derived accessor; pin_role() returns a PinSpec.
README.md: dedicated Dependencies section with libzip/pugixml install
commands for Debian/Ubuntu, Arch and Fedora.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 12:31:34 +02:00
1b507f1752 Pins: replace expected_signal_type field with a model-derived PinSpec
Introduce PinSpec (function/direction/pad/source) as the "expected" half of
pin verification, and make Pin::expected_signal_type() a derived accessor over
spec.function. pin_role() now returns a PinSpec; the connector layout (and,
later, BSDL) feed the same structure.

Pure refactor, behaviour-preserving: vpx_3u_role is still a stub, so every pin
maps to Other exactly as before. The new `pad` field will carry the BSDL
physical pin; direction/function will unlock contention/undriven/NC checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 12:01:12 +02:00
fdf86a2e17 Export: ODS meta block + header-row freeze/filter; flat CSV with aligned column names.
ODS sheets now carry a per-connection meta block (Connection / Transform
/ Left / Right) above the data; the header row anchors the freeze, the
auto-filter range, and the zebra striping. CSV stays a single flat
15-column table whose names match the ODS headers exactly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 18:21:50 +02:00
3be5bc3f6e ODS polish + reusable confirm modal + file-dialog focus/overwrite fixes.
ODS writer:
- Header row styled bold on a grey background; data rows alternate
  light-grey / white (zebra). Auto-filter buttons enabled per sheet
  via `<table:database-range table:display-filter-buttons="true">`
  — sheet names are now single-quoted in the target-range-address so
  LibreOffice actually parses ranges that contain spaces.
- First row of every sheet frozen via `settings.xml` (view setting).
  The settings layout follows LibreOffice's own writer exactly:
  `xmlns:ooo` + `xmlns:xlink` declared on the root, `ActiveTable` and
  view-level zoom/grid/headers placed *after* the Tables map (the
  order LibreOffice expects to read back). HorizontalSplitMode = 0,
  VerticalSplitMode = 2 → only the first row is frozen, the first
  column scrolls normally. ActiveSplitRange = 2 (bottom-left pane).
  `settings.xml` registered in `META-INF/manifest.xml`.

Reusable Yes/No modal:
- New `screen_confirm.cpp` exposing `Tui::ShowConfirm(msg, on_yes)`.
  Centred `borderRounded` popup, `No` first (safer default), Enter
  confirms the focused button, Esc cancels (treated as No).
- Stacked into the Modal chain in `Run()` (between file-dialog and
  error). The outer `CatchEvent` cedes events when it's open.

File dialog:
- Picks `OK` button focus reliably — previously the focus indices in
  the Renderer were remapped against the Container::Vertical child
  indices, so the OK label only flagged "focused" while the actual
  focused child was the filename input.
- OK button uses a custom `ButtonOption::transform` that renders the
  label transparent when idle, inverted when focused. No more
  cyan-fill, no more double-inversion via FocusLabel.
- After confirmation, if the picked path already exists, pops a
  `ShowConfirm("File … already exists. Overwrite?")` before invoking
  the caller's action.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 13:36:05 +02:00
aa59d1a041 ODS writer: drop duplicate XML declaration; harden sheet-name sanitiser.
LibreOffice rejected the generated `.ods` with `Format error at 2,39
in content.xml`. Root cause: `pugi::format_no_declaration` suppresses
only the *implicit* declaration auto-added at save time — the explicit
`node_declaration` I had appended to the document still got serialised,
on top of a manual `<?xml…?>` string prepend in the output. Two
declarations back-to-back, invalid XML.

Fix: let pugixml emit the explicit declaration node, drop the manual
prepend.

Also harden the sheet-name sanitiser in the export action: ODS / Excel
also forbid `< > &` in raw cell or table names, so the default
connection name `bp/J20 <-> payload1/P0` made content.xml entity-
escape `<` to `&lt;`, which a few viewers handle but Excel rejects.
Clip to 31 chars too (Excel's hard limit) so multi-name connections
don't blow up the open.

Verified by `soffice --headless --convert-to csv` round-tripping the
output without errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 12:22:51 +02:00
67de4dcaf3 Refactor: extract export commands; co-locate sigtype popup logic.
Two focused, behaviour-preserving moves:

1. `OpenSignalTypeDialog` + `ApplySignalTypeChoice` moved from
   `shell.cpp` to `screen_sigtype_modal.cpp` so the popup owns all of
   its logic instead of having its open/apply functions live in the
   shell file.

2. The `export` command extracted from `commands.cpp` to a new
   `commands_export.cpp` under a `Tui::RegisterExportCommands()`
   member. `RegisterCommands()` calls it at the end. File-local
   helpers (`csv_quote`, `pin_side`) move alongside in an anonymous
   namespace.

Establishes the pattern for future per-group splits: declare a
`Register<X>Commands()` member, define it in its own file, call it
from the orchestrator. Other groups stay in `commands.cpp` for now —
nothing else has grown large enough to warrant the split.

Sizes: shell.cpp 497 → 448, commands.cpp 846 → 675 (+ 191 for the
new commands_export.cpp). DESIGN.md updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 12:18:58 +02:00
7d307dad57 Export command (CSV + ODS), file dialog, error modal, path persistence.
New user-facing features:
- `export connections <file>` writes a tabular dump of every wire pair:
  connection, transform, left/right module/part/pin/signal/type/suspect,
  mixed-types flag. Dispatch on extension: `.csv` (flat file) or `.ods`
  (one sheet per connection). Any other extension shows an error and
  writes nothing.
- Bare `export` (or dashboard `[x]`, or palette `export`) opens an
  interactive file-picker dialog with a CSV/ODS toggle at the top.
  Picking a filter rewrites the filename's extension. Last-used
  directory and filename are remembered per-call-site.
- Two new CLI flags on the binary: `--source FILE` to run a script at
  boot, `--restore FILE` to restore a snapshot at boot. Combinable.

Reusable infrastructure:
- `OdsWriter` (`src/imports/ods_writer.{hpp,cpp}`): minimal .ods writer
  using libzip + pugixml (already in the build for the importer).
  Multi-sheet workbook of string cells. ~180 lines, no new dep.
- Generic file-picker dialog (`screen_filedialog.cpp`): one Modal
  reused for any "pick a path" interaction via
  `OpenFileDialog(title, persist_key, default_filename, filters, cb)`.
  Validates the picked extension against the filter whitelist;
  unknown ones stay in the dialog with a status message. Persists
  (dir, filename) per `persist_key`.
- Generic error modal (`screen_error.cpp`, `ShowError(msg)`): centred
  red-titled popup, dismissable with Esc/Enter. Used by the export
  failures (open-for-write, ODS save, unknown extension/kind);
  ready for adoption elsewhere.
- Per-key path persistence (`SaveLastUsed`/`LoadLastUsed` in
  `shell.cpp`): two-line file per key under the user-data dir.
- `UserDataDir()` extracted from the history path helper so the new
  per-key persistence shares the same XDG/AppData logic.
- New help-screen topic "Export"; user-facing `doc/user/analysis.md`
  gains an "Exporting" section; `DESIGN.md` gains a generics
  section covering the dialog / error modal / persistence / ODS
  writer; `DumpCommandsMd` now respects the `hidden` flag (the
  `connect` alias no longer appears in the auto-gen reference).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 12:03:39 +02:00
f62f4a0c9b Console help: revert to command listing; hide connect alias.
`help` bare went back to printing the textual list of commands rather
than opening the help screen — the screen is reachable from the
dashboard with `[h]`. This matches how every other CLI handles `help`
and avoids surprising script behaviour.

Added a `hidden` field on `CommandSpec` so registry-level aliases can
be excluded from the listing. `connect` is now hidden (the alias
`plug` is the user-facing name on the dashboard and in `help`).
Both names continue to resolve to the same action; existing scripts
that used `connect` still work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 12:27:38 +02:00
ae36026768 UI text: replace 'refuted' with 'suspect' in user-facing strings.
The analyze screen already used `[Suspect Power]`; the dashboard and
the `load` summary still said 'refuted', which felt harsher and was
out of sync. Now consistent everywhere.

- Dashboard module row: `power: X confirmed, Y suspect   gnd: K`.
- Load summary: `types: N power, M gnd, K suspect Power (name only
  — kept as Other)`.

Internal variable renamed `n_pwr_refuted` → `n_pwr_suspect`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 10:58:48 +02:00
300e871aed Help screen, explore→set-connector-type Enter, settype UI polish.
- New `screen_help.cpp` (`screen_idx = 6`). Left column: menu of 13
  topics (Overview, Dashboard, Console, Palette, Explore,
  Connect/plug, set-connector-type, Signal types, NC pins, Analyze,
  Scripting, Save/restore, Quitting). Centre column: paragraphs of
  the focused topic, word-wrapped via `paragraph()` and scrollable.
  Right column: standard help panel.
- `help` bare → opens the screen; `help <name>` keeps the existing
  textual command-help behaviour for scripts.
- Dashboard `[h]` shortcut opens the screen, and the dashboard help
  panel (both the loaded and the no-system branch) lists it.
- Console: title gets the standard breadcrumb (`essim → console —
  type commands, read textual output`). Module/connection counters
  moved off (they live on the dashboard now).
- Explore Enter on a part jumps to `set-connector-type` with the
  exact-match index pre-computed in the filtered list (avoids the
  substring-match collision where `J20` would land on the wrong
  row when J200/J21 also matched).
- set-connector-type screen: bind `focused_entry` to `selected` on
  both menus so the cursor `>` tracks the selected row when state
  is pre-seeded from outside. Right column drops its strict
  `size(WIDTH, EQUAL, 40)` in favour of `flex`, and the `new type`
  input uses `xflex` so it actually stretches across the column.
- Esc on `set-connector-type` honours `screen_back_idx` — when
  entered via Enter on a part in `explore`, Esc returns to explore;
  otherwise it returns to the dashboard like every other screen.
  Standalone command entries explicitly reset the back-link.
- Net-member rows in the explore detail pane carry a
  `module\tsignal` payload so Enter opens the popup scoped to the
  peer module rather than mis-firing on the locally selected one.
  Same scheme for local-pin rows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 10:31:09 +02:00
792e4745d3 Merge search and net screens into explore; drop both commands.
`explore` was already a superset of `search` (4 columns: module → type
→ filtered children → detail, with parts/signals/connections — vs
search's 2 columns of parts/signals only). It now also subsumes the
former `net` screen: when a signal entry is selected, the detail pane
shows the local pins followed by a `Net members (across connections)`
section listing every `(module, signal, type)` reachable through the
BFS over `Connection::pin_map`, with the count + dominant type and an
INCONSISTENT flag in the signal-detail header.

Removed:
- `src/tui/screen_search.cpp`, `src/tui/screen_net.cpp`.
- `commands["search"]`, `commands["net"]` (including its textual
  inline form). The `find_net` / `Net` API stays for explore's BFS
  panel and the analyze screen's net-mix check.
- `[s]` and `[n]` letter shortcuts on the dashboard.
- `net_*` and `search_*` state members + builders + constructor
  inits.

screen_idx renumbering (the slots vacated by search + net are
removed, not left dead):
  0 = console  (unchanged)
  1 = connect
  2 = set-connector-type
  3 = explore  (unchanged number, but now subsumes search + net)
  4 = dashboard (boot)
  5 = analyze

Palette signal items now jump to `explore` prefilled on the signals
tab with the child filter seeded to the exact signal name; the BFS
section in the detail pane is what shows the cross-module net.

Net-member rows in the detail pane are deliberately read-only for
now (Enter is a no-op): the signal-type popup is scoped to the
currently selected module, so opening it on a peer-module member
would mis-fire. Cross-module Enter navigation can come later if
needed.

DESIGN.md and user docs updated accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 21:49:26 +02:00
7145577df7 doc: fix ASCII diagram alignment in user index.
Replace `◀` / `▶` (often rendered as double-width emoji glyphs) with
`←` / `→` (single-cell in every monospace font) so the box borders
line up correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 20:43:36 +02:00
516149cdae Rename set-type to set-connector-type; help-panel & types-glossary polish.
- Command renamed from `set-type` to `set-connector-type` for
  clarity (the previous name was ambiguous — "type" of what?). No
  legacy alias kept; old scripts that still used `set-type` must be
  migrated. `test/system.essim` and all user/design docs updated.
- Help panel (RenderHelpPanel) now wraps in borderRounded with a
  centred bold title, so it is visually distinct from the main
  content on every screen. Width bumped from 30 to 32 to include
  the border.
- Analyze screen's Types tab gains a sibling "type glossary" panel
  (also borderRounded, only visible when the Types tab is focused)
  that explains Power / Suspect Power / Hard floor / Gnd in plain
  language using `paragraph()` for clean word-wrap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 20:41:35 +02:00
90502c0762 Dashboard + palette + analyze screen; consolidated categorization rules.
UI restructuring:

- Dashboard (`screen_dashboard.cpp`, `screen_idx = 6`) is the new home
  screen at boot. Reads Overview / Health / Analysis / Modules from
  the current System every frame; per-module rows list parts grouped
  by `connector_type` and a Power/Gnd inference summary (yellow when
  any name-Power signal is refuted). Scrollable via PgUp/PgDn/Home/End.
  Letter shortcuts: `c`=console, `s`=search, `p`=plug (alias of
  connect), `t`=set-type, `e`=explore, `n`=net, `a`=analyze, `q`=quit.
- Global Ctrl-P palette (`screen_palette.cpp`) — fuzzy-finds over
  registered commands + module / signal names. Activation runs the
  bare command or jumps to the matching screen with state seeded.
- Unified analyze screen (`screen_analyze.cpp`, `screen_idx = 7`):
  tabbed layout (`Issues / Groups / Types`), Tab or ←→ to switch
  tabs, ↑/↓ to navigate the focused list. Replaces the previous
  shell-bouncing `[v]erify` shortcut — `verify` content is now in
  the Issues tab. Types tab attaches the decision rationale to each
  signal row (fan-out / voltage / hard floor).
- Context help panel: `RenderHelpPanel(title, entries)` in
  `tui_helpers.{hpp,cpp}` rendered on the right of every screen.
- Console (former "log") rename: screen 0 is `[c]onsole` in the UI
  and "console" in its help-panel title. The underlying screen and
  the shell prompt are unchanged.
- Esc from any non-home screen returns to the dashboard. The
  dashboard itself swallows Esc; quit via `q` / the `quit` command.
  `quit` now calls `screen_ptr->Exit()` directly so it works from
  any screen including via the palette.

Signal type inference:

- `Signal::type` defaults to `Other` — auto-inference no longer
  happens at construction.
- `infer_signal_types(System*)` is called at the end of every load.
  Three rules: GndShield from name alone; Power requires name match
  + a hard fan-out floor (< 3 pins = always Other, regardless of
  name or voltage) + at least one positive structural signal
  (fan-out ≥ 4 OR voltage pattern in the name like `3V3`, `5V`).
- Thresholds exposed in `analysis.hpp` (`POWER_FANOUT_HARD_FLOOR`,
  `POWER_FANOUT_CONFIRM_MIN`, `has_voltage_pattern`) so the analyze
  screen can render the same rationale without duplicating logic.
- `set-signal-type` still wins; save/restore round-trips the type.

Analysis groups & anomalies:

- New `GroupKind::DiffBus` — ≥ 2 diff pairs sharing the same
  outer-stem with consecutive integer indices are aggregated into a
  single bus (`MDI[0..3]_P/N`). `MDI0` and `PCIE_TX_0` index forms
  both accepted. Solo pairs under a bus-able stem fall back to
  `DiffPair`.
- New `AnomalyKind::DiffBusGap` for missing lanes.

Documentation:

- `DESIGN.md`: dedicated "Categorization rules (normative)" section
  consolidating signal type, NC origin, signal groups, anomalies,
  component kind, and connector wiring rules with exact thresholds
  and decision order.
- `doc/user/analysis.md` (new): user-facing version of the same
  rules in plain language. Linked from `doc/user/index.md`.

Tests: +6 new cases (62 total). Adjusted `test_persist.cpp` to set
the signal type explicitly in the fixture (no more auto-inference).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 20:23:33 +02:00
5e89b33088 Signal analysis pass (analyze), NC tests, DESIGN.md catch-up.
- New `src/system/analysis.{hpp,cpp}` — stateless post-processing pass
  `analyze_system(System*) → AnalysisReport`. Per-module detection of
  signal groups and anomalies; pure read, re-runnable.
  - Groups: diff pairs (`*_P` / `*_N`, case-insensitive), buses
    (`NAME[N]` or strict `NAME_N` — the `_` before digits is required
    so names like `GETH_01_VDD12` are not misread as a bus).
  - Anomalies: `DiffPairOrphan` (asymmetric: only `_P` without `_N` is
    reported — `_N` alone is overloaded with active-low semantics and
    floods the output with false positives), `BusGap` (missing index
    inside a detected `[lo..hi]`).
  - Noise filters: signals starting with `$` (Mentor internals) are
    skipped wholesale.
- New `analyze` shell command — prints groups sorted by module +
  label, then anomalies. Sized for the upcoming dashboard.
- `tests/test_analysis.cpp` — 8 cases covering both detectors, false-
  positive guards (no-underscore digits, `$`-prefixed internals), and
  per-module scoping.
- `tests/test_nc_origin.cpp` — completes the prior NC-tagging commit
  with round-trip + drop_singleton_signals coverage.
- DESIGN.md updated: layout entry for `analysis.{hpp,cpp}` and new
  section explaining the pass; NC-origin paragraph aligned with the
  actual tag semantics and the verify three-pass summary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 13:42:58 +02:00
280526304d Signal-type popup, NC pin tagging, interactive viewer hygiene.
- Enter on a signal entry (net / explore) opens a modal popup to pick
  power / gnd / other. Recording is deduped: a sequence of toggles on
  the same signal collapses to a single `set-signal-type` line; no-op
  selections record nothing.
- Bare interactive commands (the ones that open a full-screen mode)
  are no longer recorded by `script-save`. Their inline forms still
  are. Mutating actions inside a screen record their own canonical
  line.
- Mentor importer treats signals whose name starts with `unconnected`
  as no-connect — the pin is kept on the part without a signal and
  tagged `ImportedUnconnected`.
- `drop_singleton_signals` runs at the end of `load`: any signal with
  exactly one pin is detached (singletons are NC by definition); the
  pin is tagged `DroppedSingleton`. Count is reported inline.
- `verify` gains a one-line orphan summary (imported NC / dropped
  singleton totals). Pins materialised by `FillIdentityNCs` are
  excluded via a `pin_map` filter — they are bridged to a real signal
  on the peer module and are not real NCs at system level.
- NcOrigin tag is serialized in save snapshots as an optional 4th
  field on N records (backward-compatible).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 07:56:46 +02:00
043fef0a31 User-facing docs: --commands-md flag, doc/user/ tree, anonymised script.
- `essim --commands-md [file]` instantiates the Tui, calls
  `Tui::DumpCommandsMd(ostream&)` which iterates the live registry and
  emits Markdown grouped by interactive/other, then exits. Single
  source of truth: a new `CommandSpec` field surfaces automatically.
- CMake `doc` target now `DEPENDS essim` and chains:
    doxygen → gen_api_md.py → doc/api/
    essim --commands-md      → doc/user/commands.md
- `doc/user/` adds:
    - index.md (hand-written) — first session, interactive-screen
      conventions, save/restore/replay overview.
    - scripting.md (hand-written) — `set`/`$var` expansion semantics,
      `source` event-paced execution, script-save denylist, worked
      example pointing at test/system.essim.
    - commands.md (auto-generated, regenerated by the `doc` target).
- Top-level README refocused on quick start; pointers to the new
  doc tree (user/, api/, DESIGN.md) instead of an inline command table.
- doc/README.md and DESIGN.md document the two-pipeline doc workflow.
- `test/system.essim` and user docs anonymised: bkp → backplane,
  vdn1/2/3 → payload1/2/3, cb3p → payload4, bpb/cob/ssu →
  peripheral1/2/3; netlist file names + variable names + paths all
  replaced with generic equivalents.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 08:29:45 +02:00
66460262af Auto-generated API doc: doxygen → custom Python emitter → doc/api/.
`cmake --build build --target doc` runs Doxygen to produce XML, then
`doc/gen_api_md.py` (~330 lines, stdlib-only) emits a Markdown tree
under `doc/api/` that gitea renders directly in its file browser.

- 24 class/struct pages + 51 source-file pages + indices, with source
  links of the form `../../../../src/...#L42` that gitea turns into
  clickable line-anchored links.
- Doxyfile.in templated by CMake (XML-only output to build/doc/xml/).
- Pure Python emitter, zero external deps — no doxybook2 (not packaged
  on Arch) and no moxygen (avoids Node).
- Target gracefully disabled if Doxygen or Python 3 is missing at
  configure time; regular build target unaffected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 08:13:15 +02:00
fe2dc13c89 Interactive net screen, main + per-screen title bars, focus highlight, help split.
- New `net` full-screen layout (`screen_net.cpp`, `screen_idx = 5`): three
  columns (module menu / signal filter + menu / live BFS result). Bare
  `net` opens the screen; `net <m> <s>` keeps the inline path.
- Main screen grows a title bar: " essim — system digital twin "
  (bold + dim) on the left, live "N module(s), M connection(s)" on
  the right.
- Every interactive screen now renders the same breadcrumb at the top:
  " essim → <name>  — <short description> ", followed by a separator.
- `tui_helpers.hpp` exports `FocusLabel(elem, focused)`. Every
  interactive screen wraps its field labels with it so the active
  field's label flips to inverted video. Buttons (Connect, Apply)
  invert as a whole.
- `CommandSpec` gains a `bool interactive`. `help` (no args) splits
  the listing into "Interactive (open a full-screen mode)" and
  "Other". `help <name>` tags interactive entries with [interactive]
  and explains the bare-vs-inline duality.
- `DESIGN.md` (renamed from `CLAUDE.md`): refreshed Layout, TUI, and
  screen-recipe sections to cover the new field, the title idiom,
  FocusLabel, the `net` screen, and the event-paced `Computing…`
  modal during `source`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 07:52:22 +02:00
c3bb00cb4d Altium import, nets, canonical pins, component kinds, set/$var, scrollback, source modal.
Major additions, all wired end-to-end with doctest coverage:

- Altium netlist importer (`imports/import_altium.{hpp,cpp}`): two-pass
  parser for `[ ]` parts and `( )` signals; `System::Load` no longer has
  the IMPORT_ALTIUM hole.
- `duplicate <src> <dst>` deep-copies a module (signals, parts, pins,
  rewired signals); connections excluded by design.
- Nets (`system/nets.{hpp,cpp}`): BFS over `Connection::pin_map` to
  return the transitive (Module, Signal) closure. `verify` extended with
  a second pass flagging Power↔GndShield inconsistencies in bridged
  nets; new `net <module> <signal>` command for inspection.
- Canonical pin names (`system/pin_name.{hpp,cpp}`): zero-padded digit
  suffix lets A1 ↔ A001 pair via `IdentityTransform` and
  `CheckIdentityCompatible` without losing the imported notation.
- Component classification (`system/component_kind.{hpp,cpp}`):
  `Part::kind` inferred at construction from the reference-designator
  prefix (longest-match: LED/TP/SW/FB/MK/MP/MH/HS/RA/RN/RP/RV first,
  then R/C/L/F/D/Q/U/J/P/Y/X/S).
- Identity wiring tolerance: `CheckIdentityCompatible` accepts the
  subset case (typical when one importer drops NC pins, e.g. Altium)
  and surfaces orphans as an info string. `FillIdentityNCs`
  materialises orphan canonical positions as NC pins on the missing
  side at connect time.
- Connector layout preparation: `pin_layout(kind)` and
  `FillPartFromLayout(part, kind)` stubs in `pin_role`, called from
  `set-type`. Empty today; populate alongside `vpx_3u_role`.
- TUI scrollback: PageUp/PageDown step 10 lines, Home/End jump to
  ends; `Print()` snaps back to the tail.
- `set <name> <value>` declares session variables; `$name` / `${name}`
  expanded inside `Finalize` between canonical-form recording and the
  action call — history and script-save preserve `$var` references.
- Long `source` scripts now show a centred "Computing…" modal with a
  N/M progress counter. Driven by a ticker thread that posts one
  paced `Event::Special` per processed line, ack'd by the main thread,
  so heavy lines don't backlog ticks and freeze the counter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 20:28:21 +02:00
477f3abd40 README + EUPL-1.2 licence.
Add LICENSE (full EUPL v1.2 text from the SPDX archive) and a README
covering build, commands, tests, project layout, and the licence
notice. Project is now declared open-source under EUPL-1.2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 20:38:30 +02:00
4f27686e94 Signal types, pin role expectations, and a doctest suite.
Domain
- Signal carries a SignalType (Power/GndShield/Other), auto-inferred
  from the name in Signal::Signal via infer_signal_type. Override with
  the new `set-signal-type` command.
- SignalType extracted to its own header so Pin can store an
  `expected_signal_type` without a pins↔signals include cycle.
- pin_role(connector_type, pin_name) → SignalType lookup, called from
  set-type to populate each Pin's expected_signal_type. The VPX 3U
  table is currently a stub (returns Other).
- New `verify` command walks typed parts and reports pins whose
  connected signal's type doesn't match the expectation.
- ODS importer no longer drops pins with empty signal column — they
  stay in the part as NC, matching the rule "a pin is either NC or
  connected to a signal".
- persist: new S tag for non-default signal type overrides.

Tests
- doctest v2.4.11 via FetchContent (with CMAKE_POLICY_VERSION_MINIMUM
  shim, doctest's CMakeLists has a too-old floor for current CMake).
- Source files moved into a static library `essim_lib` so both `essim`
  and `essim_tests` reuse the same compilation. main.cpp is the only
  file kept out of the lib.
- Layer 1 (pure helpers): ToLower, LongestCommonPrefix, Tokenize,
  NaturalLess (numeric/case/leading-zero edge cases + total-order
  invariants), signal_type round-trips and infer_signal_type families,
  VpxTransform registry + symmetry + reference-table mapping for
  connector P0 row 1, IdentityTransform same-name wiring.
- Layer 2 (round-trip): build a synthetic 2-module system in code,
  save → restore → assert modules / parts / connector_types / NC pins
  / signal type overrides / connections + pin_map are all preserved.
- Tui::Tokenize moved to a free function in tui_helpers so tests can
  call it without dragging ftxui into the unit-test layer.
- 27 test cases, 123 assertions, ~150 ms.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 20:28:03 +02:00
f3920964f0 ODS import, persistence, scripting, connector types + VPX transforms.
- ODS importer (libzip + pugixml): each sheet → Part, rows → Pin/Signal.
- save / restore commands: tab-delimited snapshot of modules, parts,
  signals, connections + pin_map. `restore` replaces the System.
- source / script-save: replay a file of commands; record canonical
  commands since last `new` for replay later. Interactive screens
  refused during source. `explore` marked non-scriptable.
- TUI screen_explore: 4 columns (modules, type, children, detail) with
  filters on children and detail; detail is a Menu so arrows scroll
  long pin lists.
- Connector types & transforms: each Part carries a `connector_type`
  string. `set-type` validates the part's pin layout against the type
  (cols set check). `connect` strict pair: rejects when lookup falls
  back to identity unless types are both empty AND pin sets match.
- VPX 3U transforms: 3 registered pairs (vpx-3u-bkp-pN ↔ vpx-3u-payload-pN,
  N=0/1/2) with row-pattern correspondence tables ported from the user's
  Python reference.
- Code split for maintainability: src/tui/{shell,completion,commands,
  screen_main,screen_search,screen_connect,screen_settype,screen_explore,
  tui_helpers}.cpp.
- Bug fixes: Module::add(Part*) override sets part->prnt (was always
  null, breaking save's W lines). Defensive guards in explore against
  empty Menu lists. Renderer wrapped in try/catch so domain throws
  surface as on-screen errors instead of SIGABRT.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 19:58:51 +02:00
3395469810 TUI shell + ftxui via FetchContent.
- ftxui v6.1.9 fetched at configure time; vendored .a + headers dropped.
- TUI: visualisation area on top, input prompt at the bottom; ↑/↓ history,
  Tab completion (commands + file paths), Esc cancels prompts. History is
  persisted (XDG on Linux, %LOCALAPPDATA% on Windows when ported).
- Command registry: `new`, `load`, `search`, `clear`, `help`, `quit`/`exit`.
  Inline params or interactive prompts; either way the canonical inline
  form is what gets stored in history.
- `search`: second full-screen mode with module + parts/signals menus and
  a live-filtered list; Tab cycles focus, Esc returns to the main shell.
- Domain: `System::modules()` accessor + `SystemElementContainer::size()`
  to support load summary + search.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:17:03 +02:00
8b1de63849 wip 2025-04-21 23:07:35 +02:00
d0bf09aa63 Mentor import done. 2025-04-21 18:19:37 +02:00
6448972fd8 doc added. 2025-04-21 15:21:40 +02:00
0bec49ac1e first import 2025-04-21 12:18:49 +02:00
d8122d19a2 refactoring. Everything is pointer. 2025-04-21 12:18:26 +02:00
3b8bb88fbb changes 2025-03-30 22:48:08 +02:00
a61f24e08c imports started 2025-03-30 18:06:00 +02:00
d35d9ced2f dir structure changed 2025-03-30 18:04:53 +02:00
c123001f79 wip 2025-03-30 17:15:35 +02:00
304772057f gitignore 2025-03-21 18:51:19 +01:00
a8e1193e12 Initial commit 2025-03-21 18:47:49 +01:00