xlsx2adoc/
xlsx2adoc.rs

1use std::cmp;
2use std::io::BufWriter;
3use std::io::Error;
4use std::io::Write;
5use std::path::Path;
6
7use std::fs::File;
8
9use edit_xlsx::Read;
10use edit_xlsx::WorkSheet;
11use edit_xlsx::WorkSheetCol;
12use edit_xlsx::{FormatColor, Workbook, WorkbookResult};
13use std::ops::RangeInclusive;
14
15
16use std::io::{ErrorKind};
17
18pub fn error_text(text: &str) -> Error {
19    Error::new(ErrorKind::Other, text)
20}
21
22pub fn tab_header(widths: &Vec<f64>) -> String {
23    let mut out = "[cols=\"".to_owned();
24
25    for w in widths.iter().enumerate() {
26        let w100 = w.1 * 100.0;
27        let w100 = w100.round();
28        let w100 = w100 as u32;
29        out += &format!("{}", w100);
30        if w.0 < widths.len() - 1 {
31            out += ", ";
32        };
33    }
34    out + "\"]\r"
35}
36#[derive(Default)]
37pub struct Xlsx2AdocTestResults {
38    // Todo
39    v1: u8,
40    pub v2: u8,
41}
42
43pub(crate) fn to_col(col: &str) -> u32 {
44    let mut col = col.as_bytes();
45    let mut num = 0;
46    while !col.is_empty() {
47        if col[0] > 64 && col[0] < 91 {
48            num *= 26;
49            num += (col[0] - 64) as u32;
50        }
51        col = &col[1..];
52    }
53    num
54}
55
56fn decode_col_range(column_name: &str, length: usize) -> RangeInclusive<usize> {
57    let mut nn = column_name.split(':');
58    let nl = nn.next();
59    let nl = nl.unwrap();
60    let cl = to_col(nl) as usize;
61    let nh = nn.next();
62    let nh = nh.unwrap();
63    let ch = cmp::min(to_col(nh) as usize, length);
64    cl - 1..=ch - 1
65}
66
67fn find_col_width(sheet: &WorkSheet) -> Result<Vec<f64>, Error> {
68    let mut widths = Vec::<f64>::new();
69    let default_col_width = sheet.get_default_column().unwrap_or(1.0);
70
71    for _ in 0..sheet.max_column() {
72        widths.push(default_col_width);
73    }
74
75    let formatted_col_result = sheet.get_columns_with_format((1, 1, 1, 16384));
76    let formatted_col = match formatted_col_result {
77        Ok(f) => f,
78        Err(e) => return Err(error_text(&format!("{:?}", e))),
79    };
80
81    for w in formatted_col.iter() {
82        let column_name = w.0;
83        let a = w.1;
84        let columns_specs = a.0;
85        let column_width = columns_specs.width;
86        match column_width {
87            Some(width) => {
88                let col_range = decode_col_range(column_name, widths.len());
89                for c in col_range {
90                    widths[c] = width;
91                }
92            }
93            None => {},
94        };
95}
96    Ok(widths)
97}
98
99pub fn xlsx_convert(
100    in_file_name: &Path,
101    out_file_name: &Path,
102) -> Result<Xlsx2AdocTestResults, Error> {
103    let workbook = Workbook::from_path(in_file_name);
104    let mut workbook = workbook.unwrap();
105    workbook.finish();
106
107    let reading_sheet = workbook.get_worksheet(1);
108    let sheet = reading_sheet.unwrap();
109    let default_row_hight = sheet.get_default_row();
110
111    println!(
112        "Rows {} -> ? ( {} )",
113        sheet.max_row(),
114        //        formatted_row.len(),
115        default_row_hight
116    );
117
118    let mut hights = Vec::<f64>::new();
119    for _ in 0..sheet.max_row() {
120        hights.push(default_row_hight);
121    }
122
123    let widths = find_col_width(sheet)?;
124    let bounds = "|===\r";
125    let line = tab_header(&widths);
126
127    let mut output_file = File::create(out_file_name)?; // overwrites existing file
128    let mut writer = BufWriter::new(&mut output_file);
129
130    writer.write(line.as_bytes())?;
131    writer.write(bounds.as_bytes())?;
132
133    /*     // todo test
134       writer.write("|1|2|3\r".as_bytes())?;
135       writer.write("|4|5|6\r".as_bytes())?;
136
137       writer.write(bounds.as_bytes())?;
138    */
139    for row in 0..sheet.max_row() {
140        println!("Row {} ({})", row, hights[row as usize]);
141        for col in 0..sheet.max_column() {
142            if col < sheet.max_column() {
143                writer.write("|".as_bytes())?;
144            }
145
146            let cell_content = sheet.read_cell((row + 1, col + 1)).unwrap_or_default();
147            let format = cell_content.format;
148            let mut text_color = FormatColor::Default;
149            let mut bg_color = FormatColor::Default;
150            let mut bg_bg_color = FormatColor::Default;
151            if format.is_some() {
152                let format = format.unwrap();
153                text_color = format.get_color().clone();
154                let ff = format.get_background().clone();
155                bg_color = ff.fg_color.clone();
156                bg_bg_color = ff.bg_color.clone();
157            }
158
159            let cell_format_string = format!(
160                "Text-Color = {:?}        bg = {:?}        bg_bg = {:?}",
161                text_color, bg_color, bg_bg_color
162            );
163            let cell_text = cell_content.text;
164            let text = match cell_text {
165                Some(t) => t,
166                None => "-".to_owned(),
167            };
168
169            println!(
170                "{} ({}) -> {}     Format: {}",
171                col,
172                widths[(col) as usize],
173                text,
174                cell_format_string
175            );
176            writer.write(text.as_bytes())?;
177        }
178
179        writer.write("\r".as_bytes())?;
180    }
181    writer.write(bounds.as_bytes())?;
182
183    let xlsx_2_adoc_test_results = Xlsx2AdocTestResults { v1: 0, v2: 0 };
184    Ok(xlsx_2_adoc_test_results)
185}
186
187const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
188fn main() -> std::io::Result<()> {
189    let (in_file_name, out_file_name) = (
190        Path::new("./tests/xlsx/business-budget.xlsx"),
191        Path::new("./examples/accounting.adoc"),
192    );
193
194    println!(
195        "{} {} -> {}",
196        CARGO_PKG_NAME,
197        in_file_name.display(),
198        out_file_name.display()
199    );
200
201    xlsx_convert(&in_file_name, &out_file_name)?;
202    Ok(())
203}