pub fn wrap_text(text: &str, max_width: usize) -> Vec<String> {
let max_width = max_width.max(2);
let mut result = Vec::new();
let mut current_line = String::new();
let mut current_width = 0;
for ch in text.chars() {
if ch == '\n' {
result.push(current_line.clone());
current_line.clear();
current_width = 0;
continue;
}
let ch_width = char_width(ch);
if current_width + ch_width > max_width && !current_line.is_empty() {
result.push(current_line.clone());
current_line.clear();
current_width = 0;
}
current_line.push(ch);
current_width += ch_width;
}
if !current_line.is_empty() {
result.push(current_line);
}
if result.is_empty() {
result.push(String::new());
}
result
}
pub fn display_width(s: &str) -> usize {
use unicode_width::UnicodeWidthStr;
let base = UnicodeWidthStr::width(s);
let tab_count = s.chars().filter(|&c| c == '\t').count();
base + tab_count
}
pub fn char_width(c: char) -> usize {
if c == '\t' {
return 1;
}
use unicode_width::UnicodeWidthChar;
UnicodeWidthChar::width(c).unwrap_or(0)
}
pub fn strip_ansi_codes(s: &str) -> String {
use regex::Regex;
use std::sync::OnceLock;
static RE: OnceLock<Regex> = OnceLock::new();
let re = RE.get_or_init(|| {
Regex::new(r"\x1b\[[\x20-\x3f]*[\x40-\x7e]|\x1b\][^\x07]*(?:\x07|\x1b\\)|\x1b[^\[\]()]")
.expect("正则表达式编译失败,这是一个静态模式,应该总是有效的")
});
re.replace_all(s, "").into_owned()
}
pub fn sanitize_tool_output(s: &str) -> String {
let stripped = strip_ansi_codes(s);
stripped.replace('\t', " ").replace('\r', "")
}
pub fn remove_quotes(s: &str) -> String {
let s = s.trim();
if s.len() >= 2
&& ((s.starts_with('\'') && s.ends_with('\'')) || (s.starts_with('"') && s.ends_with('"')))
{
return s[1..s.len() - 1].to_string();
}
s.to_string()
}