1use crate::config::{ColorConfig, IconColorConfig, IconConfig};
3use crate::icon::FileIcon;
4use colored::Color;
5use std::ffi::OsString;
6use std::time::SystemTime;
7
8#[derive(Debug, Clone)]
9pub struct FileEntry {
10 pub path: OsString,
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_icon_custom(&self, config: &IconConfig) -> String {
37 self.get_file_icon().as_str_custom(config)
38 }
39
40 pub fn get_color(&self, config: &ColorConfig) -> Color {
41 self.get_file_icon().get_color(config)
42 }
43
44 pub fn get_icon_color(&self, config: &IconColorConfig) -> Color {
45 self.get_file_icon().get_icon_color(config)
46 }
47
48 pub fn get_file_type(&self) -> FileType {
49 if self.is_dir {
50 FileType::Directory
51 } else if self.is_executable {
52 FileType::Executable
53 } else {
54 FileType::RegularFile
55 }
56 }
57
58 pub fn format_permissions(&self) -> String {
59 let mode = self.mode;
60
61 let file_type = if self.is_dir { 'd' } else { '-' };
63
64 let user_r = if mode & 0o400 != 0 { 'r' } else { '-' };
66 let user_w = if mode & 0o200 != 0 { 'w' } else { '-' };
67 let user_x = if mode & 0o100 != 0 { 'x' } else { '-' };
68
69 let group_r = if mode & 0o040 != 0 { 'r' } else { '-' };
71 let group_w = if mode & 0o020 != 0 { 'w' } else { '-' };
72 let group_x = if mode & 0o010 != 0 { 'x' } else { '-' };
73
74 let other_r = if mode & 0o004 != 0 { 'r' } else { '-' };
76 let other_w = if mode & 0o002 != 0 { 'w' } else { '-' };
77 let other_x = if mode & 0o001 != 0 { 'x' } else { '-' };
78
79 format!(
80 "{}{}{}{}{}{}{}{}{}{}",
81 file_type, user_r, user_w, user_x, group_r, group_w, group_x, other_r, other_w, other_x
82 )
83 }
84
85 pub fn format_size(&self) -> String {
86 let size = self.size;
87 if size < 1024 {
88 format!("{}B", size)
89 } else if size < 1024 * 1024 {
90 format!("{:.1}K", size as f64 / 1024.0)
91 } else if size < 1024 * 1024 * 1024 {
92 format!("{:.1}M", size as f64 / (1024.0 * 1024.0))
93 } else {
94 format!("{:.1}G", size as f64 / (1024.0 * 1024.0 * 1024.0))
95 }
96 }
97
98 pub fn format_modified(&self) -> String {
99 use std::time::UNIX_EPOCH;
100
101 if let Ok(duration) = self.modified.duration_since(UNIX_EPOCH) {
102 let secs = duration.as_secs();
103 let datetime = chrono::DateTime::from_timestamp(secs as i64, 0)
104 .unwrap_or_else(|| chrono::DateTime::from_timestamp(0, 0).unwrap());
105 datetime.format("%Y-%m-%d %H:%M:%S").to_string()
106 } else {
107 "Unknown".to_string()
108 }
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
113pub enum FileType {
114 Directory,
115 Executable,
116 RegularFile,
117}