editor: Fix bracket colorization with folds and large functions (#51108)
Closes #47846 `visible_excerpts` computed the visible buffer range by adding display line count directly to the buffer start row: ```rust // Before multi_buffer_visible_start + Point::new(visible_line_count, 0) ``` This ignores folds entirely. When a 700-line function is folded into one display line, content after the fold is visible on screen but falls outside the computed buffer range, so its brackets are never colorized. The fix converts through display coordinates so the fold/wrap layers are respected: ```rust // After let display_end = DisplayPoint::new(display_start.row + visible_line_count, 0); let multi_buffer_visible_end = display_end.to_point(&display_snapshot); ``` ### Results **Before Fix** <img width="852" height="778" alt="스크린샷 2026-03-10 오후 8 29 10" src="https://github.com/user-attachments/assets/a0d2d81f-a8b2-4cf4-b1f3-cf5f8288a696" /> **After Fix** <img width="1031" height="794" alt="스크린샷 2026-03-10 오후 8 32 27" src="https://github.com/user-attachments/assets/2b0496b1-8302-4248-b73a-c31f5d0b0c4b" /> Before you mark this PR as ready for review, make sure that you have: - [X] Added a solid test coverage and/or screenshots from doing manual testing - [ ] Done a self-review taking into account security and performance aspects - [ ] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - Fixed bracket colorization not working for content after folded regions and for functions with large bodies. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
1 parent
7611c0e4df
commit
addd79958a
2 files changed
+67
-11
No files matched your search
@@ -1455,6 +1455,60 @@ mod foo «1{
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
// reproduction of #47846
|
||||
async fn test_bracket_colorization_with_folds(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |language_settings| {
|
||||
language_settings.defaults.colorize_brackets = Some(true);
|
||||
});
|
||||
let mut cx = EditorLspTestContext::new(
|
||||
Arc::into_inner(rust_lang()).unwrap(),
|
||||
lsp::ServerCapabilities::default(),
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Generate a large function body. When folded, this collapses
|
||||
// to a single display line, making small_function visible on screen.
|
||||
let mut big_body = String::new();
|
||||
for i in 0..700 {
|
||||
big_body.push_str(&format!(" let var_{i:04} = ({i});\n"));
|
||||
}
|
||||
let source = format!(
|
||||
"ˇfn big_function() {{\n{big_body}}}\n\nfn small_function() {{\n let x = (1, (2, 3));\n}}\n"
|
||||
);
|
||||
|
||||
cx.set_state(&source);
|
||||
cx.executor().advance_clock(Duration::from_millis(100));
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.fold_ranges(
|
||||
vec![Point::new(0, 0)..Point::new(701, 1)],
|
||||
false,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
cx.executor().advance_clock(Duration::from_millis(100));
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
assert_eq!(
|
||||
indoc! {r#"
|
||||
⋯1»
|
||||
|
||||
fn small_function«1()1» «1{
|
||||
let x = «2(1, «3(2, 3)3»)2»;
|
||||
}1»
|
||||
|
||||
1 hsla(207.80, 16.20%, 69.19%, 1.00)
|
||||
2 hsla(29.00, 54.00%, 65.88%, 1.00)
|
||||
3 hsla(286.00, 51.00%, 75.25%, 1.00)
|
||||
"#,},
|
||||
bracket_colors_markup(&mut cx),
|
||||
);
|
||||
}
|
||||
|
||||
fn separate_with_comment_lines(head: &str, tail: &str, comment_lines: usize) -> String {
|
||||
let mut result = head.to_string();
|
||||
result.push_str("\n");
|
||||
|
||||
+13
-11
@@ -2621,16 +2621,7 @@ impl Editor {
|
||||
.await;
|
||||
editor
|
||||
.update_in(cx, |editor, window, cx| {
|
||||
editor.register_visible_buffers(cx);
|
||||
editor.colorize_brackets(false, cx);
|
||||
editor.refresh_inlay_hints(
|
||||
InlayHintRefreshReason::NewLinesShown,
|
||||
cx,
|
||||
);
|
||||
if !editor.buffer().read(cx).is_singleton() {
|
||||
editor.update_lsp_data(None, window, cx);
|
||||
editor.refresh_runnables(window, cx);
|
||||
}
|
||||
editor.update_data_on_scroll(window, cx)
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
@@ -20055,7 +20046,7 @@ impl Editor {
|
||||
&mut self,
|
||||
creases: Vec<Crease<T>>,
|
||||
auto_scroll: bool,
|
||||
_window: &mut Window,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if creases.is_empty() {
|
||||
@@ -20071,6 +20062,7 @@ impl Editor {
|
||||
cx.notify();
|
||||
|
||||
self.scrollbar_marker_state.dirty = true;
|
||||
self.update_data_on_scroll(window, cx);
|
||||
self.folds_did_change(cx);
|
||||
}
|
||||
|
||||
@@ -25367,6 +25359,16 @@ impl Editor {
|
||||
fn disable_runnables(&mut self) {
|
||||
self.enable_runnables = false;
|
||||
}
|
||||
|
||||
fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
|
||||
self.register_visible_buffers(cx);
|
||||
self.colorize_brackets(false, cx);
|
||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
if !self.buffer().read(cx).is_singleton() {
|
||||
self.update_lsp_data(None, window, cx);
|
||||
self.refresh_runnables(window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_for_markdown_paste<'a>(
|
||||
|
||||
Reference in new issue
Block a user