T21a round 1 fixes

- Enter over a selection drops it and splits at its start, one undo step
- undo and redo keep where the caret was and put it back
- a format unwraps only its own markers, so italic inside bold keeps the bold
- keys into a merged table cell land on the cell that shows
- undo rebuilds a block whose kind needs other fields, so styling comes back
- tests activate their window, as focus events need
- undo bookkeeping moves to blocks/edit.rs
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 03:49:27 -04:00
1 parent 6a9ce8a2c3
commit f3e2c6c27f
10 files changed
+330 -81

No files matched your search

+12 -7
View File
@@ -37,6 +37,16 @@ fn leading(text: &str, ch: char) -> usize {
.sum()
}
/// How many bytes at each end of `span` write `mark`: its asterisks, tildes or backticks.
pub(crate) fn edge(span: &str, mark: Mark) -> usize {
let first = span.chars().next().expect("a styled span has its marker");
let run = leading(span, first).min(span.len() / 2);
match mark {
Mark::Emphasis => run.min(first.len_utf8()),
_ => run,
}
}
/// The marks over `text`'s bytes: styles, code, links, headings and quotes, and the syntax that writes each.
pub fn marks(text: &str) -> Vec<(Range<usize>, Mark)> {
let mut out = Vec::new();
@@ -50,18 +60,13 @@ pub fn marks(text: &str) -> Vec<(Range<usize>, Mark)> {
Event::Start(Tag::Emphasis) => Mark::Emphasis,
_ => Mark::Strike,
};
let first = span.chars().next().expect("a styled span has its marker");
let edge = leading(span, first).min(span.len() / 2);
let edge = match mark {
Mark::Emphasis => edge.min(first.len_utf8()),
_ => edge,
};
let edge = edge(span, mark);
out.push((range.clone(), mark));
out.push((range.start..range.start + edge, Mark::Syntax));
out.push((range.end - edge..range.end, Mark::Syntax));
}
Event::Code(_) => {
let ticks = leading(span, '`');
let ticks = edge(span, Mark::Code);
out.push((range.clone(), Mark::Code));
out.push((range.start..range.start + ticks, Mark::Syntax));
out.push((range.end - ticks..range.end, Mark::Syntax));