use ratatui::text::{Line, Span};
use std::fs;
use super::PreviewContent;
use crate::utils::FileItem;
pub trait PreviewGeneratorTrait {
#[allow(async_fn_in_trait)]
async fn generate_preview(&self, file: &FileItem, theme: &crate::theme::Theme) -> (String, PreviewContent);
fn can_handle(&self, file: &FileItem) -> bool;
}
use super::{
DirectoryPreviewGenerator, ImagePreviewGenerator, PdfPreviewGenerator, TextPreviewGenerator,
};
pub enum PreviewGeneratorType {
Directory(DirectoryPreviewGenerator),
Image(ImagePreviewGenerator),
Pdf(PdfPreviewGenerator),
Text(TextPreviewGenerator),
Binary(BinaryPreviewGenerator),
}
impl PreviewGeneratorType {
pub fn can_handle(&self, file: &FileItem) -> bool {
match self {
PreviewGeneratorType::Directory(generator) => generator.can_handle(file),
PreviewGeneratorType::Image(generator) => generator.can_handle(file),
PreviewGeneratorType::Pdf(generator) => generator.can_handle(file),
PreviewGeneratorType::Text(generator) => generator.can_handle(file),
PreviewGeneratorType::Binary(generator) => generator.can_handle(file),
}
}
pub async fn generate_preview(&self, file: &FileItem, theme: &crate::theme::Theme) -> (String, PreviewContent) {
match self {
PreviewGeneratorType::Directory(generator) => generator.generate_preview(file, theme).await,
PreviewGeneratorType::Image(generator) => generator.generate_preview(file, theme).await,
PreviewGeneratorType::Pdf(generator) => generator.generate_preview(file, theme).await,
PreviewGeneratorType::Text(generator) => generator.generate_preview(file, theme).await,
PreviewGeneratorType::Binary(generator) => generator.generate_preview(file, theme).await,
}
}
}
pub struct PreviewGenerator;
impl PreviewGenerator {
pub async fn generate_preview_content(file: &FileItem, theme: &crate::theme::Theme) -> (String, PreviewContent) {
let generators = vec![
PreviewGeneratorType::Directory(DirectoryPreviewGenerator),
PreviewGeneratorType::Image(ImagePreviewGenerator),
PreviewGeneratorType::Pdf(PdfPreviewGenerator),
PreviewGeneratorType::Text(TextPreviewGenerator),
];
for generator in generators {
if generator.can_handle(file) {
return generator.generate_preview(file, theme).await;
}
}
let binary_gen = PreviewGeneratorType::Binary(BinaryPreviewGenerator);
binary_gen.generate_preview(file, theme).await
}
}
pub fn process_special_characters(text: &str) -> String {
let mut result = String::new();
for ch in text.chars() {
match ch {
'\t' => {
result.push_str("→ "); }
'\r' => {
result.push_str("\\r");
}
'\0' => {
result.push_str("\\0");
}
c if c.is_control() && c != '\n' => {
result.push_str(&format!("\\x{:02x}", c as u8));
}
c => {
result.push(c);
}
}
}
result
}
pub struct BinaryPreviewGenerator;
impl PreviewGeneratorTrait for BinaryPreviewGenerator {
fn can_handle(&self, _file: &FileItem) -> bool {
true
}
async fn generate_preview(&self, file: &FileItem, theme: &crate::theme::Theme) -> (String, PreviewContent) {
let title = format!("📄 {}", file.name);
let metadata = match fs::metadata(&file.path) {
Ok(metadata) => metadata,
Err(e) => {
let content = vec![Line::from(vec![Span::styled(
format!("Error reading file metadata: {e}"),
theme.preview_error_style,
)])];
return (title, PreviewContent::text(content));
}
};
let file_size = metadata.len();
let content = vec![
Line::from(vec![Span::styled(
"Binary File".to_string(),
theme.preview_placeholder_style,
)]),
Line::from(vec![Span::raw("".to_string())]),
Line::from(vec![Span::styled(
format!("Size: {file_size} bytes"),
theme.preview_info_style,
)]),
Line::from(vec![Span::styled(
"Cannot preview binary content".to_string(),
theme.preview_info_style,
)]),
Line::from(vec![Span::raw("".to_string())]),
Line::from(vec![Span::styled(
"File type: Binary/Unknown".to_string(),
theme.dir_style,
)]),
];
(title, PreviewContent::text(content))
}
}