diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9285605 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'xlsxtocsv'", + "cargo": { + "args": [ + "build", + "--bin=xlsxtocsv", + "--package=xlsxtocsv" + ], + "filter": { + "name": "xlsxtocsv", + "kind": "bin" + } + }, + "args": ["--", "test_masque.csv"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'xlsxtocsv'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=xlsxtocsv", + "--package=xlsxtocsv" + ], + "filter": { + "name": "xlsxtocsv", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.~lock.test_masque.xlsx# b/.~lock.test_masque.xlsx# index 76cea7e..0fd3f8a 100644 --- a/.~lock.test_masque.xlsx# +++ b/.~lock.test_masque.xlsx# @@ -1 +1 @@ -,sanchezn,pc-sanchezn,04.10.2025 18:38,file:///home/sanchezn/.config/libreoffice/4; \ No newline at end of file +,sanchezn,pc-sanchezn,05.10.2025 16:13,file:///home/sanchezn/.config/libreoffice/4; \ No newline at end of file diff --git a/src/arguments.rs b/src/arguments.rs index 8ae9188..d8ce6c6 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -1,4 +1,23 @@ -use clap::Parser; +use clap::{Parser, ValueEnum}; + +#[derive(Clone, Debug, ValueEnum)] +pub enum FillMergedCells { + None, + Horizontal, + Vertical, + Both +} + +impl ToString for FillMergedCells { + fn to_string(&self) -> String { + match self { + FillMergedCells::None => "none".into(), + FillMergedCells::Horizontal => "horizontal".into(), + FillMergedCells::Vertical => "vertical".into(), + FillMergedCells::Both => "both".into(), + } + } +} #[derive(Parser, Debug)] pub struct Arguments { @@ -8,10 +27,13 @@ pub struct Arguments { /// Separator #[arg(short, long, default_value_t = ';')] pub separator: char, - /// Replacement char to replace separator in cells text + /// Replacement char to replace separator in textcells #[arg(short, long)] pub replacement: Option, /// include hidden lines to output #[arg(short, long, default_value_t=false)] pub include_hidden_lines: bool, + /// If merged cells, fill horizontally, vertically, both, or none + #[arg(short, long, default_value_t = FillMergedCells::None)] + pub fill_merged_cells: FillMergedCells, } diff --git a/src/xlsxtocsv.rs b/src/xlsxtocsv.rs index 88fb8f6..070518a 100644 --- a/src/xlsxtocsv.rs +++ b/src/xlsxtocsv.rs @@ -13,7 +13,14 @@ pub fn xlsxtocsv(args: &Arguments) -> Result<(), Error> { None => return Err(Error::new("cannot open sheet")), }; - let merged_cells = MergedCells::new(sheet); + let (horiz, vert) = match args.fill_merged_cells { + crate::arguments::FillMergedCells::None => (false, false), + crate::arguments::FillMergedCells::Horizontal => (true, false), + crate::arguments::FillMergedCells::Vertical => (false, true), + crate::arguments::FillMergedCells::Both => (true, true), + }; + + let merged_cells = MergedCells::new(sheet, horiz, vert); let (num_cols, num_rows) = sheet.get_highest_column_and_row(); @@ -40,15 +47,18 @@ pub fn xlsxtocsv(args: &Arguments) -> Result<(), Error> { let cell_coordinate = cell.get_coordinate(); let mut value; - if let Some((col, row)) = merged_cells.in_merged_cell(*cell_coordinate.get_col_num(), *cell_coordinate.get_row_num()) { - value = match sheet.get_cell((col,row)) { + if let Some((col, row)) = merged_cells.in_merged_cell( + *cell_coordinate.get_col_num(), + *cell_coordinate.get_row_num(), + ) { + value = match sheet.get_cell((col, row)) { Some(merged_cell) => merged_cell.get_formatted_value(), None => String::from(""), } } else { value = cell.get_formatted_value(); } - + if let Some(ref replacement) = args.replacement { value = value.replace(args.separator, replacement); } else { @@ -75,11 +85,12 @@ pub fn xlsxtocsv(args: &Arguments) -> Result<(), Error> { struct MergedCells { merged_cells: Vec, + fill_horizontal: bool, + fill_vertical: bool, } impl MergedCells { - - pub fn new(sheet: &Worksheet) -> Self { + pub fn new(sheet: &Worksheet, fill_horizontal: bool, fill_vertical: bool) -> Self { let merged = sheet.get_merge_cells(); let mut merged_cells: Vec = vec![]; @@ -87,18 +98,32 @@ impl MergedCells { merged_cells.push(cell.clone()); } - MergedCells { merged_cells } + MergedCells { + merged_cells, + fill_horizontal, + fill_vertical, + } } pub fn in_merged_cell(&self, col: u32, row: u32) -> Option<(u32, u32)> { for range in &self.merged_cells { - if col >= *range.get_coordinate_start_col().unwrap().get_num() && col <= *range.get_coordinate_end_col().unwrap().get_num() && - row >= *range.get_coordinate_start_row().unwrap().get_num() && row <= *range.get_coordinate_end_row().unwrap().get_num() { - return Some((range.get_coordinate_start_col().unwrap().get_num().clone(), (range.get_coordinate_start_row().unwrap().get_num().clone()))); + if col >= *range.get_coordinate_start_col().unwrap().get_num() + && col <= *range.get_coordinate_end_col().unwrap().get_num() + && row >= *range.get_coordinate_start_row().unwrap().get_num() + && row <= *range.get_coordinate_end_row().unwrap().get_num() + { + let col_start = range.get_coordinate_start_col().unwrap().get_num().clone(); + let row_start = range.get_coordinate_start_row().unwrap().get_num().clone(); + + if self.fill_horizontal && self.fill_vertical + || self.fill_horizontal && row == row_start + || self.fill_vertical && col == col_start + || col == col_start && row == row_start + { + return Some((col_start, row_start)); } - + } } None } - } diff --git a/test_masque.xlsx b/test_masque.xlsx index cd7043e..653d880 100644 Binary files a/test_masque.xlsx and b/test_masque.xlsx differ diff --git a/xlsxtocsv.exe b/xlsxtocsv.exe new file mode 100755 index 0000000..db91d62 Binary files /dev/null and b/xlsxtocsv.exe differ