diff --git a/src/config.rs b/src/config.rs index 9d248cd..952be85 100644 --- a/src/config.rs +++ b/src/config.rs @@ -24,6 +24,91 @@ pub enum ColumnAlignment { Center, } +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "lowercase")] +pub enum ContentArrangement { + #[default] + Dynamic, + DynamicFullWidth, + Disabled, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "lowercase")] +pub enum TableStyle { + #[default] + Ascii, + Utf8, + Utf8Full, + Nothing, + Custom(String), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TableColor { + Black, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + White, + Gray, + DarkRed, + DarkGreen, + DarkYellow, + DarkBlue, + DarkMagenta, + DarkCyan, + Rgb(u8, u8, u8), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TableAttribute { + Bold, + Dim, + Italic, + Underlined, + SlowBlink, + RapidBlink, + Reverse, + Hidden, + CrossedOut, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct TableConfig { + #[serde(default)] + pub style: TableStyle, + #[serde(default)] + pub modifiers: Vec, + #[serde(default)] + pub content_arrangement: ContentArrangement, + #[serde(default)] + pub truncation_indicator: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct ColumnConfig { + pub name: String, + pub label: String, + #[serde(default)] + pub align: ColumnAlignment, + #[serde(default)] + pub max_len: Option, + #[serde(default)] + pub fg_color: Option, + #[serde(default)] + pub bg_color: Option, + #[serde(default)] + pub attributes: Vec, + #[serde(default)] + pub padding: Option<(u16, u16)>, +} + impl<'de> serde::Deserialize<'de> for ColumnConfig { fn deserialize(deserializer: D) -> Result where @@ -83,6 +168,8 @@ pub struct Settings { pub dir: PathBuf, pub list_format: Vec, #[serde(default)] + pub table_config: TableConfig, + #[serde(default)] pub human_readable: bool, pub output_format: Option, #[serde(default)] @@ -210,42 +297,70 @@ impl Settings { label: "Item".to_string(), align: ColumnAlignment::Right, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "time".to_string(), label: "Time".to_string(), align: ColumnAlignment::Right, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "size".to_string(), label: "Size".to_string(), align: ColumnAlignment::Right, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "meta:text_line_count".to_string(), label: "Lines".to_string(), align: ColumnAlignment::Right, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "tags".to_string(), label: "Tags".to_string(), align: ColumnAlignment::Left, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "meta:hostname_short".to_string(), label: "Host".to_string(), align: ColumnAlignment::Left, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ColumnConfig { name: "meta:command".to_string(), label: "Command".to_string(), align: ColumnAlignment::Left, max_len: None, + fg_color: None, + bg_color: None, + attributes: Vec::new(), + padding: None, }, ]; } diff --git a/src/modes/common.rs b/src/modes/common.rs index 19ed09c..f70e5d4 100644 --- a/src/modes/common.rs +++ b/src/modes/common.rs @@ -171,3 +171,57 @@ pub fn create_table(use_styling: bool) -> Table { table } +/// Create a table using the provided table configuration +pub fn create_table_with_config(table_config: &crate::config::TableConfig) -> Table { + let mut table = Table::new(); + + // Set content arrangement + match table_config.content_arrangement { + ContentArrangement::Dynamic => table.set_content_arrangement(ContentArrangement::Dynamic), + ContentArrangement::DynamicFullWidth => table.set_content_arrangement(ContentArrangement::DynamicFullWidth), + ContentArrangement::Disabled => table.set_content_arrangement(ContentArrangement::Disabled), + } + + // Set style preset + match &table_config.style { + crate::config::TableStyle::Ascii => table.load_preset(comfy_table::presets::ASCII_FULL), + crate::config::TableStyle::Utf8 => table.load_preset(comfy_table::presets::UTF8_FULL), + crate::config::TableStyle::Utf8Full => table.load_preset(comfy_table::presets::UTF8_FULL), + crate::config::TableStyle::Nothing => table.load_preset(comfy_table::presets::NOTHING), + crate::config::TableStyle::Custom(preset) => { + // For custom presets, we'd need to parse the string + // This is a placeholder for custom preset handling + if preset == "ASCII_FULL" { + table.load_preset(comfy_table::presets::ASCII_FULL); + } else if preset == "UTF8_FULL" { + table.load_preset(comfy_table::presets::UTF8_FULL); + } else if preset == "NOTHING" { + table.load_preset(comfy_table::presets::NOTHING); + } + // Add more presets as needed + } + } + + // Apply modifiers + for modifier in &table_config.modifiers { + match modifier.as_str() { + "UTF8_SOLID_INNER_BORDERS" => table.apply_modifier(comfy_table::modifiers::UTF8_SOLID_INNER_BORDERS), + "UTF8_ROUND_CORNERS" => table.apply_modifier(comfy_table::modifiers::UTF8_ROUND_CORNERS), + "UTF8_NO_BORDERS" => table.apply_modifier(comfy_table::modifiers::UTF8_NO_BORDERS), + "UTF8_NO_LINES" => table.apply_modifier(comfy_table::modifiers::UTF8_NO_LINES), + _ => {} // Ignore unknown modifiers + } + } + + // Set truncation indicator if specified + if !table_config.truncation_indicator.is_empty() { + table.set_truncation_indicator(&table_config.truncation_indicator); + } + + if !std::io::stdout().is_terminal() { + table.force_no_tty(); + } + + table +} + diff --git a/src/modes/list.rs b/src/modes/list.rs index ffdcfc0..b60fdc8 100644 --- a/src/modes/list.rs +++ b/src/modes/list.rs @@ -27,6 +27,59 @@ struct ListItem { meta: std::collections::HashMap, } +// Helper function to apply color to a cell +fn apply_color(mut cell: Cell, color: &crate::config::TableColor, is_foreground: bool) -> Cell { + use crate::config::TableColor::*; + use comfy_table::Color; + + let comfy_color = match color { + Black => Color::Black, + Red => Color::Red, + Green => Color::Green, + Yellow => Color::Yellow, + Blue => Color::Blue, + Magenta => Color::Magenta, + Cyan => Color::Cyan, + White => Color::White, + Gray => Color::Grey, + DarkRed => Color::DarkRed, + DarkGreen => Color::DarkGreen, + DarkYellow => Color::DarkYellow, + DarkBlue => Color::DarkBlue, + DarkMagenta => Color::DarkMagenta, + DarkCyan => Color::DarkCyan, + Rgb(r, g, b) => Color::Rgb { r: *r, g: *g, b: *b }, + }; + + if is_foreground { + cell = cell.fg(comfy_color); + } else { + cell = cell.bg(comfy_color); + } + + cell +} + +// Helper function to apply attribute to a cell +fn apply_attribute(mut cell: Cell, attribute: &crate::config::TableAttribute) -> Cell { + use crate::config::TableAttribute::*; + use comfy_table::Attribute; + + match attribute { + Bold => cell = cell.add_attribute(Attribute::Bold), + Dim => cell = cell.add_attribute(Attribute::Dim), + Italic => cell = cell.add_attribute(Attribute::Italic), + Underlined => cell = cell.add_attribute(Attribute::Underlined), + SlowBlink => cell = cell.add_attribute(Attribute::SlowBlink), + RapidBlink => cell = cell.add_attribute(Attribute::RapidBlink), + Reverse => cell = cell.add_attribute(Attribute::Reverse), + Hidden => cell = cell.add_attribute(Attribute::Hidden), + CrossedOut => cell = cell.add_attribute(Attribute::CrossedOut), + } + + cell +} + pub fn mode_list( cmd: &mut clap::Command, settings: &config::Settings, @@ -52,14 +105,7 @@ pub fn mode_list( return show_list_structured(items_with_meta, data_path, settings, output_format); } - let mut table = Table::new(); - table - .load_preset(NOTHING) - .set_content_arrangement(ContentArrangement::Dynamic); - - if !stdout().is_terminal() { - table.force_no_tty(); - } + let mut table = crate::modes::common::create_table_with_config(&settings.table_config); // Create header row let mut header_cells = Vec::new(); @@ -138,6 +184,25 @@ pub fn mode_list( let mut cell = Cell::new(truncated_content); + // Apply column-specific styling + if let Some(fg_color) = &column.fg_color { + cell = apply_color(cell, fg_color, true); + } + + if let Some(bg_color) = &column.bg_color { + cell = apply_color(cell, bg_color, false); + } + + for attribute in &column.attributes { + cell = apply_attribute(cell, attribute); + } + + // Apply padding if specified + if let Some((left_padding, right_padding)) = column.padding { + // Note: comfy-table doesn't directly support padding, so we'd need to handle this + // by adding spaces to the content, or use a different approach + } + // Apply styling for specific cases match column_type { ColumnType::Size => {