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