Skip to content

feat(struct): reusable bit-field and enum types, hidden fields, unified creation - #255

Merged
deviousprophet merged 90 commits into
mainfrom
feat/struct-overlay-types
Oct 19, 2026
Merged

deviousprophet merged 90 commits into
mainfrom
feat/struct-overlay-types

Conversation

@deviousprophet

@deviousprophet deviousprophet commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

Reworks the Struct overlay into Type Overlay: three named type kinds (plain struct, reusable bit-field, enum) behind one creation flow, a renamed and forward-migrated persisted contract, per-field and per-bit-child hiding, and a reworked Types list. Existing workspaces migrate forward automatically on first open.

Main changes

  • Type Overlay rename — the feature, sidebar tab, section labels, source modules, files, and identifiers are renamed (StructDef → TypeDef, StructPin → TypeInstance, core/struct/ → core/overlay/, structPanel/ → overlayPanel/). Kind values remain struct / bitfield / enum.
  • Persisted contract v2 + migration — .hexscope/structs.json → .hexscope/types.json (schema schemas/types.schema.json), keys structPins / structId / refStructId / sourceStructId → typeInstances / typeId / refTypeId / sourceTypeId. DATA_SCHEMA_VERSION 1 → 2 with a shape-dispatched MIGRATIONS[1] and a one-shot, marker-guarded file move. Legacy firmware_profiles trees, per-dir profiles, and Memento-era data are translated explicitly; once the new pool is verified, the legacy structs.json and retired schema copies are removed. Pre-rename key names are no longer read.
  • Three type kinds via one "New Type" chooser — plain struct, reusable bit-field, enum; named bit-field references render inline, and enum values render as NAME (0xNN) with a numeric fallback.
  • Hiding — a per-field hidden flag plus per-bit-child hidden (def-level), both revealed by the per-profile Show hidden control, which is now a toggle button.
  • Editors — the pure-struct editor drops inline bit-field authoring and the Bits/Alloc columns; the bit-field and enum forms gain aligned column headers (Name · Bits · Enum · Hide, Name · Value) and accessible input labels.
  • Types list — a kind chip for every type (sentence case, per-kind accent), richer details (struct byte size, bit-field used/total bits), kind-then-name sorting, a name search plus kind filter, and a chip → name → details row layout that hides the details on a narrow sidebar (full text stays available on hover).
  • Quality — the JSDOM harness's menu and toast singletons are document-scoped, which fixed 45 failing tests; the suite is green at 1312 passing / 0 failing with Fallow clean.

Migration / compatibility

  • Existing .hexscope workspaces migrate forward on first open; all definitions, fields, instances, labels, checks, and bindings are preserved.
  • A corrupt, unreadable, or newer-than-build types.json preserves the legacy pool rather than deleting it.
  • DATA_VERSION (storage envelope) is unchanged; only DATA_SCHEMA_VERSION (payload shape) is bumped.

Completes the Type Overlay rename in the internal DOM/CSS vocabulary (deferred by the persisted-rename task). Abbreviation families shift s... -> o... preserving each family's meaning: si- -> oi- (instances), se- -> oe- (editor), sfe- -> ofe- (field editor), sa- -> oa- (add/apply), sm- -> om- (manager), sd- -> od- (types-list rows). Literal names renamed by context: #s-struct-pins -> #s-overlay (fixture root), #s-struct -> #s-types, sidebar panel id 'struct' -> 'overlay' (=> #stab-overlay/#sbp-overlay), .se-struct-default-* -> .oe-type-default-*, .sa-struct-sel -> .oa-type-sel, .struct-field-row -> .field-row, .struct-addr-pfx -> .addr-pfx, .struct-h -> .type-h, .struct-arr-sep -> .type-arr-sep, data-se-view -> data-oe-view.

