mirror of
https://gitlab.com/arnekeller/ascii-table.git
synced 2024-12-04 21:49:08 +00:00
save game
This commit is contained in:
parent
bb24aa7279
commit
a0de3439c1
108
src/lib.rs
108
src/lib.rs
@ -162,23 +162,20 @@ impl AsciiTable {
|
|||||||
self.format_inner(self.stringify(data))
|
self.format_inner(self.stringify(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_inner(&self, data: Vec<Vec<String>>) -> String {
|
fn format_inner(&self, data: Vec<Vec<SmartString>>) -> String {
|
||||||
let num_cols = data.iter().map(|row| row.len()).max().unwrap_or(0);
|
let num_cols = data.iter().map(|row| row.len()).max().unwrap_or(0);
|
||||||
if !self.valid(&data, num_cols) {
|
if !self.valid(&data, num_cols) {
|
||||||
return self.format_empty()
|
return self.format_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let header = self.stringify_header();
|
||||||
let data = self.square_data(data, num_cols);
|
let data = self.square_data(data, num_cols);
|
||||||
let has_header = self.columns.iter().any(|(_, col)| !col.header.is_empty());
|
let has_header = header.iter().any(|text| !text.is_empty());
|
||||||
let widths = self.column_widths(&data, num_cols);
|
let widths = self.column_widths(&data, num_cols);
|
||||||
|
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
result.push_str(&self.format_first(&widths));
|
result.push_str(&self.format_first(&widths));
|
||||||
if has_header {
|
if has_header {
|
||||||
let default_conf = &DEFAULT_COLUMN;
|
|
||||||
let header: Vec<_> = (0..num_cols).map(|a|
|
|
||||||
self.columns.get(&a).unwrap_or(default_conf).header.as_str()
|
|
||||||
).collect();
|
|
||||||
result.push_str(&self.format_header_row(&header, &widths));
|
result.push_str(&self.format_header_row(&header, &widths));
|
||||||
result.push_str(&self.format_middle(&widths));
|
result.push_str(&self.format_middle(&widths));
|
||||||
}
|
}
|
||||||
@ -189,7 +186,7 @@ impl AsciiTable {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn valid(&self, data: &Vec<Vec<String>>, num_cols: usize) -> bool {
|
fn valid(&self, data: &Vec<Vec<SmartString>>, num_cols: usize) -> bool {
|
||||||
if data.len() == 0 {
|
if data.len() == 0 {
|
||||||
false
|
false
|
||||||
} else if num_cols == 0 {
|
} else if num_cols == 0 {
|
||||||
@ -205,27 +202,35 @@ impl AsciiTable {
|
|||||||
((num_cols - 1) * 3) + 4
|
((num_cols - 1) * 3) + 4
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stringify<L1, L2, T>(&self, data: L1) -> Vec<Vec<String>>
|
fn stringify<L1, L2, T>(&self, data: L1) -> Vec<Vec<SmartString>>
|
||||||
where L1: IntoIterator<Item = L2>,
|
where L1: IntoIterator<Item = L2>,
|
||||||
L2: IntoIterator<Item = T>,
|
L2: IntoIterator<Item = T>,
|
||||||
T: Display {
|
T: Display {
|
||||||
data.into_iter().map(|row| row.into_iter().map(|cell| cell.to_string()).collect()).collect()
|
data.into_iter().map(|row| row.into_iter().map(|cell| SmartString::from(cell)).collect()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn square_data(&self, mut data: Vec<Vec<String>>, num_cols: usize) -> Vec<Vec<String>> {
|
fn stringify_header(&self) -> Vec<SmartString> {
|
||||||
|
// let default_conf = &DEFAULT_COLUMN;
|
||||||
|
// let header: Vec<_> = (0..num_cols).map(|a|
|
||||||
|
// &self.columns.get(&a).unwrap_or(default_conf).header
|
||||||
|
// ).collect();
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn square_data(&self, mut data: Vec<Vec<SmartString>>, num_cols: usize) -> Vec<Vec<SmartString>> {
|
||||||
for row in data.iter_mut() {
|
for row in data.iter_mut() {
|
||||||
while row.len() < num_cols {
|
while row.len() < num_cols {
|
||||||
row.push(String::new())
|
row.push(SmartString::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column_widths(&self, data: &[Vec<String>], num_cols: usize) -> Vec<usize> {
|
fn column_widths(&self, data: &[Vec<SmartString>], num_cols: usize) -> Vec<usize> {
|
||||||
let result: Vec<_> = (0..num_cols).map(|a| {
|
let result: Vec<_> = (0..num_cols).map(|a| {
|
||||||
let default_conf = &DEFAULT_COLUMN;
|
let default_conf = &DEFAULT_COLUMN;
|
||||||
let conf = self.columns.get(&a).unwrap_or(default_conf);
|
let conf = self.columns.get(&a).unwrap_or(default_conf);
|
||||||
let column_width = data.iter().map(|row| self.count_characters(&row[a])).max().unwrap();
|
let column_width = data.iter().map(|row| row[a].char_len()).max().unwrap();
|
||||||
let header_width = conf.header.chars().count();
|
let header_width = conf.header.chars().count();
|
||||||
column_width.max(header_width).min(conf.max_width)
|
column_width.max(header_width).min(conf.max_width)
|
||||||
}).collect();
|
}).collect();
|
||||||
@ -266,7 +271,7 @@ impl AsciiTable {
|
|||||||
widths
|
widths
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_line(&self, row: &[String], head: &str, delim: &str, tail: &str) -> String {
|
fn format_line(&self, row: &[SmartString], head: &str, delim: &str, tail: &str) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
result.push_str(head);
|
result.push_str(head);
|
||||||
for cell in row {
|
for cell in row {
|
||||||
@ -282,12 +287,12 @@ impl AsciiTable {
|
|||||||
|
|
||||||
fn format_empty(&self) -> String {
|
fn format_empty(&self) -> String {
|
||||||
self.format_first(&vec![0])
|
self.format_first(&vec![0])
|
||||||
+ &self.format_line(&vec![String::new()], &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS))
|
+ &self.format_line(&[SmartString::new()], &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS))
|
||||||
+ &self.format_last(&vec![0])
|
+ &self.format_last(&[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_first(&self, widths: &[usize]) -> String {
|
fn format_first(&self, widths: &[usize]) -> String {
|
||||||
let row: Vec<String> = widths.iter().map(|&x| EW.repeat(x)).collect();
|
let row: Vec<SmartString> = widths.iter().map(|&x| SmartString::new(EW.repeat(x))).collect();
|
||||||
self.format_line(&row, &format!("{}{}", SE, EW), &format!("{}{}{}", EW, EWS, EW), &format!("{}{}", EW, SW))
|
self.format_line(&row, &format!("{}{}", SE, EW), &format!("{}{}{}", EW, EWS, EW), &format!("{}{}", EW, SW))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +301,7 @@ impl AsciiTable {
|
|||||||
self.format_line(&row, &format!("{}{}", NES, EW), &format!("{}{}{}", EW, NEWS, EW), &format!("{}{}", EW, NWS))
|
self.format_line(&row, &format!("{}{}", NES, EW), &format!("{}{}{}", EW, NEWS, EW), &format!("{}{}", EW, NWS))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_row(&self, row: &[String], widths: &[usize]) -> String {
|
fn format_row(&self, row: &[SmartString], widths: &[usize]) -> String {
|
||||||
let row: Vec<_> = (0..widths.len()).map(|a| {
|
let row: Vec<_> = (0..widths.len()).map(|a| {
|
||||||
let cell = &row[a];
|
let cell = &row[a];
|
||||||
let width = widths[a];
|
let width = widths[a];
|
||||||
@ -307,7 +312,7 @@ impl AsciiTable {
|
|||||||
self.format_line(&row, &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS))
|
self.format_line(&row, &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_header_row(&self, row: &[&str], widths: &[usize]) -> String {
|
fn format_header_row(&self, row: &[SmartString], widths: &[usize]) -> String {
|
||||||
let row: Vec<String> = row.iter().zip(widths.iter()).map(|(cell, &width)|
|
let row: Vec<String> = row.iter().zip(widths.iter()).map(|(cell, &width)|
|
||||||
self.format_cell(cell, width, ' ', Align::Left)
|
self.format_cell(cell, width, ' ', Align::Left)
|
||||||
).collect();
|
).collect();
|
||||||
@ -319,25 +324,29 @@ impl AsciiTable {
|
|||||||
self.format_line(&row, &format!("{}{}", NE, EW), &format!("{}{}{}", EW, NEW, EW), &format!("{}{}", EW, NW))
|
self.format_line(&row, &format!("{}{}", NE, EW), &format!("{}{}{}", EW, NEW, EW), &format!("{}{}", EW, NW))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_cell(&self, text: &str, len: usize, pad: char, align: Align) -> String {
|
fn format_cell(&self, text: &SmartString, len: usize, pad: char, align: Align) -> SmartString {
|
||||||
if text.chars().count() > len {
|
if text.char_len() > len {
|
||||||
let mut result: String = text.chars().take(len).collect();
|
// let mut result: String = text.chars().take(len).collect();
|
||||||
|
let mut result = text.clone();
|
||||||
|
while result.char_len() > len {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
if result.pop().is_some() {
|
if result.pop().is_some() {
|
||||||
result.push('+')
|
result.push('+')
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
let mut result = text.to_string();
|
let mut result = text.clone();
|
||||||
match align {
|
match align {
|
||||||
Align::Left => while result.chars().count() < len {
|
Align::Left => while result.char_len() < len {
|
||||||
result.push(pad)
|
result.push(pad)
|
||||||
}
|
}
|
||||||
Align::Right => while result.chars().count() < len {
|
Align::Right => while result.char_len() < len {
|
||||||
result.insert(0, pad)
|
result.insert(0, pad)
|
||||||
}
|
}
|
||||||
Align::Center => while result.chars().count() < len {
|
Align::Center => while result.char_len() < len {
|
||||||
result.push(pad);
|
result.push(pad);
|
||||||
if result.chars().count() < len {
|
if result.char_len() < len {
|
||||||
result.insert(0, pad)
|
result.insert(0, pad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,3 +355,48 @@ impl AsciiTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct SmartString {
|
||||||
|
fragments: Vec<(bool, String)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SmartString {
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from<T>(string: T) -> Self
|
||||||
|
where T: Display {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn char_len(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Option<char> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, ch: char) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, index: usize, ch: char) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SmartString {
|
||||||
|
|
||||||
|
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||||
|
let concat: String = self.fragments.iter().map(|(_, string)| string.as_str()).collect();
|
||||||
|
concat.fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user