From fefc91c6ad60eda7d6e775d19962634bbb9b57de Mon Sep 17 00:00:00 2001 From: Nigel Jose Date: Fri, 21 Jun 2024 10:03:06 +0300 Subject: [PATCH] Improve code folding to exclude folding line breaks in whitespace-sensitive languages (#13108) Screenshot 2024-06-16 at 15 43 31 Screenshot 2024-06-16 at 15 45 10 Updated the foldable_range method to exclude folding line breaks during code folding in whitespace-sensitive languages like Python and YAML. This adjustment ensures that folding behaves as expected, similar to other code editors. Ref #11614 Release Notes: - Improved code folds to ignore trailing newlines --- crates/editor/src/display_map.rs | 19 +++- crates/editor/src/editor_tests.rs | 169 ++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index cee3b908aa..42f3c34b15 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -983,8 +983,23 @@ impl DisplaySnapshot { break; } } - let end = end.unwrap_or(max_point); - Some((start..end, self.fold_placeholder.clone())) + + let mut row_before_line_breaks = end.unwrap_or(max_point); + while row_before_line_breaks.row > start.row + && self + .buffer_snapshot + .is_line_blank(MultiBufferRow(row_before_line_breaks.row)) + { + row_before_line_breaks.row -= 1; + } + + row_before_line_breaks = Point::new( + row_before_line_breaks.row, + self.buffer_snapshot + .line_len(MultiBufferRow(row_before_line_breaks.row)), + ); + + Some((start..row_before_line_breaks, self.fold_placeholder.clone())) } else { None } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 105b07c8ec..ac32aaadd1 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -858,6 +858,175 @@ fn test_fold_action(cx: &mut TestAppContext) { }); } +#[gpui::test] +fn test_fold_action_whitespace_sensitive_language(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let view = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple( + &" + class Foo: + # Hello! + + def a(): + print(1) + + def b(): + print(2) + + def c(): + print(3) + " + .unindent(), + cx, + ); + build_editor(buffer.clone(), cx) + }); + + _ = view.update(cx, |view, cx| { + view.change_selections(None, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(7), 0)..DisplayPoint::new(DisplayRow(10), 0) + ]); + }); + view.fold(&Fold, cx); + assert_eq!( + view.display_text(cx), + " + class Foo: + # Hello! + + def a(): + print(1) + + def b():⋯ + + def c():⋯ + " + .unindent(), + ); + + view.fold(&Fold, cx); + assert_eq!( + view.display_text(cx), + " + class Foo:⋯ + " + .unindent(), + ); + + view.unfold_lines(&UnfoldLines, cx); + assert_eq!( + view.display_text(cx), + " + class Foo: + # Hello! + + def a(): + print(1) + + def b():⋯ + + def c():⋯ + " + .unindent(), + ); + + view.unfold_lines(&UnfoldLines, cx); + assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + }); +} + +#[gpui::test] +fn test_fold_action_multiple_line_breaks(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let view = cx.add_window(|cx| { + let buffer = MultiBuffer::build_simple( + &" + class Foo: + # Hello! + + def a(): + print(1) + + def b(): + print(2) + + + def c(): + print(3) + + + " + .unindent(), + cx, + ); + build_editor(buffer.clone(), cx) + }); + + _ = view.update(cx, |view, cx| { + view.change_selections(None, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(7), 0)..DisplayPoint::new(DisplayRow(11), 0) + ]); + }); + view.fold(&Fold, cx); + assert_eq!( + view.display_text(cx), + " + class Foo: + # Hello! + + def a(): + print(1) + + def b():⋯ + + + def c():⋯ + + + " + .unindent(), + ); + + view.fold(&Fold, cx); + assert_eq!( + view.display_text(cx), + " + class Foo:⋯ + + + " + .unindent(), + ); + + view.unfold_lines(&UnfoldLines, cx); + assert_eq!( + view.display_text(cx), + " + class Foo: + # Hello! + + def a(): + print(1) + + def b():⋯ + + + def c():⋯ + + + " + .unindent(), + ); + + view.unfold_lines(&UnfoldLines, cx); + assert_eq!(view.display_text(cx), view.buffer.read(cx).read(cx).text()); + }); +} + #[gpui::test] fn test_move_cursor(cx: &mut TestAppContext) { init_test(cx, |_| {});