62 lines
1.8 KiB
Rust
62 lines
1.8 KiB
Rust
use crate::types::Message;
|
|
use textwrap::{wrap, Options};
|
|
|
|
/// Formats messages for display across different clients.
|
|
#[derive(Debug, Clone)]
|
|
pub struct MessageFormatter {
|
|
wrap_width: usize,
|
|
show_role_labels: bool,
|
|
preserve_empty_lines: bool,
|
|
}
|
|
|
|
impl MessageFormatter {
|
|
/// Create a new formatter
|
|
pub fn new(wrap_width: usize, show_role_labels: bool) -> Self {
|
|
Self {
|
|
wrap_width: wrap_width.max(20),
|
|
show_role_labels,
|
|
preserve_empty_lines: true,
|
|
}
|
|
}
|
|
|
|
/// Override whether empty lines should be preserved
|
|
pub fn with_preserve_empty(mut self, preserve: bool) -> Self {
|
|
self.preserve_empty_lines = preserve;
|
|
self
|
|
}
|
|
|
|
/// Render a message to a list of visual lines ready for display
|
|
pub fn format_message(&self, message: &Message) -> Vec<String> {
|
|
let mut lines = Vec::new();
|
|
|
|
let mut content = message.content.trim_end().to_string();
|
|
if content.is_empty() && self.preserve_empty_lines {
|
|
content.push(' ');
|
|
}
|
|
|
|
let options = Options::new(self.wrap_width)
|
|
.break_words(true)
|
|
.word_separator(textwrap::WordSeparator::UnicodeBreakProperties);
|
|
|
|
let wrapped = wrap(&content, &options);
|
|
|
|
if self.show_role_labels {
|
|
let label = format!("{}:", message.role.to_string().to_uppercase());
|
|
if let Some(first) = wrapped.first() {
|
|
lines.push(format!("{label} {first}"));
|
|
for line in wrapped.iter().skip(1) {
|
|
lines.push(format!("{:width$} {line}", "", width = label.len()));
|
|
}
|
|
} else {
|
|
lines.push(label);
|
|
}
|
|
} else {
|
|
for line in wrapped {
|
|
lines.push(line.into_owned());
|
|
}
|
|
}
|
|
|
|
lines
|
|
}
|
|
}
|