diff --git a/DESIGN.md b/DESIGN.md index 1f5bec9..a5e9f9d 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -87,7 +87,7 @@ doc/classes.puml -- PlantUML class diagram - Multi-step prompts work via a `std::deque` queue. `Submit()` pops them one by one before falling back to dispatch. Adding a new command = one entry in `RegisterCommands()`; the prompt-flow and inline-flow are both handled automatically. - Tab completion: at the top-level prompt (no `pending`), completes built-in command names. Inside a prompt with `path_completion = true` (e.g. the `filename` step of `load`), completes file paths via `std::filesystem::directory_iterator` (handles `~/`, dirs get a trailing `/`). Logic: 1 match → replace; multiple with progress on the longest common prefix → extend; multiple stuck at LCP → list candidates in the visualisation area. -Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source`, `script-save`, `connect`, `set-type`, `set-signal-type`, `search`, `explore`, `verify`, `net`, `clear`, `help`, `quit`/`exit`. `Esc` cancels an in-progress multi-step prompt. +Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source`, `script-save`, `connect`, `set-connector-type`, `set-signal-type`, `search`, `explore`, `verify`, `net`, `clear`, `help`, `quit`/`exit`. `Esc` cancels an in-progress multi-step prompt. `set ` declares a session-scoped variable. Subsequent commands expand `$name` and `${name}` in their args (substitution happens in `Finalize` between canonical-form recording and `spec.action(args)` — so `history` and `script-save` keep the **unexpanded** form, while the action sees resolved values). Unknown variables are left literal. `vars` is reset by `new`. Validation: `[A-Za-z_][A-Za-z0-9_]*`. @@ -97,7 +97,7 @@ Built-in commands: `new`, `set`, `load`, `duplicate`, `save`, `restore`, `source `source ` reads a script line by line and feeds each line through `Submit()`. While the script is running, `in_source = true` is set on the `Tui` and: - `Dispatch` / `Finalize` skip writing to memory + on-disk history. -- After each `Submit`, if `screen_idx != 0` (a screen was opened by an "interactive" command like bare `connect`/`search`/`set-type`), the script is aborted with an error message and `screen_idx` is reset to 0 — interactive screen-opening commands are explicitly disallowed in scripts. +- After each `Submit`, if `screen_idx != 0` (a screen was opened by an "interactive" command like bare `connect`/`search`/`set-connector-type`), the script is aborted with an error message and `screen_idx` is reset to 0 — interactive screen-opening commands are explicitly disallowed in scripts. Pending prompts (from incomplete inline commands) are NOT considered interactive and are filled by subsequent script lines, the way you'd expect. Lines starting with `#` and blank lines are skipped; leading/trailing whitespace is trimmed; `~/` is expanded. @@ -114,9 +114,9 @@ Pending prompts (from incomplete inline commands) are NOT considered interactive The explore screen shows the type in the signal detail header. -**Pin role expectations**: every Pin carries an `expected_signal_type` populated by `set-type` from a per-(connector_type, pin_name) lookup (`src/system/pin_role.{hpp,cpp}`). The framework is wired end-to-end; the actual VPX 3U lookup table is currently a stub returning Other for all positions — fill in `vpx_3u_role(col, row, idx)` with the real VITA 46 layout when needed. +**Pin role expectations**: every Pin carries an `expected_signal_type` populated by `set-connector-type` from a per-(connector_type, pin_name) lookup (`src/system/pin_role.{hpp,cpp}`). The framework is wired end-to-end; the actual VPX 3U lookup table is currently a stub returning Other for all positions — fill in `vpx_3u_role(col, row, idx)` with the real VITA 46 layout when needed. -**Connector pin layout (preparation)**: `pin_layout(connector_type)` returns the canonical full pin-name list for a known connector kind, and `FillPartFromLayout(part, kind)` materialises NC pins for any layout position absent from the imported netlist. `set-type` calls it after setting `connector_type` (no-op today since `pin_layout` is a stub returning `{}` for everything — populate alongside `vpx_3u_role`). End-to-end chain in place: `set-type → FillPartFromLayout → pin_role`. +**Connector pin layout (preparation)**: `pin_layout(connector_type)` returns the canonical full pin-name list for a known connector kind, and `FillPartFromLayout(part, kind)` materialises NC pins for any layout position absent from the imported netlist. `set-connector-type` calls it after setting `connector_type` (no-op today since `pin_layout` is a stub returning `{}` for everything — populate alongside `vpx_3u_role`). End-to-end chain in place: `set-connector-type → FillPartFromLayout → pin_role`. **`verify` (three passes)**: (1) walks all typed pins and reports local mismatches between `expected_signal_type` and the actual signal type; (2) walks all bridged nets reporting Power↔GndShield inconsistencies; (3) prints a single-line orphan summary `N orphan pin(s) at import (X imported NC, Y dropped singleton)`. The orphan pass filters out pins that appear in any `Connection::pin_map` — those are bridged to a real signal on the peer module (typically `FillIdentityNCs`-materialised) and not real NCs at system level. `net ` prints the BFS-reached `(module, signal)` set with types and an `[INCONSISTENT]` flag. @@ -130,7 +130,7 @@ The explore screen shows the type in the signal detail header. Exposed as the `analyze` shell command which prints groups (sorted by module + label) followed by anomalies. Designed to be consumed by the upcoming dashboard so the summary is visible at a glance. Tests: `tests/test_analysis.cpp`. -**Component classification**: every `Part` carries a `ComponentKind kind` (`Passive | Semiconductor | IntegratedCircuit | Connector | TestPoint | Switch | Crystal | Mechanical | Other`) inferred at construction by `infer_component_kind(name)` from the leading reference-designator letter(s) (longest-match: `LED/TP/SW/FB/MK/MP/MH/HS/RA/RN/RP/RV` first, then single-letter R/C/L/F/D/Q/U/J/P/Y/X/S). Recomputed on `restore` (no persistence tag). Not yet exposed in TUI commands — branchpoints will be `search` filter, `set-type` guard, and `explore` header. +**Component classification**: every `Part` carries a `ComponentKind kind` (`Passive | Semiconductor | IntegratedCircuit | Connector | TestPoint | Switch | Crystal | Mechanical | Other`) inferred at construction by `infer_component_kind(name)` from the leading reference-designator letter(s) (longest-match: `LED/TP/SW/FB/MK/MP/MH/HS/RA/RN/RP/RV` first, then single-letter R/C/L/F/D/Q/U/J/P/Y/X/S). Recomputed on `restore` (no persistence tag). Not yet exposed in TUI commands — branchpoints will be `search` filter, `set-connector-type` guard, and `explore` header. `SignalType` lives in its own header `src/system/signal_type.hpp` (extracted from signals to avoid a pins↔signals include cycle). @@ -138,13 +138,13 @@ Exposed as the `analyze` shell command which prints groups (sorted by module + l **NC origin tag**: each `Pin` carries `NcOrigin nc_origin` (`None | ImportedUnconnected | DroppedSingleton`, default `None`). Set in three places: (a) Mentor importer when the signal field starts with `unconnected` → `ImportedUnconnected`; (b) `drop_singleton_signals(Signals*)` called at the end of `load` → `DroppedSingleton` on each detached pin (signals with exactly one pin are NC by definition — see commits motivating this); (c) `duplicate` propagates the tag. Pins materialised by `FillIdentityNCs` keep `None` — they have no local signal but are bridged via `pin_map` and shouldn't be counted as orphans. The tag is persisted (see `N` record), reported as a total in `verify`, and tested in `tests/test_nc_origin.cpp`. -**Connector types & transforms**: every `Part` carries a `connector_type` string (default `""`, set via the `set-type` command — inline `set-type m p kind` or bare which opens a TUI screen with module menu, part filter+menu, type input, list of types already in use, and an Apply button). When `connect` validates a pair, it consults `TransformRegistry::lookup(p1->connector_type, p2->connector_type)` (defined in `src/system/transform.{hpp,cpp}`) — both directions of the pair are tried. If neither is registered, an `IdentityTransform` fallback wires each pin of A to the canonical-equivalent pin of B (when present). The resulting `(Pin*, Pin*)` list and the transform's name are stored on the `Connection` (`pin_map`, `transform_name`). To register a real transform: define a `Transform` subclass in `transform.cpp` and call `TransformRegistry::get().add("kindA", "kindB", new MyTransform())` at init — there's no startup hook for this yet, so a small `RegisterBuiltinTransforms()` helper is the natural place to add when more types appear. +**Connector types & transforms**: every `Part` carries a `connector_type` string (default `""`, set via the `set-connector-type` command — inline `set-connector-type m p kind` or bare which opens a TUI screen with module menu, part filter+menu, type input, list of types already in use, and an Apply button). When `connect` validates a pair, it consults `TransformRegistry::lookup(p1->connector_type, p2->connector_type)` (defined in `src/system/transform.{hpp,cpp}`) — both directions of the pair are tried. If neither is registered, an `IdentityTransform` fallback wires each pin of A to the canonical-equivalent pin of B (when present). The resulting `(Pin*, Pin*)` list and the transform's name are stored on the `Connection` (`pin_map`, `transform_name`). To register a real transform: define a `Transform` subclass in `transform.cpp` and call `TransformRegistry::get().add("kindA", "kindB", new MyTransform())` at init — there's no startup hook for this yet, so a small `RegisterBuiltinTransforms()` helper is the natural place to add when more types appear. **Identity wiring uses canonical names**: `IdentityTransform::apply` builds `unordered_map` for side B and looks up each side-A pin by its canonical form. So `A1` (one card) auto-pairs with `A001` (the other) thanks to `canonical_pin_name` (`pre + zero-padded(3) digit suffix`; mixed/non-numeric returns the original). Same canonicalisation in `CheckIdentityCompatible`. **`pin_role` doesn't need canonicalisation** because `parse_pin` extracts `(col, row)` via `stoi` which already strips leading zeros. **Subset wiring + NC backfill**: `CheckIdentityCompatible(a, b, info=&s)` accepts the case where one side's canonical pin set is a subset of the other's — typical when one importer drops NC pins (Altium) and the other doesn't (Mentor). It populates `info` with a non-fatal "N pin(s) only on ''" message. Bidirectional mismatch (both sides have orphans) is still refused. After acceptance, `connect` calls `FillIdentityNCs(p1, p2)` which materialises the orphan canonical positions on the missing side as NC pins (`new Pin(other_side_name)`) — so `Connection::pin_map.size()` matches the larger side's count. Idempotent. -`screen_idx` mapping: **6 = dashboard (home, set in the constructor)**, 0 = console (textual shell + log view), 1 = search, 2 = connect, 3 = set-type, 4 = explore, 5 = net, 7 = analyze. The dashboard is the boot screen; the console is the secondary screen reachable via the `[c]` shortcut and used to display textual output from `verify`/`analyze`/etc. plus collect arguments for multi-step commands. The label was renamed from "log" to "console" because the screen is also where commands are typed — "log" only described half of what it does. +`screen_idx` mapping: **6 = dashboard (home, set in the constructor)**, 0 = console (textual shell + log view), 1 = search, 2 = connect, 3 = set-connector-type, 4 = explore, 5 = net, 7 = analyze. The dashboard is the boot screen; the console is the secondary screen reachable via the `[c]` shortcut and used to display textual output from `verify`/`analyze`/etc. plus collect arguments for multi-step commands. The label was renamed from "log" to "console" because the screen is also where commands are typed — "log" only described half of what it does. **Dashboard letter conflicts**: with the screen renames, `[c]` now opens the **console** rather than `connect`. The connect command is surfaced as **`[p]lug`** on the dashboard (a UI rename only — the canonical command stays `connect` for script + save/restore stability, with `plug` registered as an alias so the palette finds it under either name). @@ -260,7 +260,7 @@ Type is set by `infer_signal_types(System*)` (`src/system/analysis.cpp`), called The analyze screen additionally surfaces two "verify-class" issues, computed the same way as the textual `verify` command: -- **pin-role mismatch** — a pin whose `expected_signal_type` (set by `set-type` via `pin_role(connector_type, pin_name)`) disagrees with the actual signal type. +- **pin-role mismatch** — a pin whose `expected_signal_type` (set by `set-connector-type` via `pin_role(connector_type, pin_name)`) disagrees with the actual signal type. - **net-mix** — a bridged net (BFS over `Connection::pin_map`, ≥ 2 members) where `net_type_consistent(net, &dominant)` returns false. Specifically, the net contains both `Power` and `GndShield` signals. ### Component kind @@ -271,7 +271,7 @@ The analyze screen additionally surfaces two "verify-class" issues, computed the - Single-letter fallback: `R / C / L / F → Passive`, `D / Q → Semiconductor`, `U → IntegratedCircuit`, `J / P → Connector`, `Y / X → Crystal`, `S → Switch`. - No match → `Other`. -Recomputed on `restore` (no persistence tag). Currently not used by any decision flow — branch points are search filter / `set-type` guard / explore header. +Recomputed on `restore` (no persistence tag). Currently not used by any decision flow — branch points are search filter / `set-connector-type` guard / explore header. ### Connector wiring (transforms) @@ -286,7 +286,7 @@ Pins materialised this way are bridged via `Connection::pin_map` to a real signa ## Gotchas - All three importers (`IMPORT_MENTOR`, `IMPORT_ALTIUM`, `IMPORT_ODS`) are wired in `System::Load`. Wrap calls in `try/catch` (the TUI does). -- **Altium importer drops NC pins entirely**: the source format only enumerates pins inside `(signal …)` blocks, so positions not connected to any signal on this card never become `Pin`s. Mentor (via `Explicit Pin:`) and ODS (one row per pin) materialise NC. This is the asymmetry that motivates `FillIdentityNCs` at `connect` time and (eventually) `FillPartFromLayout` at `set-type` time. +- **Altium importer drops NC pins entirely**: the source format only enumerates pins inside `(signal …)` blocks, so positions not connected to any signal on this card never become `Pin`s. Mentor (via `Explicit Pin:`) and ODS (one row per pin) materialise NC. This is the asymmetry that motivates `FillIdentityNCs` at `connect` time and (eventually) `FillPartFromLayout` at `set-connector-type` time. - **Mentor importer + NC**: the Mentor `.qcv` format names every pin's signal explicitly. Sentinel values like `'unconnected'` or `'unconnected (by TERM)'` mean NC — the parser detects them via `is_nc_signal_name` (lowercase prefix match) and keeps the pin on the part with no signal, tagged `ImportedUnconnected`. Additionally, after each `load` the system runs `drop_singleton_signals(mod->signals)`: any signal whose pin set has size 1 is unconnected by definition (electrically nowhere to go), so it is detached and the lone pin is tagged `DroppedSingleton`. The count is shown inline in the `load` output. The semantics covers both Mentor patterns and the few `NC_*`-prefixed signals that turn out to be singletons in real-world boards — the name `NC_*` alone is *not* enough (most of them connect two or more parts and are real bridges, even if cosmetically called NC). - ODS importer: each spreadsheet sheet becomes a `Part` (sheet name = part name). Rows are pin/signal pairs; the **first non-empty row of each sheet is dropped as a header** (no validation of header content). Empty cells skip the row; `"NC"` keeps the pin in the part but doesn't connect it to a signal. Pins or parts whose name collides (rare in well-formed sheets) are silently dropped. - `System::Load` throws `std::runtime_error("Unknown import type")` for any value outside the three enum cases. diff --git a/doc/user/analysis.md b/doc/user/analysis.md index b634ab1..3dc5f0a 100644 --- a/doc/user/analysis.md +++ b/doc/user/analysis.md @@ -111,7 +111,7 @@ deserves attention: | Tag | What it means | |---|---| -| `[pin-role]` | A connector pin is typed (via `set-type`) as Power or Gnd but the actual signal landing on it disagrees. | +| `[pin-role]` | A connector pin is typed (via `set-connector-type`) as Power or Gnd but the actual signal landing on it disagrees. | | `[net-mix]` | A net bridged across modules carries both Power and Gnd signals — almost always a topology mistake. | | `[diff-pair-orphan]` | `STEM_P` with no `STEM_N` in the same module. | | `[bus-gap]` | A bus is missing one or more index values inside its range. | @@ -128,7 +128,7 @@ Every classification is advisory. To force a different type: on a signal entry → a popup lets you pick `power` / `gnd` / `other`. Or type `set-signal-type ` in the console (or from the palette). -- **Connector type**: `set-type ` +- **Connector type**: `set-connector-type ` (also via the dashboard `[t]` shortcut). This drives the pin role expectations, which feed the `pin-role` check. diff --git a/doc/user/index.md b/doc/user/index.md index 825264d..7bb1202 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -31,8 +31,8 @@ commands. The most common bring-up looks like this: > new > load backplane /path/to/netlists/backplane.NET altium > load payload1 /path/to/netlists/payload.qcv mentor -> set-type backplane J20 vpx-3u-bkp-p0 -> set-type payload1 P0 vpx-3u-payload-p0 +> set-connector-type backplane J20 vpx-3u-bkp-p0 +> set-connector-type payload1 P0 vpx-3u-payload-p0 > connect backplane J20 payload1 P0 > verify > save my-system.essim @@ -46,7 +46,7 @@ Things to try at any time: | Help on one command | `help ` | | Scroll back through output | `PageUp` / `PageDown`, `Home`, `End` | | Re-run a previous command | ↑ / ↓ (also `history` is on disk) | -| Tab-complete a command name | `set‹Tab›` → `set-type` etc. | +| Tab-complete a command name | `set‹Tab›` → `set-connector-type` etc. | | Cancel a multi-step prompt | `Esc` | | Leave essim | `quit` (or `exit`) | @@ -65,7 +65,7 @@ share the same conventions: a sourced script. A sourced script must use the inline form of these commands instead. -Today's interactive screens: `connect`, `search`, `set-type`, +Today's interactive screens: `connect`, `search`, `set-connector-type`, `explore`, `net`. See [`commands.md`](commands.md) for each. ## Saving, restoring, replaying diff --git a/src/system/pin_role.cpp b/src/system/pin_role.cpp index 576aa81..445be05 100644 --- a/src/system/pin_role.cpp +++ b/src/system/pin_role.cpp @@ -15,7 +15,7 @@ // NOTE: real VITA 46 pin roles are connector-/profile-specific (data lanes, // power planes, GND chassis, etc.). The placeholders below are intentionally // minimal — fill in the actual per-(col,row) roles for your design when the -// reference is available; the rest of the chain (set-type → verify) is +// reference is available; the rest of the chain (set-connector-type → verify) is // already wired through this single function. namespace { diff --git a/src/system/pin_role.hpp b/src/system/pin_role.hpp index ce0e0e4..fb20073 100644 --- a/src/system/pin_role.hpp +++ b/src/system/pin_role.hpp @@ -9,7 +9,7 @@ class Part; // For a given connector type and pin position, return the expected SignalType -// (Power / GndShield / Other). Used at `set-type` to populate each pin's +// (Power / GndShield / Other). Used at `set-connector-type` to populate each pin's // `expected_signal_type`, then later by `verify` to flag mismatches between // the connector's expectation and the actual signal's inferred/declared type. // @@ -23,7 +23,7 @@ SignalType pin_role(const std::string &connector_type, // vector for connector types that don't have a registered layout — callers // must treat that as "unknown, do not auto-fill". // -// Used at `set-type` to materialise NC pins for positions absent from the +// Used at `set-connector-type` to materialise NC pins for positions absent from the // imported netlist (Altium drops NC, Mentor doesn't). Stub today: every // known kind returns {} — populate alongside `vpx_3u_role`. std::vector pin_layout(const std::string &connector_type); diff --git a/src/system/pins.hpp b/src/system/pins.hpp index c77d1a3..58f8913 100644 --- a/src/system/pins.hpp +++ b/src/system/pins.hpp @@ -29,7 +29,7 @@ class Pin : public SystemElement public: Pin(std::string name); Part *prnt; ///< Pointer to the parent part. - SignalType expected_signal_type; ///< Set from connector_type at set-type. + SignalType expected_signal_type; ///< Set from connector_type at set-connector-type. NcOrigin nc_origin = NcOrigin::None; bool connected(); Signal *signal() const { return sig; } diff --git a/src/system/transform_vpx.hpp b/src/system/transform_vpx.hpp index be7b91b..59edac6 100644 --- a/src/system/transform_vpx.hpp +++ b/src/system/transform_vpx.hpp @@ -19,7 +19,7 @@ // instances are registered at startup, under the type pairs // (vpx-3u-bkp-N, vpx-3u-payload-N) // for N in {0, 1, 2}. Tag each Part with the correct connector_type via -// `set-type`, then `connect` will pick the right transform automatically. +// `set-connector-type`, then `connect` will pick the right transform automatically. class VpxTransform : public Transform { public: diff --git a/src/tui/commands.cpp b/src/tui/commands.cpp index e85ae96..422cad6 100644 --- a/src/tui/commands.cpp +++ b/src/tui/commands.cpp @@ -431,7 +431,7 @@ void Tui::RegisterCommands() { "override the auto-detected signal type (power | gnd | other)", }; - commands["set-type"] = { + commands["set-connector-type"] = { {{"module", Completion::None}, {"part (name or pattern)", Completion::None}, {"connector type (free string, e.g. vpx-bp, vpx-payload)", Completion::None}}, @@ -454,7 +454,7 @@ void Tui::RegisterCommands() { } if (args.size() != 3) { - Print("usage: set-type (or no args for interactive)"); + Print("usage: set-connector-type (or no args for interactive)"); return; } @@ -480,7 +480,7 @@ void Tui::RegisterCommands() { } std::string err = ValidatePartForKind(prt, args[2]); if (!err.empty()) { - Print("set-type refused: " + err); + Print("set-connector-type refused: " + err); return; } prt->connector_type = args[2]; @@ -490,7 +490,7 @@ void Tui::RegisterCommands() { Print(mod->name + "/" + prt->name + ": connector_type = " + (args[2].empty() ? "(none)" : args[2])); if (filled > 0) - Print("set-type: materialised " + std::to_string(filled) + Print("set-connector-type: materialised " + std::to_string(filled) + " NC pin(s) from connector layout"); }, /*prompt_for_missing=*/ false, @@ -498,7 +498,6 @@ void Tui::RegisterCommands() { /*scriptable=*/ true, /*interactive=*/ true, }; - commands["connect"] = { {{"module1", Completion::None}, {"part1 (name or pattern)", Completion::None}, @@ -596,7 +595,7 @@ void Tui::RegisterCommands() { + (p1->connector_type.empty() ? "(none)" : p1->connector_type) + "' ↔ '" + (p2->connector_type.empty() ? "(none)" : p2->connector_type) - + "'. Set matching types via 'set-type' first."); + + "'. Set matching types via 'set-connector-type' first."); return; } std::string info; diff --git a/src/tui/screen_analyze.cpp b/src/tui/screen_analyze.cpp index d459a58..61d02bc 100644 --- a/src/tui/screen_analyze.cpp +++ b/src/tui/screen_analyze.cpp @@ -244,34 +244,35 @@ Component Tui::BuildAnalyzeScreen() { {"Esc", "dashboard"}, }); - // Glossary: only relevant on the Types tab. Same width as the help - // panel for visual coherence. + // Glossary: shown only when the Types tab is focused. Same border + // styling as the help panel (borderRounded) for visual coherence; + // text uses `paragraph` so lines wrap cleanly to the panel width. + auto term = [](const std::string &name, const std::string &desc) { + return vbox({ + text(name) | bold, + paragraph(desc) | dim, + text(""), + }); + }; Element types_glossary = vbox({ - text(" types ") | bold, + text(" type glossary ") | bold | center, separator(), - hbox({text(" Power ") | bold | size(WIDTH, EQUAL, 12), - text("name + structure") | flex}), - hbox({text(" ") | dim | size(WIDTH, EQUAL, 12), - text("(fan-out ≥ 4 or") | dim | flex}), - hbox({text(" ") | dim | size(WIDTH, EQUAL, 12), - text(" voltage in name)") | dim | flex}), - text(""), - hbox({text(" Suspect ") | bold | size(WIDTH, EQUAL, 12), - text("name only,") | flex}), - hbox({text(" ") | dim | size(WIDTH, EQUAL, 12), - text("weak evidence") | dim | flex}), - text(""), - hbox({text(" hard ") | bold | size(WIDTH, EQUAL, 12), - text("fan-out < 3 →") | flex}), - hbox({text(" floor ") | bold | size(WIDTH, EQUAL, 12), - text("never Power") | flex}), - text(""), - hbox({text(" Gnd ") | bold | size(WIDTH, EQUAL, 12), - text("name only") | flex}), - }) | size(WIDTH, EQUAL, 30); + term("Power", + "Name suggests Power AND structure agrees: fan-out ≥ 4 pins, " + "or a voltage pattern in the name (e.g. 3V3, 5V, 12V)."), + term("Suspect Power", + "Name suggests Power but the structural check failed — " + "fan-out too low and no voltage in the name."), + term("Hard floor", + "Fan-out below 3 pins forces Other regardless of the name. " + "A real rail physically cannot live on 1-2 pads."), + term("Gnd", + "Name matches GND, SHIELD, CHASSIS or EARTH. Name alone is " + "enough — false positives are essentially nil."), + }) | borderRounded | size(WIDTH, EQUAL, 32); Element side = (analyze_focus_idx == 2) - ? vbox({help, text(""), types_glossary}) | size(WIDTH, EQUAL, 30) + ? vbox({help, text(""), types_glossary}) | size(WIDTH, EQUAL, 32) : help; return vbox({ diff --git a/src/tui/screen_connect.cpp b/src/tui/screen_connect.cpp index ee3a94b..0d455d8 100644 --- a/src/tui/screen_connect.cpp +++ b/src/tui/screen_connect.cpp @@ -76,7 +76,7 @@ Component Tui::BuildConnectScreen() { + (p1->connector_type.empty() ? "(none)" : p1->connector_type) + "' ↔ '" + (p2->connector_type.empty() ? "(none)" : p2->connector_type) - + "'. Set matching types via 'set-type' first."); + + "'. Set matching types via 'set-connector-type' first."); screen_idx = 0; return; } diff --git a/src/tui/screen_dashboard.cpp b/src/tui/screen_dashboard.cpp index 000dd1e..d902e8b 100644 --- a/src/tui/screen_dashboard.cpp +++ b/src/tui/screen_dashboard.cpp @@ -296,7 +296,7 @@ Component Tui::BuildDashboardScreen() { {"c", "console"}, {"s", "search"}, {"p", "plug"}, - {"t", "set-type"}, + {"t", "set-connector-type"}, {"e", "explore"}, {"n", "net"}, {"a", "analyze (verify + groups)"}, diff --git a/src/tui/screen_settype.cpp b/src/tui/screen_settype.cpp index 9537d34..450ab96 100644 --- a/src/tui/screen_settype.cpp +++ b/src/tui/screen_settype.cpp @@ -58,7 +58,7 @@ Component Tui::BuildSettypeScreen() { std::string msg = mod->name + "/" + prt->name + " = " + (settype_type.empty() ? "(none)" : settype_type); settype_status = "applied: " + msg; - Print("set-type " + msg); + Print("set-connector-type " + msg); } catch (const std::exception &e) { settype_status = std::string("failed: ") + e.what(); } @@ -129,11 +129,11 @@ Component Tui::BuildSettypeScreen() { auto title = hbox({ text(" essim ") | bold, text("→ ") | dim, - text("set-type") | bold, + text("set-connector-type") | bold, text(" — tag a part with its connector kind (drives transforms + pin roles)") | dim, }); - Element help = RenderHelpPanel("set-type", { + Element help = RenderHelpPanel("set-connector-type", { {"Tab", "cycle focus"}, {"↑/↓", "navigate menu"}, {"Enter", "on [Apply] → tag"}, diff --git a/src/tui/tui.cpp b/src/tui/tui.cpp index 5978b05..a729d49 100644 --- a/src/tui/tui.cpp +++ b/src/tui/tui.cpp @@ -100,7 +100,7 @@ void Tui::Run() { if (e == Event::Character("c")) { screen_idx = 0; return true; } if (e == Event::Character("p")) { Dispatch("connect"); return true; } if (e == Event::Character("s")) { Dispatch("search"); return true; } - if (e == Event::Character("t")) { Dispatch("set-type"); return true; } + if (e == Event::Character("t")) { Dispatch("set-connector-type"); return true; } if (e == Event::Character("e")) { Dispatch("explore"); return true; } if (e == Event::Character("n")) { Dispatch("net"); return true; } // [a]nalyze is the unified verify + analyze screen (issues + @@ -121,7 +121,7 @@ void Tui::Run() { if (e == Event::TabReverse) { explore_focus_idx = (explore_focus_idx + 5) % 6; return true; } return false; - case 3: // set-type + case 3: // set-connector-type if (e == Event::Escape) { screen_idx = 6; return true; } if (e == Event::Tab) { settype_focus_idx = (settype_focus_idx + 1) % 5; return true; } if (e == Event::TabReverse) { settype_focus_idx = (settype_focus_idx + 4) % 5; return true; } diff --git a/src/tui/tui.hpp b/src/tui/tui.hpp index 938ece1..adaae19 100644 --- a/src/tui/tui.hpp +++ b/src/tui/tui.hpp @@ -188,7 +188,7 @@ private: // and close the popup. void ApplySignalTypeChoice(); - // Filtered part list rebuild (used by connect & set-type screens) + // Filtered part list rebuild (used by connect & set-connector-type screens) void RefreshFilteredPartList(const std::vector &modules, int m_idx, const std::string &filter, diff --git a/src/tui/tui_helpers.cpp b/src/tui/tui_helpers.cpp index bb9a612..d9cde68 100644 --- a/src/tui/tui_helpers.cpp +++ b/src/tui/tui_helpers.cpp @@ -14,15 +14,18 @@ Element RenderHelpPanel(const std::string &title, Elements rows; for (const auto &e : entries) { rows.push_back(hbox({ - text(" " + e.key) | bold | size(WIDTH, EQUAL, KEY_W), + text(e.key) | bold | size(WIDTH, EQUAL, KEY_W), text(e.desc) | flex, })); } + // borderRounded gives the panel a distinct visual boundary, so the + // user can find it without ambiguity even when the main content is + // dense (e.g. the analyze screen). return vbox({ - text(" " + title + " ") | bold, + text(" " + title + " ") | bold | center, separator(), vbox(std::move(rows)), - }) | size(WIDTH, EQUAL, 30); + }) | borderRounded | size(WIDTH, EQUAL, 32); } diff --git a/test/system.essim b/test/system.essim index 19676ef..013ccf8 100644 --- a/test/system.essim +++ b/test/system.essim @@ -27,32 +27,32 @@ load peripheral3 $peripheral3_nets mentor # ---------------------------------------------------------------- VPX tags # Backplane payload-side connectors, one slot per (Jx0,Jx1,Jx2): # J2x → payload1, J3x → payload2, J4x → payload3, J5x → payload4. -set-type backplane J20 vpx-3u-bkp-p0 -set-type backplane J21 vpx-3u-bkp-p1 -set-type backplane J22 vpx-3u-bkp-p2 -set-type backplane J30 vpx-3u-bkp-p0 -set-type backplane J31 vpx-3u-bkp-p1 -set-type backplane J32 vpx-3u-bkp-p2 -set-type backplane J40 vpx-3u-bkp-p0 -set-type backplane J41 vpx-3u-bkp-p1 -set-type backplane J42 vpx-3u-bkp-p2 -set-type backplane J50 vpx-3u-bkp-p0 -set-type backplane J51 vpx-3u-bkp-p1 -set-type backplane J52 vpx-3u-bkp-p2 +set-connector-type backplane J20 vpx-3u-bkp-p0 +set-connector-type backplane J21 vpx-3u-bkp-p1 +set-connector-type backplane J22 vpx-3u-bkp-p2 +set-connector-type backplane J30 vpx-3u-bkp-p0 +set-connector-type backplane J31 vpx-3u-bkp-p1 +set-connector-type backplane J32 vpx-3u-bkp-p2 +set-connector-type backplane J40 vpx-3u-bkp-p0 +set-connector-type backplane J41 vpx-3u-bkp-p1 +set-connector-type backplane J42 vpx-3u-bkp-p2 +set-connector-type backplane J50 vpx-3u-bkp-p0 +set-connector-type backplane J51 vpx-3u-bkp-p1 +set-connector-type backplane J52 vpx-3u-bkp-p2 # Payload connectors on each plug-in card. -set-type payload1 P0 vpx-3u-payload-p0 -set-type payload1 P1 vpx-3u-payload-p1 -set-type payload1 P2 vpx-3u-payload-p2 -set-type payload2 P0 vpx-3u-payload-p0 -set-type payload2 P1 vpx-3u-payload-p1 -set-type payload2 P2 vpx-3u-payload-p2 -set-type payload3 P0 vpx-3u-payload-p0 -set-type payload3 P1 vpx-3u-payload-p1 -set-type payload3 P2 vpx-3u-payload-p2 -set-type payload4 P0 vpx-3u-payload-p0 -set-type payload4 P1 vpx-3u-payload-p1 -set-type payload4 P2 vpx-3u-payload-p2 +set-connector-type payload1 P0 vpx-3u-payload-p0 +set-connector-type payload1 P1 vpx-3u-payload-p1 +set-connector-type payload1 P2 vpx-3u-payload-p2 +set-connector-type payload2 P0 vpx-3u-payload-p0 +set-connector-type payload2 P1 vpx-3u-payload-p1 +set-connector-type payload2 P2 vpx-3u-payload-p2 +set-connector-type payload3 P0 vpx-3u-payload-p0 +set-connector-type payload3 P1 vpx-3u-payload-p1 +set-connector-type payload3 P2 vpx-3u-payload-p2 +set-connector-type payload4 P0 vpx-3u-payload-p0 +set-connector-type payload4 P1 vpx-3u-payload-p1 +set-connector-type payload4 P2 vpx-3u-payload-p2 # ---------------------------------------------------------------- VPX wiring # Each connect dispatches via the registered vpx-3u transform. diff --git a/tests/test_vpx_transform.cpp b/tests/test_vpx_transform.cpp index 83ac3b3..9d1adf5 100644 --- a/tests/test_vpx_transform.cpp +++ b/tests/test_vpx_transform.cpp @@ -16,7 +16,7 @@ namespace { // Build a Part with `pin_names` pins, attached to a fresh module so prnt -// chains exist (set-type's validation depends on pins; transforms don't). +// chains exist (set-connector-type's validation depends on pins; transforms don't). Part *make_part(Module *mod, const std::string &part_name, const std::vector &pin_names) { Part *p = new Part(part_name);