lx_cli/formatter/
short.rs1use crate::config::Config;
2use crate::file_entry::{FileEntry, FileType};
3use colored::Colorize;
4use unicode_width::UnicodeWidthStr;
5
6pub fn format_short(entries: Vec<FileEntry>, config: &Config) {
7 let mut directories: Vec<FileEntry> = Vec::new();
8 let mut executables: Vec<FileEntry> = Vec::new();
9 let mut regular_files: Vec<FileEntry> = Vec::new();
10
11 for entry in entries {
12 match entry.get_file_type() {
13 FileType::Directory => directories.push(entry),
14 FileType::Executable => executables.push(entry),
15 FileType::RegularFile => regular_files.push(entry),
16 }
17 }
18
19 let column_spacing = config.display.column_spacing;
20 let max_rows = config.display.max_rows;
21
22 if max_rows > 0 {
25 format_with_max_rows(
26 directories,
27 executables,
28 regular_files,
29 max_rows,
30 column_spacing,
31 config,
32 );
33 } else {
34 format_single_column_per_type(
35 directories,
36 executables,
37 regular_files,
38 column_spacing,
39 config,
40 );
41 }
42}
43
44fn format_with_max_rows(
45 directories: Vec<FileEntry>,
46 executables: Vec<FileEntry>,
47 regular_files: Vec<FileEntry>,
48 max_rows: usize,
49 column_spacing: usize,
50 config: &Config,
51) {
52 let dir_num_cols = if directories.is_empty() {
54 0
55 } else {
56 (directories.len() + max_rows - 1) / max_rows
57 };
58
59 let exec_num_cols = if executables.is_empty() {
60 0
61 } else {
62 (executables.len() + max_rows - 1) / max_rows
63 };
64
65 let file_num_cols = if regular_files.is_empty() {
66 0
67 } else {
68 (regular_files.len() + max_rows - 1) / max_rows
69 };
70
71 let dir_width = directories
73 .iter()
74 .map(|e| {
75 let filename = e.path.file_name().unwrap().to_string_lossy();
76 UnicodeWidthStr::width(e.get_icon().as_str())
77 + 1
78 + UnicodeWidthStr::width(filename.as_ref())
79 })
80 .max()
81 .unwrap_or(0);
82
83 let exec_width = executables
84 .iter()
85 .map(|e| {
86 let filename = e.path.file_name().unwrap().to_string_lossy();
87 UnicodeWidthStr::width(e.get_icon().as_str())
88 + 1
89 + UnicodeWidthStr::width(filename.as_ref())
90 })
91 .max()
92 .unwrap_or(0);
93
94 let file_width = regular_files
95 .iter()
96 .map(|e| {
97 let filename = e.path.file_name().unwrap().to_string_lossy();
98 UnicodeWidthStr::width(e.get_icon().as_str())
99 + 1
100 + UnicodeWidthStr::width(filename.as_ref())
101 })
102 .max()
103 .unwrap_or(0);
104
105 for row in 0..max_rows {
107 let mut line = String::new();
108 let mut has_any_content = false;
109
110 if dir_num_cols > 0 {
112 for col in 0..dir_num_cols {
113 let idx = col * max_rows + row;
114 if idx < directories.len() {
115 if col > 0 {
116 line.push_str(&" ".repeat(column_spacing));
117 }
118
119 let entry = &directories[idx];
120 let filename = entry.path.file_name().unwrap().to_string_lossy();
121 let icon = entry.get_icon();
122 let actual_width = UnicodeWidthStr::width(icon.as_str())
123 + 1
124 + UnicodeWidthStr::width(filename.as_ref());
125
126 line.push_str(&format!(
127 "{} {}",
128 icon,
129 filename.color(entry.get_color(&config.colors)).bold()
130 ));
131
132 if actual_width < dir_width {
133 line.push_str(&" ".repeat(dir_width - actual_width));
134 }
135 has_any_content = true;
136 } else if col == 0 {
137 line.push_str(&" ".repeat(dir_width));
139 } else {
140 line.push_str(&" ".repeat(column_spacing + dir_width));
141 }
142 }
143
144 if exec_num_cols > 0 || file_num_cols > 0 {
146 line.push_str(&" ".repeat(column_spacing));
147 }
148 }
149
150 if exec_num_cols > 0 {
152 for col in 0..exec_num_cols {
153 let idx = col * max_rows + row;
154 if idx < executables.len() {
155 if col > 0 {
156 line.push_str(&" ".repeat(column_spacing));
157 }
158
159 let entry = &executables[idx];
160 let filename = entry.path.file_name().unwrap().to_string_lossy();
161 let icon = entry.get_icon();
162 let actual_width = UnicodeWidthStr::width(icon.as_str())
163 + 1
164 + UnicodeWidthStr::width(filename.as_ref());
165
166 line.push_str(&format!(
167 "{} {}",
168 icon,
169 filename.color(entry.get_color(&config.colors)).bold()
170 ));
171
172 if actual_width < exec_width {
173 line.push_str(&" ".repeat(exec_width - actual_width));
174 }
175 has_any_content = true;
176 } else if col == 0 {
177 line.push_str(&" ".repeat(exec_width));
178 } else {
179 line.push_str(&" ".repeat(column_spacing + exec_width));
180 }
181 }
182
183 if file_num_cols > 0 {
185 line.push_str(&" ".repeat(column_spacing));
186 }
187 }
188
189 if file_num_cols > 0 {
191 for col in 0..file_num_cols {
192 let idx = col * max_rows + row;
193 if idx < regular_files.len() {
194 if col > 0 {
195 line.push_str(&" ".repeat(column_spacing));
196 }
197
198 let entry = ®ular_files[idx];
199 let filename = entry.path.file_name().unwrap().to_string_lossy();
200 let icon = entry.get_icon();
201 let actual_width = UnicodeWidthStr::width(icon.as_str())
202 + 1
203 + UnicodeWidthStr::width(filename.as_ref());
204
205 line.push_str(&format!(
206 "{} {}",
207 icon,
208 filename.color(entry.get_color(&config.colors))
209 ));
210
211 if col < file_num_cols - 1 && actual_width < file_width {
212 line.push_str(&" ".repeat(file_width - actual_width));
213 }
214 has_any_content = true;
215 }
216 }
217 }
218
219 if has_any_content {
220 println!("{}", line.trim_end());
221 }
222 }
223}
224
225fn format_single_column_per_type(
226 directories: Vec<FileEntry>,
227 executables: Vec<FileEntry>,
228 regular_files: Vec<FileEntry>,
229 column_spacing: usize,
230 config: &Config,
231) {
232 let dir_width = directories
234 .iter()
235 .map(|e| {
236 let filename = e.path.file_name().unwrap().to_string_lossy();
237 UnicodeWidthStr::width(e.get_icon().as_str())
238 + 1
239 + UnicodeWidthStr::width(filename.as_ref())
240 })
241 .max()
242 .unwrap_or(0);
243
244 let exec_width = executables
245 .iter()
246 .map(|e| {
247 let filename = e.path.file_name().unwrap().to_string_lossy();
248 UnicodeWidthStr::width(e.get_icon().as_str())
249 + 1
250 + UnicodeWidthStr::width(filename.as_ref())
251 })
252 .max()
253 .unwrap_or(0);
254
255 let file_width = regular_files
256 .iter()
257 .map(|e| {
258 let filename = e.path.file_name().unwrap().to_string_lossy();
259 UnicodeWidthStr::width(e.get_icon().as_str())
260 + 1
261 + UnicodeWidthStr::width(filename.as_ref())
262 })
263 .max()
264 .unwrap_or(0);
265
266 let max_rows = *[directories.len(), executables.len(), regular_files.len()]
268 .iter()
269 .max()
270 .unwrap_or(&0);
271
272 for i in 0..max_rows {
274 let mut line = String::new();
275
276 if dir_width > 0 {
278 if i < directories.len() {
279 let entry = &directories[i];
280 let filename = entry.path.file_name().unwrap().to_string_lossy();
281 let icon = entry.get_icon();
282 let actual_width = UnicodeWidthStr::width(icon.as_str())
283 + 1
284 + UnicodeWidthStr::width(filename.as_ref());
285
286 line.push_str(&format!(
287 "{} {}",
288 icon,
289 filename.color(entry.get_color(&config.colors)).bold()
290 ));
291 if actual_width < dir_width {
293 line.push_str(&" ".repeat(dir_width - actual_width));
294 }
295 } else {
296 line.push_str(&" ".repeat(dir_width));
298 }
299
300 if exec_width > 0 || file_width > 0 {
302 line.push_str(&" ".repeat(column_spacing));
303 }
304 }
305
306 if exec_width > 0 {
308 if i < executables.len() {
309 let entry = &executables[i];
310 let filename = entry.path.file_name().unwrap().to_string_lossy();
311 let icon = entry.get_icon();
312 let actual_width = UnicodeWidthStr::width(icon.as_str())
313 + 1
314 + UnicodeWidthStr::width(filename.as_ref());
315
316 line.push_str(&format!(
317 "{} {}",
318 icon,
319 filename.color(entry.get_color(&config.colors)).bold()
320 ));
321 if actual_width < exec_width {
323 line.push_str(&" ".repeat(exec_width - actual_width));
324 }
325 } else {
326 line.push_str(&" ".repeat(exec_width));
328 }
329
330 if file_width > 0 {
332 line.push_str(&" ".repeat(column_spacing));
333 }
334 }
335
336 if i < regular_files.len() {
338 let entry = ®ular_files[i];
339 let filename = entry.path.file_name().unwrap().to_string_lossy();
340 let icon = entry.get_icon();
341 let actual_width = UnicodeWidthStr::width(icon.as_str())
342 + 1
343 + UnicodeWidthStr::width(filename.as_ref());
344
345 line.push_str(&format!(
346 "{} {}",
347 icon,
348 filename.color(entry.get_color(&config.colors))
349 ));
350 if actual_width < file_width {
352 line.push_str(&" ".repeat(file_width - actual_width));
353 }
354 }
355
356 println!("{}", line.trim_end());
357 }
358}