diff --git a/Cargo.lock b/Cargo.lock index 2247899..3c4f3b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -43,6 +52,7 @@ dependencies = [ "clap", "nu-ansi-term", "term_size", + "textwrap 0.14.2", "thiserror", ] @@ -75,7 +85,7 @@ dependencies = [ "atty", "bitflags", "strsim", - "textwrap", + "textwrap 0.11.0", "unicode-width", "vec_map", ] @@ -120,6 +130,12 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "nu-ansi-term" version = "0.34.0" @@ -174,6 +190,29 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "smawk" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" + [[package]] name = "strsim" version = "0.8.0" @@ -211,6 +250,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.24" @@ -242,6 +292,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "unicode-linebreak" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f" +dependencies = [ + "regex", +] + [[package]] name = "unicode-width" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index b55d9cf..10c0a9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,5 @@ clap = "~2.33" thiserror = "1.0" anyhow = "1.0.42" nu-ansi-term = "0.34.0" -term_size = "1.0.0-beta1" \ No newline at end of file +term_size = "1.0.0-beta1" +textwrap = "0.14.2" \ No newline at end of file diff --git a/src/conf.rs b/src/conf.rs index 9f78458..998a5e7 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -1,3 +1,4 @@ pub static FORMAT_DATETIME: &str = "%F %R"; pub static FORMAT_TIME: &str = "%R"; pub static FORMAT_DATE: &str = "%F"; +pub static DEFAULT_WIDTH : usize = 80; diff --git a/src/view/table.rs b/src/view/table.rs index c166815..f23318e 100644 --- a/src/view/table.rs +++ b/src/view/table.rs @@ -1,8 +1,11 @@ use std::cmp; use std::fmt; use std::str; +use std::borrow::Cow; use nu_ansi_term::Style; +use textwrap; +use crate::conf; pub enum Wrap { Wrap, @@ -74,6 +77,11 @@ impl Table { .collect() } + /* Calculates the widths for the columns in a table + + If the width of the longest line in the table exceeds the maximum width for the output + all the wrapable columns shrink to an acceptable size. + */ fn get_column_width(&self, max_width: usize) -> Vec { let mut max_column_width = self.get_max_column_width(); @@ -82,10 +90,11 @@ impl Table { let mut number_of_wrappable_columns : usize = columns_wrap.iter().filter(|w| matches!(w, Wrap::Wrap)).count(); if width <= max_width || number_of_wrappable_columns == 0 { - // we do or can not wrap + // we do not need to or can not wrap return max_column_width; } + // the total width of the columns that we may not wrap let unwrapable_width : usize = max_column_width.iter().zip(columns_wrap.iter()) .filter(|(_, wrap)| matches!(wrap, Wrap::NoWrap)) .map(|(width, _)| width) @@ -96,14 +105,14 @@ impl Table { return max_column_width; } - let mut available_width_for_wrappable_columns = max_width - unwrapable_width; - // we start with a width of 0 for all the wrapable columns let mut column_width : Vec = max_column_width.iter().zip(columns_wrap.iter()) .map(|(width, wrap)| if matches!(wrap, Wrap::NoWrap) { width.clone() } else { 0 }) .collect(); // then we distribute the available width to the wrappable columns + let mut available_width_for_wrappable_columns = max_width - unwrapable_width; + while available_width_for_wrappable_columns > 0 && number_of_wrappable_columns > 0 { // the maximum additional width we give each column in this round @@ -123,7 +132,7 @@ impl Table { available_width_for_wrappable_columns -= *max_width - *width; *width = *max_width; - // this row won't need any more width + // this column won't need any more width number_of_wrappable_columns -= 1; } } @@ -157,7 +166,11 @@ impl Table { impl fmt::Display for Table { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let column_width = self.get_column_width(1000); // TODO + + let terminal_width = term_size::dimensions_stdout().map(|d| d.0) + .unwrap_or(conf::DEFAULT_WIDTH); + + let column_width = self.get_column_width(terminal_width - self.columns.len()); let labels : Vec<&String> = self.columns.iter().map(|c| &c.label).collect(); @@ -211,15 +224,33 @@ fn write_cells + std::fmt::Display>( column_width: &[usize], style: Option