vtcode_core/ui/
markdown.rs1use crate::config::loader::SyntaxHighlightingConfig;
2use crate::ui::theme::{self, ThemeStyles};
3use anstyle::Style;
4
5#[cfg(feature = "tui")]
7pub use vtcode_ui::tui::ui::markdown::{
8 HighlightedSegment, MarkdownLine, MarkdownSegment, RenderMarkdownOptions,
9 highlight_code_to_ansi, highlight_code_to_segments, highlight_line_for_diff,
10};
11
12#[cfg(not(feature = "tui"))]
14pub use vtcode_commons::ui_protocol::{
15 HighlightedSegment, MarkdownLine, MarkdownSegment, RenderMarkdownOptions,
16};
17
18#[cfg(not(feature = "tui"))]
19pub fn highlight_code_to_ansi(code: &str, _language: Option<&str>, _theme: &str) -> String {
20 code.to_string()
21}
22
23#[cfg(not(feature = "tui"))]
24pub fn highlight_code_to_segments(
25 code: &str,
26 _language: Option<&str>,
27 _theme: &str,
28) -> Vec<HighlightedSegment> {
29 vec![HighlightedSegment {
30 style: Style::default(),
31 text: code.to_string(),
32 }]
33}
34
35#[cfg(not(feature = "tui"))]
36pub fn highlight_line_for_diff(
37 line: &str,
38 _language: Option<&str>,
39) -> Option<Vec<(Style, String)>> {
40 Some(vec![(Style::default(), line.to_string())])
41}
42
43pub fn render_markdown_to_lines(
46 source: &str,
47 base_style: Style,
48 theme_styles: &ThemeStyles,
49 highlight_config: Option<&SyntaxHighlightingConfig>,
50) -> Vec<MarkdownLine> {
51 render_markdown_to_lines_with_options(
52 source,
53 base_style,
54 theme_styles,
55 highlight_config,
56 RenderMarkdownOptions::default(),
57 )
58}
59
60#[cfg(feature = "tui")]
61pub fn render_markdown_to_lines_with_options(
62 source: &str,
63 base_style: Style,
64 theme_styles: &ThemeStyles,
65 highlight_config: Option<&SyntaxHighlightingConfig>,
66 render_options: RenderMarkdownOptions,
67) -> Vec<MarkdownLine> {
68 let tui_theme_styles = crate::ui::tui_compat::tui_theme_styles_from_core(theme_styles);
69 let tui_highlight_cfg =
70 highlight_config.map(|cfg| vtcode_ui::tui::TuiSyntaxHighlightingConfig {
71 enabled: cfg.enabled,
72 theme: cfg.theme.clone(),
73 cache_themes: cfg.cache_themes,
74 max_file_size_mb: cfg.max_file_size_mb,
75 enabled_languages: cfg.enabled_languages.clone(),
76 highlight_timeout_ms: cfg.highlight_timeout_ms,
77 });
78 vtcode_ui::tui::ui::markdown::render_markdown_to_lines_with_options(
79 source,
80 base_style,
81 &tui_theme_styles,
82 tui_highlight_cfg.as_ref(),
83 render_options,
84 )
85}
86
87#[cfg(not(feature = "tui"))]
88pub fn render_markdown_to_lines_with_options(
89 source: &str,
90 base_style: Style,
91 _theme_styles: &ThemeStyles,
92 _highlight_config: Option<&SyntaxHighlightingConfig>,
93 _render_options: RenderMarkdownOptions,
94) -> Vec<MarkdownLine> {
95 let mut lines: Vec<MarkdownLine> = source
96 .lines()
97 .map(|line| MarkdownLine {
98 segments: if line.is_empty() {
99 Vec::new()
100 } else {
101 vec![MarkdownSegment {
102 style: base_style,
103 text: line.to_string(),
104 link_target: None,
105 }]
106 },
107 })
108 .collect();
109 if lines.is_empty() {
110 lines.push(MarkdownLine::default());
111 }
112 lines
113}
114
115pub fn render_markdown(source: &str) -> Vec<MarkdownLine> {
116 let styles = theme::active_styles();
117 render_markdown_to_lines(source, Style::default(), &styles, None)
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn facade_renders_markdown() {
126 let lines = render_markdown("# Heading");
127 assert!(!lines.is_empty());
128 }
129}