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>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
#include "transform.hpp"
|
||||
|
||||
#include "parts.hpp"
|
||||
#include "pins.hpp"
|
||||
#include "transform_vpx.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <exception>
|
||||
#include <utility>
|
||||
|
||||
Transform::Transform(std::string name) : name(std::move(name)) {}
|
||||
|
||||
std::string CheckIdentityCompatible(const Part *a, const Part *b)
|
||||
{
|
||||
if (!a || !b) return "missing part";
|
||||
std::set<std::string> a_pins, b_pins;
|
||||
for (auto &kv : *a) a_pins.insert(kv.first);
|
||||
for (auto &kv : *b) b_pins.insert(kv.first);
|
||||
if (a_pins == b_pins) return "";
|
||||
|
||||
std::vector<std::string> only_a, only_b;
|
||||
for (const auto &n : a_pins) if (!b_pins.count(n)) only_a.push_back(n);
|
||||
for (const auto &n : b_pins) if (!a_pins.count(n)) only_b.push_back(n);
|
||||
|
||||
std::string msg = "identity wiring requires same pin names on both sides";
|
||||
if (!only_a.empty())
|
||||
msg += "; only on '" + a->name + "': "
|
||||
+ std::to_string(only_a.size()) + " (e.g. " + only_a.front() + ")";
|
||||
if (!only_b.empty())
|
||||
msg += "; only on '" + b->name + "': "
|
||||
+ std::to_string(only_b.size()) + " (e.g. " + only_b.front() + ")";
|
||||
return msg;
|
||||
}
|
||||
|
||||
IdentityTransform::IdentityTransform() : Transform("identity") {}
|
||||
|
||||
std::vector<std::pair<Pin *, Pin *>> IdentityTransform::apply(Part *a, Part *b) const
|
||||
{
|
||||
std::vector<std::pair<Pin *, Pin *>> out;
|
||||
for (auto &kv : *a) {
|
||||
try {
|
||||
Pin *pb = b->get(kv.first);
|
||||
out.emplace_back(kv.second, pb);
|
||||
} catch (const std::exception &) {
|
||||
// No same-name pin on the other side — skip.
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
TransformRegistry::TransformRegistry() : identity_(new IdentityTransform()) {
|
||||
RegisterVpxTransforms(*this);
|
||||
}
|
||||
|
||||
TransformRegistry::~TransformRegistry()
|
||||
{
|
||||
for (auto &kv : entries) delete kv.second;
|
||||
delete identity_;
|
||||
}
|
||||
|
||||
TransformRegistry &TransformRegistry::get()
|
||||
{
|
||||
static TransformRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void TransformRegistry::add(const std::string &kA, const std::string &kB, Transform *t)
|
||||
{
|
||||
auto key = std::make_pair(kA, kB);
|
||||
auto it = entries.find(key);
|
||||
if (it != entries.end()) {
|
||||
delete it->second;
|
||||
it->second = t;
|
||||
} else {
|
||||
entries.emplace(key, t);
|
||||
}
|
||||
}
|
||||
|
||||
Transform *TransformRegistry::lookup(const std::string &kA, const std::string &kB) const
|
||||
{
|
||||
auto it = entries.find({kA, kB});
|
||||
if (it != entries.end()) return it->second;
|
||||
auto it2 = entries.find({kB, kA});
|
||||
if (it2 != entries.end()) return it2->second;
|
||||
return identity_;
|
||||
}
|
||||
|
||||
Transform *TransformRegistry::identity() const { return identity_; }
|
||||
|
||||
Reference in New Issue
Block a user