Skip to content

Commit 960bcdc

Browse files
fix: refine mermaid rendering — restore image placeholders, use picker font size, improve UX
Restore IMAGE_PLACEHOLDER_LINES (16) and PARAGRAPH_IMAGE_PLACEHOLDER_LINES (13) to their original values since mermaid has its own MERMAID_PLACEHOLDER_LINES (22). Use picker font dimensions instead of hardcoded 8px multiplier for mermaid pixel width calculation. Truncate long mermaid error messages to fit display width. Add hint when mermaid feature is disabled. Note mermaid-rs-renderer pre-1.0 maturity.
1 parent 2b07a4e commit 960bcdc

4 files changed

Lines changed: 34 additions & 17 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ opensesame = { version = "0.1.1", features = ["serde"] }
9292
libc = "0.2"
9393

9494
# Mermaid diagram rendering (pure Rust, no external tools)
95+
# NOTE: pre-1.0 crate in early development; semver pins to >=0.2.0, <0.3.0
9596
mermaid-rs-renderer = { version = "0.2", default-features = false, optional = true }
9697
resvg = { version = "0.44", optional = true }
9798

src/tui/app.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ pub struct App {
437437
#[cfg(feature = "mermaid")]
438438
pub mermaid_render_errors: HashMap<u64, String>,
439439
#[cfg(feature = "mermaid")]
440-
pub mermaid_last_width: u16,
440+
pub mermaid_last_render_width: u32,
441441

442442
// LaTeX detection state
443443
pub latex_detected: bool,
@@ -659,7 +659,7 @@ impl App {
659659
#[cfg(feature = "mermaid")]
660660
mermaid_render_errors: HashMap::new(),
661661
#[cfg(feature = "mermaid")]
662-
mermaid_last_width: 0,
662+
mermaid_last_render_width: 0,
663663

664664
// LaTeX detection
665665
latex_detected: false,
@@ -804,11 +804,18 @@ impl App {
804804
source.hash(&mut hasher);
805805
let hash = hasher.finish();
806806

807-
// Clear caches on width change (re-rasterize at new size)
808-
if width != self.mermaid_last_width {
807+
// Use picker's actual font width for accurate pixel calculation
808+
let font_width = self.picker.as_ref().map_or(8u16, |p| {
809+
let (w, _) = p.font_size();
810+
if w < 1 { 8 } else { w }
811+
});
812+
let target_px = (width as u32) * (font_width as u32);
813+
814+
// Clear caches on render width change (re-rasterize at new size)
815+
if target_px != self.mermaid_last_render_width {
809816
self.mermaid_protocol_cache.clear();
810817
self.mermaid_render_errors.clear();
811-
self.mermaid_last_width = width;
818+
self.mermaid_last_render_width = target_px;
812819
}
813820

814821
// Already cached (success or failure)
@@ -818,9 +825,6 @@ impl App {
818825
if self.mermaid_render_errors.contains_key(&hash) {
819826
return false;
820827
}
821-
822-
// Render: target pixel width ≈ terminal columns × ~8px per cell
823-
let target_px = (width as u32) * 8;
824828
match crate::tui::mermaid::render_mermaid_to_image(source, target_px) {
825829
Ok(img) => {
826830
if let Some(picker) = self.picker.as_mut() {

src/tui/interactive.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ pub const IMAGE_OFFSET: usize = 7000;
3131

3232
/// Placeholder lines reserved for block-level images in rendered output.
3333
/// 1 label line + IMAGE_PLACEHOLDER_LINES blank lines = BLOCK_IMAGE_TOTAL_LINES.
34-
pub const IMAGE_PLACEHOLDER_LINES: usize = 22;
35-
pub const BLOCK_IMAGE_TOTAL_LINES: usize = 1 + IMAGE_PLACEHOLDER_LINES; // 23
34+
pub const IMAGE_PLACEHOLDER_LINES: usize = 16;
35+
pub const BLOCK_IMAGE_TOTAL_LINES: usize = 1 + IMAGE_PLACEHOLDER_LINES; // 17
3636

3737
/// Placeholder lines reserved for paragraphs containing inline images.
3838
/// 1 text line + PARAGRAPH_IMAGE_PLACEHOLDER_LINES blank lines = PARAGRAPH_WITH_IMAGE_TOTAL_LINES.
39-
pub const PARAGRAPH_IMAGE_PLACEHOLDER_LINES: usize = 22;
40-
pub const PARAGRAPH_WITH_IMAGE_TOTAL_LINES: usize = 1 + PARAGRAPH_IMAGE_PLACEHOLDER_LINES; // 23
39+
pub const PARAGRAPH_IMAGE_PLACEHOLDER_LINES: usize = 13;
40+
pub const PARAGRAPH_WITH_IMAGE_TOTAL_LINES: usize = 1 + PARAGRAPH_IMAGE_PLACEHOLDER_LINES; // 14
4141

4242
/// Placeholder lines reserved for mermaid diagram rendering.
4343
pub const MERMAID_PLACEHOLDER_LINES: usize = 22;

src/tui/ui/mod.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,10 +733,17 @@ fn render_mermaid_images(frame: &mut Frame, app: &mut App, area: Rect) {
733733
frame.render_stateful_widget(img_widget, render_area, protocol_state);
734734
}
735735
} else if let Some(error) = app.mermaid_render_errors.get(&hash) {
736+
let prefix = "⚠ mermaid render failed: ";
737+
let max_msg_len = (inner.width as usize).saturating_sub(prefix.len());
738+
let truncated = if error.len() > max_msg_len {
739+
format!("{}…", &error[..max_msg_len.saturating_sub(1)])
740+
} else {
741+
error.clone()
742+
};
736743
let error_line = Line::from(vec![
737744
Span::styled("⚠ ", Style::default().fg(Color::Yellow)),
738745
Span::styled(
739-
format!("mermaid render failed: {}", error),
746+
format!("mermaid render failed: {}", truncated),
740747
Style::default().fg(Color::DarkGray),
741748
),
742749
]);
@@ -1543,10 +1550,7 @@ fn render_markdown_enhanced(
15431550
.add_modifier(Modifier::BOLD),
15441551
));
15451552
}
1546-
header_spans.push(Span::styled(
1547-
"▸ mermaid diagram",
1548-
theme.code_fence_style(),
1549-
));
1553+
header_spans.push(Span::styled("▸ mermaid diagram", theme.code_fence_style()));
15501554
lines.push(Line::from(header_spans));
15511555

15521556
// Reserve blank lines for the image overlay
@@ -1571,6 +1575,14 @@ fn render_markdown_enhanced(
15711575
theme.code_fence_style(),
15721576
));
15731577

1578+
#[cfg(not(feature = "mermaid"))]
1579+
if lang_str == "mermaid" {
1580+
fence_spans.push(Span::styled(
1581+
" (enable 'mermaid' feature to render)",
1582+
Style::default().fg(Color::DarkGray),
1583+
));
1584+
}
1585+
15741586
lines.push(Line::from(fence_spans));
15751587

15761588
// Highlighted code

0 commit comments

Comments
 (0)