ratatui_toolkit/widgets/markdown_widget/foundation/elements/methods/
render.rs

1//! Main render implementation for MarkdownElement.
2
3use crate::widgets::markdown_widget::foundation::elements::constants::CodeBlockTheme;
4use crate::widgets::markdown_widget::foundation::elements::enums::ElementKind;
5use crate::widgets::markdown_widget::foundation::elements::methods::render_blockquote;
6use crate::widgets::markdown_widget::foundation::elements::methods::render_code_block;
7use crate::widgets::markdown_widget::foundation::elements::methods::render_expandable;
8use crate::widgets::markdown_widget::foundation::elements::methods::render_frontmatter;
9use crate::widgets::markdown_widget::foundation::elements::methods::render_heading;
10use crate::widgets::markdown_widget::foundation::elements::methods::render_horizontal_rule;
11use crate::widgets::markdown_widget::foundation::elements::methods::render_list_item;
12use crate::widgets::markdown_widget::foundation::elements::methods::render_paragraph;
13use crate::widgets::markdown_widget::foundation::elements::methods::render_table_border;
14use crate::widgets::markdown_widget::foundation::elements::methods::render_table_row;
15use crate::widgets::markdown_widget::foundation::elements::MarkdownElement;
16use ratatui::text::Line;
17
18/// Render options for markdown elements
19#[derive(Debug, Clone, Copy, Default)]
20pub struct RenderOptions<'a> {
21    /// Whether to show line numbers in code blocks
22    pub show_line_numbers: bool,
23    /// Color theme for code blocks
24    pub theme: CodeBlockTheme,
25    /// Optional application theme for consistent styling
26    pub app_theme: Option<&'a crate::services::theme::AppTheme>,
27    /// Whether to show collapse indicators on headings (default: false)
28    pub show_heading_collapse: bool,
29}
30
31/// Render a markdown element to ratatui Line with given width.
32pub fn render(element: &MarkdownElement, width: usize) -> Vec<Line<'static>> {
33    render_with_options(element, width, RenderOptions::default())
34}
35
36/// Render a markdown element with options.
37pub fn render_with_options(
38    element: &MarkdownElement,
39    width: usize,
40    options: RenderOptions<'_>,
41) -> Vec<Line<'static>> {
42    match &element.kind {
43        ElementKind::Heading {
44            level,
45            text,
46            collapsed,
47            ..
48        } => render_heading::render(
49            element,
50            *level,
51            text,
52            *collapsed,
53            width,
54            options.app_theme,
55            options.show_heading_collapse,
56        ),
57        ElementKind::HeadingBorder { level } => {
58            vec![render_heading::render_border(
59                element,
60                *level,
61                width,
62                options.app_theme,
63            )]
64        }
65        ElementKind::CodeBlockHeader {
66            language,
67            blockquote_depth,
68        } => {
69            vec![render_code_block::render_header(
70                element,
71                language,
72                width,
73                options.theme,
74                *blockquote_depth,
75            )]
76        }
77        ElementKind::CodeBlockContent {
78            content,
79            highlighted,
80            line_number,
81            blockquote_depth,
82        } => {
83            vec![render_code_block::render_content(
84                element,
85                content,
86                highlighted.as_ref(),
87                width,
88                if options.show_line_numbers {
89                    Some(*line_number)
90                } else {
91                    None
92                },
93                options.theme,
94                *blockquote_depth,
95            )]
96        }
97        ElementKind::CodeBlockBorder {
98            kind,
99            blockquote_depth,
100        } => {
101            vec![render_code_block::render_border(
102                element,
103                kind,
104                width,
105                options.theme,
106                *blockquote_depth,
107            )]
108        }
109        ElementKind::Paragraph(segments) => {
110            render_paragraph::render(element, segments, width, options.app_theme)
111        }
112        ElementKind::ListItem {
113            depth,
114            ordered,
115            number,
116            content,
117        } => render_list_item::render(
118            element,
119            *depth,
120            *ordered,
121            *number,
122            content,
123            width,
124            options.app_theme,
125        ),
126        ElementKind::Blockquote { content, depth } => {
127            render_blockquote::render(element, content, *depth, width, options.app_theme)
128        }
129        ElementKind::TableRow {
130            cells, is_header, ..
131        } => {
132            vec![render_table_row::render(element, cells, *is_header)]
133        }
134        ElementKind::TableBorder(kind) => {
135            vec![render_table_border::render(element, kind)]
136        }
137        ElementKind::HorizontalRule => {
138            vec![render_horizontal_rule::render(
139                element,
140                width,
141                options.app_theme,
142            )]
143        }
144        ElementKind::Empty => {
145            // Use a space so the line can receive highlight styling
146            vec![Line::from(" ")]
147        }
148        ElementKind::Frontmatter { fields, collapsed } => {
149            render_frontmatter::render(element, fields, *collapsed, width)
150        }
151        ElementKind::FrontmatterStart {
152            collapsed,
153            context_id,
154        } => {
155            vec![render_frontmatter::render_start(
156                *collapsed,
157                context_id.as_deref(),
158                width,
159            )]
160        }
161        ElementKind::FrontmatterField { key, value } => {
162            render_frontmatter::render_field(key, value, width)
163        }
164        ElementKind::FrontmatterEnd => {
165            vec![render_frontmatter::render_end(width)]
166        }
167        ElementKind::Expandable {
168            content_id,
169            lines,
170            max_lines,
171            collapsed,
172            total_lines,
173        } => render_expandable::render_expandable(
174            element,
175            content_id,
176            lines,
177            *max_lines,
178            *collapsed,
179            *total_lines,
180            width,
181            options.app_theme,
182        ),
183        ElementKind::ExpandToggle {
184            content_id,
185            expanded,
186            hidden_count,
187        } => render_expandable::render_expand_toggle(
188            element,
189            content_id,
190            *expanded,
191            *hidden_count,
192            width,
193            options.app_theme,
194        ),
195    }
196}