From 97670b1860704e7ebbf74cde1fb38a093a1318b0 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Wed, 20 Sep 2023 18:58:58 +0000 Subject: [PATCH] Switch --list-meta to --list-format --- src/main.rs | 133 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/src/main.rs b/src/main.rs index 88443f8..80c6bb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,9 +135,9 @@ struct OptionsArgs { #[arg(help("Specify the directory to use for storage"))] dir: Option, - #[arg(long, env("KEEP_LIST_META"), default_value("hostname"))] - #[arg(help("A comma separated list of item metadata names to display with --list"))] - list_meta: String, + #[arg(long, env("KEEP_LIST_FORMAT"), default_value("id,time,size,tags,meta:hostname"))] + #[arg(help("A comma separated list of columns to display with --list"))] + list_format: String, #[arg(short, long, action = clap::ArgAction::Count, conflicts_with("quiet"))] #[arg(help("Increase message verbosity, can be given more than once"))] @@ -190,12 +190,25 @@ enum NumberOrString { impl FromStr for NumberOrString { type Err = Error; fn from_str(s: &str) -> Result { - Ok (s.parse::() + Ok(s.parse::() .map(NumberOrString::Number) - .unwrap_or_else(|_| NumberOrString::Str (s.to_string()))) + .unwrap_or_else(|_| NumberOrString::Str(s.to_string()))) } } +#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString)] +#[strum(ascii_case_insensitive)] +pub enum ColumnType { + Id, + Time, + Size, + Compression, + FileSize, + FilePath, + Tags, + Meta +} + fn main() -> Result<(), Error> { let proj_dirs = ProjectDirs::from("gt0.ca", "Andrew Phillips", "Keep"); @@ -489,56 +502,91 @@ fn mode_list(cmd: &mut Command, args: Args, ids: &mut Vec, tags: &Vec"ID", - b->"Time", - b->"Stream Size", - b->"Comp", - b->"File Size", - b->"Tags", - ); + let list_format = args.options.list_format.split(","); - for name in meta_columns.clone() { - title_row.add_cell(Cell::new(name).with_style(Attr::Bold)); + let mut title_row = row!(); + + for column in list_format.clone() { + let mut column_format = column.split(":").into_iter(); + let column_name = column_format.next().expect("Unable to parse column name"); + let column_type = ColumnType::from_str(column_name.clone()).expect(format!("Unknown column {:?}", column_name).as_str()); + + if column_type == ColumnType::Meta { + let meta_name = column_format.next().expect("Unable to parse metadata name for meta column"); + title_row.add_cell(Cell::new(meta_name).with_style(Attr::Bold)); + } else { + title_row.add_cell(Cell::new(&column_type.to_string()).with_style(Attr::Bold)); + } } table.set_titles(title_row); for item in items { let item_id = item.id.unwrap(); + let tags = tags_by_item.get(&item_id).unwrap(); + let meta = meta_by_item.get(&item_id).unwrap(); let mut item_path = data_path.clone(); item_path.push(item.id.unwrap().to_string()); - let id_cell = Cell::new_align(&item.id.unwrap_or(0).to_string(), Alignment::RIGHT); - let ts_cell = Cell::new(&item.ts.with_timezone(&Local).format("%F %T").to_string()); - let size_cell = match item.size { - Some(size) => Cell::new_align(format_size(size as u64, BINARY).as_str(), Alignment::RIGHT), - None => Cell::new_align("Missing", Alignment::RIGHT).with_style(Attr::ForegroundColor(color::RED)).with_style(Attr::Bold) - }; - let compression_cell = Cell::new(&item.compression); - let file_size_cell = match item_path.metadata() { - Ok(metadata) => Cell::new_align(format_size(metadata.len(), BINARY).as_str(), Alignment::RIGHT), - Err(_) => Cell::new_align("Missing", Alignment::RIGHT).with_style(Attr::ForegroundColor(color::RED)).with_style(Attr::Bold) - }; + let mut table_row = Row::new(vec![]); - let item_tags = tags_by_item.get(&item_id).unwrap(); - let tags_cell = Cell::new(&item_tags.join(" ")); + for column in list_format.clone() { + let mut column_format = column.split(":").into_iter(); + let column_name = column_format.next().expect("Unable to parse column name"); + let column_type = ColumnType::from_str(column_name.clone()).expect(format!("Unknown column {:?}", column_name).as_str()); + let mut meta_name: Option<&str> = None; - let mut table_row = Row::new(vec![id_cell,ts_cell,size_cell, compression_cell, file_size_cell, tags_cell]); + if column_type == ColumnType::Meta { + meta_name = column_format.next(); + } - let item_meta = meta_by_item.get(&item_id).unwrap(); - for name in meta_columns.clone() { - match item_meta.get(name) { - Some(value) => table_row.add_cell(Cell::new(value)), - None => table_row.add_cell(Cell::new("")) + let column_width: usize = match column_format.next() { + Some(len) => len.parse().unwrap_or(0), + None => 0 }; - } + let cell = match column_type { + ColumnType::Id => Cell::new_align( + truncate_column(&item.id.unwrap_or(0).to_string(), column_width), + Alignment::RIGHT), + ColumnType::Time => Cell::new( + truncate_column(&item.ts.with_timezone(&Local).format("%F %T").to_string(), column_width)), + ColumnType::Size => match item.size { + Some(size) => Cell::new_align( + truncate_column(format_size(size as u64, BINARY).as_str(), column_width), + Alignment::RIGHT), + None => match item_path.metadata() { + Ok(_) => Cell::new_align("Unknown", Alignment::RIGHT) + .with_style(Attr::ForegroundColor(color::YELLOW)) + .with_style(Attr::Bold), + Err(_) => Cell::new_align("Missing", Alignment::RIGHT) + .with_style(Attr::ForegroundColor(color::RED)) + .with_style(Attr::Bold) + } + }, + ColumnType::Compression => Cell::new(truncate_column(&item.compression, column_width)), + ColumnType::FileSize => match item_path.metadata() { + Ok(metadata) => Cell::new_align( + truncate_column(format_size(metadata.len(), BINARY).as_str(), column_width), + Alignment::RIGHT), + Err(_) => Cell::new_align("Missing", Alignment::RIGHT) + .with_style(Attr::ForegroundColor(color::RED)).with_style(Attr::Bold) + }, + ColumnType::FilePath => Cell::new(truncate_column(&item_path.clone().into_os_string().into_string().unwrap(), column_width)), + ColumnType::Tags => Cell::new(truncate_column(tags.join(" ").as_str(), column_width)), + ColumnType::Meta => match meta_name { + Some(meta_name) => match meta.get(meta_name) { + Some(meta_value) => Cell::new(truncate_column(meta_value, column_width)), + None => Cell::new("") + }, + None => Cell::new("") + } + }; + table_row.add_cell(cell); + } table.add_row(table_row); } @@ -814,3 +862,14 @@ fn get_meta_from_env() -> HashMap { } meta_env } + +fn truncate_column(s: &str, column_width: usize) -> &str { + if column_width > 0 { + match s.char_indices().nth(column_width) { + None => s, + Some((idx, _)) => &s[..idx], + } + } else { + s + } +}