languages: Fix Markdown list items are automatically indented erroneously (#44381)

Smit Barmase created

Closes #44223

Regressed in https://github.com/zed-industries/zed/pull/40794 in attempt
to fix https://github.com/zed-industries/zed/issues/40757. This PR
handles both cases and add more tests around it.

Bug is only in Nightly.

Release Notes:

- N/A

Change summary

crates/editor/src/editor_tests.rs         | 134 +++++++++++++++++++++---
crates/languages/src/markdown/config.toml |   2 
crates/languages/src/markdown/indents.scm |   2 
3 files changed, 115 insertions(+), 23 deletions(-)

Detailed changes

crates/editor/src/editor_tests.rs 🔗

@@ -27499,7 +27499,7 @@ async fn test_paste_url_from_other_app_creates_markdown_link_over_selected_text(
 }
 
 #[gpui::test]
-async fn test_markdown_list_indent_with_multi_cursor(cx: &mut gpui::TestAppContext) {
+async fn test_markdown_indents(cx: &mut gpui::TestAppContext) {
     init_test(cx, |_| {});
 
     let markdown_language = languages::language("markdown", tree_sitter_md::LANGUAGE.into());
@@ -27507,6 +27507,7 @@ async fn test_markdown_list_indent_with_multi_cursor(cx: &mut gpui::TestAppConte
 
     cx.update_buffer(|buffer, cx| buffer.set_language(Some(markdown_language), cx));
 
+    // Case 1: Test if adding a character with multi cursors preserves nested list indents
     cx.set_state(&indoc! {"
         - [ ] Item 1
             - [ ] Item 1.a
@@ -27515,44 +27516,137 @@ async fn test_markdown_list_indent_with_multi_cursor(cx: &mut gpui::TestAppConte
             - [ˇ] Item 2.b
         "
     });
-
     cx.update_editor(|editor, window, cx| {
-        editor.handle_input("X", window, cx);
+        editor.handle_input("x", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        - [ ] Item 1
+            - [ ] Item 1.a
+        - [xˇ] Item 2
+            - [xˇ] Item 2.a
+            - [xˇ] Item 2.b
+        "
     });
 
+    // Case 2: Test adding new line after nested list preserves indent of previous line
+    cx.set_state(&indoc! {"
+        - [ ] Item 1
+            - [ ] Item 1.a
+        - [x] Item 2
+            - [x] Item 2.a
+            - [x] Item 2.bˇ
+        "
+    });
+    cx.update_editor(|editor, window, cx| {
+        editor.newline(&Newline, window, cx);
+    });
     cx.assert_editor_state(indoc! {"
         - [ ] Item 1
             - [ ] Item 1.a
-        - [Xˇ] Item 2
-            - [Xˇ] Item 2.a
-            - [Xˇ] Item 2.b
+        - [x] Item 2
+            - [x] Item 2.a
+            - [x] Item 2.b
+            ˇ
         "
     });
-}
 
-#[gpui::test]
-async fn test_markdown_list_indent_with_newline(cx: &mut gpui::TestAppContext) {
-    init_test(cx, |_| {});
+    // Case 3: Test adding a new nested list item preserves indent
+    cx.update_editor(|editor, window, cx| {
+        editor.handle_input("-", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        - [ ] Item 1
+            - [ ] Item 1.a
+        - [x] Item 2
+            - [x] Item 2.a
+            - [x] Item 2.b
+            -ˇ
+        "
+    });
+    cx.update_editor(|editor, window, cx| {
+        editor.handle_input(" [x] Item 2.c", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        - [ ] Item 1
+            - [ ] Item 1.a
+        - [x] Item 2
+            - [x] Item 2.a
+            - [x] Item 2.b
+            - [x] Item 2.cˇ
+        "
+    });
 
-    let markdown_language = languages::language("markdown", tree_sitter_md::LANGUAGE.into());
-    let mut cx = EditorTestContext::new(cx).await;
+    // Case 4: Test adding new line after nested ordered list preserves indent of previous line
+    cx.set_state(indoc! {"
+        1. Item 1
+            1. Item 1.a
+        2. Item 2
+            1. Item 2.a
+            2. Item 2.bˇ
+        "
+    });
+    cx.update_editor(|editor, window, cx| {
+        editor.newline(&Newline, window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        1. Item 1
+            1. Item 1.a
+        2. Item 2
+            1. Item 2.a
+            2. Item 2.b
+            ˇ
+        "
+    });
 
-    cx.update_buffer(|buffer, cx| buffer.set_language(Some(markdown_language), cx));
+    // Case 5: Adding new ordered list item preserves indent
+    cx.update_editor(|editor, window, cx| {
+        editor.handle_input("3", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        1. Item 1
+            1. Item 1.a
+        2. Item 2
+            1. Item 2.a
+            2. Item 2.b
+            3ˇ
+        "
+    });
+    cx.update_editor(|editor, window, cx| {
+        editor.handle_input(".", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        1. Item 1
+            1. Item 1.a
+        2. Item 2
+            1. Item 2.a
+            2. Item 2.b
+            3.ˇ
+        "
+    });
+    cx.update_editor(|editor, window, cx| {
+        editor.handle_input(" Item 2.c", window, cx);
+    });
+    cx.assert_editor_state(indoc! {"
+        1. Item 1
+            1. Item 1.a
+        2. Item 2
+            1. Item 2.a
+            2. Item 2.b
+            3. Item 2.cˇ
+        "
+    });
 
+    // Case 7: Test blockquote newline preserves something
     cx.set_state(indoc! {"
-        - [x] list item
-          - [x] sub list itemˇ
+        > Item 1ˇ
         "
     });
-
     cx.update_editor(|editor, window, cx| {
         editor.newline(&Newline, window, cx);
     });
-
     cx.assert_editor_state(indoc! {"
-        - [x] list item
-          - [x] sub list item
-          ˇ
+        > Item 1
+        ˇ
         "
     });
 }

crates/languages/src/markdown/config.toml 🔗

@@ -24,5 +24,5 @@ rewrap_prefixes = [
 auto_indent_on_paste = false
 auto_indent_using_last_non_empty_line = false
 tab_size = 2
-decrease_indent_pattern = "^\\s*$"
+decrease_indent_pattern = "^.*$"
 prettier_parser_name = "markdown"