mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Refactoring nu_table (#6049)
* nu-table: Remove unused dependencies Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table: Small refactoring Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table: Refactoring Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table: Refactoring alignments Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table: Add width check Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table/ Use commit instead of branch of tabled To be safe * Update Cargo.lock Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> * nu-table: Bump tabled Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
parent
8dea08929a
commit
7bf09559a6
7 changed files with 160 additions and 141 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -94,22 +94,6 @@ dependencies = [
|
||||||
"ansi-parser",
|
"ansi-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi-str"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "git+https://github.com/zhiburt/ansi-str?rev=655cd8125a032286082794690c2cc6dc835345b4#655cd8125a032286082794690c2cc6dc835345b4"
|
|
||||||
dependencies = [
|
|
||||||
"ansi_rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_rs"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "git+https://gitlab.com/zhiburt/ansi_rs#16173ad4a2812a2b0dc9faf1552d5985db4ee310"
|
|
||||||
dependencies = [
|
|
||||||
"nom 7.1.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -2856,14 +2840,11 @@ dependencies = [
|
||||||
name = "nu-table"
|
name = "nu-table"
|
||||||
version = "0.65.1"
|
version = "0.65.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-str 0.2.0 (git+https://github.com/zhiburt/ansi-str?rev=655cd8125a032286082794690c2cc6dc835345b4)",
|
|
||||||
"atty",
|
"atty",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
"regex",
|
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"tabled",
|
"tabled",
|
||||||
"unicode-width",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3187,7 +3168,7 @@ checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "papergrid"
|
name = "papergrid"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/zhiburt/tabled?branch=master#a17e76783422de7db213ef07e81ed1ef78ca599e"
|
source = "git+https://github.com/zhiburt/tabled?rev=cca285b1fc0eac48b8a386c8884092d894d0e7ae#cca285b1fc0eac48b8a386c8884092d894d0e7ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-str 0.1.1",
|
"ansi-str 0.1.1",
|
||||||
"bytecount",
|
"bytecount",
|
||||||
|
@ -4805,9 +4786,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tabled"
|
name = "tabled"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/zhiburt/tabled?branch=master#a17e76783422de7db213ef07e81ed1ef78ca599e"
|
source = "git+https://github.com/zhiburt/tabled?rev=cca285b1fc0eac48b8a386c8884092d894d0e7ae#cca285b1fc0eac48b8a386c8884092d894d0e7ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-str 0.2.0 (git+https://github.com/zhiburt/ansi-str?branch=master)",
|
"ansi-str 0.2.0",
|
||||||
"papergrid",
|
"papergrid",
|
||||||
"tabled_derive",
|
"tabled_derive",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
@ -4816,7 +4797,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tabled_derive"
|
name = "tabled_derive"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/zhiburt/tabled?branch=master#a17e76783422de7db213ef07e81ed1ef78ca599e"
|
source = "git+https://github.com/zhiburt/tabled?rev=cca285b1fc0eac48b8a386c8884092d894d0e7ae#cca285b1fc0eac48b8a386c8884092d894d0e7ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.4.0",
|
"heck 0.4.0",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
|
|
|
@ -7,7 +7,7 @@ use nu_protocol::{
|
||||||
format_error, Category, Config, DataSource, Example, IntoPipelineData, ListStream,
|
format_error, Category, Config, DataSource, Example, IntoPipelineData, ListStream,
|
||||||
PipelineData, PipelineMetadata, RawStream, ShellError, Signature, Span, SyntaxShape, Value,
|
PipelineData, PipelineMetadata, RawStream, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
use nu_table::{StyledString, TableTheme, TextStyle};
|
use nu_table::{Alignments, StyledString, TableTheme, TextStyle};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -167,9 +167,11 @@ impl Command for Table {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
let table = nu_table::Table::new(None, output, load_theme_from_config(config));
|
let table =
|
||||||
|
nu_table::Table::new(Vec::new(), output, load_theme_from_config(config));
|
||||||
|
|
||||||
let result = nu_table::draw_table(&table, term_width, &color_hm, config)
|
let result = table
|
||||||
|
.draw_table(config, &color_hm, Alignments::default(), term_width)
|
||||||
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", term_width));
|
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", term_width));
|
||||||
|
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
|
@ -426,18 +428,16 @@ fn convert_to_table(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(nu_table::Table::new(
|
Ok(Some(nu_table::Table::new(
|
||||||
Some(
|
headers
|
||||||
headers
|
.into_iter()
|
||||||
.into_iter()
|
.map(|x| StyledString {
|
||||||
.map(|x| StyledString {
|
contents: x,
|
||||||
contents: x,
|
style: TextStyle {
|
||||||
style: TextStyle {
|
alignment: nu_table::Alignment::Center,
|
||||||
alignment: nu_table::Alignment::Center,
|
color_style: Some(color_hm["header"]),
|
||||||
color_style: Some(color_hm["header"]),
|
},
|
||||||
},
|
})
|
||||||
})
|
.collect(),
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
data.into_iter()
|
data.into_iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.into_iter()
|
x.into_iter()
|
||||||
|
@ -554,7 +554,8 @@ impl Iterator for PagingTableCreator {
|
||||||
|
|
||||||
match table {
|
match table {
|
||||||
Ok(Some(table)) => {
|
Ok(Some(table)) => {
|
||||||
let result = nu_table::draw_table(&table, term_width, &color_hm, &self.config)
|
let result = table
|
||||||
|
.draw_table(&self.config, &color_hm, Alignments::default(), term_width)
|
||||||
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", term_width));
|
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", term_width));
|
||||||
|
|
||||||
Some(Ok(result.as_bytes().to_vec()))
|
Some(Ok(result.as_bytes().to_vec()))
|
||||||
|
|
|
@ -14,9 +14,6 @@ path = "src/main.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.65.1" }
|
nu-protocol = { path = "../nu-protocol", version = "0.65.1" }
|
||||||
regex = "1.4"
|
|
||||||
unicode-width = "0.1.8"
|
|
||||||
strip-ansi-escapes = "0.1.1"
|
strip-ansi-escapes = "0.1.1"
|
||||||
ansi-str = { git = "https://github.com/zhiburt/ansi-str", rev = "655cd8125a032286082794690c2cc6dc835345b4" }
|
|
||||||
atty = "0.2.14"
|
atty = "0.2.14"
|
||||||
tabled = { git = "https://github.com/zhiburt/tabled", branch = "master", features = ["color"] }
|
tabled = { git = "https://github.com/zhiburt/tabled", rev = "9c831d5bc5bcd5a7b7a349ce63f746a64bf1c278", features = ["color"] }
|
||||||
|
|
|
@ -3,6 +3,6 @@ mod table_theme;
|
||||||
mod textstyle;
|
mod textstyle;
|
||||||
mod width_control;
|
mod width_control;
|
||||||
|
|
||||||
pub use table::{draw_table, Table};
|
pub use table::{Alignments, Table};
|
||||||
pub use table_theme::TableTheme;
|
pub use table_theme::TableTheme;
|
||||||
pub use textstyle::{Alignment, StyledString, TextStyle};
|
pub use textstyle::{Alignment, StyledString, TextStyle};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use nu_protocol::Config;
|
use nu_protocol::Config;
|
||||||
use nu_table::{draw_table, StyledString, Table, TableTheme, TextStyle};
|
use nu_table::{Alignments, StyledString, Table, TableTheme, TextStyle};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -23,13 +23,14 @@ fn main() {
|
||||||
// The table rows
|
// The table rows
|
||||||
let rows = vec_of_str_to_vec_of_styledstr(&row_data, false);
|
let rows = vec_of_str_to_vec_of_styledstr(&row_data, false);
|
||||||
// The table itself
|
// The table itself
|
||||||
let table = Table::new(Some(headers), vec![rows; 3], TableTheme::rounded());
|
let table = Table::new(headers, vec![rows; 3], TableTheme::rounded());
|
||||||
// FIXME: Config isn't available from here so just put these here to compile
|
// FIXME: Config isn't available from here so just put these here to compile
|
||||||
let color_hm: HashMap<String, nu_ansi_term::Style> = HashMap::new();
|
let color_hm: HashMap<String, nu_ansi_term::Style> = HashMap::new();
|
||||||
// get the default config
|
// get the default config
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
// Capture the table as a string
|
// Capture the table as a string
|
||||||
let output_table = draw_table(&table, width, &color_hm, &config)
|
let output_table = table
|
||||||
|
.draw_table(&config, &color_hm, Alignments::default(), width)
|
||||||
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", width));
|
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", width));
|
||||||
// Draw the table
|
// Draw the table
|
||||||
println!("{}", output_table)
|
println!("{}", output_table)
|
||||||
|
|
|
@ -5,14 +5,15 @@ use nu_protocol::{Config, FooterMode, TrimStrategy};
|
||||||
use tabled::{
|
use tabled::{
|
||||||
builder::Builder,
|
builder::Builder,
|
||||||
formatting_settings::AlignmentStrategy,
|
formatting_settings::AlignmentStrategy,
|
||||||
object::{Cell, Columns, Rows},
|
object::{Cell, Columns, Rows, Segment},
|
||||||
papergrid,
|
papergrid,
|
||||||
style::BorderColor,
|
style::BorderColor,
|
||||||
Alignment, Modify, TableOption, Width,
|
Alignment, AlignmentHorizontal, Modify, ModifyObject, TableOption, Width,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{table_theme::TableTheme, width_control::maybe_truncate_columns, StyledString};
|
use crate::{table_theme::TableTheme, width_control::maybe_truncate_columns, StyledString};
|
||||||
|
|
||||||
|
/// Table represent a table view.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
headers: Option<Vec<StyledString>>,
|
headers: Option<Vec<StyledString>>,
|
||||||
|
@ -20,15 +21,36 @@ pub struct Table {
|
||||||
theme: TableTheme,
|
theme: TableTheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Alignments {
|
||||||
|
data: AlignmentHorizontal,
|
||||||
|
index: AlignmentHorizontal,
|
||||||
|
header: AlignmentHorizontal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Alignments {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
data: AlignmentHorizontal::Center,
|
||||||
|
index: AlignmentHorizontal::Right,
|
||||||
|
header: AlignmentHorizontal::Center,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
|
/// Creates a [Table] instance.
|
||||||
|
///
|
||||||
|
/// If `headers.is_empty` then no headers will be rendered.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
headers: Option<Vec<StyledString>>,
|
headers: Vec<StyledString>,
|
||||||
data: Vec<Vec<StyledString>>,
|
data: Vec<Vec<StyledString>>,
|
||||||
theme: TableTheme,
|
theme: TableTheme,
|
||||||
) -> Table {
|
) -> Table {
|
||||||
let headers = match headers {
|
let headers = if headers.is_empty() {
|
||||||
Some(headers) if headers.is_empty() => None,
|
None
|
||||||
headers => headers,
|
} else {
|
||||||
|
Some(headers)
|
||||||
};
|
};
|
||||||
|
|
||||||
Table {
|
Table {
|
||||||
|
@ -37,34 +59,59 @@ impl Table {
|
||||||
theme,
|
theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws a trable on a String.
|
||||||
|
///
|
||||||
|
/// It returns None in case where table cannot be fit to a terminal width.
|
||||||
|
pub fn draw_table(
|
||||||
|
&self,
|
||||||
|
config: &Config,
|
||||||
|
color_hm: &HashMap<String, Style>,
|
||||||
|
alignments: Alignments,
|
||||||
|
termwidth: usize,
|
||||||
|
) -> Option<String> {
|
||||||
|
draw_table(self, config, color_hm, alignments, termwidth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_table(
|
fn draw_table(
|
||||||
table: &Table,
|
table: &Table,
|
||||||
termwidth: usize,
|
|
||||||
color_hm: &HashMap<String, Style>,
|
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
color_hm: &HashMap<String, Style>,
|
||||||
|
alignments: Alignments,
|
||||||
|
termwidth: usize,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let (mut headers, mut data, count_columns) =
|
let mut headers = colorize_headers(table.headers.as_deref());
|
||||||
table_fix_lengths(table.headers.as_ref(), &table.data);
|
let mut data = colorize_data(&table.data, table.headers.as_ref().map_or(0, |h| h.len()));
|
||||||
|
|
||||||
|
let count_columns = table_fix_lengths(headers.as_mut(), &mut data);
|
||||||
|
|
||||||
maybe_truncate_columns(&mut headers, &mut data, count_columns, termwidth);
|
maybe_truncate_columns(&mut headers, &mut data, count_columns, termwidth);
|
||||||
|
|
||||||
let alignments = build_alignment_map(&table.data);
|
let table_data = &table.data;
|
||||||
|
|
||||||
let headers = table_header_to_strings(headers);
|
|
||||||
let data = table_data_to_strings(data, count_columns);
|
|
||||||
|
|
||||||
let theme = &table.theme;
|
let theme = &table.theme;
|
||||||
let with_header = headers.is_some();
|
let with_header = headers.is_some();
|
||||||
let with_footer = with_header && need_footer(config, data.len() as u64);
|
let with_footer = with_header && need_footer(config, data.len() as u64);
|
||||||
|
let with_index = !config.disable_table_indexes;
|
||||||
|
|
||||||
let table = build_table(data, headers, Some(alignments), config, with_footer);
|
let table = build_table(data, headers, with_footer);
|
||||||
let table = load_theme(table, color_hm, theme, with_footer, with_header);
|
let table = load_theme(table, color_hm, theme, with_footer, with_header);
|
||||||
|
let table = align_table(
|
||||||
|
table,
|
||||||
|
alignments,
|
||||||
|
with_index,
|
||||||
|
with_header,
|
||||||
|
with_footer,
|
||||||
|
table_data,
|
||||||
|
);
|
||||||
let table = table_trim_columns(table, termwidth, &config.trim_strategy);
|
let table = table_trim_columns(table, termwidth, &config.trim_strategy);
|
||||||
|
|
||||||
Some(print_table(table, config))
|
let table = print_table(table, config);
|
||||||
|
if table_width(&table) > termwidth {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(table)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_table(table: tabled::Table, config: &Config) -> String {
|
fn print_table(table: tabled::Table, config: &Config) -> String {
|
||||||
|
@ -83,19 +130,20 @@ fn print_table(table: tabled::Table, config: &Config) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_data_to_strings(
|
fn table_width(table: &str) -> usize {
|
||||||
table_data: Vec<Vec<StyledString>>,
|
table.lines().next().map_or(0, papergrid::string_width)
|
||||||
count_headers: usize,
|
}
|
||||||
) -> Vec<Vec<String>> {
|
|
||||||
let mut data = vec![Vec::with_capacity(count_headers); table_data.len()];
|
fn colorize_data(table_data: &[Vec<StyledString>], count_columns: usize) -> Vec<Vec<String>> {
|
||||||
for (row, row_data) in table_data.into_iter().enumerate() {
|
let mut data = vec![Vec::with_capacity(count_columns); table_data.len()];
|
||||||
|
for (row, row_data) in table_data.iter().enumerate() {
|
||||||
for cell in row_data {
|
for cell in row_data {
|
||||||
let colored_text = cell
|
let colored_text = cell
|
||||||
.style
|
.style
|
||||||
.color_style
|
.color_style
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|color| color.paint(&cell.contents).to_string())
|
.map(|color| color.paint(&cell.contents).to_string())
|
||||||
.unwrap_or(cell.contents);
|
.unwrap_or_else(|| cell.contents.clone());
|
||||||
|
|
||||||
data[row].push(colored_text)
|
data[row].push(colored_text)
|
||||||
}
|
}
|
||||||
|
@ -104,8 +152,8 @@ fn table_data_to_strings(
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_header_to_strings(table_headers: Option<Vec<StyledString>>) -> Option<Vec<String>> {
|
fn colorize_headers(headers: Option<&[StyledString]>) -> Option<Vec<String>> {
|
||||||
table_headers.map(|table_headers| {
|
headers.map(|table_headers| {
|
||||||
let mut headers = Vec::with_capacity(table_headers.len());
|
let mut headers = Vec::with_capacity(table_headers.len());
|
||||||
for cell in table_headers {
|
for cell in table_headers {
|
||||||
let colored_text = cell
|
let colored_text = cell
|
||||||
|
@ -113,7 +161,7 @@ fn table_header_to_strings(table_headers: Option<Vec<StyledString>>) -> Option<V
|
||||||
.color_style
|
.color_style
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|color| color.paint(&cell.contents).to_string())
|
.map(|color| color.paint(&cell.contents).to_string())
|
||||||
.unwrap_or(cell.contents);
|
.unwrap_or_else(|| cell.contents.clone());
|
||||||
|
|
||||||
headers.push(colored_text)
|
headers.push(colored_text)
|
||||||
}
|
}
|
||||||
|
@ -122,28 +170,11 @@ fn table_header_to_strings(table_headers: Option<Vec<StyledString>>) -> Option<V
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_alignment_map(data: &[Vec<StyledString>]) -> Vec<Vec<Alignment>> {
|
|
||||||
let mut v = vec![Vec::new(); data.len()];
|
|
||||||
for (i, row) in data.iter().enumerate() {
|
|
||||||
let mut row_alignments = Vec::with_capacity(row.len());
|
|
||||||
for col in row {
|
|
||||||
row_alignments.push(Alignment::Horizontal(col.style.alignment));
|
|
||||||
}
|
|
||||||
|
|
||||||
v[i] = row_alignments;
|
|
||||||
}
|
|
||||||
|
|
||||||
v
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_table(
|
fn build_table(
|
||||||
data: Vec<Vec<String>>,
|
data: Vec<Vec<String>>,
|
||||||
headers: Option<Vec<String>>,
|
headers: Option<Vec<String>>,
|
||||||
alignment_map: Option<Vec<Vec<Alignment>>>,
|
|
||||||
config: &Config,
|
|
||||||
need_footer: bool,
|
need_footer: bool,
|
||||||
) -> tabled::Table {
|
) -> tabled::Table {
|
||||||
let header_present = headers.is_some();
|
|
||||||
let mut builder = Builder::from(data);
|
let mut builder = Builder::from(data);
|
||||||
|
|
||||||
if let Some(headers) = headers {
|
if let Some(headers) = headers {
|
||||||
|
@ -154,38 +185,65 @@ fn build_table(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut table = builder.build();
|
builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn align_table(
|
||||||
|
mut table: tabled::Table,
|
||||||
|
alignments: Alignments,
|
||||||
|
with_index: bool,
|
||||||
|
with_header: bool,
|
||||||
|
with_footer: bool,
|
||||||
|
data: &[Vec<StyledString>],
|
||||||
|
) -> tabled::Table {
|
||||||
table = table.with(
|
table = table.with(
|
||||||
Modify::new(Rows::new(1..))
|
Modify::new(Segment::all())
|
||||||
.with(Alignment::left())
|
.with(Alignment::Horizontal(alignments.data))
|
||||||
.with(AlignmentStrategy::PerLine),
|
.with(AlignmentStrategy::PerLine),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !config.disable_table_indexes {
|
if with_index {
|
||||||
table = table.with(Modify::new(Columns::first()).with(Alignment::right()));
|
table =
|
||||||
|
table.with(Modify::new(Columns::first()).with(Alignment::Horizontal(alignments.index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if header_present {
|
if with_header {
|
||||||
table = table.with(Modify::new(Rows::first()).with(Alignment::center()));
|
let alignment = Alignment::Horizontal(alignments.header);
|
||||||
|
table = table.with(Modify::new(Rows::first()).with(alignment.clone()));
|
||||||
|
|
||||||
|
if with_footer {
|
||||||
|
table = table.with(Modify::new(Rows::last()).with(alignment));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(alignments) = alignment_map {
|
table = override_alignments(table, data, with_header, with_index, alignments);
|
||||||
table = apply_alignments(table, alignments, header_present);
|
|
||||||
}
|
|
||||||
|
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_alignments(
|
fn override_alignments(
|
||||||
mut table: tabled::Table,
|
mut table: tabled::Table,
|
||||||
alignment: Vec<Vec<Alignment>>,
|
data: &[Vec<StyledString>],
|
||||||
header_present: bool,
|
header_present: bool,
|
||||||
|
index_present: bool,
|
||||||
|
alignments: Alignments,
|
||||||
) -> tabled::Table {
|
) -> tabled::Table {
|
||||||
let offset = if header_present { 1 } else { 0 };
|
let offset = if header_present { 1 } else { 0 };
|
||||||
for (row, alignments) in alignment.into_iter().enumerate() {
|
for (row, rows) in data.iter().enumerate() {
|
||||||
for (col, alignment) in alignments.into_iter().enumerate() {
|
for (col, s) in rows.iter().enumerate() {
|
||||||
table = table.with(Modify::new(Cell(row + offset, col)).with(alignment));
|
if index_present && col == 0 && s.style.alignment == alignments.index {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.style.alignment == alignments.data {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
table = table.with(
|
||||||
|
Cell(row + offset, col)
|
||||||
|
.modify()
|
||||||
|
.with(Alignment::Horizontal(s.style.alignment)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,31 +365,21 @@ impl tabled::TableOption for &TrimStrategyModifier<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_fix_lengths(
|
fn table_fix_lengths(headers: Option<&mut Vec<String>>, data: &mut [Vec<String>]) -> usize {
|
||||||
headers: Option<&Vec<StyledString>>,
|
let length = table_find_max_length(headers.as_deref(), data);
|
||||||
data: &[Vec<StyledString>],
|
|
||||||
) -> (Option<Vec<StyledString>>, Vec<Vec<StyledString>>, usize) {
|
|
||||||
let length = table_find_max_length(headers, data);
|
|
||||||
|
|
||||||
let headers_fixed = headers.map(|h| {
|
if let Some(headers) = headers {
|
||||||
let mut headers_fixed = Vec::with_capacity(length);
|
headers.extend(std::iter::repeat(String::default()).take(length - headers.len()));
|
||||||
headers_fixed.extend(h.iter().cloned());
|
|
||||||
headers_fixed.extend(std::iter::repeat(StyledString::default()).take(length - h.len()));
|
|
||||||
headers_fixed
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut data_fixed = Vec::with_capacity(data.len());
|
|
||||||
for row in data {
|
|
||||||
let mut row_fixed = Vec::with_capacity(length);
|
|
||||||
row_fixed.extend(row.iter().cloned());
|
|
||||||
row_fixed.extend(std::iter::repeat(StyledString::default()).take(length - row.len()));
|
|
||||||
data_fixed.push(row_fixed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(headers_fixed, data_fixed, length)
|
for row in data {
|
||||||
|
row.extend(std::iter::repeat(String::default()).take(length - row.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
length
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_find_max_length(headers: Option<&Vec<StyledString>>, data: &[Vec<StyledString>]) -> usize {
|
fn table_find_max_length<T>(headers: Option<&Vec<T>>, data: &[Vec<T>]) -> usize {
|
||||||
let mut length = headers.map_or(0, |h| h.len());
|
let mut length = headers.map_or(0, |h| h.len());
|
||||||
for row in data {
|
for row in data {
|
||||||
length = std::cmp::max(length, row.len());
|
length = std::cmp::max(length, row.len());
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::textstyle::TextStyle;
|
|
||||||
use crate::StyledString;
|
|
||||||
|
|
||||||
pub(crate) fn maybe_truncate_columns(
|
pub(crate) fn maybe_truncate_columns(
|
||||||
headers: &mut Option<Vec<StyledString>>,
|
headers: &mut Option<Vec<String>>,
|
||||||
data: &mut [Vec<StyledString>],
|
data: &mut [Vec<String>],
|
||||||
length: usize,
|
length: usize,
|
||||||
termwidth: usize,
|
termwidth: usize,
|
||||||
) {
|
) {
|
||||||
|
@ -14,20 +11,14 @@ pub(crate) fn maybe_truncate_columns(
|
||||||
if let Some(headers) = headers {
|
if let Some(headers) = headers {
|
||||||
if max_num_of_columns < length {
|
if max_num_of_columns < length {
|
||||||
headers.truncate(max_num_of_columns);
|
headers.truncate(max_num_of_columns);
|
||||||
headers.push(StyledString::new(
|
headers.push(String::from("..."));
|
||||||
String::from("..."),
|
|
||||||
TextStyle::basic_center(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if max_num_of_columns < length {
|
if max_num_of_columns < length {
|
||||||
for entry in data.iter_mut() {
|
for entry in data.iter_mut() {
|
||||||
entry.truncate(max_num_of_columns);
|
entry.truncate(max_num_of_columns);
|
||||||
entry.push(StyledString::new(
|
entry.push(String::from("..."));
|
||||||
String::from("..."),
|
|
||||||
TextStyle::basic_center(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue