lx_cli/formatter/
recursive.rs1use crate::config::Config;
2use crate::file_entry::FileEntry;
3use colored::Colorize;
4use std::fs;
5use std::os::unix::fs::PermissionsExt;
6use std::path::Path;
7
8pub fn format_recursive(path: &Path, config: &Config, show_hidden: bool) {
9 if let Some(dir_name) = path.file_name() {
11 let dir_name_str = dir_name.to_string_lossy();
12
13 let temp_entry = FileEntry {
15 path: dir_name.to_os_string(),
16 is_dir: true,
17 is_executable: false,
18 mode: 0o755,
19 size: 0,
20 modified: std::time::SystemTime::UNIX_EPOCH,
21 owner: String::new(),
22 group: String::new(),
23 nlink: 0,
24 };
25
26 let icon = temp_entry.get_icon_custom(&config.icons);
27 let icon_colored = icon.color(temp_entry.get_icon_color(&config.icons.colors));
28 let dir_name_colored = dir_name_str
29 .color(temp_entry.get_color(&config.colors))
30 .bold();
31
32 if icon.is_empty() {
34 println!("{}", dir_name_colored);
35 } else {
36 println!("{} {}", icon_colored, dir_name_colored);
37 }
38 }
39
40 print_directory_tree(path, config, show_hidden, "", &config.display.tree.style);
42}
43
44fn print_directory_tree(
45 path: &Path,
46 config: &Config,
47 show_hidden: bool,
48 prefix: &str,
49 tree_style: &str,
50) {
51 match fs::read_dir(path) {
52 Ok(entries_iter) => {
53 let mut entries: Vec<_> = entries_iter.filter_map(|e| e.ok()).collect();
54
55 entries.sort_by(|a, b| {
57 let a_name = a.file_name();
58 let b_name = b.file_name();
59 a_name.cmp(&b_name)
60 });
61
62 let entries: Vec<_> = entries
64 .into_iter()
65 .filter(|e| {
66 if show_hidden {
67 true
68 } else {
69 let file_name = e.file_name();
70 let name_str = file_name.to_string_lossy();
71 !name_str.starts_with('.')
72 }
73 })
74 .collect();
75
76 for (idx, entry) in entries.iter().enumerate() {
77 let is_last = idx == entries.len() - 1;
78 let entry_path = entry.path();
79 let file_name = entry.file_name();
80 let file_name_str = file_name.to_string_lossy();
81
82 if let Ok(metadata) = entry.metadata() {
84 let is_dir = metadata.is_dir();
85 let is_executable = !is_dir && (metadata.permissions().mode() & 0o111) != 0;
86
87 let file_entry = FileEntry {
89 path: file_name.clone(),
90 is_dir,
91 is_executable,
92 mode: metadata.permissions().mode(),
93 size: metadata.len(),
94 modified: metadata
95 .modified()
96 .unwrap_or(std::time::SystemTime::UNIX_EPOCH),
97 owner: String::new(),
98 group: String::new(),
99 nlink: 0,
100 };
101
102 let (connector, extension_prefix) = if tree_style == "ascii" {
104 if is_last {
105 ("└──", " ")
106 } else {
107 ("├──", "│ ")
108 }
109 } else {
110 ("", " ")
112 };
113
114 let icon = file_entry.get_icon_custom(&config.icons);
116 let icon_colored = icon.color(file_entry.get_icon_color(&config.icons.colors));
117
118 let filename_colored = match file_entry.get_file_type() {
120 crate::file_entry::FileType::Directory
121 | crate::file_entry::FileType::Executable => file_name_str
122 .color(file_entry.get_color(&config.colors))
123 .bold(),
124 crate::file_entry::FileType::RegularFile => {
125 file_name_str.color(file_entry.get_color(&config.colors))
126 }
127 };
128
129 println!(
131 "{}{}{} {}",
132 prefix, connector, icon_colored, filename_colored
133 );
134
135 if is_dir {
137 let new_prefix = if tree_style == "ascii" {
138 format!("{}{}", prefix, extension_prefix)
139 } else {
140 format!("{} ", prefix)
141 };
142
143 print_directory_tree(
144 &entry_path,
145 config,
146 show_hidden,
147 &new_prefix,
148 tree_style,
149 );
150 }
151 }
152 }
153 }
154 Err(_) => {}
155 }
156}