Improve code folding to exclude folding line breaks in whitespace-sensitive languages (#13108)

<img width="1219" alt="Screenshot 2024-06-16 at 15 43 31"
src="https://github.com/zed-industries/zed/assets/87859239/dd05de16-7f20-4c88-9e95-021555b8b78b">
<img width="1219" alt="Screenshot 2024-06-16 at 15 45 10"
src="https://github.com/zed-industries/zed/assets/87859239/b1b78cdd-f34d-4ea3-9728-4741727a9643">

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
This commit is contained in:
Nigel Jose 2024-06-21 10:03:06 +03:00 committed by GitHub
parent 3076567f6b
commit fefc91c6ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 186 additions and 2 deletions

View File

@ -983,8 +983,23 @@ impl DisplaySnapshot {
break; 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 { } else {
None None
} }

View File

@ -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] #[gpui::test]
fn test_move_cursor(cx: &mut TestAppContext) { fn test_move_cursor(cx: &mut TestAppContext) {
init_test(cx, |_| {}); init_test(cx, |_| {});