documents: Shift-Tab takes four columns out of any mix of spaces and tabs
This commit is contained in:
2 files changed
+32
-5
No files matched your search
@@ -91,6 +91,22 @@ fn ordered(rest: &str) -> Option<(String, usize)> {
|
|||||||
Some((format!("{}{close}", number + 1), digits + 1))
|
Some((format!("{}{close}", number + 1), digits + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Leading bytes that make one step, tabs to stops of four.
|
||||||
|
fn outdent(line: &str) -> usize {
|
||||||
|
let mut columns = 0;
|
||||||
|
for (bytes, ch) in line.char_indices() {
|
||||||
|
if columns >= STEP {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
columns = match ch {
|
||||||
|
' ' => columns + 1,
|
||||||
|
'\t' => (columns / STEP + 1) * STEP,
|
||||||
|
_ => return bytes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
line.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Lines `range` touches, a step in or out.
|
/// Lines `range` touches, a step in or out.
|
||||||
pub(super) fn shift(text: &str, range: Range<usize>, deeper: bool) -> (String, Range<usize>) {
|
pub(super) fn shift(text: &str, range: Range<usize>, deeper: bool) -> (String, Range<usize>) {
|
||||||
let first = text[..range.start].rfind('\n').map_or(0, |at| at + 1);
|
let first = text[..range.start].rfind('\n').map_or(0, |at| at + 1);
|
||||||
@@ -102,13 +118,12 @@ pub(super) fn shift(text: &str, range: Range<usize>, deeper: bool) -> (String, R
|
|||||||
let mut at = first;
|
let mut at = first;
|
||||||
loop {
|
loop {
|
||||||
let line = &text[at..text[at..].find('\n').map_or(text.len(), |end| at + end)];
|
let line = &text[at..text[at..].find('\n').map_or(text.len(), |end| at + end)];
|
||||||
let spaces = line.len() - line.trim_start_matches(' ').len();
|
|
||||||
match deeper {
|
match deeper {
|
||||||
true => changes.push((at, STEP as isize)),
|
true => changes.push((at, STEP as isize)),
|
||||||
// A leading tab is one step out.
|
false => match outdent(line) {
|
||||||
false if line.starts_with('\t') => changes.push((at, -1)),
|
0 => {}
|
||||||
false if spaces > 0 => changes.push((at, -(spaces.min(STEP) as isize))),
|
bytes => changes.push((at, -(bytes as isize))),
|
||||||
false => {}
|
},
|
||||||
}
|
}
|
||||||
match text[at..].find('\n') {
|
match text[at..].find('\n') {
|
||||||
Some(end) if at + end < last => at += end + 1,
|
Some(end) if at + end < last => at += end + 1,
|
||||||
@@ -276,5 +291,9 @@ mod tests {
|
|||||||
assert_eq!(shift("a\nb", 1..3, true), (" a\n b".into(), 5..11));
|
assert_eq!(shift("a\nb", 1..3, true), (" a\n b".into(), 5..11));
|
||||||
assert_eq!(shift(" a", 7..7, false), (" a".into(), 3..3));
|
assert_eq!(shift(" a", 7..7, false), (" a".into(), 3..3));
|
||||||
assert_eq!(shift(" a\nb", 1..1, false), ("a\nb".into(), 0..0));
|
assert_eq!(shift(" a\nb", 1..1, false), ("a\nb".into(), 0..0));
|
||||||
|
// Spaces and tabs mixed: four columns go.
|
||||||
|
assert_eq!(shift(" \t- b", 6..6, false), ("- b".into(), 3..3));
|
||||||
|
assert_eq!(shift("\t - b", 6..6, false), (" - b".into(), 5..5));
|
||||||
|
assert_eq!(shift(" \t\t- b", 6..6, false), ("\t- b".into(), 4..4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,6 +223,14 @@ fn shift_tab_takes_a_tab_indent_out(cx: &mut TestAppContext) {
|
|||||||
assert_eq!(opened(&document, cx), "- a\n- b");
|
assert_eq!(opened(&document, cx), "- a\n- b");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn shift_tab_takes_spaces_then_a_tab_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]
|
#[gpui::test]
|
||||||
fn a_table_on_an_indented_blank_line_is_a_table(cx: &mut TestAppContext) {
|
fn a_table_on_an_indented_blank_line_is_a_table(cx: &mut TestAppContext) {
|
||||||
let (document, cx) = open(
|
let (document, cx) = open(
|
||||||
|
|||||||
Reference in new issue
Block a user