editor: Fix Python docstring formatting in hover popovers (#59480)
# Objective Fixes #59426 Python (and possible others like JS/TS ) docstrings in hover popovers currently have broken indentation and alignment. This happens because markdown soft breaks (single newlines) are parsed and replaced with spaces by default. This collapses multi-line Python docstrings into single wraps, ruining code example layouts and line-wrapped formatting. ## Solution Configure the `MarkdownStyle` returned by `hover_markdown_style` in `crates/editor/src/hover_popover.rs` to treat soft breaks as hard breaks (`soft_break_as_hard_break: true`). This ensures single newlines in docstrings are preserved and rendered correctly in the hover popover. ## Testing - Verified hover popovers locally on Python methods/classes to confirm that multi-line docstring indentation and alignment are preserved. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed Python and Markdown docstring formatting/alignment in hover popovers. --------- Co-authored-by: Martin Ye <martin@zed.dev>
This commit is contained in:
1 parent
c4103e5ad9
commit
9d696a585c
1 file changed
+41
@@ -739,6 +739,7 @@ pub fn hover_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
|
||||
.mt(rems(1.))
|
||||
.mb_0(),
|
||||
table_columns_min_size: true,
|
||||
soft_break_as_hard_break: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -1275,6 +1276,46 @@ mod tests {
|
||||
cx.read(|cx: &App| -> u64 { EditorSettings::get_global(cx).hover_popover_delay.0 })
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_hover_markdown_preserves_soft_breaks(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let cx = cx.add_empty_window();
|
||||
let text = concat!(
|
||||
"class super(object)\n",
|
||||
"| super(type) -> unbound super object\n",
|
||||
"| super(type, obj) -> bound super object"
|
||||
);
|
||||
let markdown = cx.new(|cx| Markdown::new(text.into(), None, None, cx));
|
||||
cx.run_until_parked();
|
||||
|
||||
let rendered = MarkdownElement::rendered_text(markdown, cx, hover_markdown_style);
|
||||
|
||||
// The two soft breaks must render as real newline characters rather
|
||||
// than being collapsed into spaces.
|
||||
assert_eq!(
|
||||
rendered.matches('\n').count(),
|
||||
2,
|
||||
"expected two hard line breaks, got {rendered:?}"
|
||||
);
|
||||
let lines: Vec<&str> = rendered.split('\n').collect();
|
||||
assert_eq!(
|
||||
lines,
|
||||
[
|
||||
"class super(object)",
|
||||
"| super(type) -> unbound super object",
|
||||
"| super(type, obj) -> bound super object",
|
||||
]
|
||||
);
|
||||
// The two spaces after each `|` continuation marker are preserved verbatim.
|
||||
assert!(lines[1].starts_with("| super"));
|
||||
assert!(lines[2].starts_with("| super"));
|
||||
// No tabs are introduced anywhere in the rendered output.
|
||||
assert!(!rendered.contains('\t'));
|
||||
// And the full rendering matches the source exactly.
|
||||
assert_eq!(rendered, text);
|
||||
}
|
||||
|
||||
impl InfoPopover {
|
||||
fn get_rendered_text(&self, cx: &gpui::App) -> String {
|
||||
let mut rendered_text = String::new();
|
||||
|
||||
Reference in new issue
Block a user