From f5bae4662093ab35ded6cb9f0fd2b4b24dc74457 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Sat, 14 Mar 2026 19:49:31 -0300 Subject: [PATCH] fix: all tables respect table_config from settings Extract shared render_item_info_table() and render_list_table() in modes/common.rs. Update client/info, client/list, client/status, info, status, and status_plugins to use create_table_with_config with settings.table_config instead of hardcoded presets. Previously only local --list used table_config; all other tables (client modes, status, status-plugins) ignored it. --- src/modes/client/info.rs | 43 +++++++-------- src/modes/client/list.rs | 43 ++++++--------- src/modes/client/status.rs | 9 ++- src/modes/common.rs | 107 +++++++++++++++++++++++++++++------- src/modes/info.rs | 74 +++++++------------------ src/modes/status.rs | 19 ++++--- src/modes/status_plugins.rs | 26 ++++++--- 7 files changed, 181 insertions(+), 140 deletions(-) diff --git a/src/modes/client/info.rs b/src/modes/client/info.rs index d8b19b2..8352058 100644 --- a/src/modes/client/info.rs +++ b/src/modes/client/info.rs @@ -1,5 +1,7 @@ use crate::client::KeepClient; -use crate::modes::common::{OutputFormat, format_size, settings_output_format}; +use crate::modes::common::{ + DisplayItemInfo, OutputFormat, format_size, render_item_info_table, settings_output_format, +}; use clap::Command; use log::debug; @@ -36,27 +38,24 @@ pub fn mode( println!("{}", serde_yaml::to_string(&item)?); } OutputFormat::Table => { - use comfy_table::{Table, presets::UTF8_FULL}; - - let mut table = Table::new(); - table.load_preset(UTF8_FULL); - - let size_str = item - .size - .map(|s| format_size(s as u64, settings.human_readable)) - .unwrap_or_else(|| "N/A".to_string()); - - table.add_row(vec!["ID".to_string(), item.id.to_string()]); - table.add_row(vec!["Time".to_string(), item.ts.clone()]); - table.add_row(vec!["Size".to_string(), size_str]); - table.add_row(vec!["Compression".to_string(), item.compression.clone()]); - table.add_row(vec!["Tags".to_string(), item.tags.join(", ")]); - - for (key, value) in &item.metadata { - table.add_row(vec![format!("Meta: {}", key), value.clone()]); - } - - println!("{table}"); + let display = DisplayItemInfo { + id: item.id, + timestamp: item.ts.clone(), + path: String::new(), + stream_size: item + .size + .map(|s| format_size(s as u64, settings.human_readable)) + .unwrap_or_else(|| "N/A".to_string()), + compression: item.compression.clone(), + file_size: String::new(), + tags: item.tags.clone(), + metadata: item + .metadata + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + }; + render_item_info_table(&display, &settings.table_config); } } } diff --git a/src/modes/client/list.rs b/src/modes/client/list.rs index 44230ae..274cec4 100644 --- a/src/modes/client/list.rs +++ b/src/modes/client/list.rs @@ -1,5 +1,7 @@ use crate::client::KeepClient; -use crate::modes::common::{OutputFormat, format_size, settings_output_format}; +use crate::modes::common::{ + DisplayListItem, OutputFormat, format_size, render_list_table, settings_output_format, +}; use clap::Command; use log::debug; @@ -28,31 +30,20 @@ pub fn mode( println!("{}", serde_yaml::to_string(&items)?); } OutputFormat::Table => { - use comfy_table::{Table, presets::UTF8_FULL}; - - let mut table = Table::new(); - table.load_preset(UTF8_FULL); - - // Header - let headers = ["ID", "Time", "Size", "Compression", "Tags"]; - table.set_header(headers.iter().map(|h| h.to_string()).collect::>()); - - for item in &items { - let size_str = item - .size - .map(|s| format_size(s as u64, settings.human_readable)) - .unwrap_or_default(); - - table.add_row(vec![ - item.id.to_string(), - item.ts.clone(), - size_str, - item.compression.clone(), - item.tags.join(", "), - ]); - } - - println!("{table}"); + let display_items: Vec = items + .iter() + .map(|item| DisplayListItem { + id: item.id, + time: item.ts.clone(), + size: item + .size + .map(|s| format_size(s as u64, settings.human_readable)) + .unwrap_or_default(), + compression: item.compression.clone(), + tags: item.tags.clone(), + }) + .collect(); + render_list_table(&display_items, &settings.table_config); } } diff --git a/src/modes/client/status.rs b/src/modes/client/status.rs index 59568b4..a334b7b 100644 --- a/src/modes/client/status.rs +++ b/src/modes/client/status.rs @@ -25,7 +25,8 @@ pub fn mode( } OutputFormat::Table => { // Paths - let mut path_table = crate::modes::common::create_table(true); + let mut path_table = + crate::modes::common::create_table_with_config(&settings.table_config); path_table.set_header(vec![ Cell::new("Type").add_attribute(Attribute::Bold), Cell::new("Path").add_attribute(Attribute::Bold), @@ -46,7 +47,8 @@ pub fn mode( let mut sorted = configured.clone(); sorted.sort_by(|a, b| a.name.cmp(&b.name)); - let mut table = crate::modes::common::create_table(true); + let mut table = + crate::modes::common::create_table_with_config(&settings.table_config); table.set_header(vec![ Cell::new("Plugin Name").add_attribute(Attribute::Bold), Cell::new("Enabled").add_attribute(Attribute::Bold), @@ -68,7 +70,8 @@ pub fn mode( // Compression if !status_info.compression.is_empty() { - let mut table = crate::modes::common::create_table(true); + let mut table = + crate::modes::common::create_table_with_config(&settings.table_config); table.set_header(vec![ Cell::new("Type").add_attribute(Attribute::Bold), Cell::new("Found").add_attribute(Attribute::Bold), diff --git a/src/modes/common.rs b/src/modes/common.rs index 1ca2ef4..3aee15b 100644 --- a/src/modes/common.rs +++ b/src/modes/common.rs @@ -337,26 +337,8 @@ pub fn trim_lines_end(s: &str) -> String { /// let mut table = create_table(true); /// table.add_row(vec!["Header1", "Header2"]); /// ``` -pub fn create_table(use_styling: bool) -> Table { - let mut table = Table::new(); - table.set_content_arrangement(ContentArrangement::Dynamic); - - if use_styling { - if std::io::stdout().is_terminal() { - table - .load_preset(comfy_table::presets::UTF8_FULL) - .apply_modifier(comfy_table::modifiers::UTF8_SOLID_INNER_BORDERS); - } else { - table.load_preset(comfy_table::presets::ASCII_FULL); - } - } else { - table.load_preset(comfy_table::presets::NOTHING); - } - - if !std::io::stdout().is_terminal() { - table.force_no_tty(); - } - table +pub fn create_table(_use_styling: bool) -> Table { + create_table_with_config(&crate::config::TableConfig::default()) } /// Creates a table configured from application table settings. @@ -447,3 +429,88 @@ pub fn create_table_with_config(table_config: &crate::config::TableConfig) -> Ta table } + +/// Display data for a single item's detail view (used by --info). +pub struct DisplayItemInfo { + pub id: i64, + pub timestamp: String, + pub path: String, + pub stream_size: String, + pub compression: String, + pub file_size: String, + pub tags: Vec, + pub metadata: Vec<(String, String)>, +} + +/// Display data for a single list row (used by --list). +pub struct DisplayListItem { + pub id: i64, + pub time: String, + pub size: String, + pub compression: String, + pub tags: Vec, +} + +/// Renders item detail table. Shared by local and client info modes. +pub fn render_item_info_table(info: &DisplayItemInfo, table_config: &config::TableConfig) { + use comfy_table::{Attribute, Cell}; + + let mut table = create_table_with_config(table_config); + + table.add_row(vec![ + Cell::new("ID").add_attribute(Attribute::Bold), + Cell::new(info.id.to_string()), + ]); + table.add_row(vec![ + Cell::new("Time").add_attribute(Attribute::Bold), + Cell::new(&info.timestamp), + ]); + table.add_row(vec![ + Cell::new("Size").add_attribute(Attribute::Bold), + Cell::new(&info.stream_size), + ]); + table.add_row(vec![ + Cell::new("Compression").add_attribute(Attribute::Bold), + Cell::new(&info.compression), + ]); + table.add_row(vec![ + Cell::new("Tags").add_attribute(Attribute::Bold), + Cell::new(info.tags.join(" ")), + ]); + + for (key, value) in &info.metadata { + table.add_row(vec![ + Cell::new(format!("Meta: {key}")).add_attribute(Attribute::Bold), + Cell::new(value), + ]); + } + + println!("{}", trim_lines_end(&table.trim_fmt())); +} + +/// Renders list table. Shared by local and client list modes. +pub fn render_list_table(items: &[DisplayListItem], table_config: &config::TableConfig) { + use comfy_table::{Attribute, Cell}; + + let mut table = create_table_with_config(table_config); + + table.set_header(vec![ + Cell::new("ID").add_attribute(Attribute::Bold), + Cell::new("Time").add_attribute(Attribute::Bold), + Cell::new("Size").add_attribute(Attribute::Bold), + Cell::new("Compression").add_attribute(Attribute::Bold), + Cell::new("Tags").add_attribute(Attribute::Bold), + ]); + + for item in items { + table.add_row(vec![ + item.id.to_string(), + item.time.clone(), + item.size.clone(), + item.compression.clone(), + item.tags.join(" "), + ]); + } + + println!("{}", trim_lines_end(&table.trim_fmt())); +} diff --git a/src/modes/info.rs b/src/modes/info.rs index cd4823e..ed753b8 100644 --- a/src/modes/info.rs +++ b/src/modes/info.rs @@ -1,5 +1,5 @@ use crate::config; -use crate::modes::common::{OutputFormat, format_size}; +use crate::modes::common::{DisplayItemInfo, OutputFormat, format_size, render_item_info_table}; use crate::services::types::ItemWithMeta; use anyhow::{Context, Result, anyhow}; use clap::Command; @@ -9,7 +9,6 @@ use std::path::PathBuf; use crate::services::item_service::ItemService; use chrono::prelude::*; -use comfy_table::{Attribute, Cell}; /// Displays detailed information about an item or the last item if no ID/tags specified. /// @@ -148,73 +147,40 @@ fn show_item( let item_id = item.id.context("Item missing ID")?; let item_tags: Vec = item_with_meta.tags.iter().map(|t| t.name.clone()).collect(); - let mut table = crate::modes::common::create_table(false); - - // Add all the rows - table.add_row(vec![ - Cell::new("ID").add_attribute(Attribute::Bold), - Cell::new(item_id.to_string()), - ]); - - let timestamp_str = item.ts.with_timezone(&Local).format("%F %T %Z").to_string(); - table.add_row(vec![ - Cell::new("Timestamp").add_attribute(Attribute::Bold), - Cell::new(×tamp_str), - ]); - let mut item_path_buf = data_path.clone(); item_path_buf.push(item_id.to_string()); - let path_str = item_path_buf - .to_str() - .ok_or_else(|| anyhow::anyhow!("non-UTF-8 item path"))? - .to_string(); - table.add_row(vec![ - Cell::new("Path").add_attribute(Attribute::Bold), - Cell::new(&path_str), - ]); let size_str = match item.size { Some(size) => format_size(size as u64, settings.human_readable), None => "Missing".to_string(), }; - table.add_row(vec![ - Cell::new("Stream Size").add_attribute(Attribute::Bold), - Cell::new(&size_str), - ]); - - table.add_row(vec![ - Cell::new("Compression").add_attribute(Attribute::Bold), - Cell::new(&item.compression), - ]); let file_size_str = match item_path_buf.metadata() { Ok(metadata) => format_size(metadata.len(), settings.human_readable), Err(_) => "Missing".to_string(), }; - table.add_row(vec![ - Cell::new("File Size").add_attribute(Attribute::Bold), - Cell::new(&file_size_str), - ]); - let tags_str = item_tags.join(" "); - table.add_row(vec![ - Cell::new("Tags").add_attribute(Attribute::Bold), - Cell::new(&tags_str), - ]); + let metadata: Vec<(String, String)> = item_with_meta + .meta + .iter() + .map(|m| (m.name.clone(), m.value.clone())) + .collect(); - // Add meta rows - for meta in item_with_meta.meta { - let meta_name = format!("Meta: {}", &meta.name); - table.add_row(vec![ - Cell::new(&meta_name).add_attribute(Attribute::Bold), - Cell::new(&meta.value), - ]); - } + let display = DisplayItemInfo { + id: item_id, + timestamp: item.ts.with_timezone(&Local).format("%F %T %Z").to_string(), + path: item_path_buf + .to_str() + .ok_or_else(|| anyhow::anyhow!("non-UTF-8 item path"))? + .to_string(), + stream_size: size_str, + compression: item.compression.clone(), + file_size: file_size_str, + tags: item_tags, + metadata, + }; - println!( - "{}", - crate::modes::common::trim_lines_end(&table.trim_fmt()) - ); + render_item_info_table(&display, &settings.table_config); Ok(()) } diff --git a/src/modes/status.rs b/src/modes/status.rs index fdcd49e..f9ba839 100644 --- a/src/modes/status.rs +++ b/src/modes/status.rs @@ -14,8 +14,8 @@ use crate::common::status::PathInfo; use crate::meta_plugin::MetaPluginType; use crate::meta_plugin::get_meta_plugin; -fn build_path_table(path_info: &PathInfo) -> Table { - let mut path_table = crate::modes::common::create_table(true); +fn build_path_table(path_info: &PathInfo, table_config: &config::TableConfig) -> Table { + let mut path_table = crate::modes::common::create_table_with_config(table_config); path_table.set_header(vec![ Cell::new("Type").add_attribute(Attribute::Bold), @@ -29,7 +29,7 @@ fn build_path_table(path_info: &PathInfo) -> Table { } fn build_config_table(settings: &config::Settings) -> Table { - let mut config_table = crate::modes::common::create_table(true); + let mut config_table = crate::modes::common::create_table_with_config(&settings.table_config); config_table.set_header(vec![ Cell::new("Setting").add_attribute(Attribute::Bold), @@ -52,7 +52,10 @@ fn build_config_table(settings: &config::Settings) -> Table { config_table } -fn build_meta_plugins_configured_table(status_info: &StatusInfo) -> Option { +fn build_meta_plugins_configured_table( + status_info: &StatusInfo, + table_config: &config::TableConfig, +) -> Option
{ let meta_plugins = status_info.configured_meta_plugins.as_ref()?; if meta_plugins.is_empty() { return None; @@ -62,7 +65,7 @@ fn build_meta_plugins_configured_table(status_info: &StatusInfo) -> Option
, + table_config: &crate::config::TableConfig, ) -> Table { // Builds a formatted table displaying meta plugin information. // @@ -72,7 +73,7 @@ fn build_meta_plugin_table( // # Returns // // A formatted `comfy_table::Table`. - let mut meta_plugin_table = crate::modes::common::create_table(true); + let mut meta_plugin_table = crate::modes::common::create_table_with_config(table_config); meta_plugin_table.set_header(vec![ Cell::new("Plugin Name").add_attribute(Attribute::Bold), @@ -126,7 +127,10 @@ fn build_meta_plugin_table( meta_plugin_table } -fn build_compression_table(compression_info: &Vec) -> Table { +fn build_compression_table( + compression_info: &Vec, + table_config: &crate::config::TableConfig, +) -> Table { // Builds a formatted table displaying compression plugin information. // // # Arguments @@ -136,7 +140,7 @@ fn build_compression_table(compression_info: &Vec) -> Table { // # Returns // // A formatted `comfy_table::Table`. - let mut compression_table = crate::modes::common::create_table(true); + let mut compression_table = crate::modes::common::create_table_with_config(table_config); compression_table.set_header(vec![ Cell::new("Type").add_attribute(Attribute::Bold), @@ -167,7 +171,10 @@ fn build_compression_table(compression_info: &Vec) -> Table { compression_table } -fn build_filter_plugin_table(filter_plugins: &[crate::common::status::FilterPluginInfo]) -> Table { +fn build_filter_plugin_table( + filter_plugins: &[crate::common::status::FilterPluginInfo], + table_config: &crate::config::TableConfig, +) -> Table { // Builds a formatted table displaying filter plugin information. // // Sorts plugins by name and formats options as YAML sequence. @@ -179,7 +186,7 @@ fn build_filter_plugin_table(filter_plugins: &[crate::common::status::FilterPlug // # Returns // // A formatted `comfy_table::Table`. - let mut filter_plugin_table = crate::modes::common::create_table(true); + let mut filter_plugin_table = crate::modes::common::create_table_with_config(table_config); filter_plugin_table.set_header(vec![ Cell::new("Plugin Name").add_attribute(Attribute::Bold), @@ -304,7 +311,8 @@ pub fn mode_status_plugins( match output_format { OutputFormat::Table => { println!("META PLUGINS:"); - let meta_table = build_meta_plugin_table(&status_info.meta_plugins); + let meta_table = + build_meta_plugin_table(&status_info.meta_plugins, &settings.table_config); println!( "{}", crate::modes::common::trim_lines_end(&meta_table.trim_fmt()) @@ -312,7 +320,8 @@ pub fn mode_status_plugins( println!(); println!("COMPRESSION PLUGINS:"); - let compression_table = build_compression_table(&status_info.compression); + let compression_table = + build_compression_table(&status_info.compression, &settings.table_config); println!( "{}", crate::modes::common::trim_lines_end(&compression_table.trim_fmt()) @@ -320,7 +329,8 @@ pub fn mode_status_plugins( println!(); println!("FILTER PLUGINS:"); - let filter_table = build_filter_plugin_table(&status_info.filter_plugins); + let filter_table = + build_filter_plugin_table(&status_info.filter_plugins, &settings.table_config); println!( "{}", crate::modes::common::trim_lines_end(&filter_table.trim_fmt())