From 4c28d2c2e26e64cb9b4131a39e23e0265c7263f7 Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Sat, 24 May 2025 22:55:15 +0200 Subject: [PATCH] language: Improve auto-indentation when using round brackets in Python (#31260) Follow-up to #29625 and #30902 This PR reintroduces auto-intents for brackets in Python and fixes some cases where an indentation would be triggered if it should not. For example, upon typing ```python a = [] ``` and inserting a newline after, the next line would be indented although it shoud not be. Bracket auto-indentation was tested prior to #29625 but removed there and the test updated accordingly. #30902 reintroduced this for all brackets but `()`. I reintroduced this here, reverted the changes to the test so that indents also happen after typing `()`. This is frequently used for tuples and multiline statements in Python. Release Notes: - Improved auto-indentation when using round brackets in Python. --- crates/editor/src/editor_tests.rs | 28 ++++++++++++++++++++++++- crates/language/src/buffer.rs | 2 +- crates/languages/src/python.rs | 4 ++-- crates/languages/src/python/indents.scm | 1 + 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index a0368858f1..a3508b247a 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -20860,7 +20860,7 @@ async fn test_indent_on_newline_for_python(cx: &mut TestAppContext) { ˇ "}); - // test correct indent after newline in curly brackets + // test correct indent after newline in brackets cx.set_state(indoc! {" {ˇ} "}); @@ -20873,6 +20873,32 @@ async fn test_indent_on_newline_for_python(cx: &mut TestAppContext) { ˇ } "}); + + cx.set_state(indoc! {" + (ˇ) + "}); + cx.update_editor(|editor, window, cx| { + editor.newline(&Newline, window, cx); + }); + cx.run_until_parked(); + cx.assert_editor_state(indoc! {" + ( + ˇ + ) + "}); + + // do not indent after empty lists or dictionaries + cx.set_state(indoc! {" + a = []ˇ + "}); + cx.update_editor(|editor, window, cx| { + editor.newline(&Newline, window, cx); + }); + cx.run_until_parked(); + cx.assert_editor_state(indoc! {" + a = [] + ˇ + "}); } fn empty_range(row: usize, column: usize) -> Range { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 140b9f62b2..38a1034d0f 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2901,7 +2901,7 @@ impl BufferSnapshot { end }; if let Some((start, end)) = start.zip(end) { - if start.row == end.row && !significant_indentation { + if start.row == end.row && (!significant_indentation || start.column < end.column) { continue; } let range = start..end; diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index da7ab9cb6e..e68c43d805 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -1236,12 +1236,12 @@ mod tests { "def a():\n \n if a:\n b()\n else:\n " ); - // indent after an open paren. the closing paren is not indented + // indent after an open paren. the closing paren is not indented // because there is another token before it on the same line. append(&mut buffer, "foo(\n1)", cx); assert_eq!( buffer.text(), - "def a():\n \n if a:\n b()\n else:\n foo(\n 1)" + "def a():\n \n if a:\n b()\n else:\n foo(\n 1)" ); // dedent the closing paren if it is shifted to the beginning of the line diff --git a/crates/languages/src/python/indents.scm b/crates/languages/src/python/indents.scm index 34557f3b2a..f306d81435 100644 --- a/crates/languages/src/python/indents.scm +++ b/crates/languages/src/python/indents.scm @@ -1,3 +1,4 @@ +(_ "(" ")" @end) @indent (_ "[" "]" @end) @indent (_ "{" "}" @end) @indent