lx_cli/
file_entry.rs

1/// Core data structures (FileEntry and FileType) that represent files and its metadata.
2use 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        // File type
54        let file_type = if self.is_dir { 'd' } else { '-' };
55
56        // Owner permissions
57        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        // Group permissions
62        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        // Other permissions
67        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}