Rendered WYSIWYG blocks use a stable egui id hierarchy so commits during editing do not remap TextEdit focus/cursor state.
Inside show_rendered_editor (src/markdown/editor.rs):
ui.push_id(editor_id, |ui| { // per tab (e.g. main_editor_rendered + tab.id)
ui.push_id(source_epoch, |ui| { // bumps only on external invalidation
// Block widgets: ui.id().with("heading_text").with(line), etc.
});
});editor_id—rendered_editor_id(tab.id)fromrendered_session.rs(set incentral_panel.rsfor both rendered-only and split preview). See split view parity.source_epoch— fromTab::source_epoch()viaMarkdownEditor::source_epoch(...).
Block-level suffixes are defined by BlockRef::widget_id_in_scope in rendered_session.rs.
A hash of self.content remains for viewport culling and block height caches (ViewportCullingState). It is not used in ui.push_id for widget identity.
| Concern | Key |
|---|---|
| Widget focus / TextEdit ids | editor_id + source_epoch |
| Scroll culling / height cache | content_hash + available width |
See Phase 0 doc. Rendered WYSIWYG commits use Tab::record_edit_from_snapshot() and do not bump epoch.
| File | Role |
|---|---|
src/markdown/editor.rs |
push_id hierarchy in rendered view |
src/app/central_panel.rs |
Passes tab.source_epoch() into MarkdownEditor |
src/state.rs |
Tab::source_epoch(), bump helpers |
src/markdown/rendered_session.rs |
BlockRef::widget_id_in_scope, rendered_widget_scope_id |
rendered_session::tests— scope id stability vs epoch bump vs content_hash scopemarkdown::editor::tests—source_epochbuilder; eguipush_idintegration for heading ids
- Open a doc with two headings in rendered mode.
- Edit heading A — cursor should stay visible (no flash/disappear each keystroke).
- Switch to raw, edit, return to rendered — content updates; epoch bumped (trace log on
Tab). - Rendered-only edit —
source_epochunchanged in logs.