pub const PROMPT_PREVIEW_LEN: usize = 60;
pub const CONTENT_HASH_BYTES: usize = 16;
pub const DIFF_HASH_BYTES: usize = 8;
pub const SHORT_COMMIT_LEN: usize = 7;
pub fn truncate(s: &str, max: usize) -> String {
let len = s.chars().count();
if len <= max {
return s.to_string();
}
let keep = max.saturating_sub(3);
let truncated: String = s.chars().take(keep).collect();
format!("{}...", truncated)
}
pub fn truncate_prompt(text: &str, max_len: usize) -> String {
let trimmed = text.trim();
truncate(trimmed, max_len)
}
pub fn pad_right(s: &str, len: usize) -> String {
let count = s.chars().count();
if count >= len {
return s.chars().take(len).collect();
}
format!("{}{}", s, " ".repeat(len - count))
}
pub fn truncate_or_pad(s: &str, len: usize) -> String {
let count = s.chars().count();
if count > len {
let keep = len.saturating_sub(1);
let truncated: String = s.chars().take(keep).collect();
format!("{}…", truncated)
} else {
format!("{:<width$}", s, width = len)
}
}
pub fn word_wrap(text: &str, width: usize) -> Vec<String> {
let mut lines = Vec::new();
let mut current_line = String::new();
for word in text.split_whitespace() {
if current_line.is_empty() {
current_line = word.to_string();
} else if current_line.len() + 1 + word.len() <= width {
current_line.push(' ');
current_line.push_str(word);
} else {
lines.push(current_line);
current_line = word.to_string();
}
}
if !current_line.is_empty() {
lines.push(current_line);
}
if lines.is_empty() {
lines.push(String::new());
}
lines
}
pub mod hex {
pub fn encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_truncate() {
assert_eq!(truncate("hello", 10), "hello");
assert_eq!(truncate("hello world", 8), "hello...");
assert_eq!(truncate("hi", 2), "hi");
assert_eq!(truncate("abc", 3), "abc");
}
#[test]
fn test_truncate_unicode() {
assert_eq!(truncate("你好世界", 3), "...");
assert_eq!(truncate("🙂🙂🙂🙂", 3), "...");
}
#[test]
fn test_truncate_prompt() {
assert_eq!(truncate_prompt(" hello ", 10), "hello");
assert_eq!(truncate_prompt(" long text here ", 8), "long ...");
}
#[test]
fn test_pad_right() {
assert_eq!(pad_right("hi", 5), "hi ");
assert_eq!(pad_right("hello", 3), "hel");
assert_eq!(pad_right("abc", 3), "abc");
}
#[test]
fn test_pad_right_unicode() {
assert_eq!(pad_right("你好", 4), "你好 ");
assert_eq!(pad_right("🙂🙂🙂", 2), "🙂🙂");
}
#[test]
fn test_truncate_or_pad() {
assert_eq!(truncate_or_pad("hi", 5), "hi ");
assert_eq!(truncate_or_pad("hello world", 5), "hell…");
}
#[test]
fn test_truncate_or_pad_unicode() {
assert_eq!(truncate_or_pad("你好世界", 3), "你好…");
assert_eq!(truncate_or_pad("🙂🙂🙂🙂", 3), "🙂🙂…");
}
#[test]
fn test_word_wrap() {
let lines = word_wrap("hello world foo bar", 10);
assert_eq!(lines, vec!["hello", "world foo", "bar"]);
let empty = word_wrap("", 10);
assert_eq!(empty, vec![""]);
}
#[test]
fn test_hex_encode() {
assert_eq!(hex::encode(&[0x00, 0xff, 0x10]), "00ff10");
assert_eq!(hex::encode(&[]), "");
}
}