This describes the implementation as of 2026-09-05. It is a reference for working on the code, not an attribution of design intent to the owner. Earlier models and unverified rationale are preserved in historical notes. Open work is listed separately in deferred work.
GID defines Value as cell references, blobs, lists, and records.
A document has an optional root and a CellId -> Value table. An identity with
no table entry is a bare cell. Record labels are cell identities; text, names,
numbers, absence reasons, and domain data are library conventions.
A cell may accidentally occur in several sources, for example when editing a document that also exists as a loaded library. Normal lookup selects the document definition first, otherwise the first loaded library definition. Names, structural display, and cell evaluation use that value. Definitions are neither merged nor implicitly composed. Duplicate indicators and inspection UI are deferred.
Each library has one definition per cell: either an ordinary value or a native definition pairing a descriptive value with its Rust implementation. Reads and calls use the same lookup. Reading a native definition uses its description; calling it invokes its implementation. An absent or non-callable result does not try another source. Library descriptions (currently name records) live in that same table under the library identities, not in a separate metadata store. Replacing a loaded library replaces all its contributions in place, including projections and completions, before those are composed. Explicit source-qualified paths still reach a particular definition; loaded library values remain read-only. See Sources, Library and Libraries, and Grap evaluation.
The text bridge is a temporary import/export representation. Its binders and spelling do not add GID semantics. Native binary storage is not implemented; see the bridge format.
A Path is a sequence of GID steps interpreted in a supplied document and
library context:
Key(cell)enters a record field.Element(position)enters a list element at its stable position.Follow(Document | Library(id))crosses a cell into a particular definition.
The empty path is the document root; it need not be a cell. Library sources use
stable identities, so changing load order cannot silently retarget a Follow.
List positions preserve an occurrence across edits that retain that position;
they are not content identities or globally meaningful addresses.
Selection also names its owning workspace view. Two panes can show the same
stored path while keeping separate focus, scroll, and folds. A workspace
Root supplies this session identity; it is not a GID cell.
SourceTrace serves source-linked widgets, drawing, and
highlighting. It is either a stored path or a cell, definition source, and path
relative to that definition. Normalizing to the nearest followed definition
lets different occurrences highlight the same source without conflating two
libraries' definitions of one cell. Both forms still need the caller's
resolution context. Neither is an execution stack or global address.
Computed values use at at their own displayed occurrences. They and their
children can be selected, copied, and folded, but have no document destination
for edits. Selecting a result does not select its producing expression.
Computed output uses the same read-only ground as external definitions. Nested
read-only occurrences do not stack washes; an explicit jump to writable source
restores the paper ground. This decoration does not change edit permissions:
those still follow the occurrence's source/conject. A reference to an external
definition can itself still be replaced or removed from a writable document.
Selection owns a workspace root, path, GID
payload, and optional Rust editor. Its stages distinguish an existing edge,
a pending value, and a pending record label. Annotation records live in a
path-keyed Annotations trie owned by the view;
folding is one convention in those records.
Selection also retains a native editing scope. Ordinary document projection
uses its allocation-free identity case. A scope installs a conject at an
occurrence: an ordinary function of the remaining projection path and a document
path, returning Option<DocumentPath>. Reads and writes use the same function;
there is no independently configurable read/write pair or inverse mapping.
Several occurrences may conject to one source. Selection, navigation, and
annotations stay occurrence-local, while source-linked hover uses the conject.
Line editing, gestures, completion insertion, structural paste/deletion, and
history retain that interpretation. Undo restores the scope with the selected
path; scopes contain no document snapshot or borrow of the editor.
The scope stores a resolver function from occurrence path to optional document
path. The standard boundary constructor captures the occurrence prefix,
document starting path, conject, and enclosing fallback in that function;
there is no separately interpreted route record. Identity scopes borrow their
input path without allocating.
If a projection changes what a selected occurrence means, its caller is
responsible for clearing the selection when necessary; the editor does not
try to repair arbitrary changes of interpretation.
descend extends the current occurrence, jump gives a new occurrence an actual
document source, and at projects a supplied value without a source. None
means no document location, not a missing value: Some(path) can name an absent
field and still offer editing. A library source is present but read-only.
Ordinary descendants of at stay detached, including cell follows; an explicit
jump can establish a source again. Outline list entries project their referenced
fields through jumps: the heading is the real list element, and its body has an
occurrence beneath that element. Repeating a field yields independent folds and
selection locations while both bodies edit the same source field.
Copy and fold do not resolve an occurrence through conject. The shared
projection boundary installs handlers that copy the displayed Value and
change the occurrence's fold annotation using the default already determined
during projection. This also works for source-less at values. Inner widget
handlers take precedence (for example, copying a text selection). Structural
cut copies that same value, then attempts deletion through the selection's
conject; a source-less value can be copied but not deleted.
Ordinary selection does not initialize editing state. Its role is derived from the current location: a writable missing value uses the pending picker, while an existing value is selected normally. An explicit pending or label payload can still request those modes intentionally, but no caller needs one as setup. The picker renders an empty query by default without writing selection state and materializes its editor only on input; query, caret, choice, scroll, and expansion state are optional. This applies to empty roots, bare-cell definitions, missing record fields, and inserted list positions, without a special selection callback for each. Read-only locations do not enter a picker.
The live LineEditState owns text, caret, IME, and text-drag state. A projection
at the selected location receives a GID description derived from that state.
A capability replacement decodes it once into the live editor; there is no
second retained editor representation to synchronize. The path library encodes
typed paths as ordinary GID lists: {key: cell}, {element: {indexable: blob}},
and {follow: document} or {follow: {library: cell}}. Decoding checks each
step and the canonical list-position bytes. Encoding a position does not
extend its lifetime: loading a document still regenerates its list positions.
Generic Grap handlers receive GID events and caller-supplied capabilities.
Site and selection access are scoped foreign calls. site path returns the
projected site's document path; selection get reads the selection payload
there. selection set takes an explicit path and value, interpreted in
the supplied document and view, so it can move selection to another location.
An absent value clears selection only at the specified path. Reads observe
staged writes; an explicitly declined or halted handler commits no effects.
Ordinary absent results keep preceding effects. Setters return {} on successful
set or clear; absent remains an input convention for clearing, not its return value.
Site and selection getters return their own missing-state reasons when empty.
A function must decline before performing effects, including effects in its
arguments or nested calls. Declining afterward halts the evaluation and prints
an error. Only the complete editor operation is staged,
with no per-call snapshots or rollback. Tests can replace these foreign functions
with a recording interpreter.
The projection supplies a line's spelling, presentation, and conversion callback.
The current line handler owns the callback; selection retains neither a Rust
callback nor a Grap callable. The line is the stock native widget function
carried by Layout::widget; layout has no line-editor constructor or interpreter
arm. The editor supplies current state and scoped editing capabilities, then
incorporates the widget's render closures, handlers, hover claim, and navigation
transition. Progred's line control
runs an editing operation, then converts only when the accepted operation changed
the text. The callback receives the live value and spelling; None declines a
write. An equal result does not rewrite the document. Invalid intermediate text
can remain in the editor while the last valid value remains in the document.
Loaded library values decline writes. Projections decide how unrelated fields
survive an edit. Native atomic libraries use native conversion functions; the
line library's grap adapter calls a Grap conversion with text and current value
as data, mapping absent to None.
The line control groups the first document write into undo and coalesces later writes in that editing run. The shell no longer runs a general post-event conversion step. Query editing similarly resets its completion choice and scroll at the editing operation, not after unrelated events.
In the normal projection, blobs use a monospace hex line with a fixed 0x
prefix. The buffer contains the full hex digits, including for blobs longer
than the structural summary. Edits accept complete bytes in either case;
empty hex denotes an empty blob. Query entry and editing share the blob
library's parser. Raw retains its compact structural blob display.
A selected, writable line with no editing state uses its current projected spelling with the caret at the end. Rendering and input use the same default; projection does not store it just because the line is selected. On an editing interaction, the line control materializes state from that default. Its current handler supplies conversion. Existing caret, in-progress spelling, and IME state take precedence. Raw and read-only views do not acquire an editor from a plain selection.
Ordinary selection therefore needs only a location, including after completion, paste, deletion, and undo. Navigation targets receive an optional arrival direction. The line widget places the caret at the beginning when moving Right into it and at the end when moving Left; ordinary and vertical arrivals keep the default. This policy belongs to the widget, not navigation dispatch. Pointer placement remains an explicit interaction. The shell does not inspect values or the render tree to infer editability. See navigation.
Unhandled arrows, regardless of modifiers, become Event::Navigate(direction) after focused
controls and editing handlers decline the raw key. These semantic events run
through the ordinary handler chain. A frame contains only the handlers for its
selected occurrence's available directions, not a complete navigation graph
or special destination table. With no selection, a root navigation handler
selects the document's root occurrence. Select All remains an explicit command.
Projections declare selectable stops; the chosen layout determines their order. During placement, ordinary columns concatenate logical lines and rows align their children's logical baselines. No pixel coordinates, measured heights, or distance thresholds choose destinations. Padding and inert decorations add no stops or lines. Only placed alternatives contribute.
display::projection::group(content) adds the whole-value stop before its
contents. Multiline contents put that stop on an additional leading logical
line; single-line contents keep it on the same line. The added entry line
does not itself make enclosing single-line contents multiline. Cells, lists,
records, and custom forms use this same rule. group_hug combines a selectable
whole with inline/indented head-body alternatives; ordinary row and col
need no navigation-specific counterpart.
Left/Right traverse all stops in logical reading order, wrapping between lines. Up/Down select the first stop of the adjacent logical line. Thus Down enters a multiline cell or list before its first content line, while passing over a single-line container to the next line. Different painted heights do not change this logical order. Center-aligned rows currently combine top-first. No retained column, directional history, geometric tie-breaking, or Tab routing is present.
A call groups its function and argument fields together. Its arguments use
record_fragment_with, arranging fields without another whole-call stop.
An outline groups its heading and body in a column, then composes sections and
extras vertically. Extras use record_fragment so they do not add a second
root-record stop. Empty lists stop once; empty cells offer both the reference and
the missing contents. A leaf facet can supply its widget-specific selection
callback at the same occurrence as an enclosing whole-value stop without
adding another navigation stop. Punctuation and other inert decoration do not
declare separate stops.
Each pane builds its own temporary collection of stops and logical lines. After placement, it retains only the current selection's four destinations in an ordinary navigation handler and drops the collection. Destinations preserve the existing occurrence path and editing/conject context: jumps remain editable, and computed children remain read-only. Navigation never resolves document paths to choose a destination. Landmarks separately provide geometry for revealing a landing, pointer/source selection, and Select All. See layout navigation for examples and the checkpoint measurements.
Line editing uses the host-supplied keyboard convention: Mac Command+Left/Right moves to the content's ends and Option+Left/Right moves by words. Control-based hosts use Control+Left/Right for words. Shift extends the selection in each case. These controls handle movement before structural navigation; affixes remain outside the editable span.
Ordinary hover, selection, and related-occurrence highlights share one padded outline. Each occurrence paints at most one mark: selection takes precedence, then related selection, direct hover, and related hover. Pending text frames keep their own tighter outline through focus and editing; this widget styling does not determine the geometry of ordinary value highlights.
The editor owns an explicit Palette input, used by text, selections, library
grounds, menus, completion cards, and popovers. Theme::Light uses white paper,
blue names, violet field labels, and orange literals. Theme::Dark supplies
brighter corresponding colors on navy paper. The macOS shell follows the system
appearance at startup and on changes. Its native View menu offers Follow System
Appearance, Light Mode, and Dark Mode; this application-wide override lasts for
the session, including newly opened windows, and also updates window chrome.
Other hosts default to Light; the browser host can explicitly choose either theme.
Read-only projection boundaries use a faint tint; returning to writable source
restores the same opaque paper used by the window. Changing the
palette rebuilds the ordinary complete frame without replacing the document,
selection, or undo history. Authored drawing colors remain document data, not
theme colors. These styles change presentation, not projection recognition or
source/selection policy.
Cmd+A (Ctrl+A on non-Mac hosts) selects the current view's root through its landmark's direct-selection callback. With no selection, it targets the document root. Focused text fields handle the shortcut first and select their own text.
The projection rendering a pending value or label explicitly requests
completion and may supply a lazy vocabulary. Completion is an ordinary native
widget function; its explicit kind and provider arguments go to a scoped app
adapter returning the same measured widget output as other projections. No
provider is hidden in traversal context. Only the active picker asks the
provider for offers. Each request includes the query, field/value kind,
suggestion/Everything scope, Raw mode (so providers can omit interactions whose
presentation needs a library projection), source-qualified path, and read-only
path and cell lookups, plus lazy enumeration of defined cells. Cell lookup
exposes the selected definition's value, source, and whether it has a native
implementation, without evaluating it.
The path names a missing value or the record receiving a new label. A local
projection provider takes precedence; otherwise library providers contribute
in library order. None leaves the vocabulary unspecified, while Some([])
means an empty narrow list with the … escape. If no provider specifies a
vocabulary, the editor uses its universal offers directly.
Completion display text and detail can be literal text or a named cell reference. Library, constructor, parameter, and numeric-type labels use references; the picker resolves their current names before filtering each frame. Renaming a definition therefore updates even retained offers without changing their activation handler. An explicit empty name stays empty; a missing name uses the usual short cell identity. Typed values remain literal text. Cell search entries show their source name as a right-aligned note, without appending the cell identity. Identities are low-level inspection information, not routine disambiguation labels; Raw still shows them as the primary spelling.
The completion library's labels helper turns cell identities into label offers;
combine concatenates applicable lazy providers in order, preserving an explicitly
empty vocabulary. Grap's parameter_labels reads an inline or stored lambda's
declared parameters when asked. The same metadata reader supplies call field order
and call_completion's initial pending parameter. It follows cell aliases, declines
cycles and computed callables, and does not interpret native descriptions as lambdas.
Filtering names and excluding existing record labels remain picker responsibilities.
For nonempty value searches, Grap also offers calls to named stored lambdas,
closures, and native functions discovered through those definitions. These are
ordinary call_completion offers, distinguished by a call detail; choosing one
inserts {function: cell} and opens its first declared argument when known.
Call suggestions put document-defined functions before library functions, sorting
each group alphabetically by display name, ignoring case. Typed-query matching
still takes precedence; this order breaks equally ranked matches.
The bare reference remains a separate choice. Discovery does not evaluate code
or guess the result of computed callables. Function/FFI reference slots and label
pickers do not receive these call offers.
Grap expression slots supply a focused provider: statically visible lambda
parameters, preceding let/where bindings and the current match case's pattern
bindings, plus named function calls, library literal/constructor offers, text,
lists, and records. This is an explicit local projection, including the items of
do, not a global change to data completion. Existing domain-specific suggestions
are tried first. Binding suggestions put the nearest enclosing lexical scope
first, then outer scopes, sorting names alphabetically within each scope.
Rebinding a cell gives it the nearer scope's rank; scrolling and layout have no
effect on this order. Typed-query match quality still ranks ahead of proximity.
The projection environment exposes
the loaded library provider for composition; Grap reuses those offers rather than
duplicating numeric conventions. Scope discovery reads source structure only;
quoted template declarations do not introduce bindings into unquotes. Computed
binding lists and runtime callable types are not inferred. … restores all cell
references, including function values, named constants, and library vocabulary.
Root templates and root field suggestions are ordinary library providers checking the path, not separate editor hooks. The name library offers the query as text at a name field, including an empty string and optional surrounding quotes. A missing-name marker, such as an anonymous lambda's, only selects that name location; the name library's offer supplies its text. Expanding the picker still allows other values. Fidget uses the same interface for shape expressions, parameter labels, and f32 parameter values, including through cell references, source-list items, and existing Grap constructor calls. Shape templates open their first missing parameter without inventing a value. Label offers omit fields already in the record. Fidget field-expression suggestions put shapes before scalar constants; numeric parameter slots still lead with their f32 offer, including zero for an empty query. Circle and sphere are ordinary named Grap lambdas that use quote/unquote to return Fidget arithmetic; the Fidget parser has no circle or sphere forms. Their parameter suggestions and initial focus come from their current definitions; the native Fidget forms retain explicit domain schemas. Their completions insert calls only in evaluated positions (the domain's source entries and Fidget constructor arguments), not inside inert Fidget records.
Libraries can also contribute query-dependent value offers to the universal
vocabulary. The numeric libraries offer f32, f64, and u64 interpretations
when the query parses, showing the representation and the actual stored
number. An empty or whitespace-only query offers zero in each available
representation; it remains a suggestion until committed. Other invalid numeric
queries offer no number. Universal offers use a general ordering: exact nonempty
display-name matches from library interpretations, strong named cell and constructor
matches, remaining library-provided interpretations in library order,
plain text (or a new label), then weak fuzzy and unnamed references. The editor
does not distinguish particular numeric representations for ranking. With an
empty query, the zero interpretations therefore follow named cells and
constructors, just before the empty string. Explicit quoted text and blob syntax
lead instead. Numeric providers decline label requests. A projection's narrow
vocabulary still takes precedence until the user expands it.
Universal constructor offers accept delimiter aliases: [ for new list,
( for new cell, and { for new record. In an empty completion query,
those keys activate the constructors directly, including in a provider's narrow
list. A field label permits only the cell constructor. Nonempty queries and
IME composition keep ordinary text input; quoted punctuation leads with literal
text. Shortcuts use the same insertion callbacks as the constructor offers.
A library completion consists of presentation metadata and an activation handler
receiving &mut Editor. Clicking or pressing Enter runs it; highlighting or
moving between suggestions does not. Handlers may edit, change selection, or
start an interaction without inserting data. An optional advertised value supplies
source/filter metadata only; it never determines activation behavior.
The completion library's insert and generated helpers build ordinary insertion
handlers. They accept an optional on_commit continuation, run at the committed
location against the staged selection and annotation state. site::grap adapts
a Grap callable to that continuation interface. Insertion
and continuation effects are prepared together and installed only if the
continuation accepts; Grap explicitly declining or halting declines the whole
operation. Ordinary absent results do not veto it. Selection changes are
effectful calls, not a special return-value format. Insertion itself does not change selection: the
continuation receives the existing selection, and only its explicit effects
replace or clear it. A low-level offer with no continuation leaves that selection
unchanged, including an active pending query. Stock offer combinators supply the
policy: completion::select selects the inserted value, and completion::label
opens the label's missing value. Text, numbers, and blobs simply select their
location; their line controls supply default editing when projected. Completions
do not copy editor text, caret, or write-back rules into the selection. Query
caret positions are not translated across parsing. These same offers work in
Raw without an override, since that projection contains no atomic line control.
Enter commits only through the placed completion control; the shell has no
fallback which inserts query text after its offers decline.
The color library's new color offer changes selection to picker state at the
same missing location. No color is inserted and no undo entry is made until the
first picker interaction. List insertion positions remain stable through that
transition. The existing point-control gesture writes the selected color and
groups the drag into one undo step. Escape before choosing returns to completion;
leaving the location discards the picker without an edit. The seed color belongs
only to the picker. Raw mode omits this offer because it does not render the
color library's picker; ordinary value-inserting offers remain available.
Root grap and fidget offers create a fresh bare
cell shared by their domain field and a left pane. Fidget's pane applies
preview 3d; Grap's pane renders the evaluated result. The continuation opens
the cell's pending document definition through the domain field, without
inventing a placeholder value. Offers that mint identities construct their
value on activation, so reusing an offer creates independent cells.
panes remains an independent root field suggestion.
The placed frame retains the exact visible offers, so hover and commit never
reconstruct a different list. Each offer has an activation
callback plus explicit text, styling, matching spans, and source attribution.
The reusable puri-widgets completion widget shapes and draws rows. Progred's
native card widget composes navigation,
interaction, and the shared column and scroll container; the row widget has no
scroll viewport of its own. Its caller supplies state and
activation callbacks; the widget knows nothing about paths, insertion, or Grap.
The editor owns document operations, query state, and popup placement. See
offer construction and
document adaptation.
The card meets the query's painted frame, accounting for the frame outline and
both border widths. Placement uses those same drawing parameters above or below
the query, and includes the card's stroke when keeping it within the viewport.
A provider starts with its narrow vocabulary. The trailing … participates in
row navigation but activates expansion rather than committing a value. Expansion
also happens when pressing Down on the selected … row. The expanded list keeps
the provider's offers first and adds universal atoms, constructors, and cell
search; the … row disappears. Expansion keeps the
selected index, clamped to the available rows. Changing the query filters the
expanded list and resets selection and scroll; expansion lasts for that picker.
Returning to an older query does not restore an old choice. A new picker starts
with its provider's narrow vocabulary. Pointer and keyboard activation use the
same callbacks.
Keyboard navigation and unpressed mouse motion over a visible row update the
same chosen-row state. Only that row is highlighted, and Enter activates it.
Hover remains available for pointer activation but does not paint a second
highlight or overwrite the choice during a redraw. Touch motion and active
mouse drags do not choose rows, so scrolling and text selection can keep their
gestures.
Activating a visible offer consumes the input even if its continuation declines;
Enter must not then fall through to inserting the raw query.
workspace recognizes a direct, coherent root
record convention:
{panes: {left: [...values...], right: [...values...]}, ...}
The lists determine side and order; entries are ordinary values. Deleting a pane's root removes that list element. Opening and moving panes edit these lists, so they save and undo with the document. A malformed pane container or nonrecord root is not overwritten to make the operation possible.
Pane identity, projection mode, folds, scroll, and requested size are session
state. The document view starts with the contents of panes folded; individual
pane entries have no initial fold. Expanding the field is preserved when panes
are added, removed, or moved. Surviving declarations retain their view state.
Moving an entry assigns a new list position and explicitly retargets selection;
its size, scroll, and projection mode carry across, while path-keyed folds reset.
{value: source, projection: function} is a presentation-library convention,
not workspace configuration. The document's normal projection shows this
declaration as editable data. At pane entry, including through cell definitions,
the view tries the presentation library's declaration interpreter first. Nested
values, computed results, and the source shown after an absent result use the
normal projection, so declarations inside them remain data. This pane-entry
following is separate from explicit local or scoped projection composition.
Raw shows the structural data in either view. See
projection composition.
An assigned-size pane uses {value: source, viewport: function} instead. The
function receives value, width, and height (logical display units) and
returns ordinary display content, including handlers. Its pane has no automatic
padding or document scrolling; the assigned rectangle clips its output. Pane
splitting determines that rectangle before the function runs, so there is no
feedback from content measurement to pane sizing. View annotations and selection
keep their existing per-view ownership. Raw returns to ordinary scrolling source
display. The viewport convention applies only at pane entry, including through
cell aliases; the main document and nested declarations remain editable data.
The Fidget example and template use this contract. Preview image dimensions are explicit arguments, separate from the Fidget field and camera volume. Raster resolution follows the display scale; rectangular 3D views preserve square pixels rather than stretching the geometry. Ordinary preview calls without size arguments retain the 256-point default.
preview 3d accepts either one Fidget field (white) or a scene value:
{scene: [{field: sdf, color: rgb}, ...]}. A scene groups separately colored
objects; it is not a CSG operator. Geometry is depth-merged before lighting,
and equal depths keep the earlier object. Colors use the existing color
library's RGB/RGBA values; omitted colors are white and alpha must be opaque.
An empty scene is transparent. Fidget's 16-bit object index limits one scene to
65,536 objects. Scene data is inert like other records: Grap code constructs
it with ordinary quote/unquote, not implicit evaluation inside the scene.
The native renderer uses Fidget's GPU color pass; the CPU/web renderer shades
the winning geometry with the same object's color. Their lighting differs.
The IoP example uses an inline Grap viewport function to construct a drawing
program with the assigned width and height. Those dimensions also reach tree scene; its drawing units and editable tree parameters are not rescaled.
The drawn menu contributes its keyboard handler along with its bar and popups. Frame composition places that handler ahead of content handlers; omitting the menu also omits its shortcuts and keyboard navigation. Undo/redo have a separate editing handler, so embedded tutorials retain history without inheriting Raw, example switching, or pane commands. Native menus keep their own command routing.
Examples and replace-in-place New Document are development/demo conveniences, not the intended production File menu. Cmd+N (Ctrl+N on non-Mac hosts) and the example shortcuts replace the current document after confirming any unsaved changes. With no desktop window, they create one. Cmd+Shift+N / Ctrl+Shift+N is New Window; Open also continues to create a separate window.
Replacement keeps the window, surface, geometry, fonts, text-shaping cache,
clipboard, library stack, physical pointer/modifier input, and debug-display
preference. It resets document/saved identity, history, selection and text/IME
state, all pane identities and annotations (including camera and folds), scroll,
projection modes, divider state, binders, menus, gestures, queued input, retained
handlers/paint, and hover attribution. The successor frame is built immediately.
On macOS the old file's frame-autosave name is detached without deleting its
saved geometry; the represented file, title, and edited flag are refreshed.
These development commands are currently present in optimized make dev builds
too; optimization level is not a distribution feature flag.
History is a generic pair of snapshot stacks;
recording a new branch clears redo. The editor's snapshot contains its shared
document, view-qualified selection, and per-view folds. Collapse and expand
record steps without editing the document. Undo restores fold overrides and
their view identities, including when a deleted pane returns; it leaves current
scroll positions, projection modes, and unrelated annotations alone in surviving
views. Selection paths include the owning view rather than borrowing whichever
pane happens to be selected when Undo is invoked.
The editor holds its current and saved documents as Rc<Document>. Dirty state
is pointer inequality, constant-time at any document size. Successful writes use
copy-on-write; rejected writes do not detach the snapshot. Undoing to the saved
snapshot clears the dirty flag, while manually recreating equal contents does
not. Folding never changes document identity, and branch depth has no bearing on
saved state. The GID document and its on-disk representation remain unchanged.
A line's first write records its undo step; subsequent writes in that edit run
coalesce. Saving or recording a fold breaks the run. Projection gestures have one
caller-owned slot in gesture. An ordinary native
widget's accepting handler supplies the continuation; the slot does not
distinguish number, camera, or color controls. Widgets process pointer samples,
closing over document-edit runs or view-annotation setters supplied by the
editor. An edit run groups its successful writes into one undo step. Creating
the run, moving the caret, and writing an equal value do not write the document.
Release, cancellation, replacing/restoring the document, saving, or recording
a fold ends the gesture.
The platform supplies persistence and clipboard capabilities. macOS uses its native atomic write API. Linux writes a unique sibling temporary file, synchronizes it, renames it over the destination, and synchronizes the parent directory. Browser capabilities differ; see persistence and platform notes.
Frame construction, dispatch order, hover, and clipping are described in Puri and the editor frame.