1use crate::config::ColorConfig;
3use crate::icon::FileIcon;
4use colored::Color;
5use std::path::PathBuf;
6use std::time::SystemTime;
7
8#[derive(Debug)]
9pub struct FileEntry {
10 pub path: PathBuf,
11 pub is_dir: bool,
12 pub is_executable: bool,
13 pub mode: u32,
14 pub size: u64,
15 pub modified: SystemTime,
16 pub owner: String,
17 pub group: String,
18 pub nlink: u64,
19}
20
21impl FileEntry {
22 fn get_file_icon(&self) -> FileIcon {
23 if self.is_dir {
24 FileIcon::Directory
25 } else if self.is_executable {
26 FileIcon::Executable
27 } else {
28 FileIcon::RegularFile
29 }
30 }
31
32 pub fn get_icon(&self) -> String {
33 self.get_file_icon().as_str().to_string()
34 }
35
36 pub fn get_color(&self, config: &ColorConfig) -> Color {
37 self.get_file_icon().get_color(config)
38 }
39
40 pub fn get_file_type(&self) -> FileType {
41 if self.is_dir {
42 FileType::Directory
43 } else if self.is_executable {
44 FileType::Executable
45 } else {
46 FileType::RegularFile
47 }
48 }
49
50 pub fn format_permissions(&self) -> String {
51 let mode = self.mode;
52
53 let file_type = if self.is_dir { 'd' } else { '-' };
55
56 let user_r = if mode & 0o400 != 0 { 'r' } else { '-' };
58 let user_w = if mode & 0o200 != 0 { 'w' } else { '-' };
59 let user_x = if mode & 0o100 != 0 { 'x' } else { '-' };
60
61 let group_r = if mode & 0o040 != 0 { 'r' } else { '-' };
63 let group_w = if mode & 0o020 != 0 { 'w' } else { '-' };
64 let group_x = if mode & 0o010 != 0 { 'x' } else { '-' };
65
66 let other_r = if mode & 0o004 != 0 { 'r' } else { '-' };
68 let other_w = if mode & 0o002 != 0 { 'w' } else { '-' };
69 let other_x = if mode & 0o001 != 0 { 'x' } else { '-' };
70
71 format!(
72 "{}{}{}{}{}{}{}{}{}{}",
73 file_type, user_r, user_w, user_x, group_r, group_w, group_x, other_r, other_w, other_x
74 )
75 }
76
77 pub fn format_size(&self) -> String {
78 let size = self.size;
79 if size < 1024 {
80 format!("{}B", size)
81 } else if size < 1024 * 1024 {
82 format!("{:.1}K", size as f64 / 1024.0)
83 } else if size < 1024 * 1024 * 1024 {
84 format!("{:.1}M", size as f64 / (1024.0 * 1024.0))
85 } else {
86 format!("{:.1}G", size as f64 / (1024.0 * 1024.0 * 1024.0))
87 }
88 }
89
90 pub fn format_modified(&self) -> String {
91 use std::time::UNIX_EPOCH;
92
93 if let Ok(duration) = self.modified.duration_since(UNIX_EPOCH) {
94 let secs = duration.as_secs();
95 let datetime = chrono::DateTime::from_timestamp(secs as i64, 0)
96 .unwrap_or_else(|| chrono::DateTime::from_timestamp(0, 0).unwrap());
97 datetime.format("%Y-%m-%d %H:%M:%S").to_string()
98 } else {
99 "Unknown".to_string()
100 }
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum FileType {
106 Directory,
107 Executable,
108 RegularFile,
109}