From eccdb0e13ee8b8e733957ec7b51a5861dc4a8d48 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Mon, 8 Sep 2025 18:26:39 -0300 Subject: [PATCH] refactor: Remove duplicated functionality by relying on comfy-table Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) --- Cargo.toml | 1 - src/modes/common.rs | 118 -------------------------------------------- src/modes/list.rs | 74 ++++----------------------- 3 files changed, 10 insertions(+), 183 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 616776f..c5955f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,6 @@ md5 = "0.7.0" stderrlog = "0.6.0" strum = { version = "0.27.2", features = ["derive"] } term = "1.1.0" -termsize = "0.1.9" tokio = { version = "1.0", features = ["full"] } tokio-stream = "0.1" tokio-util = "0.7.16" diff --git a/src/modes/common.rs b/src/modes/common.rs index e8b2a0b..6f99eff 100644 --- a/src/modes/common.rs +++ b/src/modes/common.rs @@ -42,39 +42,6 @@ pub fn format_size(size: u64, human_readable: bool) -> String { } } -pub fn string_column(s: String, column_width: usize) -> String { - if column_width > 0 { - match s.char_indices().nth(column_width) { - None => s.to_string(), - Some((idx, _)) => { - if column_width > 1 { - // Find where to cut to fit the ellipsis - let mut cut_idx = idx; - // We need to make room for the ellipsis character - // Find the character boundary before the cut index - for i in (0..idx).rev() { - if s.is_char_boundary(i) { - if idx - i >= 3 { // Make sure we have enough room - cut_idx = i; - break; - } - } - } - // If we can't find a good place, just truncate without ellipsis - if cut_idx >= 3 { - format!("{}…", &s[..cut_idx - 1]) - } else { - s[..idx].to_string() - } - } else { - s[..idx].to_string() - } - } - } - } else { - s.to_string() - } -} pub fn size_column(size: u64, human_readable: bool, column_width: usize) -> String { string_column(format_size(size, human_readable), column_width) @@ -175,88 +142,3 @@ pub fn settings_output_format(settings: &config::Settings) -> OutputFormat { .unwrap_or(OutputFormat::Table) } -/// Get the terminal width, considering environment variables and actual terminal size -/// Returns 0 if output is not a terminal or width cannot be determined -pub fn get_terminal_width() -> usize { - use std::io::{stdout, IsTerminal}; - - // Check if output is a terminal - if !stdout().is_terminal() { - return 0; - } - - // Try to get width from COLUMNS environment variable first - if let Ok(columns_env) = env::var("COLUMNS") { - if let Ok(width) = columns_env.parse::() { - return width; - } - } - - // Fall back to querying the terminal size - if let Some(size) = termsize::get() { - return size.cols as usize; - } - - // Default to 80 if all else fails - 80 -} - -/// Calculate the maximum width for the last column in a table -/// Takes into account the widths of other columns and table borders -pub fn calculate_last_column_width(column_widths: &[usize], terminal_width: usize) -> usize { - if terminal_width == 0 { - return 0; - } - - // Each column has 1 character padding on each side, and there are borders between columns - // The table format uses '│' characters between columns, which take 1 character each - let total_other_columns_width: usize = column_widths.iter().map(|&w| w + 2).sum(); - let border_characters = column_widths.len().saturating_sub(1); - - // Total width used by other columns and their formatting - let used_width = total_other_columns_width + border_characters; - - if used_width >= terminal_width { - return 0; - } - - // The last column also has 2 characters for padding - terminal_width - used_width - 2 -} - -/// Truncate a string to fit within a maximum width, adding an ellipsis if truncated -pub fn truncate_with_ellipsis(s: &str, max_width: usize) -> String { - debug!("Truncating '{}' to max_width: {}", s, max_width); - if max_width == 0 { - debug!("Max width is 0, returning empty string"); - return String::new(); - } - - let char_count = s.chars().count(); - if char_count <= max_width { - debug!("String fits within max_width ({} <= {}), returning original", char_count, max_width); - return s.to_string(); - } - - // We need to truncate and add an ellipsis - // The ellipsis takes 1 character, so we can show max_width-1 characters - if max_width == 1 { - debug!("Max width is 1, returning ellipsis only"); - return "…".to_string(); - } - - let mut result = String::new(); - let mut current_width = 0; - - for c in s.chars() { - if current_width + 1 > max_width - 1 { - break; - } - result.push(c); - current_width += 1; - } - - result.push('…'); - debug!("Truncated result: '{}'", result); - result -} diff --git a/src/modes/list.rs b/src/modes/list.rs index ab8ec2a..b16db5e 100644 --- a/src/modes/list.rs +++ b/src/modes/list.rs @@ -52,14 +52,6 @@ pub fn mode_list( return show_list_structured(items_with_meta, data_path, settings, output_format); } - // Check if output is a terminal - let is_terminal = stdout().is_terminal(); - debug!("Output is terminal: {}", is_terminal); - - // Get terminal width using the common function - let term_width = crate::modes::common::get_terminal_width(); - debug!("Terminal width: {}", term_width); - let mut table = Table::new(); table .load_preset(NOTHING) @@ -91,45 +83,6 @@ pub fn mode_list( .unwrap_or_else(|_| panic!("Unknown column {:?}", column.name)); let mut meta_name: Option<&str> = None; - - // Parse max_len, handling numbers, percentages, and negative values - // Only apply max_len when output is a terminal - let column_width = if is_terminal { - if let Some(max_len_str) = &column.max_len { - debug!("Processing max_len for column '{}': {}", column.name, max_len_str); - // Check if it's a negative number - if max_len_str.starts_with('-') { - // Parse as negative number - let abs_value = max_len_str[1..].parse::().unwrap_or(0); - if abs_value > term_width { - 0 - } else { - term_width - abs_value - } - } else if max_len_str.ends_with('%') { - // Parse percentage - let percent_str = max_len_str.trim_end_matches('%'); - let percent = percent_str.parse::().unwrap_or(0.0); - debug!("Percentage: {}%", percent); - let computed_width = (term_width as f64 * percent / 100.0) as usize; - debug!("Computed width: {}", computed_width); - computed_width - } else { - // Parse absolute number - let absolute_width = max_len_str.parse::().unwrap_or(0); - debug!("Absolute width: {}", absolute_width); - absolute_width - } - } else { - debug!("No max_len specified for column '{}'", column.name); - 0 - } - } else { - debug!("Output is not a terminal, ignoring max_len"); - 0 - }; - - debug!("Final column width for '{}': {}", column.name, column_width); if let ColumnType::Meta = column_type { let parts: Vec<&str> = column.name.split(':').collect(); @@ -140,8 +93,7 @@ pub fn mode_list( let cell = match column_type { ColumnType::Id => { - let mut cell = - Cell::new(&string_column(item.id.unwrap_or(0).to_string(), column_width)); + let mut cell = Cell::new(item.id.unwrap_or(0).to_string()); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right); @@ -153,13 +105,12 @@ pub fn mode_list( cell } ColumnType::Time => { - let mut cell = Cell::new(&string_column( + let mut cell = Cell::new( item.ts .with_timezone(&chrono::Local) .format("%F %T") .to_string(), - column_width, - )); + ); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right); @@ -172,10 +123,9 @@ pub fn mode_list( } ColumnType::Size => match item.size { Some(size) => { - let mut cell = Cell::new(&size_column( + let mut cell = Cell::new(format_size( size as u64, settings.human_readable, - column_width, )); match column.align { crate::config::ColumnAlignment::Right => { @@ -208,8 +158,7 @@ pub fn mode_list( } }, ColumnType::Compression => { - let mut cell = - Cell::new(&string_column(item.compression.to_string(), column_width)); + let mut cell = Cell::new(item.compression.to_string()); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right); @@ -222,10 +171,9 @@ pub fn mode_list( } ColumnType::FileSize => match item_path.metadata() { Ok(metadata) => { - let mut cell = Cell::new(&size_column( + let mut cell = Cell::new(format_size( metadata.len(), settings.human_readable, - column_width, )); match column.align { crate::config::ColumnAlignment::Right => { @@ -253,10 +201,9 @@ pub fn mode_list( } }, ColumnType::FilePath => { - let mut cell = Cell::new(&string_column( + let mut cell = Cell::new( item_path.clone().into_os_string().into_string().unwrap(), - column_width, - )); + ); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right); @@ -268,7 +215,7 @@ pub fn mode_list( cell } ColumnType::Tags => { - let mut cell = Cell::new(&string_column(tags.join(" "), column_width)); + let mut cell = Cell::new(tags.join(" ")); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right); @@ -282,8 +229,7 @@ pub fn mode_list( ColumnType::Meta => match meta_name { Some(meta_name) => match meta.get(meta_name) { Some(meta_value) => { - let mut cell = - Cell::new(&string_column(meta_value.to_string(), column_width)); + let mut cell = Cell::new(meta_value.to_string()); match column.align { crate::config::ColumnAlignment::Right => { cell = cell.set_alignment(CellAlignment::Right);