Files
NeitzelFXDesigner/docs/source-preserving-projection.md
T

8.4 KiB

Authoritative documents and source-preserving projection

This stage replaces whole-document XML serialization with source-range edits and extends the shared Kit projection. Both hosts use the same implementation and live qualification scenarios. It establishes the document/projection foundation; structural authoring and complete target-type discovery are later work.

Source ownership and edits

The host Document remains authoritative. A securely parsed DOM identifies elements and compares Kit's projected state, while a lexical index records the original start tags and attribute-value ranges. An accepted canvas edit produces an EditBatch containing only changed ranges, with the expected host revision and one named undo transaction. Kit's generated XML never replaces the source document.

Unchanged characters stay unchanged: import-only binding types, Model processing instructions, comments, unknown declarations, namespace versions, attribute order, quote style, whitespace, entities and line endings. Attribute values are escaped for their existing quote delimiter. Removing an attribute removes only that attribute; new attributes are inserted into its original start tag. A newly edited attached constraint adds its required layout-class import if absent, without moving existing processing instructions. No-op round trips return the original text exactly.

Source edits use a minimal changed range. Shared source selection is mapped through visual ranges, while native IntelliJ editors retain their Document range markers. A source edit queued during an asynchronous visual transaction retains disjoint visual changes; later overlapping source typing wins in its own undo command. Revisions belong to each host adapter and do not assume that IntelliJ modification stamps increase across undo.

flowchart LR
    D[Host Document and revision] --> L[Secure DOM + lexical ranges]
    L --> P[Kit projection with private identities]
    P --> C[Canvas property or layout proposal]
    C --> V[Validate identities and structure]
    V --> E[Attribute-range EditBatch]
    E --> D
    D --> O[Private draft overlay]
    O --> W[Target-runtime rendering]

Broader Component coverage

  • Explicitly imported and fully qualified Component declarations, multiple instances, and Components nested in standard layout containers.
  • Anonymous Components and standard nodes receive collision-checked projection identities. They are never saved into source. Anonymous Component render identities are added only to the private FXML overlay.
  • fx:root bodies project through their declared type, allowing ordinary controls inside a Component's own FXML to be edited while retaining the original fx:root declaration.
  • Component internals remain opaque to the parent canvas. Inline content and unknown attributes stay in source; target rendering sees the original declaration. Open Component continues to navigate to its separate source.
  • The shared Component panel shows the real declared class and existing FXML properties. Enter applies an escaped source-range edit; target rendering validates application-specific values. It does not infer application property types from SnapshotRegion.
  • Native Kit picking, resize handles and relocation commands operate on proxies. Attribute editing now includes AnchorPane constraints, GridPane spans/growth, HBox/VBox growth, alignment, transforms and existing scalar/layout properties.

Kit's built-in hierarchy/inspector still identifies the host placeholder as SnapshotRegion; the shared Component panel supplies the actual class/properties. There is no new upstream Kit patch in this stage. A full target-aware hierarchy/typed inspector remains a later integration seam.

Failure and external-edit behavior

Source, Design and Split are explicit modes over the same draft. Invalid or unrepresentable source leaves source editing available and disables the retained canvas and Component property panel. Correcting the source restores the projection. Unsupported structural proposals, identifier changes and unsupported property changes are rejected without rewriting the source. Changes of property ownership, such as moving a node from BorderPane.left to right, cannot be silently ignored.

Standalone polls clean files through document snapshots, reloads changed contents, advances the revision and clears obsolete local history. IntelliJ refreshes/reloads clean Documents through its native file/document manager. If native autosave already made disk and Document identical, it only advances the disk baseline; it does not reload the same text or invalidate a render revision. Dirty drafts are preserved; saving checks the disk baseline and rejects a conflict. Standalone rechecks immediately before its atomic replacement. There is no cross-process filesystem lock or interactive three-way merge UI; source editing and the retained draft remain available for resolution.

The tests reuse independent handles for the same authoritative draft, including native IDE Documents opened through path aliases. Context-specific workflows do not create independent document histories.

Verification

Run the full bootstrap and real-IDE checks from README. The same ProjectionHostChecks test artifact runs in native standalone windows and the disposable IntelliJ companion, for classpath and module-path applications. The artifact is test-only and excluded from the delivered plugin.

The live scenarios cover exact source preservation, nested/fully qualified/anonymous Components, declared-property editing, unaffected source selection, native undo/redo, mode transitions, target NeitzelLib loading, native picking, resize-handle gestures, Kit relocation commands and attached constraints, save/reopen, invalid-source recovery, fx:root editing and source typing queued during a visual edit. Existing text-selection and worker-lifetime regressions remain required. Unit/adapter tests cover alternate XML prefixes, CDATA/comments/quoted delimiters, safe rejection of property reparenting, clean external reload, dirty conflicts, stale revisions and native caret/selection preservation.

Verified on 2026-11-12: 65 tests (58 Maven, seven IntelliJ), zero failures/errors/skips, plus the retained 346 target assertions in 24 JVMs, 14 Build and Refresh checks and 64 connected workflow assertions. Both native standalone layouts and both real registered IntelliJ layouts passed the shared projection scenarios. The final unchanged-property/entity-spelling and missing constraint-import regressions passed in the subsequent Maven/IDE builds. Plugin packaging, dependency/bytecode boundaries, test-artifact exclusion and documentation checks pass. Both isolated IDEs loaded exactly one Glass library with the recorded JavaFX 26 artifact hash. Evidence remains under target/connected-workflow/ and target/ide-workflow/. The intentional SDK until-build warning is unchanged.

Physical OS drag-and-drop delivery is not qualified by this automated result. Synthetic mouse events cannot start JavaFX's native dragboard; a desktop Robot attempt did not result in a document move, including after bringing the test process to the foreground. The suite therefore tests the actual Kit relocation command separately from resize-handle events. A human drag/drop check in both hosts remains part of stage-2 platform qualification.

Remaining boundaries

This stage preserves arbitrary source, but does not make arbitrary structure visually editable. Insert/delete/reparent, binding-aware renames and subtree copy/paste require later structural transactions. Application wildcard imports, fx:include, scripts and unrepresentable roots retain source fallback. Arbitrary target properties use declared FXML text editing until shared discovery supplies typed metadata. Anonymous identities are local to a projection revision, not the persistent occurrence identities needed for repeated/Table Components. Target node lookup still uses the initial CSS-ID route; separate CSS IDs and repeated/internal scopes need stage 3's occurrence identity work.

Qualification remains scoped to the recorded macOS arm64 / IntelliJ 263.7307.200 / JavaFX and Kit 26 host baseline and Java 21 / JavaFX 21.0.7 application fixtures. Product packaging, a broader platform matrix, lossless structural editing and physical drag/drop qualification are not implied. Next implementation stage: target-runtime sessions, sizing and navigation, while retaining the explicit manual stage-2 input gate.