From a0de3439c1cc585a40711fa495ffcaf8ebf7173b Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:14:25 +0200 Subject: [PATCH 01/27] save game --- src/lib.rs | 108 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4f65481..34c65e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,23 +162,20 @@ impl AsciiTable { self.format_inner(self.stringify(data)) } - fn format_inner(&self, data: Vec>) -> String { + fn format_inner(&self, data: Vec>) -> String { let num_cols = data.iter().map(|row| row.len()).max().unwrap_or(0); if !self.valid(&data, num_cols) { return self.format_empty() } + let header = self.stringify_header(); 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 mut result = String::new(); result.push_str(&self.format_first(&widths)); 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_middle(&widths)); } @@ -189,7 +186,7 @@ impl AsciiTable { result } - fn valid(&self, data: &Vec>, num_cols: usize) -> bool { + fn valid(&self, data: &Vec>, num_cols: usize) -> bool { if data.len() == 0 { false } else if num_cols == 0 { @@ -205,27 +202,35 @@ impl AsciiTable { ((num_cols - 1) * 3) + 4 } - fn stringify(&self, data: L1) -> Vec> + fn stringify(&self, data: L1) -> Vec> where L1: IntoIterator, L2: IntoIterator, 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>, num_cols: usize) -> Vec> { + fn stringify_header(&self) -> Vec { +// 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>, num_cols: usize) -> Vec> { for row in data.iter_mut() { while row.len() < num_cols { - row.push(String::new()) + row.push(SmartString::new()) } } data } - fn column_widths(&self, data: &[Vec], num_cols: usize) -> Vec { + fn column_widths(&self, data: &[Vec], num_cols: usize) -> Vec { let result: Vec<_> = (0..num_cols).map(|a| { let default_conf = &DEFAULT_COLUMN; 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(); column_width.max(header_width).min(conf.max_width) }).collect(); @@ -266,7 +271,7 @@ impl AsciiTable { 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(); result.push_str(head); for cell in row { @@ -282,12 +287,12 @@ impl AsciiTable { fn format_empty(&self) -> String { self.format_first(&vec![0]) - + &self.format_line(&vec![String::new()], &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS)) - + &self.format_last(&vec![0]) + + &self.format_line(&[SmartString::new()], &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS)) + + &self.format_last(&[0]) } fn format_first(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| EW.repeat(x)).collect(); + let row: Vec = widths.iter().map(|&x| SmartString::new(EW.repeat(x))).collect(); 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)) } - 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 cell = &row[a]; let width = widths[a]; @@ -307,7 +312,7 @@ impl AsciiTable { 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 = row.iter().zip(widths.iter()).map(|(cell, &width)| self.format_cell(cell, width, ' ', Align::Left) ).collect(); @@ -319,25 +324,29 @@ impl AsciiTable { 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 { - if text.chars().count() > len { - let mut result: String = text.chars().take(len).collect(); + fn format_cell(&self, text: &SmartString, len: usize, pad: char, align: Align) -> SmartString { + if text.char_len() > len { +// 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() { result.push('+') } result } else { - let mut result = text.to_string(); + let mut result = text.clone(); match align { - Align::Left => while result.chars().count() < len { + Align::Left => while result.char_len() < len { result.push(pad) } - Align::Right => while result.chars().count() < len { + Align::Right => while result.char_len() < len { result.insert(0, pad) } - Align::Center => while result.chars().count() < len { + Align::Center => while result.char_len() < len { result.push(pad); - if result.chars().count() < len { + if result.char_len() < len { 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(string: T) -> Self + where T: Display { + todo!() + } + + fn char_len(&self) -> usize { + todo!() + } + + fn is_empty(&self) -> bool { + todo!() + } + + fn pop(&mut self) -> Option { + 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) + } +} From 603d183c571e0fe616728021760697924b1a0332 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:15:44 +0200 Subject: [PATCH 02/27] save game --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 34c65e7..94d4afa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,12 +292,12 @@ impl AsciiTable { } fn format_first(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| SmartString::new(EW.repeat(x))).collect(); + let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", SE, EW), &format!("{}{}{}", EW, EWS, EW), &format!("{}{}", EW, SW)) } fn format_middle(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| EW.repeat(x)).collect(); + let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", NES, EW), &format!("{}{}{}", EW, NEWS, EW), &format!("{}{}", EW, NWS)) } @@ -313,14 +313,14 @@ impl AsciiTable { } fn format_header_row(&self, row: &[SmartString], widths: &[usize]) -> String { - let row: Vec = row.iter().zip(widths.iter()).map(|(cell, &width)| + let row: Vec = row.iter().zip(widths.iter()).map(|(cell, &width)| self.format_cell(cell, width, ' ', Align::Left) ).collect(); self.format_line(&row, &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS)) } fn format_last(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| EW.repeat(x)).collect(); + let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", NE, EW), &format!("{}{}{}", EW, NEW, EW), &format!("{}{}", EW, NW)) } From 1b7ccc31aa6e169c4b2a8819564595f90c09d509 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:23:38 +0200 Subject: [PATCH 03/27] save game --- src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 94d4afa..f99e911 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,7 +168,7 @@ impl AsciiTable { return self.format_empty() } - let header = self.stringify_header(); + let header = self.stringify_header(num_cols); let data = self.square_data(data, num_cols); let has_header = header.iter().any(|text| !text.is_empty()); let widths = self.column_widths(&data, num_cols); @@ -209,12 +209,11 @@ impl AsciiTable { data.into_iter().map(|row| row.into_iter().map(|cell| SmartString::from(cell)).collect()).collect() } - fn stringify_header(&self) -> Vec { -// 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 stringify_header(&self, num_cols: usize) -> Vec { + let default_conf = &DEFAULT_COLUMN; + (0..num_cols).map(|a| + SmartString::from(&self.columns.get(&a).unwrap_or(default_conf).header) + ).collect() } fn square_data(&self, mut data: Vec>, num_cols: usize) -> Vec> { @@ -326,7 +325,6 @@ impl AsciiTable { fn format_cell(&self, text: &SmartString, len: usize, pad: char, align: Align) -> SmartString { if text.char_len() > len { -// let mut result: String = text.chars().take(len).collect(); let mut result = text.clone(); while result.char_len() > len { result.pop(); From dd590a9dfb8d217d1aa24f7137ce0175102f63b4 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:28:14 +0200 Subject: [PATCH 04/27] save game --- src/lib.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f99e911..79ae374 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -362,20 +362,26 @@ struct SmartString { impl SmartString { fn new() -> Self { - todo!() + Self { fragments: Vec::new() } } fn from(string: T) -> Self where T: Display { - todo!() + // TODO: + Self { fragments: vec![(true, string.to_string())] } } fn char_len(&self) -> usize { - todo!() + self.fragments.iter() + .filter(|(visible, _)| *visible) + .map(|(_, string)| string.chars().count()) + .sum() } fn is_empty(&self) -> bool { - todo!() + self.fragments.iter() + .filter(|(visible, _)| *visible) + .all(|(_, string)| string.is_empty()) } fn pop(&mut self) -> Option { From 967acfed9f712d4cd0e11052583a9b497d3567cc Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:48:55 +0200 Subject: [PATCH 05/27] save game --- src/lib.rs | 5 ++++- src/test.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 79ae374..ff40935 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -385,7 +385,10 @@ impl SmartString { } fn pop(&mut self) -> Option { - todo!() + self.fragments.iter_mut() + .filter(|(visible, string)| *visible && !string.is_empty()) + .last() + .and_then(|(_, string)| string.pop()) } fn push(&mut self, ch: char) { diff --git a/src/test.rs b/src/test.rs index c67cca2..f2821a0 100644 --- a/src/test.rs +++ b/src/test.rs @@ -538,7 +538,7 @@ fn color_codes() { fn color_codes_in_header() { let mut config = AsciiTable::default(); let text = "Hello".color(Color::Blue).bg_color(Color::Yellow).bold(); - config.columns.insert(0, Column {header: text, ..Column::default()}); + config.columns.insert(0, Column {header: text.to_string(), ..Column::default()}); let input = vec![&[""]]; let expected = "┌───────┐\n\ │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mHello\u{1b}[0m │\n\ From 757531723adb0b1dd96c983f5fb9e686c61ec701 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:53:38 +0200 Subject: [PATCH 06/27] save game --- src/lib.rs | 64 +++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ff40935..49e7a0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,28 +236,6 @@ impl AsciiTable { self.truncate_widths(result) } - fn count_characters(&self, cell: &str) -> usize { -// let mut count = 0; -// let mut block = false; -// let mut iter = cell.chars().peekable(); -// while let Some(ch) = iter.next() { -// if block { -// if ch != '\u{1b}' && ch != '[' && ch != ';' && ch != 'm' && !('0'..'9').contains(&ch) { -// block = false; -// count += 1; -// } -// } else { -// if ch == '\u{1b}' && Some(&'[') == iter.peek() { -// block = true; -// } else { -// count += 1; -// } -// } -// } -// count - cell.chars().count() - } - fn truncate_widths(&self, mut widths: Vec) -> Vec { let max_width = self.max_width; let table_padding = Self::smallest_width(widths.len()); @@ -330,22 +308,22 @@ impl AsciiTable { result.pop(); } if result.pop().is_some() { - result.push('+') + result.push_visible('+') } result } else { let mut result = text.clone(); match align { Align::Left => while result.char_len() < len { - result.push(pad) + result.push_visible(pad) } Align::Right => while result.char_len() < len { - result.insert(0, pad) + result.lpush_visible(pad) } Align::Center => while result.char_len() < len { - result.push(pad); + result.push_visible(pad); if result.char_len() < len { - result.insert(0, pad) + result.lpush_visible(pad) } } } @@ -368,6 +346,24 @@ impl SmartString { fn from(string: T) -> Self where T: Display { // TODO: +// let mut count = 0; +// let mut block = false; +// let mut iter = cell.chars().peekable(); +// while let Some(ch) = iter.next() { +// if block { +// if ch != '\u{1b}' && ch != '[' && ch != ';' && ch != 'm' && !('0'..'9').contains(&ch) { +// block = false; +// count += 1; +// } +// } else { +// if ch == '\u{1b}' && Some(&'[') == iter.peek() { +// block = true; +// } else { +// count += 1; +// } +// } +// } +// count Self { fragments: vec![(true, string.to_string())] } } @@ -391,11 +387,19 @@ impl SmartString { .and_then(|(_, string)| string.pop()) } - fn push(&mut self, ch: char) { - todo!() + fn push_visible(&mut self, ch: char) { + let last_fragment = self.fragments.iter_mut() + .filter(|(visible, _)| *visible) + .map(|(_, string)| string) + .last(); + if let Some(fragment) = last_fragment { + fragment.push(ch); + } else { + self.fragments.push((true, ch.to_string())); + } } - fn insert(&mut self, index: usize, ch: char) { + fn lpush_visible(&mut self, ch: char) { todo!() } } From e6f23201c40356a429f195e4cda0b2ecb9459536 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:54:39 +0200 Subject: [PATCH 07/27] save game --- src/lib.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 49e7a0e..0b84dcb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -400,7 +400,15 @@ impl SmartString { } fn lpush_visible(&mut self, ch: char) { - todo!() + let last_fragment = self.fragments.iter_mut() + .filter(|(visible, _)| *visible) + .map(|(_, string)| string) + .next(); + if let Some(fragment) = last_fragment { + fragment.push(ch); + } else { + self.fragments.insert(0, (true, ch.to_string())); + } } } From a93a2a8eb3fae7f425fa4ad0b9a4d47ace7aabf0 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:55:13 +0200 Subject: [PATCH 08/27] save game --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0b84dcb..e157d74 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -400,11 +400,11 @@ impl SmartString { } fn lpush_visible(&mut self, ch: char) { - let last_fragment = self.fragments.iter_mut() + let first_fragment = self.fragments.iter_mut() .filter(|(visible, _)| *visible) .map(|(_, string)| string) .next(); - if let Some(fragment) = last_fragment { + if let Some(fragment) = first_fragment { fragment.push(ch); } else { self.fragments.insert(0, (true, ch.to_string())); From 0e5bf7131319047325a5cb038e7546c9185de67e Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:55:28 +0200 Subject: [PATCH 09/27] save game --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e157d74..a122d67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -405,7 +405,7 @@ impl SmartString { .map(|(_, string)| string) .next(); if let Some(fragment) = first_fragment { - fragment.push(ch); + fragment.insert(0, ch); } else { self.fragments.insert(0, (true, ch.to_string())); } From c06a4aa793305f5e0dc51aeac7def2d8c15a9d67 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 11:59:06 +0200 Subject: [PATCH 10/27] save game --- src/test.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test.rs b/src/test.rs index f2821a0..a286e6e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -525,8 +525,9 @@ fn mixed_types() { #[test] fn color_codes() { let config = AsciiTable::default(); - let text = "Hello".color(Color::Blue).bg_color(Color::Yellow).bold(); - let input = vec![vec![text]]; + let input = vec![vec![ + "Hello".color(Color::Blue).bg_color(Color::Yellow).bold() + ]]; let expected = "┌───────┐\n\ │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mHello\u{1b}[0m │\n\ └───────┘\n"; From cc8b6b52239203309691abf3f8aaf9cabeda7389 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:08:36 +0200 Subject: [PATCH 11/27] save game --- src/lib.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a122d67..cfc5097 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -364,7 +364,34 @@ impl SmartString { // } // } // count - Self { fragments: vec![(true, string.to_string())] } + let string = string.to_string(); + let mut fragments = Vec::new(); + let mut visible = true; + let mut buf = String::new(); + let mut iter = string.chars().peekable(); + + while let Some(ch) = iter.next() { + if visible { + if ch == '\u{1b}' && Some(&'[') == iter.peek() { + fragments.push((visible, buf)); + visible = !visible; + buf = String::new(); + } + buf.push(ch); + } else { + if ch != '\u{1b}' && ch != '[' && ch != ';' && ch != 'm' && !('0'..'9').contains(&ch) { + fragments.push((visible, buf)); + visible = !visible; + buf = String::new(); + } + buf.push(ch); + } + } + if !buf.is_empty() { + fragments.push((visible, buf)); + } + + Self { fragments } } fn char_len(&self) -> usize { From d3c20f6ff95a63551a1d5257ebd09d8a45658655 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:10:45 +0200 Subject: [PATCH 12/27] save game --- src/lib.rs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cfc5097..315f2b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,7 +171,7 @@ impl AsciiTable { let header = self.stringify_header(num_cols); let data = self.square_data(data, num_cols); let has_header = header.iter().any(|text| !text.is_empty()); - let widths = self.column_widths(&data, num_cols); + let widths = self.column_widths(&header, &data, num_cols); let mut result = String::new(); result.push_str(&self.format_first(&widths)); @@ -225,12 +225,12 @@ impl AsciiTable { data } - fn column_widths(&self, data: &[Vec], num_cols: usize) -> Vec { + fn column_widths(&self, header: &[SmartString], data: &[Vec], num_cols: usize) -> Vec { let result: Vec<_> = (0..num_cols).map(|a| { let default_conf = &DEFAULT_COLUMN; let conf = self.columns.get(&a).unwrap_or(default_conf); let column_width = data.iter().map(|row| row[a].char_len()).max().unwrap(); - let header_width = conf.header.chars().count(); + let header_width = header[a].char_len(); column_width.max(header_width).min(conf.max_width) }).collect(); self.truncate_widths(result) @@ -345,25 +345,6 @@ impl SmartString { fn from(string: T) -> Self where T: Display { - // TODO: -// let mut count = 0; -// let mut block = false; -// let mut iter = cell.chars().peekable(); -// while let Some(ch) = iter.next() { -// if block { -// if ch != '\u{1b}' && ch != '[' && ch != ';' && ch != 'm' && !('0'..'9').contains(&ch) { -// block = false; -// count += 1; -// } -// } else { -// if ch == '\u{1b}' && Some(&'[') == iter.peek() { -// block = true; -// } else { -// count += 1; -// } -// } -// } -// count let string = string.to_string(); let mut fragments = Vec::new(); let mut visible = true; From 41a688ea8b6a5788ee983977334f6cc783a7b009 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:17:58 +0200 Subject: [PATCH 13/27] save game --- src/test.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/test.rs b/src/test.rs index a286e6e..3c1876c 100644 --- a/src/test.rs +++ b/src/test.rs @@ -523,13 +523,28 @@ fn mixed_types() { } #[test] -fn color_codes() { +fn color_codes_zero() { let config = AsciiTable::default(); let input = vec![vec![ - "Hello".color(Color::Blue).bg_color(Color::Yellow).bold() + "\u{1b}[0mHello\u{1b}[0m" ]]; + let expected = "┌───────┐\n\ + │ \u{1b}[0mHello\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + +#[test] +fn color_codes() { + let config = AsciiTable::default(); + let input = vec![ + vec!["Hello".color(Color::Blue).bg_color(Color::Yellow).bold()], + vec!["Hello".gradient(Color::Red)] + ]; let expected = "┌───────┐\n\ │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mHello\u{1b}[0m │\n\ + │ \u{1b}[38;2;255;0;0mH\u{1b}[38;2;255;6;0me\u{1b}[38;2;255;13;0ml\u{1b}[38;2;255;19;0ml\u{1b}[38;2;255;26;0mo\u{1b}[0m │\n\ └───────┘\n"; assert_eq!(expected, config.format(input)); From 919e0599ea21c87702eb72350dcff4d106ed7db5 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:19:12 +0200 Subject: [PATCH 14/27] save game --- src/test.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test.rs b/src/test.rs index 3c1876c..3c9971f 100644 --- a/src/test.rs +++ b/src/test.rs @@ -535,6 +535,19 @@ fn color_codes_zero() { assert_eq!(expected, config.format(input)); } +#[test] +fn color_codes_m5() { + let config = AsciiTable::default(); + let input = vec![ + vec!["mmmmm".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mmmmmm\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + #[test] fn color_codes() { let config = AsciiTable::default(); From 71451d313bde6b9ae92b13dbf7945e3bcdb7daeb Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:19:57 +0200 Subject: [PATCH 15/27] save game --- src/test.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test.rs b/src/test.rs index 3c9971f..fd00d71 100644 --- a/src/test.rs +++ b/src/test.rs @@ -548,6 +548,19 @@ fn color_codes_m5() { assert_eq!(expected, config.format(input)); } +#[test] +fn color_codes_b5() { + let config = AsciiTable::default(); + let input = vec![ + vec!["[[[[[".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1m[[[[[\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + #[test] fn color_codes() { let config = AsciiTable::default(); From 7d75017e727e1f75ccaa7633dcfb9b138e245fcb Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:20:40 +0200 Subject: [PATCH 16/27] save game --- src/test.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test.rs b/src/test.rs index fd00d71..9009c34 100644 --- a/src/test.rs +++ b/src/test.rs @@ -561,6 +561,32 @@ fn color_codes_b5() { assert_eq!(expected, config.format(input)); } +#[test] +fn color_codes_s5() { + let config = AsciiTable::default(); + let input = vec![ + vec![";;;;;".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1m;;;;;\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + +#[test] +fn color_codes_n5() { + let config = AsciiTable::default(); + let input = vec![ + vec!["00000".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1m00000\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + #[test] fn color_codes() { let config = AsciiTable::default(); From 36113ce9f75ff52901ddd90e8a41225a2f258c63 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:26:38 +0200 Subject: [PATCH 17/27] save game --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 315f2b3..2570ae5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,12 +360,19 @@ impl SmartString { } buf.push(ch); } else { - if ch != '\u{1b}' && ch != '[' && ch != ';' && ch != 'm' && !('0'..'9').contains(&ch) { + if ch == 'm' { + buf.push(ch); fragments.push((visible, buf)); visible = !visible; buf = String::new(); + } else if ch != '[' && ch != ';' && !('0'..'9').contains(&ch) { + fragments.push((visible, buf)); + visible = !visible; + buf = String::new(); + buf.push(ch); + } else { + buf.push(ch); } - buf.push(ch); } } if !buf.is_empty() { From 481ede8a6f0ba7df6db99fe00afd611e3cf4198e Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:28:27 +0200 Subject: [PATCH 18/27] save game --- src/test.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test.rs b/src/test.rs index 9009c34..cc55102 100644 --- a/src/test.rs +++ b/src/test.rs @@ -587,6 +587,19 @@ fn color_codes_n5() { assert_eq!(expected, config.format(input)); } +#[test] +fn color_codes_missing_m() { + let config = AsciiTable::default(); + let input = vec![vec![ + "\u{1b}[0Hello\u{1b}[0" + ]]; + let expected = "┌───────┐\n\ + │ \u{1b}[0Hello\u{1b}[0 │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + #[test] fn color_codes() { let config = AsciiTable::default(); From d84a0de94380899a782495995708a58dabf483dc Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:32:15 +0200 Subject: [PATCH 19/27] save game --- src/lib.rs | 3 ++- src/test.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2570ae5..bc33cd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -365,7 +365,7 @@ impl SmartString { fragments.push((visible, buf)); visible = !visible; buf = String::new(); - } else if ch != '[' && ch != ';' && !('0'..'9').contains(&ch) { + } else if ch != '[' && ch != ';' && !('0'..='9').contains(&ch) { fragments.push((visible, buf)); visible = !visible; buf = String::new(); @@ -378,6 +378,7 @@ impl SmartString { if !buf.is_empty() { fragments.push((visible, buf)); } + println!("FRAGMENTS: {:?}", fragments); Self { fragments } } diff --git a/src/test.rs b/src/test.rs index cc55102..91728cf 100644 --- a/src/test.rs +++ b/src/test.rs @@ -615,6 +615,26 @@ fn color_codes() { assert_eq!(expected, config.format(input)); } +// \u{1b}[38;2;255;0;0mH +// \u{1b}[38;2;255;6;0me +// \u{1b}[38;2;255;13;0ml +// \u{1b}[38;2;255;19;0ml +// \u{1b}[38;2;255;26;0mo +// \u{1b}[0m + +// (true, ""), +// (false, "\u{1b}[38;2;255;0;0m"), +// (true, "H"), +// (false, "\u{1b}[38;2;255;6;0m"), +// (true, "e"), +// (false, "\u{1b}[38;2;255;13;0m"), +// (true, "l"), +// (false, "\u{1b}[38;2;255;1"), +// (true, "9;0ml"), +// (false, "\u{1b}[38;2;255;26;0m"), +// (true, "o"), +// (false, "\u{1b}[0m") + #[test] fn color_codes_in_header() { let mut config = AsciiTable::default(); From d7f0279051021d8527faa6bb5fa71d49672caa24 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:33:10 +0200 Subject: [PATCH 20/27] save game --- src/test.rs | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/test.rs b/src/test.rs index 91728cf..fd39131 100644 --- a/src/test.rs +++ b/src/test.rs @@ -535,6 +535,19 @@ fn color_codes_zero() { assert_eq!(expected, config.format(input)); } +#[test] +fn color_codes_zero_inbetween() { + let config = AsciiTable::default(); + let input = vec![vec![ + "He\u{1b}[0ml\u{1b}[0mlo" + ]]; + let expected = "┌───────┐\n\ + │ He\u{1b}[0ml\u{1b}[0mlo │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + #[test] fn color_codes_m5() { let config = AsciiTable::default(); @@ -615,26 +628,6 @@ fn color_codes() { assert_eq!(expected, config.format(input)); } -// \u{1b}[38;2;255;0;0mH -// \u{1b}[38;2;255;6;0me -// \u{1b}[38;2;255;13;0ml -// \u{1b}[38;2;255;19;0ml -// \u{1b}[38;2;255;26;0mo -// \u{1b}[0m - -// (true, ""), -// (false, "\u{1b}[38;2;255;0;0m"), -// (true, "H"), -// (false, "\u{1b}[38;2;255;6;0m"), -// (true, "e"), -// (false, "\u{1b}[38;2;255;13;0m"), -// (true, "l"), -// (false, "\u{1b}[38;2;255;1"), -// (true, "9;0ml"), -// (false, "\u{1b}[38;2;255;26;0m"), -// (true, "o"), -// (false, "\u{1b}[0m") - #[test] fn color_codes_in_header() { let mut config = AsciiTable::default(); From 239da146c06b3a8c63c38c7bd8b7c62f621f9cd5 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:35:46 +0200 Subject: [PATCH 21/27] save game --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index bc33cd0..b031ef8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,6 +383,11 @@ impl SmartString { Self { fragments } } + fn from_visible(string: T) -> Self + where T: Display { + Self { fragments: vec![(true, string.to_string())] } + } + fn char_len(&self) -> usize { self.fragments.iter() .filter(|(visible, _)| *visible) From 72af1f2db0a49392db6eaffd7005191ac10ad664 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:37:48 +0200 Subject: [PATCH 22/27] save game --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b031ef8..988df66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,12 +269,12 @@ impl AsciiTable { } fn format_first(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); + let row: Vec<_> = widths.iter().map(|&x| SmartString::from_visible(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", SE, EW), &format!("{}{}{}", EW, EWS, EW), &format!("{}{}", EW, SW)) } fn format_middle(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); + let row: Vec<_> = widths.iter().map(|&x| SmartString::from_visible(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", NES, EW), &format!("{}{}{}", EW, NEWS, EW), &format!("{}{}", EW, NWS)) } @@ -290,14 +290,14 @@ impl AsciiTable { } fn format_header_row(&self, row: &[SmartString], widths: &[usize]) -> String { - let row: Vec = row.iter().zip(widths.iter()).map(|(cell, &width)| + let row: Vec<_> = row.iter().zip(widths.iter()).map(|(cell, &width)| self.format_cell(cell, width, ' ', Align::Left) ).collect(); self.format_line(&row, &format!("{}{}", NS, ' '), &format!("{}{}{}", ' ', NS, ' '), &format!("{}{}", ' ', NS)) } fn format_last(&self, widths: &[usize]) -> String { - let row: Vec = widths.iter().map(|&x| SmartString::from(EW.repeat(x))).collect(); + let row: Vec<_> = widths.iter().map(|&x| SmartString::from_visible(EW.repeat(x))).collect(); self.format_line(&row, &format!("{}{}", NE, EW), &format!("{}{}{}", EW, NEW, EW), &format!("{}{}", EW, NW)) } From 020efce014207241a701dc456da602491b307051 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:38:56 +0200 Subject: [PATCH 23/27] save game --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 988df66..018c654 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,9 +383,8 @@ impl SmartString { Self { fragments } } - fn from_visible(string: T) -> Self - where T: Display { - Self { fragments: vec![(true, string.to_string())] } + fn from_visible(string: String) -> Self { + Self { fragments: vec![(true, string)] } } fn char_len(&self) -> usize { From 2d37bcc295b20edd893ee82bf67c075c94181088 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:40:30 +0200 Subject: [PATCH 24/27] save game --- src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 018c654..f781995 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,7 +354,9 @@ impl SmartString { while let Some(ch) = iter.next() { if visible { if ch == '\u{1b}' && Some(&'[') == iter.peek() { - fragments.push((visible, buf)); + if !buf.is_empty() { + fragments.push((visible, buf)); + } visible = !visible; buf = String::new(); } @@ -362,11 +364,15 @@ impl SmartString { } else { if ch == 'm' { buf.push(ch); - fragments.push((visible, buf)); + if !buf.is_empty() { + fragments.push((visible, buf)); + } visible = !visible; buf = String::new(); } else if ch != '[' && ch != ';' && !('0'..='9').contains(&ch) { - fragments.push((visible, buf)); + if !buf.is_empty() { + fragments.push((visible, buf)); + } visible = !visible; buf = String::new(); buf.push(ch); From 78e6eb043a21b4165505aba331d6f7555b696321 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:42:32 +0200 Subject: [PATCH 25/27] save game --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f781995..ca1b6d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -384,7 +384,6 @@ impl SmartString { if !buf.is_empty() { fragments.push((visible, buf)); } - println!("FRAGMENTS: {:?}", fragments); Self { fragments } } From c2355fd6845c7a16838d241fc74819d6c8a84af3 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:51:00 +0200 Subject: [PATCH 26/27] save game --- src/test.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test.rs b/src/test.rs index fd39131..3bddec4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -642,3 +642,34 @@ fn color_codes_in_header() { assert_eq!(expected, config.format(input)); } + +#[test] +fn color_codes_pad_right() { + let config = AsciiTable::default(); + let input = vec![ + vec!["Hello".color(Color::Blue).bg_color(Color::Yellow).bold()], + vec!["H".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mHello\u{1b}[0m │\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mH \u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} + +#[test] +fn color_codes_pad_left() { + let mut config = AsciiTable::default(); + config.columns.insert(0, Column {header: String::new(), align: Right, ..Column::default()}); + let input = vec![ + vec!["Hello".color(Color::Blue).bg_color(Color::Yellow).bold()], + vec!["H".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌───────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mHello\u{1b}[0m │\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1m H\u{1b}[0m │\n\ + └───────┘\n"; + + assert_eq!(expected, config.format(input)); +} From b5bbc0be3bb9d2817904920e372be52927a7adb4 Mon Sep 17 00:00:00 2001 From: Gerrit Viljoen Date: Sun, 17 May 2020 12:52:19 +0200 Subject: [PATCH 27/27] save game --- src/test.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test.rs b/src/test.rs index 3bddec4..2a90ae8 100644 --- a/src/test.rs +++ b/src/test.rs @@ -673,3 +673,19 @@ fn color_codes_pad_left() { assert_eq!(expected, config.format(input)); } + +#[test] +fn color_codes_trunc() { + let mut config = AsciiTable::default(); + config.columns.insert(0, Column {header: String::new(), max_width: 2, ..Column::default()}); + let input = vec![ + vec!["Hello".color(Color::Blue).bg_color(Color::Yellow).bold()], + vec!["H".color(Color::Blue).bg_color(Color::Yellow).bold()] + ]; + let expected = "┌────┐\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mH+\u{1b}[0m │\n\ + │ \u{1b}[38;5;4m\u{1b}[48;5;3;1mH \u{1b}[0m │\n\ + └────┘\n"; + + assert_eq!(expected, config.format(input)); +}