use crate::style::Color;
use std::io::Write;
pub mod text {
pub fn truncate(text: &str, max_length: usize) -> String {
text.chars().take(max_length).collect()
}
pub fn pad(text: &str, length: usize, fill_char: char) -> String {
if text.len() >= length {
text.chars().take(length).collect()
}
else {
format!("{}{}", text, fill_char.to_string().repeat(length - text.len()))
}
}
pub fn center(text: &str, width: usize) -> String {
if text.len() >= width {
text.chars().take(width).collect()
}
else {
let padding = (width - text.len()) / 2;
format!("{}{}{}", " ".repeat(padding), text, " ".repeat(width - text.len() - padding))
}
}
}
pub mod color {
use super::Color;
use crossterm::style as crossterm_style;
pub fn rgb(r: u8, g: u8, b: u8) -> Color {
Color::Rgb(r, g, b)
}
pub fn to_crossterm_color(color: Color) -> crossterm_style::Color {
color.into()
}
}
pub mod terminal_utils {
use crossterm::{cursor, terminal as crossterm_terminal};
use std::io::{self, Result as CrosstermResult, Write};
#[allow(dead_code)]
pub fn clear() -> CrosstermResult<()> {
let mut stdout = io::stdout();
write!(stdout, "{}", crossterm_terminal::Clear(crossterm_terminal::ClearType::All))?;
stdout.flush()?;
Ok(())
}
#[allow(dead_code)]
pub fn move_cursor(x: u16, y: u16) -> CrosstermResult<()> {
let mut stdout = io::stdout();
write!(stdout, "{}", cursor::MoveTo(x, y))?;
stdout.flush()?;
Ok(())
}
#[allow(dead_code)]
pub fn hide_cursor() -> CrosstermResult<()> {
let mut stdout = io::stdout();
write!(stdout, "{}", cursor::Hide)?;
stdout.flush()?;
Ok(())
}
#[allow(dead_code)]
pub fn show_cursor() -> CrosstermResult<()> {
let mut stdout = io::stdout();
write!(stdout, "{}", cursor::Show)?;
stdout.flush()?;
Ok(())
}
}
pub mod math {
pub fn clamp<T: PartialOrd>(value: T, min: T, max: T) -> T {
if value < min {
min
}
else if value > max {
max
}
else {
value
}
}
pub fn lerp(start: f64, end: f64, t: f64) -> f64 {
start + (end - start) * t
}
}
pub fn select<T>(items: &[T], prompt: &str) -> Option<usize>
where
T: std::fmt::Display,
{
println!("{}", prompt);
for (i, item) in items.iter().enumerate() {
println!("{}: {}", i + 1, item);
}
loop {
print!("请选择 (1-{}): ", items.len());
std::io::stdout().flush().unwrap();
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
match input.trim().parse::<usize>() {
Ok(choice) if choice >= 1 && choice <= items.len() => {
return Some(choice - 1);
}
_ => {
println!("无效的选择,请重新输入");
}
}
}
}
pub fn loading_animation(duration: std::time::Duration, message: &str) {
let chars = ["|", "/", "-", "\\"];
let start = std::time::Instant::now();
print!("{}", message);
std::io::stdout().flush().unwrap();
let mut i = 0;
while start.elapsed() < duration {
print!("\r{}{}", message, chars[i % chars.len()]);
std::io::stdout().flush().unwrap();
std::thread::sleep(std::time::Duration::from_millis(100));
i += 1;
}
print!("\r{}{}", message, " ");
println!();
}