Doc grid generation
This commit is contained in:
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@@ -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 'configotron'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=configotron",
|
||||||
|
"--package=configotron"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "configotron",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'configotron'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=configotron",
|
||||||
|
"--package=configotron"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "configotron",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
.vscode/tasks.json
vendored
17
.vscode/tasks.json
vendored
@@ -16,6 +16,23 @@
|
|||||||
"showReuseMessage": true,
|
"showReuseMessage": true,
|
||||||
"clear": true
|
"clear": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "cargo",
|
||||||
|
"command": "test",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$rustc"
|
||||||
|
],
|
||||||
|
"group": "test",
|
||||||
|
"label": "rust: cargo test",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": true,
|
||||||
|
"panel": "dedicated",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
89
Cargo.lock
generated
89
Cargo.lock
generated
@@ -8,11 +8,18 @@ version = "1.0.98"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "configotron"
|
name = "configotron"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pad",
|
"pad",
|
||||||
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yml",
|
"serde_yml",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -24,6 +31,17 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.3"
|
version = "0.15.3"
|
||||||
@@ -46,6 +64,12 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.172"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libyml"
|
name = "libyml"
|
||||||
version = "0.0.5"
|
version = "0.0.5"
|
||||||
@@ -71,6 +95,15 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.95"
|
version = "1.0.95"
|
||||||
@@ -89,6 +122,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
@@ -178,3 +241,29 @@ name = "version_check"
|
|||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ pad = "0.1.6"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_yml = "0.0.12"
|
serde_yml = "0.0.12"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
rand = "0.8"
|
||||||
|
|||||||
54
src/configotron/conf.rs
Normal file
54
src/configotron/conf.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use std::{fs};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub enum UserConfigItem {
|
||||||
|
String {
|
||||||
|
name: String,
|
||||||
|
max_length: u64
|
||||||
|
},
|
||||||
|
IPv4 {
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
Boolean {
|
||||||
|
name: String
|
||||||
|
},
|
||||||
|
Number {
|
||||||
|
name: String,
|
||||||
|
max: Option<i32>,
|
||||||
|
min: Option<i32>
|
||||||
|
},
|
||||||
|
Submenu(UserConfigData)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct UserConfigData {
|
||||||
|
pub name: String,
|
||||||
|
pub config_items: Vec<UserConfigItem>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum ConfigotronError {
|
||||||
|
#[error("IO Operation failed: {}", ._0.to_string())]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
|
||||||
|
#[error("Failed to parse YAML File: {}", ._0.to_string())]
|
||||||
|
YamlParsingError(#[from] serde_yml::Error),
|
||||||
|
|
||||||
|
#[error("Missing field {} (line {} col {}) {}", .missing_filed, .line, .col, .context)]
|
||||||
|
MissingFieldError{
|
||||||
|
col: i32,
|
||||||
|
line: i32,
|
||||||
|
missing_filed: Box<str>,
|
||||||
|
context: Box<str>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_and_parse_yaml_file(input_file: &str) -> Result<UserConfigData, ConfigotronError> {
|
||||||
|
let file_content = fs::read_to_string(&input_file)?;
|
||||||
|
let config: UserConfigData = serde_yml::from_str(&file_content)?;
|
||||||
|
return Ok(config);
|
||||||
|
}
|
||||||
575
src/configotron/doc/grid.rs
Normal file
575
src/configotron/doc/grid.rs
Normal file
@@ -0,0 +1,575 @@
|
|||||||
|
use std::{fmt::format, usize};
|
||||||
|
use crate::configotron::{conf::{UserConfigData, UserConfigItem}, doc::grid};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
pub enum DocGridCellType{
|
||||||
|
Boarder,
|
||||||
|
Empty,
|
||||||
|
SubMenu { name: String },
|
||||||
|
Item { name: String },
|
||||||
|
ItemJoin
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocGridCellType {
|
||||||
|
fn to_debug_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
DocGridCellType::Empty => "E".to_string(),
|
||||||
|
DocGridCellType::Item { .. } => "I".to_string(),
|
||||||
|
DocGridCellType::ItemJoin => "i".to_string(),
|
||||||
|
DocGridCellType::SubMenu { .. } => "S".to_string(),
|
||||||
|
DocGridCellType::Boarder => "B".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ResultingGridCell {
|
||||||
|
Grid(DocGrid),
|
||||||
|
Cell(DocGridCellType)
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Submenu(user_config_data) => ResultingGridCell::Grid(DocGrid::from(user_config_data)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DocGrid {
|
||||||
|
rows: usize,
|
||||||
|
cols: usize,
|
||||||
|
array_cells: Vec<DocGridCellType>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocGrid {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { rows: 0, cols: 2, array_cells: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.cols * self.rows
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_row(&self) -> usize {
|
||||||
|
self.rows
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_title(&mut self, cell: DocGridCellType) {
|
||||||
|
self.array_cells.resize(self.len() + self.cols, DocGridCellType::Empty);
|
||||||
|
self.array_cells[0] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_item(&mut self, item: ResultingGridCell) {
|
||||||
|
match item {
|
||||||
|
ResultingGridCell::Cell(cell_type) => {
|
||||||
|
self.array_cells.resize(self.len() + self.cols, DocGridCellType::Empty);
|
||||||
|
self.array_cells[self.rows*self.cols + 1] = cell_type;
|
||||||
|
|
||||||
|
self.rows += 1;
|
||||||
|
},
|
||||||
|
ResultingGridCell::Grid(grid) => {
|
||||||
|
let new_col_size = std::cmp::max(self.cols, grid.cols + 1);
|
||||||
|
let new_row_size = self.rows + grid.rows;
|
||||||
|
self.array_cells.resize(new_col_size * new_row_size, DocGridCellType::Empty);
|
||||||
|
|
||||||
|
|
||||||
|
let row_offset = self.rows;
|
||||||
|
let old_cols = self.cols;
|
||||||
|
self.cols = new_col_size;
|
||||||
|
self.rows = new_row_size;
|
||||||
|
|
||||||
|
for row_index in (0..new_row_size).rev() {
|
||||||
|
for col_index in (0..new_col_size).rev() {
|
||||||
|
let new_index = row_index * new_col_size + col_index;
|
||||||
|
if col_index < old_cols && row_index < self.rows {
|
||||||
|
// Reshuffel Stuff Old Stuff
|
||||||
|
let old_index = row_index * old_cols + col_index;
|
||||||
|
self.array_cells[new_index] = self.array_cells[old_index].clone();
|
||||||
|
} else {
|
||||||
|
// Make Cells left to inset empty
|
||||||
|
self.array_cells[new_index] = DocGridCellType::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy in new stuff
|
||||||
|
for row_index in 0..grid.rows {
|
||||||
|
for col_index in 0..grid.cols {
|
||||||
|
let (target_row_index, target_col_index) = (
|
||||||
|
row_index + row_offset,
|
||||||
|
col_index + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_index = target_col_index + target_row_index * self.cols;
|
||||||
|
let src_index = row_index * grid.cols + col_index;
|
||||||
|
|
||||||
|
self.array_cells[target_index] = grid.array_cells[src_index].clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_debug_string(&self) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
|
||||||
|
for row_index in 0..self.rows {
|
||||||
|
s.push_str("| ");
|
||||||
|
for col_index in 0..self.cols {
|
||||||
|
s.push_str(&format!("{} ", self.array_cells[row_index * self.cols + col_index].to_debug_string()));
|
||||||
|
}
|
||||||
|
s.push_str("|\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&UserConfigData> for DocGrid {
|
||||||
|
fn from(value: &UserConfigData) -> Self {
|
||||||
|
let mut res = DocGrid::new();
|
||||||
|
res.set_title(DocGridCellType::SubMenu { name: value.name.clone() });
|
||||||
|
value.config_items.iter().for_each(|i| {
|
||||||
|
res.append_item(user_config_item_to_grid_cells(i));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add ItemJoins
|
||||||
|
for row_index in 0..res.rows {
|
||||||
|
for col_index in 2..res.cols {
|
||||||
|
let index = col_index + row_index * res.cols;
|
||||||
|
match res.array_cells[col_index-1 + row_index * res.cols] {
|
||||||
|
DocGridCellType::Item { .. } => {
|
||||||
|
res.array_cells[index] = DocGridCellType::ItemJoin;
|
||||||
|
},
|
||||||
|
DocGridCellType::ItemJoin => {
|
||||||
|
res.array_cells[index] = DocGridCellType::ItemJoin;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum DocGridLineType {
|
||||||
|
NONE, VERTICAL, HORIZONTAL
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum DocGridLineCrossType {
|
||||||
|
NONE, FULL, VERTICAL, HORIZONTAL
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DocGridLayout {
|
||||||
|
grid: DocGrid,
|
||||||
|
lines_hort: Vec<DocGridLineType>,
|
||||||
|
lines_vert: Vec<DocGridLineType>,
|
||||||
|
lines_cross: Vec<DocGridLineCrossType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocGridLayout {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
&DocGridLineType::NONE
|
||||||
|
} else {
|
||||||
|
&self.lines_vert[r as usize * (self.grid.cols + 1) + c as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_vert_line(&mut self, r: usize, c: usize, v: DocGridLineType) {
|
||||||
|
self.lines_vert[r as usize * (self.grid.cols + 1) + c as usize] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_hort_line (&self, r: i32, c: i32) -> &DocGridLineType {
|
||||||
|
if r < 0 || r > (self.grid.rows as i32) || c < 0 || c >= (self.grid.cols as i32) {
|
||||||
|
&DocGridLineType::NONE
|
||||||
|
} else {
|
||||||
|
&self.lines_hort[(r as usize) * self.grid.cols + (c as usize)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_hort_line(&mut self, r: usize, c: usize, v: DocGridLineType) {
|
||||||
|
self.lines_hort[r as usize * (self.grid.cols) + c as usize] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_cross (&self, r: i32, c: i32) -> &DocGridLineCrossType {
|
||||||
|
if r < 0 || r > (self.grid.rows as i32) || c < 0 || c > (self.grid.cols as i32) {
|
||||||
|
&DocGridLineCrossType::NONE
|
||||||
|
} else {
|
||||||
|
&self.lines_cross[(r as usize) * (self.grid.cols + 1) + (c as usize)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cross (&mut self, r: usize, c: usize, v: DocGridLineCrossType) {
|
||||||
|
self.lines_cross[r * (self.grid.cols + 1) + c] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new<FLineV, FLineH, FCross>(grid: &DocGrid, vertical_mapper: FLineV, horizontal_mapper: FLineH, cross_mapper: FCross) -> DocGridLayout
|
||||||
|
where FLineV: Fn(&DocGridCellType, &DocGridCellType) -> DocGridLineType,
|
||||||
|
FLineH: Fn(&DocGridCellType, &DocGridCellType) -> DocGridLineType,
|
||||||
|
FCross: Fn(&DocGridLineType, &DocGridLineType, &DocGridLineType, &DocGridLineType) -> DocGridLineCrossType
|
||||||
|
{
|
||||||
|
let mut lines_hort = Vec::new();
|
||||||
|
let mut lines_vert = Vec::new();
|
||||||
|
let mut crosses = Vec::new();
|
||||||
|
|
||||||
|
lines_hort.resize(grid.cols * (1 + grid.rows), DocGridLineType::NONE);
|
||||||
|
lines_vert.resize((grid.cols + 1) * grid.rows , DocGridLineType::NONE );
|
||||||
|
crosses.resize((grid.rows + 1) * (grid.cols + 1), DocGridLineCrossType::NONE);
|
||||||
|
|
||||||
|
let mut res: DocGridLayout = DocGridLayout {
|
||||||
|
grid: grid.clone(),
|
||||||
|
lines_cross: crosses,
|
||||||
|
lines_hort: lines_hort,
|
||||||
|
lines_vert: lines_vert
|
||||||
|
};
|
||||||
|
|
||||||
|
let get_cell = |r: i32, c: i32| -> &DocGridCellType {
|
||||||
|
if r < 0 || (r as usize) >= grid.rows || c < 0 || (c as usize) >= grid.cols {
|
||||||
|
&DocGridCellType::Boarder
|
||||||
|
} else {
|
||||||
|
&grid.array_cells[r as usize * grid.cols + c as usize]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculating Lines Horizontal lines
|
||||||
|
for row in 0..(grid.rows + 1) {
|
||||||
|
for col in 0..grid.cols {
|
||||||
|
let top = get_cell(row as i32 - 1 , col as i32);
|
||||||
|
let bottom = get_cell(row as i32 , col as i32);
|
||||||
|
res.set_hort_line(row, col, horizontal_mapper(top, bottom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculating Lines Vertical lines
|
||||||
|
for row in 0..grid.get_row() {
|
||||||
|
for col in 0..(grid.cols + 1) {
|
||||||
|
let left = get_cell(row as i32, col as i32 - 1);
|
||||||
|
let right = get_cell(row as i32 , col as i32);
|
||||||
|
res.set_vert_line(row, col, vertical_mapper(left, right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Calculating Crossings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for row in 0..(grid.rows + 1) {
|
||||||
|
for col in 0..(grid.cols + 1) {
|
||||||
|
let north = res.get_vert_line((row as i32) - 1, col as i32);
|
||||||
|
let south = res.get_vert_line(row as i32, col as i32);
|
||||||
|
|
||||||
|
let east = res.get_hort_line(row as i32, col as i32);
|
||||||
|
let west = res.get_hort_line(row as i32, (col as i32) - 1);
|
||||||
|
|
||||||
|
res.set_cross(row, col, cross_mapper(north, east, south, west));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
s.push_str(&format!("{}\n", &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.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))));
|
||||||
|
};
|
||||||
|
|
||||||
|
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))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
s.push_str(&format!("{}\n", &map_cross_to_chr(self.get_cross(self.grid.rows as i32, self.grid.cols as i32))));
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod DocGridLayoutMappers {
|
||||||
|
use super::{DocGridLineType, DocGridLineCrossType, DocGridCellType};
|
||||||
|
|
||||||
|
pub fn vert_line_ascii(left: &DocGridCellType, right: &DocGridCellType) -> DocGridLineType {
|
||||||
|
use DocGridCellType::{ItemJoin, Item};
|
||||||
|
match (left, right) {
|
||||||
|
(ItemJoin, Item { .. }) => DocGridLineType::NONE,
|
||||||
|
(Item { .. }, ItemJoin) => DocGridLineType::NONE,
|
||||||
|
|
||||||
|
(_, _) => DocGridLineType::VERTICAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hort_line_ascii(top: &DocGridCellType, bottom: &DocGridCellType) -> DocGridLineType {
|
||||||
|
use DocGridCellType::{Boarder, Empty, ItemJoin, Item, SubMenu};
|
||||||
|
match (top, bottom) {
|
||||||
|
(Empty, Empty) => DocGridLineType::NONE,
|
||||||
|
|
||||||
|
// Sub Menu "Joins"
|
||||||
|
(Empty, SubMenu { .. }) => DocGridLineType::HORIZONTAL,
|
||||||
|
(SubMenu { .. }, Empty) => DocGridLineType::NONE,
|
||||||
|
(SubMenu { .. }, SubMenu { .. }) => DocGridLineType::HORIZONTAL,
|
||||||
|
|
||||||
|
// Horizontal Rules
|
||||||
|
|
||||||
|
(Boarder, _) => DocGridLineType::HORIZONTAL,
|
||||||
|
(_, Boarder) => DocGridLineType::HORIZONTAL,
|
||||||
|
|
||||||
|
(Item { .. }, _) => DocGridLineType::HORIZONTAL,
|
||||||
|
(_, Item { .. }) => DocGridLineType::HORIZONTAL,
|
||||||
|
|
||||||
|
(ItemJoin, _) => DocGridLineType::HORIZONTAL,
|
||||||
|
(_, ItemJoin) => DocGridLineType::HORIZONTAL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cross_ascii(n: &DocGridLineType, e: &DocGridLineType, s: &DocGridLineType, w: &DocGridLineType) -> DocGridLineCrossType{
|
||||||
|
use DocGridLineType::{NONE, HORIZONTAL, VERTICAL};
|
||||||
|
match (n, e, s, w) {
|
||||||
|
(VERTICAL, NONE, VERTICAL, NONE) => DocGridLineCrossType::VERTICAL,
|
||||||
|
(NONE, HORIZONTAL, NONE, HORIZONTAL) => DocGridLineCrossType::HORIZONTAL,
|
||||||
|
(_, _, _, _) => DocGridLineCrossType::FULL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_ascii_doc_string(grid: &DocGrid) -> String {
|
||||||
|
let layout = DocGridLayout::new(grid,
|
||||||
|
DocGridLayoutMappers::vert_line_ascii,
|
||||||
|
DocGridLayoutMappers::hort_line_ascii,
|
||||||
|
DocGridLayoutMappers::cross_ascii
|
||||||
|
);
|
||||||
|
|
||||||
|
return layout.to_debug_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::configotron::{conf::{UserConfigData, UserConfigItem}};
|
||||||
|
use super::{DocGrid, DocGridCellType, ResultingGridCell};
|
||||||
|
|
||||||
|
// Helper functino for creating elements for testing
|
||||||
|
fn create_item() -> UserConfigItem {
|
||||||
|
UserConfigItem::Boolean { name: "Test".to_string() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_submenu(v: Vec<UserConfigItem>) -> UserConfigItem {
|
||||||
|
UserConfigItem::Submenu(UserConfigData { name: "SubMenu".to_string(), config_items: v })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_menu(v: Vec<UserConfigItem>) -> UserConfigData {
|
||||||
|
UserConfigData { name: "TestMenu".to_string(), config_items: v }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actuall Test
|
||||||
|
#[test]
|
||||||
|
fn test_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.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::ItemJoin));
|
||||||
|
grid.append_item(ResultingGridCell::Cell(DocGridCellType::SubMenu { name: "name".to_string() }));
|
||||||
|
|
||||||
|
assert_eq!(grid.to_debug_string(), r#"| S I |
|
||||||
|
| E i |
|
||||||
|
| E I |
|
||||||
|
| E I |
|
||||||
|
| E i |
|
||||||
|
| E S |
|
||||||
|
"#);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_grid_assembly_from_data() {
|
||||||
|
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);
|
||||||
|
|
||||||
|
assert_eq!(grid.to_debug_string(), r#"| S I i |
|
||||||
|
| E I i |
|
||||||
|
| E S I |
|
||||||
|
| E E I |
|
||||||
|
| E E I |
|
||||||
|
| E I i |
|
||||||
|
| E I i |
|
||||||
|
| E I i |
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_grid_deep_assembly_from_data() {
|
||||||
|
let data = create_menu(vec![
|
||||||
|
create_submenu(vec![
|
||||||
|
create_submenu(vec![
|
||||||
|
create_submenu(vec![
|
||||||
|
create_item()
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let grid = DocGrid::from(&data);
|
||||||
|
|
||||||
|
assert_eq!(grid.to_debug_string(), r#"| S S S S I |
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_grid_complex_assembly_from_data() {
|
||||||
|
let data = create_menu(vec![
|
||||||
|
create_item(),
|
||||||
|
create_item(),
|
||||||
|
create_submenu(vec![
|
||||||
|
create_item(),
|
||||||
|
create_item(),
|
||||||
|
create_submenu(vec![
|
||||||
|
create_item(),
|
||||||
|
create_item(),
|
||||||
|
create_submenu(vec![
|
||||||
|
create_item(),
|
||||||
|
create_item(),
|
||||||
|
]),
|
||||||
|
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());
|
||||||
|
|
||||||
|
assert_eq!(grid.to_debug_string(), r#"| S I i i i |
|
||||||
|
| E I i i i |
|
||||||
|
| E S I i i |
|
||||||
|
| E E I i i |
|
||||||
|
| E E S I i |
|
||||||
|
| E E E I i |
|
||||||
|
| E E E S I |
|
||||||
|
| E E E E I |
|
||||||
|
| E E E I i |
|
||||||
|
| E E I i i |
|
||||||
|
| E E S I i |
|
||||||
|
| E E E I i |
|
||||||
|
| E E I i i |
|
||||||
|
| E E I i i |
|
||||||
|
| E I i i i |
|
||||||
|
| E I i i i |
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ascii_docs {
|
||||||
|
use crate::configotron::{conf::{UserConfigData, UserConfigItem}, doc::grid::create_ascii_doc_string};
|
||||||
|
use super::{DocGrid, create_item, create_menu, create_submenu};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ascii_docs_simple() {
|
||||||
|
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#"+-+---+
|
||||||
|
|S|I i|
|
||||||
|
| +---+
|
||||||
|
|E|I i|
|
||||||
|
| +-+-+
|
||||||
|
|E|S|I|
|
||||||
|
| | +-+
|
||||||
|
|E|E|I|
|
||||||
|
| | +-+
|
||||||
|
|E|E|I|
|
||||||
|
| +-+-+
|
||||||
|
|E|I i|
|
||||||
|
| +---+
|
||||||
|
|E|I i|
|
||||||
|
| +---+
|
||||||
|
|E|I i|
|
||||||
|
+-+---+
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/configotron/doc/mod.rs
Normal file
1
src/configotron/doc/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod grid;
|
||||||
2
src/configotron/mod.rs
Normal file
2
src/configotron/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod conf;
|
||||||
|
pub mod doc;
|
||||||
117
src/main.rs
117
src/main.rs
@@ -1,111 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
mod configotron;
|
||||||
use serde_yml;
|
|
||||||
|
|
||||||
use std::fs;
|
use configotron::conf::{read_and_parse_yaml_file};
|
||||||
use pad::PadStr;
|
use configotron::doc::grid::{DocGrid};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
|
||||||
enum UserConfigItem {
|
|
||||||
String {
|
|
||||||
name: String,
|
|
||||||
max_length: u64
|
|
||||||
},
|
|
||||||
IPv4 {
|
|
||||||
name: String,
|
|
||||||
},
|
|
||||||
Boolean {
|
|
||||||
name: String
|
|
||||||
},
|
|
||||||
Number {
|
|
||||||
name: String,
|
|
||||||
max: Option<i32>,
|
|
||||||
min: Option<i32>
|
|
||||||
},
|
|
||||||
Submenu(UserConfigData)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
|
||||||
struct UserConfigData {
|
|
||||||
name: String,
|
|
||||||
config_items: Vec<UserConfigItem>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum ConfigotronError {
|
|
||||||
#[error("IO Operation failed: {}", ._0.to_string())]
|
|
||||||
IoError(#[from] std::io::Error),
|
|
||||||
|
|
||||||
#[error("Failed to parse YAML File: {}", ._0.to_string())]
|
|
||||||
YamlParsingError(#[from] serde_yml::Error),
|
|
||||||
|
|
||||||
#[error("Missing field {} (line {} col {}) {}", .missing_filed, .line, .col, .context)]
|
|
||||||
MissingFieldError{
|
|
||||||
col: i32,
|
|
||||||
line: i32,
|
|
||||||
missing_filed: Box<str>,
|
|
||||||
context: Box<str>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_and_parse_yaml_file(input_file: &str) -> Result<UserConfigData, ConfigotronError> {
|
|
||||||
let file_content = fs::read_to_string(&input_file)?;
|
|
||||||
let config: UserConfigData = serde_yml::from_str(&file_content)?;
|
|
||||||
return Ok(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn generate_text_report_from_item(item: &UserConfigItem) -> Vec<String> {
|
|
||||||
return match item {
|
|
||||||
UserConfigItem::Boolean {name} => vec![String::from(name), String::from("[y/n]")] ,
|
|
||||||
UserConfigItem::IPv4 { name } => vec![String::from(name), format!("[ipv4]")],
|
|
||||||
UserConfigItem::String { name, max_length } => vec![String::from(name), format!("[text, max length {}]", max_length)],
|
|
||||||
UserConfigItem::Number { name, min, max } => match (min, max) {
|
|
||||||
(None, None) => vec![String::from(name), String::from("[number]")],
|
|
||||||
(None, Some(maximum)) => vec![String::from(name), format!("[number, ..{}]", maximum)],
|
|
||||||
(Some(minmum), None) => vec![String::from(name), format!("[number, {}..]", minmum)],
|
|
||||||
(Some(minmum), Some(maximum)) => vec![String::from(name), format!("[number, {}..{}]", minmum, maximum)],
|
|
||||||
},
|
|
||||||
UserConfigItem::Submenu(c) => generate_text_report(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_text_report(config: &UserConfigData) -> Vec<String> {
|
|
||||||
let lines: Vec<Vec<String>> = config.config_items
|
|
||||||
.iter()
|
|
||||||
.map(|i| generate_text_report_from_item(i))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let block_width = lines
|
|
||||||
.iter()
|
|
||||||
.map(|l: &Vec<String>|
|
|
||||||
l
|
|
||||||
.iter()
|
|
||||||
.map(|s: &String| s.chars().count())
|
|
||||||
.max().unwrap_or(0)
|
|
||||||
)
|
|
||||||
.max().unwrap_or(0);
|
|
||||||
|
|
||||||
let line_seperator = format!("+{}+", "-".repeat(block_width + 2));
|
|
||||||
|
|
||||||
let config_name_width = config.name.chars().count() + 2;
|
|
||||||
let mut lines_flattend: Vec<String> = lines
|
|
||||||
.iter()
|
|
||||||
.map(|i| i
|
|
||||||
.iter()
|
|
||||||
.map(|s| format!("| {} |", s.pad_to_width(block_width)))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
)
|
|
||||||
.flat_map(|seg| [seg, vec![String::from(&line_seperator)]])
|
|
||||||
.flatten()
|
|
||||||
.into_iter()
|
|
||||||
.map(|e| format!("{}{}", " ".repeat(config_name_width), e))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
lines_flattend.insert(0, format!("{}{}", config.name.pad_to_width(config_name_width), line_seperator));
|
|
||||||
|
|
||||||
return lines_flattend;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
@@ -116,8 +12,9 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let res = generate_text_report(&data).join("\n");
|
|
||||||
println!("{}", res);
|
|
||||||
|
|
||||||
println!("Hello, world!");
|
let grid = DocGrid::from(&data);
|
||||||
|
println!("{}", grid.to_debug_string());
|
||||||
|
|
||||||
|
println!("Done!");
|
||||||
}
|
}
|
||||||
|
|||||||
12
test.txt
Normal file
12
test.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
+-------------+----------------------+-----------------+------+
|
||||||
|
| ssbc_remote | (1) network settings | (1) ip | IPv4 |
|
||||||
|
| | +-----------------+------+
|
||||||
|
| | | (2) subnet_mask | IPv4 |
|
||||||
|
| | +-----------------+------+
|
||||||
|
| | | (3) gateway | IPv4 |
|
||||||
|
| +----------------------+-----------------+------+
|
||||||
|
| | (2) wifi_ssid | text (64) |
|
||||||
|
| +----------------------+------------------------+
|
||||||
|
| | (3) wifi_password | text (64) |
|
||||||
|
+-------------+----------------------+------------------------+
|
||||||
Reference in New Issue
Block a user