text_view: Fix li > strong render not in same line. (#1016)

## Before

<img width="1294" alt="image"
src="https://github.com/user-attachments/assets/0620f33a-914e-4d2a-8832-16c037351352"
/>

## After

<img width="1131" alt="image"
src="https://github.com/user-attachments/assets/a31b9b5a-6d41-4c04-a415-ff97e7cd1f31"
/>
This commit is contained in:
Jason Lee 2025-06-27 18:41:28 +08:00 committed by GitHub
parent b18a3ff7a9
commit 5b17281374
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 38 deletions

View file

@ -5,8 +5,9 @@
<p>
This is a paragraph inside a div element, have
<mention>@Mention Tag</mention>
<a href="https://google.com">Link with: <b>Bold <i>italic</i></b></a>, <strong>bold</strong>,
<em>italic</em>, and
<a href="https://google.com"
>Link with: <b>Bold <i>italic</i></b></a
>, <strong>bold</strong>, <em>italic</em>, and
<code>code</code> text.
</p>
<script>
@ -24,7 +25,10 @@
}
</style>
<p>
<img src="https://is1-ssl.mzstatic.com/image/thumb/avICmr1PbBRB-PAeplGreA/1378x774.jpg" height="400px" />
<img
src="https://is1-ssl.mzstatic.com/image/thumb/avICmr1PbBRB-PAeplGreA/1378x774.jpg"
height="400px"
/>
</p>
<div>
<p>This is second paragraph.</p>
@ -47,11 +51,11 @@
<li>
Numbered item 1
<ol>
<li>Sub item 1</li>
<li>Sub item 2</li>
<li>Sub <strong>item</strong> 1</li>
<li>Sub <foo>item</foo> 2</li>
</ol>
</li>
<li>Numbered item 2</li>
<li>Numbered <em>item</em> 2</li>
<li>Numbered item 3</li>
</ol>
Text after the Numbered List.
@ -95,15 +99,27 @@
Text after the section.
<section>
<h2>Images</h2>
<img src="https://is1-ssl.mzstatic.com/image/thumb/5tQkYfzU9bSMUol0GajO4w/1378x774.jpg" height="400px" />
<img
src="https://is1-ssl.mzstatic.com/image/thumb/5tQkYfzU9bSMUol0GajO4w/1378x774.jpg"
height="400px"
/>
<p>
(A Tesla Model X on display at the June 2024 Shanghai new energy
vehicle show. Image credit: CnEVPost)
</p>
<img src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*-Y9ozbNWSViiCmal1TT32w.jpeg" width="100%" />
<img
src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*-Y9ozbNWSViiCmal1TT32w.jpeg"
width="100%"
/>
Text before the image.
<img src="https://miro.medium.com/v2/resize:fit:1400/format:webp/0*u4La03Nh6E4zIc9-.jpeg" width="100%" />
<img
src="https://miro.medium.com/v2/resize:fit:1400/format:webp/0*u4La03Nh6E4zIc9-.jpeg"
width="100%"
/>
Text after the image.
<img src="https://miro.medium.com/v2/resize:fit:1400/format:webp/0*Q_JiltniByWLWoUv" style="width: 100%" />
<img
src="https://miro.medium.com/v2/resize:fit:1400/format:webp/0*Q_JiltniByWLWoUv"
style="width: 100%"
/>
</section>
</article>
</article>

View file

@ -2,7 +2,7 @@ use std::ops::Range;
use gpui::{
div, img, prelude::FluentBuilder as _, px, relative, rems, AnyElement, App, DefiniteLength,
ElementId, FontStyle, FontWeight, Half, HighlightStyle, InteractiveElement as _,
Div, ElementId, FontStyle, FontWeight, Half, HighlightStyle, InteractiveElement as _,
InteractiveText, IntoElement, Length, ObjectFit, ParentElement, Rems, RenderOnce, SharedString,
SharedUri, Styled, StyledImage as _, StyledText, Window,
};
@ -310,14 +310,7 @@ impl RenderOnce for Paragraph {
for text_node in children.into_iter() {
let text_len = text_node.text.len();
let part = if text.len() == 0 {
// trim start for first text
text_node.text.trim_start()
} else {
text_node.text.as_str()
};
text.push_str(part);
text.push_str(&text_node.text);
let mut node_highlights = vec![];
for (range, style) in text_node.marks {
@ -415,10 +408,33 @@ impl Node {
} => v_flex()
.when(spread, |this| this.child(div()))
.children({
let mut items = Vec::with_capacity(children.len());
for child in children.into_iter() {
let mut items: Vec<Div> = Vec::with_capacity(children.len());
for (child_ix, child) in children.iter().enumerate() {
match &child {
Node::Paragraph(_) => {
let last_not_list = child_ix > 0
&& !matches!(children[child_ix - 1], Node::List { .. });
let text = child.clone().render(
Some(ListState {
depth: state.depth + 1,
ordered: state.ordered,
todo: checked.is_some(),
}),
true,
text_view_style,
window,
cx,
);
// merge content into last item.
if last_not_list {
if let Some(item_item) = items.last_mut() {
item_item.extend(vec![text.into_any_element()]);
continue;
}
}
items.push(
h_flex()
.relative()
@ -455,23 +471,11 @@ impl Node {
}),
)
})
.child(div().flex_1().overflow_hidden().child(
child.render(
Some(ListState {
depth: state.depth + 1,
ordered: state.ordered,
todo: checked.is_some(),
}),
true,
text_view_style,
window,
cx,
),
)),
.child(text),
);
}
Node::List { .. } => {
items.push(div().ml(rems(1.)).child(child.render(
items.push(div().ml(rems(1.)).child(child.clone().render(
Some(ListState {
depth: state.depth + 1,
ordered: state.ordered,

View file

@ -417,7 +417,6 @@ fn parse_paragraph(
let (child_text, child_marks) = parse_paragraph(&mut child_paragraph, &child);
merge_child_text(&mut text, &mut marks, &child_text, &child_marks);
}
marks.push((
0..text.len(),
InlineTextStyle {
@ -530,7 +529,7 @@ fn parse_paragraph(
let (child_text, child_marks) = parse_paragraph(&mut child_paragraph, &child);
merge_child_text(&mut text, &mut marks, &child_text, &child_marks);
}
paragraph.push(element::TextNode {
paragraph.push(TextNode {
text: text.clone(),
marks: marks.clone(),
});
@ -639,6 +638,7 @@ fn parse_node(node: &Rc<Node>, paragraph: &mut Paragraph) -> element::Node {
let ordered = name.local == local_name!("ol");
let mut list_children = vec![];
for child in node.children.borrow().iter() {
let mut child_paragraph = Paragraph::default();
list_children.push(parse_node(child, &mut child_paragraph));