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 directories.sort_by(|a, b| {
21 let a_name = a.path.to_string_lossy();
22 let b_name = b.path.to_string_lossy();
23 a_name.cmp(&b_name)
24 });
25 executables.sort_by(|a, b| {
26 let a_name = a.path.to_string_lossy();
27 let b_name = b.path.to_string_lossy();
28 a_name.cmp(&b_name)
29 });
30 regular_files.sort_by(|a, b| {
31 let a_name = a.path.to_string_lossy();
32 let b_name = b.path.to_string_lossy();
33 a_name.cmp(&b_name)
34 });
35
36 let column_spacing = config.display.column_spacing;
37 let max_rows = config.display.max_rows;
38
39 if max_rows > 0 {
42 format_with_max_rows(
43 directories,
44 executables,
45 regular_files,
46 max_rows,
47 column_spacing,
48 config,
49 );
50 } else {
51 format_single_column_per_type(
52 directories,
53 executables,
54 regular_files,
55 column_spacing,
56 config,
57 );
58 }
59}
60
61fn format_with_max_rows(
62 directories: Vec<FileEntry>,
63 executables: Vec<FileEntry>,
64 regular_files: Vec<FileEntry>,
65 max_rows: usize,
66 column_spacing: usize,
67 config: &Config,
68) {
69 let dir_num_cols = if directories.is_empty() {
71 0
72 } else {
73 directories.len().div_ceil(max_rows)
74 };
75
76 let exec_num_cols = if executables.is_empty() {
77 0
78 } else {
79 executables.len().div_ceil(max_rows)
80 };
81
82 let file_num_cols = if regular_files.is_empty() {
83 0
84 } else {
85 regular_files.len().div_ceil(max_rows)
86 };
87
88 let dir_width = directories
90 .iter()
91 .map(|e| {
92 let filename = e.path.to_string_lossy();
93 UnicodeWidthStr::width(e.get_icon().as_str())
94 + 1
95 + UnicodeWidthStr::width(filename.as_ref())
96 })
97 .max()
98 .unwrap_or(0);
99
100 let exec_width = executables
101 .iter()
102 .map(|e| {
103 let filename = e.path.to_string_lossy();
104 UnicodeWidthStr::width(e.get_icon().as_str())
105 + 1
106 + UnicodeWidthStr::width(filename.as_ref())
107 })
108 .max()
109 .unwrap_or(0);
110
111 let file_width = regular_files
112 .iter()
113 .map(|e| {
114 let filename = e.path.to_string_lossy();
115 UnicodeWidthStr::width(e.get_icon().as_str())
116 + 1
117 + UnicodeWidthStr::width(filename.as_ref())
118 })
119 .max()
120 .unwrap_or(0);
121
122 for row in 0..max_rows {
124 let mut line = String::new();
125 let mut has_any_content = false;
126
127 if dir_num_cols > 0 {
129 for col in 0..dir_num_cols {
130 let idx = col * max_rows + row;
131 if idx < directories.len() {
132 if col > 0 {
133 line.push_str(&" ".repeat(column_spacing));
134 }
135
136 let entry = &directories[idx];
137 let filename = entry.path.to_string_lossy();
138 let icon = entry.get_icon_custom(&config.icons);
139 let actual_width = UnicodeWidthStr::width(icon.as_str())
140 + 1
141 + UnicodeWidthStr::width(filename.as_ref());
142
143 line.push_str(&format!(
144 "{} {}",
145 icon.color(entry.get_icon_color(&config.icons.colors)),
146 filename.color(entry.get_color(&config.colors)).bold()
147 ));
148
149 if actual_width < dir_width {
150 line.push_str(&" ".repeat(dir_width - actual_width));
151 }
152 has_any_content = true;
153 } else if col == 0 {
154 line.push_str(&" ".repeat(dir_width));
156 } else {
157 line.push_str(&" ".repeat(column_spacing + dir_width));
158 }
159 }
160
161 if exec_num_cols > 0 || file_num_cols > 0 {
163 line.push_str(&" ".repeat(column_spacing));
164 }
165 }
166
167 if exec_num_cols > 0 {
169 for col in 0..exec_num_cols {
170 let idx = col * max_rows + row;
171 if idx < executables.len() {
172 if col > 0 {
173 line.push_str(&" ".repeat(column_spacing));
174 }
175
176 let entry = &executables[idx];
177 let filename = entry.path.to_string_lossy();
178 let icon = entry.get_icon_custom(&config.icons);
179 let actual_width = UnicodeWidthStr::width(icon.as_str())
180 + 1
181 + UnicodeWidthStr::width(filename.as_ref());
182
183 line.push_str(&format!(
184 "{} {}",
185 icon.color(entry.get_icon_color(&config.icons.colors)),
186 filename.color(entry.get_color(&config.colors)).bold()
187 ));
188
189 if actual_width < exec_width {
190 line.push_str(&" ".repeat(exec_width - actual_width));
191 }
192 has_any_content = true;
193 } else if col == 0 {
194 line.push_str(&" ".repeat(exec_width));
195 } else {
196 line.push_str(&" ".repeat(column_spacing + exec_width));
197 }
198 }
199
200 if file_num_cols > 0 {
202 line.push_str(&" ".repeat(column_spacing));
203 }
204 }
205
206 if file_num_cols > 0 {
208 for col in 0..file_num_cols {
209 let idx = col * max_rows + row;
210 if idx < regular_files.len() {
211 if col > 0 {
212 line.push_str(&" ".repeat(column_spacing));
213 }
214
215 let entry = ®ular_files[idx];
216 let filename = entry.path.to_string_lossy();
217 let icon = entry.get_icon_custom(&config.icons);
218 let actual_width = UnicodeWidthStr::width(icon.as_str())
219 + 1
220 + UnicodeWidthStr::width(filename.as_ref());
221
222 line.push_str(&format!(
223 "{} {}",
224 icon.color(entry.get_icon_color(&config.icons.colors)),
225 filename.color(entry.get_color(&config.colors))
226 ));
227
228 if col < file_num_cols - 1 && actual_width < file_width {
229 line.push_str(&" ".repeat(file_width - actual_width));
230 }
231 has_any_content = true;
232 }
233 }
234 }
235
236 if has_any_content {
237 println!("{}", line.trim_end());
238 }
239 }
240}
241
242fn format_single_column_per_type(
243 directories: Vec<FileEntry>,
244 executables: Vec<FileEntry>,
245 regular_files: Vec<FileEntry>,
246 column_spacing: usize,
247 config: &Config,
248) {
249 let dir_width = directories
251 .iter()
252 .map(|e| {
253 let filename = e.path.to_string_lossy();
254 let icon = e.get_icon_custom(&config.icons);
255 UnicodeWidthStr::width(icon.as_str()) + 1 + UnicodeWidthStr::width(filename.as_ref())
256 })
257 .max()
258 .unwrap_or(0);
259
260 let exec_width = executables
261 .iter()
262 .map(|e| {
263 let filename = e.path.to_string_lossy();
264 let icon = e.get_icon_custom(&config.icons);
265 UnicodeWidthStr::width(icon.as_str()) + 1 + UnicodeWidthStr::width(filename.as_ref())
266 })
267 .max()
268 .unwrap_or(0);
269
270 let file_width = regular_files
271 .iter()
272 .map(|e| {
273 let filename = e.path.to_string_lossy();
274 let icon = e.get_icon_custom(&config.icons);
275 UnicodeWidthStr::width(icon.as_str()) + 1 + UnicodeWidthStr::width(filename.as_ref())
276 })
277 .max()
278 .unwrap_or(0);
279
280 let max_rows = *[directories.len(), executables.len(), regular_files.len()]
282 .iter()
283 .max()
284 .unwrap_or(&0);
285
286 for i in 0..max_rows {
288 let mut line = String::new();
289
290 if dir_width > 0 {
292 if i < directories.len() {
293 let entry = &directories[i];
294 let filename = entry.path.to_string_lossy();
295 let icon = entry.get_icon_custom(&config.icons);
296 let actual_width = UnicodeWidthStr::width(icon.as_str())
297 + 1
298 + UnicodeWidthStr::width(filename.as_ref());
299
300 line.push_str(&format!(
301 "{} {}",
302 icon.color(entry.get_icon_color(&config.icons.colors)),
303 filename.color(entry.get_color(&config.colors)).bold()
304 ));
305 if actual_width < dir_width {
307 line.push_str(&" ".repeat(dir_width - actual_width));
308 }
309 } else {
310 line.push_str(&" ".repeat(dir_width));
312 }
313
314 if exec_width > 0 || file_width > 0 {
316 line.push_str(&" ".repeat(column_spacing));
317 }
318 }
319
320 if exec_width > 0 {
322 if i < executables.len() {
323 let entry = &executables[i];
324 let filename = entry.path.to_string_lossy();
325 let icon = entry.get_icon_custom(&config.icons);
326 let actual_width = UnicodeWidthStr::width(icon.as_str())
327 + 1
328 + UnicodeWidthStr::width(filename.as_ref());
329
330 line.push_str(&format!(
331 "{} {}",
332 icon.color(entry.get_icon_color(&config.icons.colors)),
333 filename.color(entry.get_color(&config.colors)).bold()
334 ));
335 if actual_width < exec_width {
337 line.push_str(&" ".repeat(exec_width - actual_width));
338 }
339 } else {
340 line.push_str(&" ".repeat(exec_width));
342 }
343
344 if file_width > 0 {
346 line.push_str(&" ".repeat(column_spacing));
347 }
348 }
349
350 if i < regular_files.len() {
352 let entry = ®ular_files[i];
353 let filename = entry.path.to_string_lossy();
354 let icon = entry.get_icon_custom(&config.icons);
355 let actual_width = UnicodeWidthStr::width(icon.as_str())
356 + 1
357 + UnicodeWidthStr::width(filename.as_ref());
358
359 line.push_str(&format!(
360 "{} {}",
361 icon.color(entry.get_icon_color(&config.icons.colors)),
362 filename.color(entry.get_color(&config.colors))
363 ));
364 if actual_width < file_width {
366 line.push_str(&" ".repeat(file_width - actual_width));
367 }
368 }
369
370 println!("{}", line.trim_end());
371 }
372}