pub fn shorten_path(path: &str) -> String {
if let Some(home) = dirs::home_dir() {
let home_str = home.to_string_lossy();
if let Some(rest) = path.strip_prefix(home_str.as_ref()) {
return format!("~{}", rest);
}
}
path.to_string()
}
pub fn replace_tabs(text: &str) -> &str {
if !text.contains('\t') {
return text;
}
text
}
pub fn replace_tabs_owned(text: &str) -> String {
text.replace('\t', " ")
}
pub fn normalize_display_text(text: &str) -> String {
text.replace('\r', "")
}
pub fn sanitize_binary_output(text: &str) -> String {
let mut result = String::with_capacity(text.len());
for ch in text.chars() {
if ch == '\n' || ch == '\t' || ch.is_ascii_graphic() || ch == ' ' {
result.push(ch);
} else if ch == '\r' {
} else {
result.push('�');
}
}
result
}
pub fn get_text_output(content: &str) -> String {
let sanitized = sanitize_binary_output(content);
normalize_display_text(&sanitized)
}
pub fn truncate_output_preview(text: &str, max_lines: usize, max_bytes: usize) -> String {
let lines: Vec<&str> = text.lines().collect();
if lines.len() <= max_lines && text.len() <= max_bytes {
return text.to_string();
}
let selected: Vec<&str> = lines.into_iter().take(max_lines).collect();
let mut result = selected.join("\n");
if result.len() > max_bytes {
result.truncate(max_bytes);
while !result.is_char_boundary(result.len()) {
result.pop();
}
}
result
}
pub fn invalid_arg_text() -> &'static str {
"[invalid arg]"
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shorten_path_with_home() {
let home = dirs::home_dir().unwrap();
let home_str = home.to_string_lossy().to_string();
let path = format!("{}/foo/bar.txt", home_str);
assert_eq!(shorten_path(&path), "~/foo/bar.txt");
}
#[test]
fn test_shorten_path_no_home() {
assert_eq!(shorten_path("/tmp/foo.txt"), "/tmp/foo.txt");
}
#[test]
fn test_replace_tabs_no_tabs() {
assert_eq!(replace_tabs("hello world"), "hello world");
}
#[test]
fn test_replace_tabs_owned_with_tabs() {
assert_eq!(replace_tabs_owned("hello\tworld"), "hello world");
}
#[test]
fn test_normalize_display_text() {
assert_eq!(normalize_display_text("hello\r\nworld"), "hello\nworld");
assert_eq!(normalize_display_text("no-cr"), "no-cr");
}
#[test]
fn test_sanitize_binary_output() {
assert_eq!(sanitize_binary_output("hello\nworld"), "hello\nworld");
assert_eq!(sanitize_binary_output("tab\there"), "tab\there");
let with_control = "hello\x01world";
let result = sanitize_binary_output(with_control);
assert!(result.contains('�'));
}
#[test]
fn test_get_text_output() {
assert_eq!(get_text_output("hello\r\nworld"), "hello\nworld");
}
#[test]
fn test_truncate_output_preview_within_limits() {
let text = "line1\nline2\nline3";
assert_eq!(truncate_output_preview(text, 10, 1000), text);
}
#[test]
fn test_truncate_output_preview_by_lines() {
let text = "line1\nline2\nline3\nline4\nline5";
let result = truncate_output_preview(text, 2, 1000);
assert!(result.contains("line1"));
assert!(result.contains("line2"));
assert!(!result.contains("line5"));
}
#[test]
fn test_invalid_arg_text() {
assert_eq!(invalid_arg_text(), "[invalid arg]");
}
}