documents: block commands as Typora's Paragraph menu

MarkdownDocument::block runs a BlockCommand at the caret: heading
levels, paragraph, promote and demote; quote and list toggles;
rule, code, math, toc, footnote, link definition and front matter
inserts; empty paragraphs before and after; delete. Formats and
block commands share one runner off the UI thread; FormatRefusal
is now EditRefusal.

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 13:44:42 -04:00
1 parent 1d0354592b
commit 58e212d4ec
15 files changed
+1849 -188

No files matched your search

+3 -3
View File
@@ -4,7 +4,7 @@ use std::ops::Range;
use markdown::mdast::Node;
use super::{Change, FormatRefusal, after, block, cut, holder, marks, room};
use super::{Change, EditRefusal, after, block, cut, holder, marks, room};
use crate::documents::{markdown::span, tree::inside};
/// The backslashes of escapes in a text node's span.
@@ -46,14 +46,14 @@ pub(super) fn clear(
text: &str,
nodes: &[&Node],
selection: Range<usize>,
) -> Result<Change, FormatRefusal> {
) -> Result<Change, EditRefusal> {
let mut blocks: Vec<Range<usize>> = (nodes.iter())
.filter(|node| block(node))
.map(|node| room(node, text))
.filter(|range| range.start <= selection.end && selection.start <= range.end)
.collect();
if blocks.is_empty() {
return Err(FormatRefusal::Outside);
return Err(EditRefusal::Outside);
}
blocks.sort_by_key(|block| block.start);
let mut autolinks: Vec<Range<usize>> = (nodes.iter())