use rnk::prelude::*;
use sage_core::ui::bridge::state::{Message, Role, UiMessageContent};
use crate::ui::rnk_app::formatting::{truncate_to_width, wrap_text_with_prefix};
use crate::ui::rnk_app::theme::TerminalTheme;
use super::tool_call::render_tool_call;
use rnk::prelude::Box as RnkBox;
fn role_color(role: &Role, theme: &TerminalTheme) -> Color {
match role {
Role::User => theme.accent_user,
Role::Assistant => theme.accent_assistant,
Role::System => theme.accent_system,
}
}
fn content_line(color: Color, text: String, text_color: Color, is_first: bool) -> Element {
RnkBox::new()
.flex_direction(FlexDirection::Row)
.child(
Text::new(if is_first { "● " } else { " " })
.color(color)
.into_element(),
)
.child(Text::new(text).color(text_color).into_element())
.into_element()
}
pub fn format_message(msg: &Message, theme: &TerminalTheme) -> Element {
let term_width = crossterm::terminal::size()
.map(|(w, _)| w as usize)
.unwrap_or(80);
let color = role_color(&msg.role, theme);
match &msg.content {
UiMessageContent::Text(text) => {
let mut container = RnkBox::new().flex_direction(FlexDirection::Column);
match msg.role {
Role::User | Role::Assistant => {
let mut is_first = true;
for paragraph in text.split('\n') {
let wrapped =
wrap_text_with_prefix("", paragraph, term_width.saturating_sub(4));
for line in wrapped {
container = container.child(content_line(
color,
line,
theme.text_primary,
is_first,
));
is_first = false;
}
}
}
Role::System => {
let sys_text = truncate_to_width(text, term_width.saturating_sub(4));
container =
container.child(content_line(color, sys_text, theme.text_muted, true));
}
}
container.into_element()
}
UiMessageContent::Thinking(text) => {
let preview: String = text.lines().take(2).collect::<Vec<_>>().join(" ");
RnkBox::new()
.flex_direction(FlexDirection::Row)
.child(Text::new("💭 ").color(theme.text_subtle).into_element())
.child(
Text::new(format!(
"{}…",
truncate_to_width(&preview, term_width.saturating_sub(6))
))
.color(theme.text_subtle)
.into_element(),
)
.into_element()
}
UiMessageContent::ToolCall {
tool_name,
params,
result,
} => render_tool_call(tool_name, params, result.as_ref(), theme),
}
}