documents: drawn text reads back from its end, decoded as written

Each piece records how its source decodes: Markdown's escapes and
references for text, HTML's for an HTML block's runs, none for code
spans, cut as CommonMark cuts their end spaces. Matching runs from the
piece's end, so quote marks and indents at a line's start are never
taken for text, and an alert's text needs no moved position: alert()
takes no source again.

Lines split on LF, CRLF and CR alike; LineMap matches each drawn line
to the written line it ends once, so an HTML block maps in linear time
and a tab cut to spaces lands on the tab. A write-back refuses the
press when the pressed block's kind, text or drawing changed.

The hostile HTML test measures growth: a fixed 2 s budget failed under
the full suite's load on the old code too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-14 11:07:25 -04:00
1 parent 83d747d87e
commit d4c614cb7f
10 files changed
+536 -221

No files matched your search

+5 -3
View File
@@ -13,6 +13,7 @@ mod stack;
pub use blocks::{AlertKind, DocumentHeading, alert, is_toc};
use html_block::html_block_text;
pub use sources::Escapes;
pub(crate) use sources::lines_at;
use stack::close;
@@ -38,7 +39,7 @@ pub struct Inline {
pub styles: Vec<(Range<usize>, Style)>,
pub links: Vec<(Range<usize>, String)>,
/// Where each piece was written: drawn start, source span.
pub sources: Vec<(usize, Range<usize>)>,
pub sources: Vec<(usize, Range<usize>, Escapes)>,
}
/// A block of a markdown document.
@@ -342,8 +343,9 @@ impl<'a> Reader<'a> {
if !matches!(node, mdast::Node::Text(_) | mdast::Node::Html(_)) {
run.shortcodes.split();
}
if let Some(written) = sources::written(node, self.source) {
run.text.sources.push((run.text.text.len(), written));
if let Some((written, escapes)) = sources::written(node, self.source) {
let at = run.text.text.len();
run.text.sources.push((at, written, escapes));
}
let text = &mut run.text;
let (children, (name, style), url) = match node {