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:
54
src/tui/tui_helpers.cpp
Normal file
54
src/tui/tui_helpers.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "tui/tui_helpers.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
std::string ToLower(std::string s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return s;
|
||||
}
|
||||
|
||||
bool NaturalLess(const std::string &a, const std::string &b) {
|
||||
size_t i = 0, j = 0;
|
||||
while (i < a.size() && j < b.size()) {
|
||||
unsigned char ca = (unsigned char)a[i];
|
||||
unsigned char cb = (unsigned char)b[j];
|
||||
if (std::isdigit(ca) && std::isdigit(cb)) {
|
||||
size_t za = 0, zb = 0;
|
||||
while (i + za < a.size() && a[i + za] == '0') ++za;
|
||||
while (j + zb < b.size() && b[j + zb] == '0') ++zb;
|
||||
size_t ea = i + za;
|
||||
while (ea < a.size() && std::isdigit((unsigned char)a[ea])) ++ea;
|
||||
size_t eb = j + zb;
|
||||
while (eb < b.size() && std::isdigit((unsigned char)b[eb])) ++eb;
|
||||
size_t la = ea - (i + za);
|
||||
size_t lb = eb - (j + zb);
|
||||
if (la != lb) return la < lb;
|
||||
int cmp = a.compare(i + za, la, b, j + zb, lb);
|
||||
if (cmp != 0) return cmp < 0;
|
||||
if (za != zb) return za > zb;
|
||||
i = ea;
|
||||
j = eb;
|
||||
} else {
|
||||
char la = (char)std::tolower(ca);
|
||||
char lb = (char)std::tolower(cb);
|
||||
if (la != lb) return la < lb;
|
||||
++i; ++j;
|
||||
}
|
||||
}
|
||||
if (i < a.size()) return false;
|
||||
if (j < b.size()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string LongestCommonPrefix(const std::vector<std::string> &v) {
|
||||
if (v.empty()) return "";
|
||||
std::string lcp = v[0];
|
||||
for (size_t i = 1; i < v.size(); ++i) {
|
||||
size_t k = 0;
|
||||
while (k < lcp.size() && k < v[i].size() && lcp[k] == v[i][k]) ++k;
|
||||
lcp.resize(k);
|
||||
}
|
||||
return lcp;
|
||||
}
|
||||
Reference in New Issue
Block a user