Rendered Edit Session

May 22, 2026 · View on GitHub

Foundation types for the Rendered Edit Session PRD. Start with the architecture overview for motivation, commit policy, regression matrix, and design decisions. Block-type wiring is documented in linked pages below.

Module: src/markdown/rendered_session.rs

Types

TypePurpose
BlockRefStable block identity (line + kind); widget_id for egui TextEdit ids
BlockEditStatePer-block buffer, dirty flag, formatted edit mode, pending activation
PendingActivationOne-shot cursor/focus request for next frame
CommitPolicySaveIfDirty or Discard on close
RenderedEditSessionAt most one active block; HashMap of buffers

Session API

MethodBehavior
switch_toClose previous (SaveIfDirty), set active, queue activation
switch_to_uiSame + surrender previous block's egui focus
close_active / close_active_uiClear active; commit or discard per policy
on_text_changedUpdate buffer, mark dirty (no source write)
commit_activeForce-commit active buffer via callback
discard_activeReload buffer from source via callback
invalidate_buffersClear all state after source_epoch bump
load_for_epoch / save_for_epochLoad/save with epoch tracking; auto-invalidate on mismatch
open_formatted_displaySet formatted_editing = false for a block

Commit callbacks receive (BlockRef, &BlockEditState) so callers write to tab source without the session owning Tab. Undo is recorded at commit boundaries via rendered_commit_undo (not per in-session keystroke).

egui storage

Tab-scoped temp memory keyed by editor id (not global):

let session = rendered_session::load(ui, editor_id);
// ... mutate ...
rendered_session::save(ui, editor_id, session);

Storage id: editor_id.with("rendered_edit_session").

Widget ids

BlockRef::widget_id(ui) uses stable key paths under the rendered editor scope (e.g. heading_text, para_text, list_item_text, table/cell). Do not invent new suffixes when wiring render paths.

Block wiring status

Block typeSession-backedDoc
HeadingsYesHeadings
Plain paragraphsYesParagraphs & lists
Simple list itemsYesParagraphs & lists
Formatted blocksYesFormatted
TablesYes (BlockRef::TableCell + force-commit signal)Tables

Widget identity: show_rendered_editor uses ui.push_id(editor_id) + ui.push_id(source_epoch). See rendered-widget-identity.md.

Tests

cargo test rendered_session:: — switch/commit/discard invariants, widget_id suffix stability, storage roundtrip.