documents: an empty task ends a list; Shift-Tab takes a tab out; a table on a blank indented line is a table
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e162082f6f
commit
4fb59bb8e1
3 files changed
+61
-9
No files matched your search
@@ -50,10 +50,14 @@ pub(super) fn enter(source: &str, at: usize) -> Option<(Range<usize>, String)> {
|
||||
"" => " ",
|
||||
written => written,
|
||||
};
|
||||
let task = matches!(item, mdast::Node::ListItem(item) if item.checked.is_some());
|
||||
let body = source[start + after..span(item).end].trim_start();
|
||||
let body = match task {
|
||||
true => body.get(3..).unwrap_or_default(),
|
||||
// A bare box has no `checked`: it is still a task.
|
||||
let boxed = ["[ ]", "[x]", "[X]"]
|
||||
.iter()
|
||||
.any(|task| body.starts_with(task));
|
||||
let task = boxed || matches!(item, mdast::Node::ListItem(item) if item.checked.is_some());
|
||||
let body = match boxed {
|
||||
true => &body[3..],
|
||||
false => body,
|
||||
};
|
||||
let end = source[at..]
|
||||
@@ -101,6 +105,8 @@ pub(super) fn shift(text: &str, range: Range<usize>, deeper: bool) -> (String, R
|
||||
let spaces = line.len() - line.trim_start_matches(' ').len();
|
||||
match deeper {
|
||||
true => changes.push((at, STEP as isize)),
|
||||
// A leading tab is one step out.
|
||||
false if line.starts_with('\t') => changes.push((at, -1)),
|
||||
false if spaces > 0 => changes.push((at, -(spaces.min(STEP) as isize))),
|
||||
false => {}
|
||||
}
|
||||
|
||||
@@ -214,10 +214,16 @@ impl MarkdownDocument {
|
||||
let at = self.editor.read(cx).primary().range().start;
|
||||
let end = text[at..].find('\n').map_or(text.len(), |found| at + found);
|
||||
let start = text[..at].rfind('\n').map_or(0, |found| found + 1);
|
||||
let before = if text[start..end].trim().is_empty() {
|
||||
""
|
||||
} else {
|
||||
"\n\n"
|
||||
// A blank line gives way; a written one keeps.
|
||||
let blank = text[start..end].trim().is_empty();
|
||||
let above = text[..start.saturating_sub(1)]
|
||||
.rsplit('\n')
|
||||
.next()
|
||||
.unwrap_or_default();
|
||||
let (from, before) = match (blank, above.trim().is_empty()) {
|
||||
(true, true) => (start, ""),
|
||||
(true, false) => (start, "\n"),
|
||||
(false, _) => (end, "\n\n"),
|
||||
};
|
||||
let after = if text[end..].starts_with("\n\n") || end == text.len() {
|
||||
""
|
||||
@@ -225,10 +231,10 @@ impl MarkdownDocument {
|
||||
"\n"
|
||||
};
|
||||
let written = format!("{before}{NEW}{after}");
|
||||
let caret = end + before.len() + 2;
|
||||
let caret = from + before.len() + 2;
|
||||
log::info!("markdown document: a table goes in");
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.edit([(end..end, written)], cx);
|
||||
editor.edit([(from..end, written)], cx);
|
||||
editor.select(std::iter::once(caret..caret), cx);
|
||||
});
|
||||
Ok(())
|
||||
|
||||
@@ -201,3 +201,43 @@ fn a_newer_match_takes_the_place_of_a_waiting_one(cx: &mut TestAppContext) {
|
||||
cx.simulate_input("z");
|
||||
assert_eq!(text(&document, cx), "a b z\n");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn an_empty_task_ends_the_list(cx: &mut TestAppContext) {
|
||||
let (document, cx) = open("- [x] done", MarkdownMode::Source, cx);
|
||||
document.update(cx, |document, cx| document.set_caret(0, 10, cx));
|
||||
let editor = document.read_with(cx, |document, _| document.editor().clone());
|
||||
let focus = editor.read_with(cx, gpui::Focusable::focus_handle);
|
||||
cx.update(|window, cx| window.focus(&focus, cx));
|
||||
cx.simulate_keystrokes("enter");
|
||||
cx.run_until_parked();
|
||||
cx.simulate_keystrokes("enter");
|
||||
assert_eq!(text(&document, cx), "- [x] done\n");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn shift_tab_takes_a_tab_indent_out(cx: &mut TestAppContext) {
|
||||
let (document, cx) = open("- a\n\t- b\n", MarkdownMode::Visual, cx);
|
||||
press(0, Modifiers::none(), cx);
|
||||
cx.simulate_keystrokes("shift-tab");
|
||||
assert_eq!(opened(&document, cx), "- a\n- b");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_table_on_an_indented_blank_line_is_a_table(cx: &mut TestAppContext) {
|
||||
let (document, cx) = open(
|
||||
"
|
||||
",
|
||||
MarkdownMode::Source,
|
||||
cx,
|
||||
);
|
||||
document.update(cx, |document, cx| {
|
||||
document.set_caret(0, 4, cx);
|
||||
document.insert_table(cx).expect("inserted");
|
||||
});
|
||||
let column = document.update(cx, |document, cx| {
|
||||
document.edit_table(crate::documents::TableEdit::ColumnRight, cx)
|
||||
});
|
||||
assert_eq!(column, Ok(()), "{}", text(&document, cx));
|
||||
assert!(text(&document, cx).starts_with("| "));
|
||||
}
|
||||
Reference in new issue
Block a user