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:
1 parent
83d747d87e
commit
d4c614cb7f
10 files changed
+536
-221
No files matched your search
@@ -3,11 +3,10 @@ use std::rc::Rc;
|
||||
use gpui::{Context, MouseButton, Window};
|
||||
use markdown::mdast;
|
||||
|
||||
use super::{DocumentEvent, MarkdownDocument, edit::Landing, edit::moved};
|
||||
use super::{DocumentEvent, MarkdownDocument, edit::Landing, edit::moved, parse::Block};
|
||||
use crate::documents::{
|
||||
render::{OnPoint, Place, Pointed},
|
||||
tree::lines_at,
|
||||
tree::{alert, is_toc},
|
||||
tree::{Node, alert, is_toc, lines_at},
|
||||
};
|
||||
|
||||
/// A top-level block's kind.
|
||||
@@ -36,7 +35,7 @@ impl TargetBlock {
|
||||
mdast::Node::Paragraph(_) if is_toc(node, source) => Self::Toc,
|
||||
mdast::Node::Paragraph(_) => Self::Paragraph,
|
||||
mdast::Node::Heading(heading) => Self::Heading(heading.depth),
|
||||
mdast::Node::Blockquote(quote) if alert(quote, source).is_some() => Self::Alert,
|
||||
mdast::Node::Blockquote(quote) if alert(quote).is_some() => Self::Alert,
|
||||
mdast::Node::Blockquote(_) => Self::Quote,
|
||||
mdast::Node::List(_) => Self::List,
|
||||
mdast::Node::Code(_) => Self::Code,
|
||||
@@ -95,6 +94,12 @@ impl MarkdownDocument {
|
||||
})
|
||||
}
|
||||
|
||||
/// A block's kind, text and what it draws.
|
||||
fn drawn(&self, block: &Block) -> (TargetBlock, String, Option<Vec<Node>>) {
|
||||
let text = self.parsed.text[block.range.clone()].to_string();
|
||||
(block.kind, text, block.nodes.clone())
|
||||
}
|
||||
|
||||
/// Caret to `at`, else block `ix`; the owner hears.
|
||||
pub(super) fn point(
|
||||
&mut self,
|
||||
@@ -109,7 +114,7 @@ impl MarkdownDocument {
|
||||
block => block.flatten(),
|
||||
};
|
||||
let kind = block.map(|block| block.kind);
|
||||
let pressed = block.map(|block| self.parsed.text[block.range.clone()].to_string());
|
||||
let pressed = block.map(|block| self.drawn(block));
|
||||
let at = at.or(block.map(|block| block.range.start));
|
||||
let written = self.commit(cx);
|
||||
if written.is_some() {
|
||||
@@ -128,7 +133,7 @@ impl MarkdownDocument {
|
||||
// A write-back may change the pressed block.
|
||||
let now = (self.parsed.blocks.iter())
|
||||
.find(|block| block.range.start <= at && at <= block.range.end)
|
||||
.map(|block| self.parsed.text[block.range.clone()].to_string());
|
||||
.map(|block| self.drawn(block));
|
||||
if written.is_some() && pressed.is_some() && now != pressed {
|
||||
return log::warn!("markdown document: the write-back changed the pressed block");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user