Files
essim/src/tui/tui_helpers.cpp
François 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

72 lines
2.2 KiB
C++

#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;
}
std::vector<std::string> Tokenize(const std::string &s) {
std::vector<std::string> out;
std::string cur;
bool in_q = false;
for (char c : s) {
if (c == '"') { in_q = !in_q; continue; }
if (!in_q && std::isspace((unsigned char)c)) {
if (!cur.empty()) { out.push_back(std::move(cur)); cur.clear(); }
} else {
cur.push_back(c);
}
}
if (!cur.empty()) out.push_back(std::move(cur));
return out;
}