improved markdown support

- handle headings, bold and italic texts properly
This commit is contained in:
Dmitry Stepanov
2026-10-04 12:23:36 +03:00
parent 6c7962595c
commit cc6c564877
+43 -19
View File
@@ -25,14 +25,14 @@ use crate::{
formatted_text::WrapMode,
grid::{Column, GridBuilder, Row},
stack_panel::StackPanelBuilder,
style::{resource::StyleResourceExt, Style},
style::{resource::StyleResourceExt, Style, StyledProperty},
text::{TextBuilder, TextMessage},
vector_image::{Primitive, VectorImageBuilder},
widget::{WidgetBuilder, WidgetMessage},
BuildContext, Thickness, UiNode, UserInterface, VerticalAlignment,
};
fn heading_depth_to_font_size(heading_depth: u8) -> f32 {
fn heading_depth_to_font_size(heading_depth: u8) -> StyledProperty<f32> {
match heading_depth {
1 => 24.0,
2 => 22.0,
@@ -41,6 +41,7 @@ fn heading_depth_to_font_size(heading_depth: u8) -> f32 {
5 => 16.0,
_ => 14.0,
}
.into()
}
fn make_text_with_border(
@@ -55,7 +56,7 @@ fn make_text_with_border(
.with_background(ctx.style.property(Style::BRUSH_DARK))
.with_child(
TextBuilder::new(WidgetBuilder::new())
.with_font_size(heading_depth_to_font_size(heading_depth).into())
.with_font_size(heading_depth_to_font_size(heading_depth))
.with_text(text)
.with_wrap(wrap_mode)
.build(ctx),
@@ -69,6 +70,7 @@ fn make_text_with_border(
fn make_list_item(widget_builder: WidgetBuilder, ctx: &mut BuildContext) -> Handle<UiNode> {
let bullet = VectorImageBuilder::new(
WidgetBuilder::new()
.with_vertical_alignment(VerticalAlignment::Top)
.on_row(0)
.on_column(0)
.with_width(16.0)
@@ -104,20 +106,46 @@ pub fn markdown_to_visual_tree(ui: &mut UserInterface, text: impl AsRef<str>) ->
let prev_heading_depth = *heading_depth;
match ast_node {
Node::Paragraph(_) | Node::Link(_) => {
Node::Paragraph(_)
| Node::Link(_)
| Node::Heading(_)
| Node::Strong(_)
| Node::Emphasis(_) => {
let mut widget_builder = WidgetBuilder::new();
let is_link = matches!(ast_node, Node::Link(_));
if is_link {
// TODO: Add navigation for links.
widget_builder =
widget_builder.with_foreground(Brush::Solid(Color::DEEP_SKY_BLUE).into());
} else {
widget_builder = widget_builder.with_margin(Thickness::top(16.0));
let default_font_resource = ui.default_font.clone();
let mut font = default_font_resource.clone();
let default_font = default_font_resource.data_ref();
match ast_node {
Node::Heading(heading) => {
*heading_depth = heading.depth;
widget_builder = widget_builder.with_margin(Thickness::top_bottom(8.0));
}
Node::Link(_) => {
// TODO: Add navigation for links.
widget_builder = widget_builder
.with_foreground(Brush::Solid(Color::DEEP_SKY_BLUE).into());
}
Node::Strong(_) => {
font = default_font
.bold
.clone()
.unwrap_or_else(|| default_font_resource.clone());
}
Node::Emphasis(_) => {
font = default_font
.italic
.clone()
.unwrap_or_else(|| default_font_resource.clone());
}
_ => {}
}
drop(default_font);
let paragraph_text = TextBuilder::new(widget_builder)
.with_font_size(heading_depth_to_font_size(*heading_depth).into())
.with_font_size(heading_depth_to_font_size(*heading_depth))
.with_font(font)
.with_wrap(WrapMode::Word)
.with_baseline_alignment(VerticalAlignment::Center)
.build(&mut ui.build_ctx())
@@ -145,15 +173,13 @@ pub fn markdown_to_visual_tree(ui: &mut UserInterface, text: impl AsRef<str>) ->
}
}
*heading_depth = prev_heading_depth;
ui.send(paragraph_text, TextMessage::Text(full_text));
paragraph_text
}
ast_node => {
if let Node::Heading(heading) = ast_node {
*heading_depth = heading.depth;
}
let mut widget_builder = WidgetBuilder::new();
if let Some(children) = ast_node.children() {
@@ -164,8 +190,6 @@ pub fn markdown_to_visual_tree(ui: &mut UserInterface, text: impl AsRef<str>) ->
}
}
*heading_depth = prev_heading_depth;
let ctx = &mut ui.build_ctx();
match ast_node {
@@ -197,7 +221,7 @@ pub fn markdown_to_visual_tree(ui: &mut UserInterface, text: impl AsRef<str>) ->
let text = text.as_ref();
match dbg!(to_mdast(text, &Default::default())) {
match to_mdast(text, &Default::default()) {
Ok(root) => {
let mut heading_depth = 0;
return traverse_ast_recursively(&root, &mut heading_depth, ui);