Skip to content

Commit d070cff

Browse files
committed
Fix code block height with virtual list remeasure
1 parent ae792df commit d070cff

File tree

3 files changed

+523
-73
lines changed

3 files changed

+523
-73
lines changed

crates/gpui-markdown/src/render.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::future::Future;
88
use std::sync::Arc;
99

1010
use gpui::*;
11-
use gpui_component::{h_flex, scroll::ScrollableElement, v_flex, ActiveTheme};
11+
use gpui_component::{h_flex, v_flex, ActiveTheme};
1212

1313
use crate::parser::{MarkdownElement, MarkdownParser};
1414

@@ -235,6 +235,10 @@ impl RenderContext {
235235
fn code_block_cache_key(&self, index: usize) -> ElementId {
236236
ElementId::from((self.cache_key.clone(), format!("code-block-{}", index)))
237237
}
238+
239+
fn code_block_scroll_id(&self, index: usize) -> ElementId {
240+
ElementId::from((self.cache_key.clone(), format!("code-block-scroll-{}", index)))
241+
}
238242
}
239243

240244
/// Render plain code without syntax highlighting, splitting by lines to avoid extra spacing
@@ -243,9 +247,15 @@ fn render_plain_code(code: &str) -> AnyElement {
243247
let code = code.trim_end_matches('\n');
244248
let lines: Vec<AnyElement> = code
245249
.lines()
246-
.map(|line| div().child(line.to_string()).into_any_element())
250+
.map(|line| {
251+
div()
252+
.whitespace_nowrap()
253+
.flex_shrink_0()
254+
.child(line.to_string())
255+
.into_any_element()
256+
})
247257
.collect();
248-
v_flex().children(lines).into_any_element()
258+
v_flex().flex_shrink_0().children(lines).into_any_element()
249259
}
250260

251261
fn render_element(
@@ -330,7 +340,8 @@ fn render_element(
330340
.p_3()
331341
.text_sm()
332342
.font_family("monospace")
333-
.overflow_x_scrollbar()
343+
.id(context.code_block_scroll_id(code_block_index))
344+
.overflow_x_scroll()
334345
.overflow_y_hidden();
335346

336347
if let Some(lang) = lang_label {

docs/logs/2026-01-19.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# 2026-01-19 - Markdown Code Block Height + Virtual List Measurement
2+
3+
## Summary
4+
- Fixed markdown code blocks rendering with a fixed/tall height by removing the scrollbar wrapper that forced size_full.
5+
- Added periodic re-measurement for visible assistant messages containing fenced code to pick up async markdown/highlight layout changes.
6+
7+
## Context
8+
- After switching chat history to a virtual list with estimated sizes, code block heights stayed large even for 1-2 lines.
9+
- The UI showed tall, empty code blocks and inconsistent height updates during streaming/async parsing.
10+
11+
## Root Cause
12+
- `overflow_x_scrollbar()` wraps the code block in a Scrollable that uses a `size_full()` container, which forces the code block to match the parent height.
13+
- Virtual list item sizing relied on cached estimates; async markdown/highlight updates could change real height without triggering re-measurement.
14+
15+
## Changes
16+
- `crates/gpui-markdown/src/render.rs`
17+
- Use `overflow_x_scroll()` instead of `overflow_x_scrollbar()` to avoid the size_full wrapper.
18+
- `src/message_list.rs`
19+
- Track last measured time per item.
20+
- Re-measure visible assistant messages that contain fenced code blocks on a short interval to catch async layout changes.
21+
22+
## Result
23+
- Code block height now matches content length instead of a fixed tall box.
24+
- Virtual list item heights stay in sync when markdown/highlighting finishes.
25+
26+
## Follow-ups
27+
- If a visible horizontal scrollbar is required, implement a custom scrollbar layer that does not enforce size_full.
28+
- Consider tuning the re-measure interval if needed for performance.

0 commit comments

Comments
 (0)