From bfb7851c7bc0d9d02cf964bfbf1c16e98d75b41c Mon Sep 17 00:00:00 2001 From: AlexanderHD27 Date: Sun, 25 May 2025 20:24:26 +0200 Subject: [PATCH] Made propber doc string --- src/configotron/doc/grid.rs | 278 +++++++++++++++++++++++++++++------- src/main.rs | 7 +- 2 files changed, 233 insertions(+), 52 deletions(-) diff --git a/src/configotron/doc/grid.rs b/src/configotron/doc/grid.rs index 26737f0..6ad2d32 100644 --- a/src/configotron/doc/grid.rs +++ b/src/configotron/doc/grid.rs @@ -1,12 +1,14 @@ use std::{fmt::format, usize}; +use pad::PadStr; + use crate::configotron::{conf::{UserConfigData, UserConfigItem}, doc::grid}; #[derive(Clone, PartialEq, Debug)] pub enum DocGridCellType{ Boarder, Empty, - SubMenu { name: String }, - Item { name: String }, + SubMenu { text: Vec }, + Item { text: Vec }, ItemJoin } @@ -27,12 +29,33 @@ pub enum ResultingGridCell { Cell(DocGridCellType) } +fn split_string(s: &String) -> Vec { + s.split('\n').map(|s| s.to_string()).collect::>() +} + fn user_config_item_to_grid_cells(item: &UserConfigItem) -> ResultingGridCell { + match item { - UserConfigItem::String { name, max_length } => ResultingGridCell::Cell(DocGridCellType::Item { name: name.clone() }), - UserConfigItem::IPv4 { name } => ResultingGridCell::Cell(DocGridCellType::Item { name: name.clone() }), - UserConfigItem::Boolean { name } => ResultingGridCell::Cell(DocGridCellType::Item { name: name.clone() }), - UserConfigItem::Number { name, max, min } => ResultingGridCell::Cell(DocGridCellType::Item { name: name.clone() }), + UserConfigItem::String { name, max_length } => { + ResultingGridCell::Cell(DocGridCellType::Item { text: vec![ + name.to_string(), format!("[length: 0..{}]", max_length) + ]} + )}, + UserConfigItem::IPv4 { name } => ResultingGridCell::Cell(DocGridCellType::Item { text: vec![ + name.to_string(), "[Address IPv4]".to_string() + ]}), + UserConfigItem::Boolean { name } => ResultingGridCell::Cell(DocGridCellType::Item { text: vec![ + name.to_string(), "[Yes/No]".to_string() + ] }), + UserConfigItem::Number { name, max, min } => ResultingGridCell::Cell(DocGridCellType::Item { text: vec![ + name.to_string(), + match (min, max) { + (None, None) => "[Integers]".to_string(), + (None, Some(h)) => format!("[Integers: ..{}]", h), + (Some(l), None) => format!("[Integers: {}..]", l), + (Some(l), Some(h)) => format!("[Integers: {}..{}]", l, h), + } + ] }), UserConfigItem::Submenu(user_config_data) => ResultingGridCell::Grid(DocGrid::from(user_config_data)), } } @@ -126,12 +149,66 @@ impl DocGrid { s } + + fn row_size_max(&self, c: usize) -> usize { + let max = (0..self.rows) + .map(|r| { match &self.array_cells[r*self.cols + c] { + DocGridCellType::Boarder => 1, + DocGridCellType::Empty => 1, + DocGridCellType::SubMenu { text: name } => { + name + .iter() + .map(|s| s.len()).max().unwrap_or(0) + }, + DocGridCellType::Item { text: name } => { + name + .iter() + .map(|s| s.len()).max().unwrap_or(0) + }, + DocGridCellType::ItemJoin => 1, + } }).max().unwrap_or(1); + + max + } + + pub fn row_sizes(&self) -> Vec { + let mut res = Vec::with_capacity(self.cols); + for c in 0..self.cols { + res.push(self.row_size_max(c)); + } + res + } + + fn col_size_max(&self, r: usize) -> usize { + let max = (0..self.cols) + .map(|c| { match &self.array_cells[r*self.cols + c] { + DocGridCellType::Boarder => 1, + DocGridCellType::Empty => 1, + DocGridCellType::SubMenu { text: name } => { + name.len() + }, + DocGridCellType::Item { text: name } => { + name.len() + }, + DocGridCellType::ItemJoin => 1, + } }).max().unwrap_or(1); + + max + } + + pub fn col_sizes(&self) -> Vec { + let mut res = Vec::with_capacity(self.rows); + for r in 0..self.rows { + res.push(self.col_size_max(r)); + } + res + } } impl From<&UserConfigData> for DocGrid { fn from(value: &UserConfigData) -> Self { let mut res = DocGrid::new(); - res.set_title(DocGridCellType::SubMenu { name: value.name.clone() }); + res.set_title(DocGridCellType::SubMenu { text: split_string(&value.name) }); value.config_items.iter().for_each(|i| { res.append_item(user_config_item_to_grid_cells(i)); }); @@ -174,7 +251,24 @@ pub struct DocGridLayout { lines_cross: Vec, } + impl DocGridLayout { + fn map_line_to_char(l: &DocGridLineType) -> String { + match l { + DocGridLineType::HORIZONTAL => "-".to_string(), + DocGridLineType::NONE => " ".to_string(), + DocGridLineType::VERTICAL => "|".to_string() + } + } + + fn map_cross_to_chr(c: &DocGridLineCrossType) -> String { + match c { + DocGridLineCrossType::NONE => " ".to_string(), + DocGridLineCrossType::FULL => "+".to_string(), + DocGridLineCrossType::VERTICAL => "|".to_string(), + DocGridLineCrossType::HORIZONTAL => "-".to_string(), + } + } fn get_vert_line (&self, r: i32, c: i32) -> &DocGridLineType { if r < 0 || r >= (self.grid.rows as i32) || c < 0 || c > (self.grid.cols as i32) { @@ -280,55 +374,88 @@ impl DocGridLayout { pub fn to_debug_string(&self) -> String { let mut s = String::new(); - fn map_line_to_char(l: &DocGridLineType) -> String { - match l { - DocGridLineType::HORIZONTAL => "-".to_string(), - DocGridLineType::NONE => " ".to_string(), - DocGridLineType::VERTICAL => "|".to_string() - } - } - - fn map_cross_to_chr(c: &DocGridLineCrossType) -> String { - match c { - DocGridLineCrossType::NONE => " ".to_string(), - DocGridLineCrossType::FULL => "+".to_string(), - DocGridLineCrossType::VERTICAL => "|".to_string(), - DocGridLineCrossType::HORIZONTAL => "-".to_string(), - } - } - for r in 0..self.grid.rows { for c in 0..self.grid.cols { s.push_str(&format!("{}{}", - &map_cross_to_chr(self.get_cross(r as i32, c as i32)), - &map_line_to_char(self.get_hort_line(r as i32, c as i32)) + &Self::map_cross_to_chr(self.get_cross(r as i32, c as i32)), + &Self::map_line_to_char(self.get_hort_line(r as i32, c as i32)) )); } - s.push_str(&format!("{}\n", &map_cross_to_chr(self.get_cross(r as i32, self.grid.cols as i32)))); + s.push_str(&format!("{}\n", &Self::map_cross_to_chr(self.get_cross(r as i32, self.grid.cols as i32)))); for c in 0..self.grid.cols { s.push_str(&format!("{}{}", - &map_line_to_char(self.get_vert_line(r as i32, c as i32)), + &Self::map_line_to_char(self.get_vert_line(r as i32, c as i32)), &self.grid.array_cells[self.grid.cols * r + c].to_debug_string() )); } s.push_str(&format!("{}\n", - &map_line_to_char(self.get_vert_line(r as i32, self.grid.cols as i32)))); + &Self::map_line_to_char(self.get_vert_line(r as i32, self.grid.cols as i32)))); }; for c in 0..self.grid.cols { s.push_str(&format!("{}{}", - &map_cross_to_chr(self.get_cross(self.grid.rows as i32, c as i32)), - &map_line_to_char(self.get_hort_line(self.grid.rows as i32, c as i32)) + &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, c as i32)), + &Self::map_line_to_char(self.get_hort_line(self.grid.rows as i32, c as i32)) )); } - s.push_str(&format!("{}\n", &map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32)))); + s.push_str(&format!("{}\n", &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32)))); + + s + } + + pub fn to_ascii_doc_string(&self) -> String { + let col_sizes = self.grid.col_sizes(); + let row_sizes = self.grid.row_sizes(); + let mut s = String::new(); + + let empty_string = "".to_string(); + + let map_cell = |cell: &DocGridCellType, sub_c: &usize| -> String { + match cell { + DocGridCellType::Boarder => empty_string.clone(), + DocGridCellType::Empty => empty_string.clone(), + DocGridCellType::SubMenu { text } => text.get(*sub_c).cloned().unwrap_or(empty_string.clone()), + DocGridCellType::Item { text } => text.get(*sub_c).cloned().unwrap_or(empty_string.clone()), + DocGridCellType::ItemJoin => empty_string.clone(), + } + }; + + for r in 0..self.grid.rows { + for c in 0..self.grid.cols { + s.push_str(&format!("{}{}", + &Self::map_cross_to_chr(self.get_cross(r as i32, c as i32)), + &Self::map_line_to_char(self.get_hort_line(r as i32, c as i32)).repeat(row_sizes[c] + 2) + )); + } + s.push_str(&format!("{}\n", &Self::map_cross_to_chr(self.get_cross(r as i32, self.grid.cols as i32)))); + + for sub_c in 0..col_sizes[r] { + for c in 0..self.grid.cols { + s.push_str(&format!("{} {} ", + &Self::map_line_to_char(self.get_vert_line(r as i32, c as i32)), + &map_cell(&self.grid.array_cells[self.grid.cols * r + c], &sub_c).pad_to_width(row_sizes[c]) + )); + } + s.push_str(&format!("{}\n", + &Self::map_line_to_char(self.get_vert_line(r as i32, self.grid.cols as i32)))); + } + }; + + for c in 0..self.grid.cols { + s.push_str(&format!("{}{}", + &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, c as i32)), + &Self::map_line_to_char(self.get_hort_line(self.grid.rows as i32, c as i32)).repeat(row_sizes[c] + 2) + )); + } + + s.push_str(&format!("{}\n", &Self::map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32)))); s } } -mod DocGridLayoutMappers { +mod doc_grid_layout_mappers { use super::{DocGridLineType, DocGridLineCrossType, DocGridCellType}; pub fn vert_line_ascii(left: &DocGridCellType, right: &DocGridCellType) -> DocGridLineType { @@ -374,16 +501,26 @@ mod DocGridLayoutMappers { } } -pub fn create_ascii_doc_string(grid: &DocGrid) -> String { +pub fn create_ascii_debug_string(grid: &DocGrid) -> String { let layout = DocGridLayout::new(grid, - DocGridLayoutMappers::vert_line_ascii, - DocGridLayoutMappers::hort_line_ascii, - DocGridLayoutMappers::cross_ascii + doc_grid_layout_mappers::vert_line_ascii, + doc_grid_layout_mappers::hort_line_ascii, + doc_grid_layout_mappers::cross_ascii ); return layout.to_debug_string(); } +pub fn create_ascii_doc_string(grid: &DocGrid) -> String { + let layout = DocGridLayout::new(grid, + doc_grid_layout_mappers::vert_line_ascii, + doc_grid_layout_mappers::hort_line_ascii, + doc_grid_layout_mappers::cross_ascii + ); + + return layout.to_ascii_doc_string(); +} + #[cfg(test)] mod tests { use crate::configotron::{conf::{UserConfigData, UserConfigItem}}; @@ -404,16 +541,16 @@ mod tests { // Actuall Test #[test] - fn test_grid_extend() { + fn grid_extend() { let mut grid = DocGrid::new(); - grid.set_title(DocGridCellType::SubMenu { name: "name".to_string() }); - grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { name: "name".to_string() })); + grid.set_title(DocGridCellType::SubMenu { text: vec!["name".to_string()] }); + grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { text: vec!["name".to_string()] })); grid.append_item(ResultingGridCell::Cell(DocGridCellType::ItemJoin)); - grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { name: "name".to_string() })); - grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { name: "name".to_string() })); + grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { text: vec!["name".to_string()] })); + grid.append_item(ResultingGridCell::Cell(DocGridCellType::Item { text: vec!["name".to_string()] })); grid.append_item(ResultingGridCell::Cell(DocGridCellType::ItemJoin)); - grid.append_item(ResultingGridCell::Cell(DocGridCellType::SubMenu { name: "name".to_string() })); + grid.append_item(ResultingGridCell::Cell(DocGridCellType::SubMenu { text: vec!["name".to_string()] })); assert_eq!(grid.to_debug_string(), r#"| S I | | E i | @@ -427,7 +564,7 @@ mod tests { } #[test] - fn test_grid_assembly_from_data() { + fn grid_assembly_from_data() { let data = create_menu(vec![ create_item(), create_item(), @@ -455,7 +592,7 @@ mod tests { } #[test] - fn test_grid_deep_assembly_from_data() { + fn grid_deep_assembly_from_data() { let data = create_menu(vec![ create_submenu(vec![ create_submenu(vec![ @@ -473,7 +610,7 @@ mod tests { } #[test] - fn test_grid_complex_assembly_from_data() { + fn grid_complex_assembly_from_data() { let data = create_menu(vec![ create_item(), create_item(), @@ -525,11 +662,11 @@ mod tests { } mod ascii_docs { - use crate::configotron::{conf::{UserConfigData, UserConfigItem}, doc::grid::create_ascii_doc_string}; + use crate::configotron::{conf::{UserConfigData, UserConfigItem}, doc::grid::create_ascii_debug_string, doc::grid::create_ascii_doc_string}; use super::{DocGrid, create_item, create_menu, create_submenu}; #[test] - fn ascii_docs_simple() { + fn ascii_docs_debug() { let data = create_menu(vec![ create_item(), create_item(), @@ -547,7 +684,7 @@ mod tests { println!("{}", grid.to_debug_string()); - let s = create_ascii_doc_string(&grid); + let s = create_ascii_debug_string(&grid); println!("{}", s); @@ -568,6 +705,49 @@ mod tests { | +---+ |E|I i| +-+---+ +"#); + } + + #[test] + fn ascii_docs_real() { + let data = create_menu(vec![ + create_item(), + create_item(), + create_submenu(vec![ + create_item(), + create_item(), + create_item(), + ]), + create_item(), + create_item(), + create_item() + ]); + + let grid = DocGrid::from(&data); + + println!("{}", grid.to_debug_string()); + + let s = create_ascii_doc_string(&grid); + + println!("{}", s); + + assert_eq!(s, r#"+----------+----------------+ +| TestMenu | Test | +| +----------------+ +| | Test | +| +---------+------+ +| | SubMenu | Test | +| | +------+ +| | | Test | +| | +------+ +| | | Test | +| +---------+------+ +| | Test | +| +----------------+ +| | Test | +| +----------------+ +| | Test | ++----------+----------------+ "#); } diff --git a/src/main.rs b/src/main.rs index a4a3606..3c993c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod configotron; use configotron::conf::{read_and_parse_yaml_file}; -use configotron::doc::grid::{DocGrid}; +use configotron::doc::grid::{DocGrid, create_ascii_doc_string}; fn main() { @@ -13,8 +13,9 @@ fn main() { } }; - let grid = DocGrid::from(&data); - println!("{}", grid.to_debug_string()); + let grid: DocGrid = DocGrid::from(&data); + let ascii_docs = create_ascii_doc_string(&grid); + println!("{}", ascii_docs); println!("Done!"); }