use crate::widgets::markdown_widget::foundation::elements::constants::{
get_link_icon, CHECKBOX_CHECKED, CHECKBOX_TODO, CHECKBOX_UNCHECKED,
};
use crate::widgets::markdown_widget::foundation::elements::enums::{CheckboxState, TextSegment};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::Span;
pub fn render_text_segment(segment: &TextSegment, base_style: Style) -> Span<'static> {
match segment {
TextSegment::Plain(text) => Span::styled(text.clone(), base_style),
TextSegment::Bold(text) => {
Span::styled(text.clone(), base_style.add_modifier(Modifier::BOLD))
}
TextSegment::Italic(text) => {
Span::styled(text.clone(), base_style.add_modifier(Modifier::ITALIC))
}
TextSegment::BoldItalic(text) => Span::styled(
text.clone(),
base_style
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC),
),
TextSegment::InlineCode(text) => Span::styled(
format!(" {} ", text),
base_style
.bg(Color::Rgb(60, 60, 60))
.fg(Color::Rgb(230, 180, 100)),
),
TextSegment::Link {
text,
url,
is_autolink,
bold,
italic,
show_icon,
} => {
let full_text = if *show_icon {
let icon = get_link_icon(url);
format!("{}{}", icon, text)
} else {
text.clone()
};
let mut style = if *is_autolink {
base_style
.fg(Color::Rgb(100, 150, 255))
.add_modifier(Modifier::ITALIC)
.add_modifier(Modifier::UNDERLINED)
} else {
base_style.fg(Color::Rgb(100, 200, 100))
};
if *bold {
style = style.add_modifier(Modifier::BOLD);
}
if *italic && !*is_autolink {
style = style.add_modifier(Modifier::ITALIC);
}
Span::styled(full_text, style)
}
TextSegment::Strikethrough(text) => Span::styled(
text.clone(),
base_style
.fg(Color::Rgb(150, 150, 150))
.add_modifier(Modifier::CROSSED_OUT),
),
TextSegment::Html(text) => Span::styled(
text.clone(),
base_style
.fg(Color::Rgb(100, 180, 100))
.add_modifier(Modifier::ITALIC),
),
TextSegment::Checkbox(state) => {
let (icon, color) = match state {
CheckboxState::Unchecked => (CHECKBOX_UNCHECKED, Color::Rgb(180, 180, 180)),
CheckboxState::Checked => (CHECKBOX_CHECKED, Color::Rgb(100, 200, 100)),
CheckboxState::Todo => (CHECKBOX_TODO, Color::Rgb(255, 200, 100)),
};
Span::styled(icon.to_string(), base_style.fg(color))
}
}
}
pub fn segments_to_plain_text(segments: &[TextSegment]) -> String {
segments
.iter()
.map(|seg| match seg {
TextSegment::Plain(text) => text.clone(),
TextSegment::Bold(text) => text.clone(),
TextSegment::Italic(text) => text.clone(),
TextSegment::BoldItalic(text) => text.clone(),
TextSegment::InlineCode(text) => format!("`{}`", text),
TextSegment::Link {
text,
url,
show_icon,
..
} => {
if *show_icon {
let icon = get_link_icon(url);
format!("{}{}", icon, text)
} else {
text.clone()
}
}
TextSegment::Strikethrough(text) => text.clone(),
TextSegment::Html(text) => text.clone(),
TextSegment::Checkbox(_) => String::new(), })
.collect::<Vec<_>>()
.join("")
}
pub fn wrap_text(text: &str, width: usize) -> Vec<String> {
if width == 0 || text.is_empty() {
return vec![text.to_string()];
}
let mut lines = Vec::new();
let mut current_line = String::new();
let mut current_width = 0;
for word in text.split_whitespace() {
let word_width = word.chars().count();
if current_width == 0 {
current_line = word.to_string();
current_width = word_width;
} else if current_width + 1 + word_width <= width {
current_line.push(' ');
current_line.push_str(word);
current_width += 1 + word_width;
} else {
lines.push(current_line);
current_line = word.to_string();
current_width = word_width;
}
}
if !current_line.is_empty() {
lines.push(current_line);
}
if lines.is_empty() {
lines.push(String::new());
}
lines
}