|
1 | 1 | use crate::{ |
2 | | - core::{cache::sync_cache, types::OutputFormat}, |
| 2 | + core::{ |
| 3 | + cache::sync_cache, |
| 4 | + display::{truncate_path, truncate_string}, |
| 5 | + types::OutputFormat, |
| 6 | + }, |
3 | 7 | utils::error::{Error, Result}, |
4 | 8 | }; |
5 | 9 | use std::io::{self, Write}; |
| 10 | +use tabled::{Table, Tabled}; |
| 11 | + |
| 12 | +#[derive(Tabled)] |
| 13 | +struct FileDisplay { |
| 14 | + #[tabled(rename = "File Path")] |
| 15 | + path: String, |
| 16 | + #[tabled(rename = "Owners")] |
| 17 | + owners: String, |
| 18 | + #[tabled(rename = "Tags")] |
| 19 | + tags: String, |
| 20 | +} |
6 | 21 |
|
7 | 22 | /// Find and list files with their owners based on filter criteria |
8 | 23 | pub(crate) fn run( |
@@ -66,107 +81,58 @@ pub(crate) fn run( |
66 | 81 | // Output the filtered files in the requested format |
67 | 82 | match format { |
68 | 83 | OutputFormat::Text => { |
69 | | - // Set column widths that work better for most displays |
70 | | - let path_width = 45; // Max width for path display |
71 | | - let owner_width = 26; // More space for owners |
72 | | - let tag_width = 26; // More space for tags |
73 | | - |
74 | | - // Print header |
75 | | - println!( |
76 | | - "===============================================================================" |
77 | | - ); |
78 | | - println!( |
79 | | - " {:<path_width$} {:<owner_width$} {:<tag_width$}", |
80 | | - "File Path", |
81 | | - "Owners", |
82 | | - "Tags", |
83 | | - path_width = path_width, |
84 | | - owner_width = owner_width, |
85 | | - tag_width = tag_width |
86 | | - ); |
87 | | - println!( |
88 | | - "===============================================================================" |
89 | | - ); |
90 | | - |
91 | | - // Print each file entry |
92 | | - for file in &filtered_files { |
93 | | - // Format the path - keep the filename but truncate the path if needed |
94 | | - let path_str = file.path.to_string_lossy(); |
95 | | - let path_display = if path_str.len() > path_width { |
96 | | - // Extract filename |
97 | | - let filename = file |
98 | | - .path |
99 | | - .file_name() |
100 | | - .map(|f| f.to_string_lossy().to_string()) |
101 | | - .unwrap_or_default(); |
102 | | - |
103 | | - // Calculate available space for parent path |
104 | | - let available_space = path_width.saturating_sub(filename.len() + 4); // +4 for ".../" |
105 | | - |
106 | | - if available_space > 5 { |
107 | | - // Show part of the parent path |
108 | | - let parent_path = path_str.to_string(); |
109 | | - let start_pos = parent_path.len().saturating_sub(path_width - 3); |
110 | | - format!("...{}", &parent_path[start_pos..]) |
| 84 | + // Create table data |
| 85 | + let table_data: Vec<FileDisplay> = filtered_files |
| 86 | + .iter() |
| 87 | + .map(|file| { |
| 88 | + let path_str = file.path.to_string_lossy().to_string(); |
| 89 | + |
| 90 | + let owners_str = if file.owners.is_empty() { |
| 91 | + "None".to_string() |
111 | 92 | } else { |
112 | | - // Just show the filename with ellipsis |
113 | | - format!(".../{}", filename) |
114 | | - } |
115 | | - } else { |
116 | | - path_str.to_string() |
117 | | - }; |
118 | | - |
119 | | - // Format owners with more space |
120 | | - let owners_str = if file.owners.is_empty() { |
121 | | - "None".to_string() |
122 | | - } else { |
123 | | - file.owners |
124 | | - .iter() |
125 | | - .map(|o| o.identifier.clone()) |
126 | | - .collect::<Vec<_>>() |
127 | | - .join(", ") |
128 | | - }; |
| 93 | + file.owners |
| 94 | + .iter() |
| 95 | + .map(|o| o.identifier.clone()) |
| 96 | + .collect::<Vec<_>>() |
| 97 | + .join(", ") |
| 98 | + }; |
129 | 99 |
|
130 | | - let owners_display = if owners_str.len() > owner_width { |
131 | | - format!("{}...", &owners_str[0..owner_width - 3]) |
132 | | - } else { |
133 | | - owners_str |
134 | | - }; |
| 100 | + let tags_str = if file.tags.is_empty() { |
| 101 | + "None".to_string() |
| 102 | + } else { |
| 103 | + file.tags |
| 104 | + .iter() |
| 105 | + .map(|t| t.0.clone()) |
| 106 | + .collect::<Vec<_>>() |
| 107 | + .join(", ") |
| 108 | + }; |
| 109 | + |
| 110 | + FileDisplay { |
| 111 | + path: truncate_path(&path_str, 60), |
| 112 | + owners: truncate_string(&owners_str, 40), |
| 113 | + tags: truncate_string(&tags_str, 30), |
| 114 | + } |
| 115 | + }) |
| 116 | + .collect(); |
135 | 117 |
|
136 | | - // Format tags with more space |
137 | | - let tags_str = if file.tags.is_empty() { |
138 | | - "None".to_string() |
| 118 | + // Get terminal width, fallback to 80 if unavailable |
| 119 | + let terminal_width = |
| 120 | + if let Some((terminal_size::Width(w), _)) = terminal_size::terminal_size() { |
| 121 | + w as usize |
139 | 122 | } else { |
140 | | - file.tags |
141 | | - .iter() |
142 | | - .map(|t| t.0.clone()) |
143 | | - .collect::<Vec<_>>() |
144 | | - .join(", ") |
| 123 | + 80 |
145 | 124 | }; |
146 | 125 |
|
147 | | - let tags_display = if tags_str.len() > tag_width { |
148 | | - format!("{}...", &tags_str[0..tag_width - 3]) |
149 | | - } else { |
150 | | - tags_str |
151 | | - }; |
| 126 | + let mut table = Table::new(table_data); |
| 127 | + table |
| 128 | + .with(tabled::settings::Style::modern()) |
| 129 | + .with(tabled::settings::Width::wrap( |
| 130 | + terminal_width.saturating_sub(4), |
| 131 | + )) |
| 132 | + .with(tabled::settings::Padding::new(1, 1, 0, 0)); |
152 | 133 |
|
153 | | - println!( |
154 | | - " {:<path_width$} {:<owner_width$} {:<tag_width$}", |
155 | | - path_display, |
156 | | - owners_display, |
157 | | - tags_display, |
158 | | - path_width = path_width, |
159 | | - owner_width = owner_width, |
160 | | - tag_width = tag_width |
161 | | - ); |
162 | | - } |
163 | | - println!( |
164 | | - "===============================================================================" |
165 | | - ); |
166 | | - println!(" Total: {} files", filtered_files.len()); |
167 | | - println!( |
168 | | - "===============================================================================" |
169 | | - ); |
| 134 | + println!("{}", table); |
| 135 | + println!("Total: {} files", filtered_files.len()); |
170 | 136 | } |
171 | 137 | OutputFormat::Json => { |
172 | 138 | println!("{}", serde_json::to_string_pretty(&filtered_files).unwrap()); |
|
0 commit comments