diff --git a/src/markdown/mermaid/flowchart/layout/mod.rs b/src/markdown/mermaid/flowchart/layout/mod.rs index f554f47..ad8cae7 100644 --- a/src/markdown/mermaid/flowchart/layout/mod.rs +++ b/src/markdown/mermaid/flowchart/layout/mod.rs @@ -23,6 +23,11 @@ use config::FlowLayoutConfig; use graph::FlowGraph; use sugiyama::SugiyamaLayout; +fn stable_min_width_for_title(title: &str, font_size: f32, text_measurer: &impl TextMeasurer) -> f32 { + let title_text_size = text_measurer.measure(title, font_size); + (title_text_size.width + 24.0).ceil() +} + /// Compute layout for a flowchart using a Sugiyama-style layered graph algorithm. /// /// The `text_measurer` parameter enables accurate text sizing. Use `EguiTextMeasurer` @@ -118,8 +123,8 @@ fn compute_subgraph_layouts( // Ensure subgraph width accommodates the title text if let Some(title) = &subgraph.title { - let title_text_size = text_measurer.measure(title, font_size); - let min_width_for_title = title_text_size.width + 24.0; + let min_width_for_title = + stable_min_width_for_title(title, font_size, text_measurer); if existing.size.x < min_width_for_title { existing.size.x = min_width_for_title; } @@ -183,8 +188,8 @@ fn compute_subgraph_layouts( // Ensure subgraph width accommodates the title text if let Some(title) = &subgraph.title { - let title_text_size = text_measurer.measure(title, font_size); - let min_width_for_title = title_text_size.width + 24.0; + let min_width_for_title = + stable_min_width_for_title(title, font_size, text_measurer); let current_width = padded_max.x - padded_min.x; if current_width < min_width_for_title { padded_max.x = padded_min.x + min_width_for_title; diff --git a/src/markdown/video_embed.rs b/src/markdown/video_embed.rs index 24cd46e..2c95821 100644 --- a/src/markdown/video_embed.rs +++ b/src/markdown/video_embed.rs @@ -144,18 +144,17 @@ pub fn try_parse_video_paragraph(node: &MarkdownNode) -> Option } fn extract_bare_youtube_url(node: &MarkdownNode) -> Option { - let significant: Vec<_> = node + let meaningful_children: Vec<&MarkdownNode> = node .children .iter() - .filter(|child| match &child.node_type { - MarkdownNodeType::Text(text) => !text.is_empty(), - _ => true, + .filter(|child| { + !matches!(&child.node_type, MarkdownNodeType::Text(text) if text.trim().is_empty()) }) .collect(); - match significant.len() { + match meaningful_children.len() { 0 => None, - 1 => match &significant[0].node_type { + 1 => match &meaningful_children[0].node_type { MarkdownNodeType::Text(text) => { let trimmed = text.trim(); if trimmed.is_empty() || trimmed.contains('\n') { @@ -168,10 +167,9 @@ fn extract_bare_youtube_url(node: &MarkdownNode) -> Option { _ => None, }, _ => { - if node - .children + if meaningful_children .iter() - .any(|child| !matches!(child.node_type, MarkdownNodeType::Text(_))) + .any(|child| !matches!(&child.node_type, MarkdownNodeType::Text(_))) { return None; }