documents: a press opens its block on the pressed character; a secondary press points

Each drawn text piece keeps its written span, so a press maps back to a
source byte. A secondary press opens nothing: it moves the caret there and
emits DocumentEvent::Pointed with the block's kind, link, picture and
whether it lies in a table or code. Block nodes count from their own start.

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 09:38:08 -04:00
1 parent 12512217bd
commit 5af11fe489
17 files changed
+813 -82

No files matched your search

+18 -4
View File
@@ -7,6 +7,7 @@ use super::markdown::{span, tree, walk};
mod blocks;
mod emoji;
mod html;
mod sources;
use blocks::html_block_text;
pub use blocks::{AlertKind, DocumentHeading, alert, is_toc};
@@ -33,6 +34,8 @@ pub struct Inline {
pub text: String,
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>)>,
}
/// A block of a markdown document.
@@ -44,6 +47,8 @@ pub enum Node {
Code {
language: Option<String>,
text: String,
/// Where `text` starts in the source, if written as drawn.
from: Option<usize>,
},
/// Items and blocks; ordered from `start`; tasks carry checkboxes.
List {
@@ -63,6 +68,8 @@ pub enum Node {
alt: String,
url: String,
link: Option<String>,
/// Its source start.
at: usize,
},
Footnote {
label: String,
@@ -315,6 +322,7 @@ impl<'a> Reader<'a> {
mdast::Node::Code(code) => out.push(Node::Code {
language: code.lang.clone(),
text: code.value.clone(),
from: sources::code_from(self.source, node, &code.value),
}),
mdast::Node::Math(math) => out.push(Node::Math(math.value.clone())),
mdast::Node::List(list) => {
@@ -386,7 +394,10 @@ impl<'a> Reader<'a> {
pub fn label(&self, note: &mdast::FootnoteDefinition) -> String {
match self.note(&note.identifier) {
Some(number) => number.to_string(),
None => note.label.clone().unwrap_or_else(|| note.identifier.clone()),
None => note
.label
.clone()
.unwrap_or_else(|| note.identifier.clone()),
}
}
@@ -404,6 +415,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));
}
let text = &mut run.text;
let (children, (name, style), url) = match node {
mdast::Node::Text(words) => return run.push_text(&words.value),
@@ -422,14 +436,14 @@ impl<'a> Reader<'a> {
}
_ => unreachable!("matched as an image"),
};
let link = run.link();
let (link, at) = (run.link(), span(node).start);
return match images {
Images::Alt => run.text.text.push_str(&alt),
Images::Split(out) => {
text_block(run.cut(), out);
out.push(Node::Image { alt, url, link })
out.push(Node::Image { alt, url, link, at })
}
Images::After(out) => out.push(Node::Image { alt, url, link }),
Images::After(out) => out.push(Node::Image { alt, url, link, at }),
};
}
mdast::Node::Html(written) => return run.html(&written.value),