Internal only: no user-visible, persisted-contract, or behavior change. Kind vocabulary (type:'struct'), the persisted/legacy struct* identifiers, the intentional data-source-struct-id parity fold-back literal, and the stats-item .si/.si-fmt namespace are unchanged.
Documents the new DOM/CSS families (oi-/oe-/ofe-/oa-/om-/od-), the contextual literal renames, and the data-* attributes that mirror a persisted key. Corrects the frozen-id list to name the real runtime ids (#sbp-overlay, #stab-overlay, #oi-instances/#oi-types) with the JSDOM fixture root (#s-overlay) marked as such.
Closes the documented one-release window. The general readers now accept only canonical v2 keys: normalizeTypeDefsValue no longer aliases, and candidateTypeInstances reads only typeInstances (no typeInstances ?? structPins ?? pins, no per-instance/source aliasing).

The one-time legacy migrations stay lossless: hexScopeMigration aliases each legacy input explicitly before normalization (pre-rename firmware_profiles structs.json refs, tree index.json pins, per-dir profile.json, Memento-era arrays), and migrateLegacyProfileDirs takes an aliasRecord hook. overlayAliases is migration-internal now; DATA_SCHEMA_VERSION, MIGRATIONS[1], the structs.json -> types.json file migration, and the schema are unchanged, so versioned v1 and bare-array payloads still migrate through the runner.

Tests retargeted rather than weakened: the old general-reader tolerance assertions moved to the migration path, and the retirement now has explicit negative assertions (a v2 payload carrying only legacy keys yields no defs/instances).
Documents the retirement: the general readers accept only v2 keys, and the aliases are internal to the one-time migrations and the v1->v2 payload runner. Fixes two stale passages (state-management's 'reads typeInstances ?? structPins ?? pins', and hexscope-storage implying the v1 runner also renames the v0 pins key).
…d filtering

Every kind now renders a sentence-case chip (Struct / Bit-field / Enum) with a per-kind accent; plain structs previously had no badge at all, so the absence had to be inferred as 'struct'. Row order is name -> chip -> meta -> actions. Meta gains real numbers: struct byte size (nested-safe via the full defs pool), bit-field used/total bits, enum base + entries. The list is sorted kind-grouped then case-insensitive name, on a copy — allTypes() and the pickers keep their stored order.

Adds a filter bar (name search + kind select) that rebuilds only #om-list, so the input keeps focus and the editor is untouched; filter state is panel-local, cleared by resetViewState, and never persisted or posted. Empty states stay distinct (no types vs no match). Presentational only: no persisted, schema, decode, or C-preview change.
Records the kind chip contract (all three kinds, sentence case, per-kind accent), the row order, the per-kind meta fields, kind-then-name sorting with the picker-order guarantee, and the filter bar's transient state and list-only refresh. Fixes the stale 'N children' meta line.
…schema copies

The v2 file migration re-seeded the pool into types.json and left .hexscope/structs.json behind forever, and seedSchemaCopies only wrote current schemas so retired copies (schemas/structs.schema.json) were orphaned. The one-shot pass now hard-deletes the legacy pool once types.json is verified usable, and prunes *.schema.json copies that are no longer shipped.

Deletion is gated on verification, not on the write succeeding: types.json must read back ok with a NON-EMPTY defs array. Empty, absent, non-array, corrupt, or newer payloads preserve the legacy file (it may be the only good copy). A failed delete is non-fatal and withholds the marker so a later session retries; verification outcomes stay one-shot. Pruning is limited to *.schema.json inside .hexscope/schemas/, keeps profiles/types/bindings, and never touches non-schema files or other directories.

No schemaVersion, MIGRATIONS, schema-content, or firmware_profiles tree changes.
Replaces the old 'never delete structs.json' guidance with the verify-then-delete contract: a non-empty verified defs array is required, the full preserve matrix (empty/absent/non-array/corrupt/newer), the marker-withheld-on-failed-delete retry, the hard-delete rollback trade-off, and the schema-copy prune scope.
…ter controls

The Types row was a flex line whose chip and meta widths varied per label and text, so no two rows shared a column: the chip's left edge, the meta's left edge, and the name's right edge all drifted. It is now a shared grid: name (flexible, ellipsis) | kind (52px, centered) | meta (58px, right-aligned, ellipsis) | two action cells. Measured in Chromium: the name gets 69px at the 260px sidebar minimum and grows to 209px at 400px, with no row wrapping or overflow at any width; a literal 4-track template would wrap the second action button and double the row height, hence the trailing auto auto pair.

Name and meta carry a title with their full text, and the meta text node is escaped (it was interpolated raw). The filter controls now share one explicit 20px box with the same font - both are component-scoped so the override beats sb-input-sm, and the native select arrow is kept. The select was taller because neither control had an explicit height and a native select resolves its own intrinsic metrics.

Presentation only: no sort/filter/behavior, persisted, schema, decode, or C-preview change; no id/class renames.
Records the shared four-cell/five-track row grid with its measured budget (kind 52px, meta 58px, name 69px at the 260px minimum), the ellipsis + title contract, the escaping rule for the meta text, and the shared 20px filter control box.
…ow-width hide

The row read name -> chip -> meta, and the meta was capped to a 58px track, so the info the user needs was ellipsized; the chip was only centered in its track, so each kind still hugged its own label width. The row is now chip -> name -> info -> actions: a fixed 56px leading chip track that the chip fills (identical-width badges in one aligned column), a content-sized info track so the full text shows, and the name as the only flexible/truncating cell.

Below a 300px list container the name would be squeezed, so a container query on #om-list hides the info AND drops its grid track (display:none alone would leave the column reserved). The row carries title='<name> - <info>' so the hidden info stays discoverable. Measured in Chromium: chips 56px each, info fully rendered at 300/400px, name 152px at 260 and 216px at 400, no wrap or horizontal overflow at any width.

Presentation only: sort, filters, empty states, actions, the 20px filter-control box, ids/classes and persisted shape are unchanged.
Corrects two stale [Unreleased] claims (the legacy structs.json is now deleted after a verified migration, and the pre-rename key names are no longer read) and records the remaining user-visible work: per-bit-child hiding, the bit-field/enum editor column headers, the Types filter bar, chips for every kind with richer details and kind-then-name sorting, and the chip -> name -> details row order with the narrow-width hide.
@deviousprophet
deviousprophet marked this pull request as ready for review October 19, 2026 14:46
@deviousprophet
deviousprophet merged commit edca056 into main Oct 19, 2026
9 checks passed
@deviousprophet
deviousprophet deleted the feat/struct-overlay-types branch October 19, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request webview Any changes to Webview UI, frontend, or interactions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce clutter in Struct Instance View Add support for enums

2 participants