Architecture and maintenance

Documentation index

Separation of responsibilities

The core document/session model is independent of the browser DOM. Commands mutate the model through validated operations and history. The surface adapter translates native browser input/selection to model commands and renders current state. The public editor coordinates policy, codecs, preview, imports and host notifications.

graph TD; H["Host API and toolbar"] --> E["Editor coordinator"] N["Native browser input"] --> S["Surface adapter"] S --> M["Model, commands and history"] E --> M M --> S E --> C["Codecs and policy"] C --> P["Preview pipeline"] E --> A["Host asset callbacks"]

The DOM is a projection. Do not save element.innerHTML or use execCommand as the application command architecture. Native browser editing is intercepted/normalized, with DOM reconciliation as an input fallback; the model remains authoritative.

Runtime modules

File Responsibility
formats/codecs.js Markdown parse/serialize, source metadata and safe URL helpers
model/core.js Sessions, source/rich documents, positions, selections, history, revisions, bookmarks
commands/commands.js Editing operations, block/mark operations, input rules, search/comment helpers
formats/documents.js Supported HTML import/export and structured document helpers
model/structures.js Lists, tables, cell navigation, image blocks, structural replacement
policy/policy.js Presets, feature compatibility, diagnostics and import handling
commands/markdown.js Markdown Source bold/italic delimiter operations
preview/preview.js Preview preprocessing/sanitization, iframe, CSS, mapping and divider
languages/languages.js Lexical source decoration and bracket-matching helper
editing/paste.js Clipboard import/input fallback helpers
editing/surface.js contenteditable rendering/input, composition, native selection, measurement
editing/controller.js Private component lifecycle, surface coordination and base command routing
editor.js Single public editor implementation: policy, structures, images and preview
images/image-host.js Optional sample native/browser image transport
samples/browser/app.js, feature-ui.js Sample host UI and optional bridge, outside the runtime
styles/editor.css, styles/features.css Scoped surface, structure and preview layout rules

All paths in this table are relative to src/CODE.Editor.Web/ unless specified otherwise. assets.json defines initialization order. The private controller and public editor are assembled once; no later script replaces CODEEditor.Editor/create. The DOM-independent model, commands and history remain replaceable independently of the input surface.

Document shapes

A source document has a text string. A rich document contains ordered blocks with stable IDs and marked text runs. Supported block kinds include paragraph, headings, list/task items, quote, code, thematic break, raw fragment, cell and image. Structure metadata connects related list/table nodes and builds a normalized structural index.

Runs carry text plus marks such as bold/italic/code/link and supported style values. A table is represented through cell blocks with shared table/row/column metadata; it is not arbitrary nested HTML. An image is a block with reference/state metadata. Opaque raw content preserves unsupported source without pretending to offer editable semantics.

Rich selections use block IDs and offsets; source uses string offsets. Helpers flatten rich positions when needed for search, native transport and range operations. Source metadata and fingerprints allow unchanged source to be retained; edited structures can be serialized canonically.

Transactions and rendering

An edit captures model/selection state, validates the mutation and stores history. Source transaction batches validate all ranges against one revision. History is bounded and adjacent typing can be grouped. A rebuild can replace the surface without discarding this state.

The current surface uses browser contenteditable and browser selection/caret layout. It does not draw its own blinking caret. Some rendering paths replace substantial DOM content and measurement/colorizing can scan the document. There is no viewport virtualization, piece table optimized for huge files, worker parser, or semantic language engine.

Composition requires special handling: rerendering during an IME's intermediate state can destroy input. The adapter protects composition and reconciles the committed result. Operations needing committed values must respect that lifecycle.

Preview is separate from serialization

Preview hooks receive a serialized snapshot of content but return display-only substitutions or HTML. They do not mutate the document. The standard output path adds measurement anchors. Arbitrary host HTML cannot automatically retain source mapping, so following falls back to proportional scrolling.

Preview-only CSS lives in the iframe. Source/visual editor display CSS remains separate. Keeping these paths separate lets a blog preview imitate a site without leaking that site's CSS into the input surface.

Native wrapper layout

File Responsibility
TextEditor.cs Complete control: WebView2 setup, queue, state cache, typed properties/methods/events, preview callbacks, focus management and lifecycle
EditorOptions.cs Settings, validation, notifications and wire values
EditorTypes.cs Public enums, records and event arguments
NativeImages.cs Bounded image transport, validation and callback routing
../CODE.Editor.Web/hosts/winforms/control.html Minimal editing shell
../CODE.Editor.Web/hosts/winforms/control-host.js Typed-wrapper bridge, state serialization and internal find UI
../CODE.Editor.Web/hosts/winforms/control.css Control-only layout

Assets are embedded resources under CODE.Editor.WinForms.Assets.*. The sample Form is a consumer, not the control implementation. Keep native API names, bridge operations, and JavaScript contracts aligned when adding a capability.

In Solution Explorer, the WinForms project's linked browser files appear under Assets/, with subfolders matching the shared source responsibilities. The generated Link metadata controls that display; explicit LogicalName metadata preserves the existing embedded resource names and runtime URLs. Edit build/assets.cjs when changing these links, since build/EditorAssets.props is generated.

Maintaining the shared implementation

Edit only the authoritative runtime under src/CODE.Editor.Web/. Run the build command to regenerate distributions, verify tests and rebuild the embedded assets/package. There are no maintained runtime copies to synchronize.

A later custom-rendered source surface

The model boundary helps a future Monaco-like surface: it can retain document operations, history, serialization and host APIs. It still requires a new input/caret/selection strategy, line layout and hit testing, viewport rendering, scroll metrics, composition support, accessibility integration, and mobile behavior. Existing offset mapping and tests become useful constraints, not an implementation of those capabilities.

Keep Source and Visual views free to use different adapters. A highly optimized source surface need not force a rich document editor to abandon native contenteditable. Introduce an explicit adapter contract before replacing either, and keep host selection/save semantics stable.

Source and build layout

The root solution is CODE.Editor.sln. src/CODE.Editor.Web/ is the only maintained browser runtime. src/CODE.Editor.WinForms/ links those assets as embedded resources using build/EditorAssets.props, generated from assets.json. build/assets.cjs creates the native page, flat browser distribution and standalone demo deterministically. Generated outputs live in ignored artifacts/. Run ./build/build.ps1; direct repository project builds require node build/assets.cjs first. Package consumers require neither Node nor loose assets.

Browser, ASP.NET and Photino examples consume the same runtime; sample headers, toolbars, content and storage remain under samples/. Tests live under tests/web and tests/winforms, with historical evidence under tests/fixtures. The original sources were backed up before restructuring; see artifacts/backup/.

The solution also exposes the authoritative runtime under src > CODE.Editor.Web and the manual under a root docs solution folder. These solution items point directly to the existing files. Add new files to their matching solution folder when needed. docs/history/ contains archived milestone notes; use docs/README.md and its 18 topic chapters for current behavior.