From 33aea56ccd21238cf510b6683a16cacfc0badf36 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Thu, 15 Dec 2022 17:47:04 +0300 Subject: [PATCH] Try to fix #7380 (#7446) fix https://github.com/nushell/nushell/issues/7380 --- Cargo.lock | 6 +- crates/nu-command/Cargo.toml | 1 + crates/nu-command/src/viewers/table.rs | 217 +++++++---- crates/nu-command/tests/commands/table.rs | 4 +- crates/nu-explore/src/nu_common/table.rs | 152 +++++--- crates/nu-protocol/src/config.rs | 12 + crates/nu-table/Cargo.toml | 3 +- crates/nu-table/examples/table_demo.rs | 28 +- crates/nu-table/src/lib.rs | 50 +-- crates/nu-table/src/nu_protocol_table.rs | 13 +- crates/nu-table/src/table.rs | 454 ++++++++++++++++------ crates/nu-table/src/util.rs | 54 +++ crates/nu-table/tests/common.rs | 68 ++++ crates/nu-table/tests/constrains.rs | 323 ++++++++------- crates/nu-table/tests/expand.rs | 43 +- crates/nu-table/tests/style.rs | 187 +++++---- 16 files changed, 1006 insertions(+), 609 deletions(-) create mode 100644 crates/nu-table/src/util.rs create mode 100644 crates/nu-table/tests/common.rs diff --git a/Cargo.lock b/Cargo.lock index f6788c4b05..a77351905f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1889,9 +1889,9 @@ dependencies = [ [[package]] name = "json_to_table" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "408f09e42613f7a9902ecf2f30bcd053cf9f5668d0b1493ae1669070338d661b" +checksum = "a0be33515faeb3773f550c80fd7a889148164e58f7e3cf36467718c8ce71ee55" dependencies = [ "serde_json", "tabled", @@ -2576,6 +2576,7 @@ version = "0.72.2" dependencies = [ "Inflector", "alphanumeric-sort", + "atty", "base64", "byteorder", "bytesize", @@ -2811,7 +2812,6 @@ dependencies = [ name = "nu-table" version = "0.72.2" dependencies = [ - "atty", "json_to_table", "nu-ansi-term", "nu-protocol", diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 0c55084e25..81f4aa13ef 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -29,6 +29,7 @@ num-format = { version = "0.4.3" } # Potential dependencies for extras alphanumeric-sort = "1.4.4" +atty = "0.2.14" base64 = "0.13.0" byteorder = "1.4.3" bytesize = "1.1.0" diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index ad60e38be7..b532b0e204 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -8,7 +8,7 @@ use nu_protocol::{ PipelineData, PipelineMetadata, RawStream, ShellError, Signature, Span, SyntaxShape, TableIndexMode, Value, }; -use nu_table::{string_width, Alignment, Alignments, Table as NuTable, TableTheme, TextStyle}; +use nu_table::{string_width, Alignment, Table as NuTable, TableConfig, TableTheme, TextStyle}; use nu_utils::get_ls_colors; use std::sync::Arc; use std::time::Instant; @@ -302,6 +302,8 @@ fn handle_table_command( TableView::Collapsed => build_collapsed_table(cols, vals, config, term_width), }?; + let result = strip_output_color(result, config); + let ctrl_c_was_triggered = || match &ctrlc { Some(ctrlc) => ctrlc.load(Ordering::SeqCst), None => false, @@ -411,19 +413,12 @@ fn build_general_table2( } let data_len = data.len(); - let table = NuTable::new(data, (data_len, 2), term_width, false, false); - - let theme = load_theme_from_config(config); let color_hm = get_color_config(config); + let table_config = create_table_config(config, &color_hm, data_len, false, false, false); - let table = table.draw_table( - config, - &color_hm, - Alignments::default(), - &theme, - term_width, - false, - ); + let table = NuTable::new(data, (data_len, 2)); + + let table = table.draw(table_config, term_width); Ok(table) } @@ -440,16 +435,18 @@ fn build_expanded_table( flatten: bool, flatten_sep: &str, ) -> Result, ShellError> { - let theme = load_theme_from_config(config); let color_hm = get_color_config(config); - let alignments = Alignments::default(); + let theme = load_theme_from_config(config); // calculate the width of a key part + the rest of table so we know the rest of the table width available for value. let key_width = cols.iter().map(|col| string_width(col)).max().unwrap_or(0); let key = NuTable::create_cell(" ".repeat(key_width), TextStyle::default()); - let key_table = NuTable::new(vec![vec![key]], (1, 2), term_width, false, false); + let key_table = NuTable::new(vec![vec![key]], (1, 2)); let key_width = key_table - .draw_table(config, &color_hm, alignments, &theme, usize::MAX, false) + .draw( + create_table_config(config, &color_hm, 1, false, false, false), + usize::MAX, + ) .map(|table| string_width(&table)) .unwrap_or(0); @@ -486,7 +483,6 @@ fn build_expanded_table( config, span, &color_hm, - &theme, deep, flatten, flatten_sep, @@ -494,21 +490,23 @@ fn build_expanded_table( )?; match table { - Some(mut table) => { + Some((mut table, with_header, with_index)) => { // controll width via removing table columns. let theme = load_theme_from_config(config); table.truncate(remaining_width, &theme); is_expanded = true; - let val = table.draw_table( + let table_config = create_table_config( config, &color_hm, - alignments, - &theme, - remaining_width, + table.count_rows(), + with_header, + with_index, false, ); + + let val = table.draw(table_config, remaining_width); match val { Some(result) => result, None => return Ok(None), @@ -573,11 +571,10 @@ fn build_expanded_table( } let data_len = data.len(); - let table = NuTable::new(data, (data_len, 2), term_width, false, false); + let table_config = create_table_config(config, &color_hm, data_len, false, false, false); + let table = NuTable::new(data, (data_len, 2)); - let table_s = table - .clone() - .draw_table(config, &color_hm, alignments, &theme, term_width, false); + let table_s = table.clone().draw(table_config.clone(), term_width); let table = match table_s { Some(s) => { @@ -590,7 +587,8 @@ fn build_expanded_table( let used_percent = width as f32 / term_width as f32; if width < term_width && used_percent > EXPAND_TREASHHOLD { - table.draw_table(config, &color_hm, alignments, &theme, term_width, true) + let table_config = table_config.expand(); + table.draw(table_config, term_width) } else { Some(s) } @@ -760,15 +758,15 @@ fn make_clickable_link( } } +#[allow(clippy::too_many_arguments)] fn convert_to_table( row_offset: usize, input: &[Value], ctrlc: Option>, config: &Config, head: Span, - termwidth: usize, color_hm: &NuColorMap, -) -> Result, ShellError> { +) -> Result, ShellError> { let mut headers = get_columns(input); let mut input = input.iter().peekable(); let float_precision = config.float_precision as usize; @@ -861,15 +859,9 @@ fn convert_to_table( } let count_rows = data.len(); - let table = NuTable::new( - data, - (count_rows, count_columns), - termwidth, - with_header, - with_index, - ); + let table = NuTable::new(data, (count_rows, count_columns)); - Ok(Some(table)) + Ok(Some((table, with_header, with_index))) } #[allow(clippy::too_many_arguments)] @@ -881,12 +873,11 @@ fn convert_to_table2<'a>( config: &Config, head: Span, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, available_width: usize, -) -> Result, ShellError> { +) -> Result, ShellError> { const PADDING_SPACE: usize = 2; const SPLIT_LINE_SPACE: usize = 1; const ADDITIONAL_CELL_SPACE: usize = PADDING_SPACE + SPLIT_LINE_SPACE; @@ -984,7 +975,6 @@ fn convert_to_table2<'a>( config, &ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -997,9 +987,10 @@ fn convert_to_table2<'a>( let count_columns = if with_index { 2 } else { 1 }; let size = (data.len(), count_columns); - let table = NuTable::new(data, size, usize::MAX, with_header, with_index); - return Ok(Some(table)); + let table = NuTable::new(data, size); + + return Ok(Some((table, with_header, with_index))); } let mut widths = Vec::new(); @@ -1045,7 +1036,6 @@ fn convert_to_table2<'a>( config, &ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -1162,9 +1152,9 @@ fn convert_to_table2<'a>( let count_rows = data.len(); let size = (count_rows, count_columns); - let table = NuTable::new(data, size, usize::MAX, with_header, with_index); + let table = NuTable::new(data, size); - Ok(Some(table)) + Ok(Some((table, with_header, with_index))) } fn lookup_index_value(item: &Value, config: &Config) -> Option { @@ -1210,7 +1200,6 @@ fn create_table2_entry( config: &Config, ctrlc: &Option>, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, @@ -1228,7 +1217,6 @@ fn create_table2_entry( config, ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -1242,7 +1230,6 @@ fn create_table2_entry( config, ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -1266,7 +1253,6 @@ fn convert_to_table2_entry( config: &Config, ctrlc: &Option>, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, @@ -1289,7 +1275,6 @@ fn convert_to_table2_entry( config, *span, color_hm, - theme, deep.map(|i| i - 1), flatten, flatten_sep, @@ -1297,9 +1282,17 @@ fn convert_to_table2_entry( ); let inner_table = table.map(|table| { - table.and_then(|table| { - let alignments = Alignments::default(); - table.draw_table(config, color_hm, alignments, theme, usize::MAX, false) + table.and_then(|(table, with_header, with_index)| { + let table_config = create_table_config( + config, + color_hm, + table.count_rows(), + with_header, + with_index, + false, + ); + + table.draw(table_config, usize::MAX) }) }); @@ -1329,7 +1322,6 @@ fn convert_to_table2_entry( config, *span, color_hm, - theme, deep.map(|i| i - 1), flatten, flatten_sep, @@ -1337,11 +1329,20 @@ fn convert_to_table2_entry( ); let inner_table = table.map(|table| { - table.and_then(|table| { - let alignments = Alignments::default(); - table.draw_table(config, color_hm, alignments, theme, usize::MAX, false) + table.and_then(|(table, with_header, with_index)| { + let table_config = create_table_config( + config, + color_hm, + table.count_rows(), + with_header, + with_index, + false, + ); + + table.draw(table_config, usize::MAX) }) }); + if let Ok(Some(table)) = inner_table { (table, TextStyle::default()) } else { @@ -1445,9 +1446,10 @@ impl PagingTableCreator { return Ok(None); } - let theme = load_theme_from_config(&self.config); let term_width = get_width_param(self.width_param); let color_hm = get_color_config(&self.config); + let theme = load_theme_from_config(&self.config); + let table = convert_to_table2( self.row_offset, batch.iter(), @@ -1455,29 +1457,30 @@ impl PagingTableCreator { &self.config, self.head, &color_hm, - &theme, limit, flatten, flatten_separator.as_deref().unwrap_or(" "), term_width, )?; - let mut table = match table { + let (mut table, with_header, with_index) = match table { Some(table) => table, None => return Ok(None), }; table.truncate(term_width, &theme); - let table_s = table.clone().draw_table( + let table_config = create_table_config( &self.config, &color_hm, - Alignments::default(), - &theme, - term_width, + table.count_rows(), + with_header, + with_index, false, ); + let table_s = table.clone().draw(table_config.clone(), term_width); + let table = match table_s { Some(s) => { // check whether we need to expand table or not, @@ -1489,14 +1492,8 @@ impl PagingTableCreator { let used_percent = width as f32 / term_width as f32; if width < term_width && used_percent > EXPAND_TREASHHOLD { - table.draw_table( - &self.config, - &color_hm, - Alignments::default(), - &theme, - term_width, - true, - ) + let table_config = table_config.expand(); + table.draw(table_config, term_width) } else { Some(s) } @@ -1538,7 +1535,6 @@ impl PagingTableCreator { fn build_general(&self, batch: &[Value]) -> Result, ShellError> { let term_width = get_width_param(self.width_param); let color_hm = get_color_config(&self.config); - let theme = load_theme_from_config(&self.config); let table = convert_to_table( self.row_offset, @@ -1546,24 +1542,25 @@ impl PagingTableCreator { self.ctrlc.clone(), &self.config, self.head, - term_width, &color_hm, )?; - let table = match table { + let (table, with_header, with_index) = match table { Some(table) => table, None => return Ok(None), }; - let table = table.draw_table( + let table_config = create_table_config( &self.config, &color_hm, - Alignments::default(), - &theme, - term_width, + table.count_rows(), + with_index, + with_header, false, ); + let table = table.draw(table_config, term_width); + Ok(table) } } @@ -1617,8 +1614,12 @@ impl Iterator for PagingTableCreator { match table { Ok(Some(table)) => { + let table = + strip_output_color(Some(table), &self.config).expect("must never happen"); + let mut bytes = table.as_bytes().to_vec(); - bytes.push(b'\n'); // tabled tables don't come with a newline on the end + bytes.push(b'\n'); // nu-table tables don't come with a newline on the end + Some(Ok(bytes)) } Err(err) => Some(Err(err)), @@ -1696,3 +1697,59 @@ enum TableView { flatten_separator: Option, }, } + +fn strip_output_color(output: Option, config: &Config) -> Option { + match output { + Some(output) => { + // the atty is for when people do ls from vim, there should be no coloring there + if !config.use_ansi_coloring || !atty::is(atty::Stream::Stdout) { + // Draw the table without ansi colors + Some(nu_utils::strip_ansi_string_likely(output)) + } else { + // Draw the table with ansi colors + Some(output) + } + } + None => None, + } +} + +fn create_table_config( + config: &Config, + color_hm: &HashMap, + count_records: usize, + with_header: bool, + with_index: bool, + expand: bool, +) -> TableConfig { + let theme = load_theme_from_config(config); + let append_footer = with_footer(config, with_header, count_records); + + let mut table_cfg = TableConfig::new(theme, with_header, with_index, append_footer); + + let sep_color = lookup_separator_color(color_hm); + if let Some(color) = sep_color { + table_cfg = table_cfg.splitline_style(color); + } + + if expand { + table_cfg = table_cfg.expand(); + } + + table_cfg.trim(config.trim_strategy.clone()) +} + +fn lookup_separator_color( + color_hm: &HashMap, +) -> Option { + color_hm.get("separator").cloned() +} + +fn with_footer(config: &Config, with_header: bool, count_records: usize) -> bool { + with_header && need_footer(config, count_records as u64) +} + +fn need_footer(config: &Config, count_records: u64) -> bool { + matches!(config.footer_mode, FooterMode::RowCount(limit) if count_records > limit) + || matches!(config.footer_mode, FooterMode::Always) +} diff --git a/crates/nu-command/tests/commands/table.rs b/crates/nu-command/tests/commands/table.rs index ed3ca3e929..3d378080b1 100644 --- a/crates/nu-command/tests/commands/table.rs +++ b/crates/nu-command/tests/commands/table.rs @@ -19,7 +19,7 @@ fn table_collapse_0() { let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table --collapse"#); assert_eq!( actual.out, - "\u{1b}[37m╭───\u{1b}[39m\u{1b}[37m┬───\u{1b}[39m\u{1b}[37m┬───╮\u{1b}[39m\u{1b}[37m│\u{1b}[39m a \u{1b}[37m│\u{1b}[39m b \u{1b}[37m│\u{1b}[39m c \u{1b}[37m│\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m 1 \u{1b}[37m│\u{1b}[39m 2 \u{1b}[37m│\u{1b}[39m 3 \u{1b}[37m│\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m 4 \u{1b}[37m│\u{1b}[39m 5 \u{1b}[37m│\u{1b}[39m 1 \u{1b}[37m│\u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m 2 \u{1b}[37m│\u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m 3 \u{1b}[37m│\u{1b}[39m\u{1b}[37m╰───\u{1b}[39m\u{1b}[37m┴───\u{1b}[39m\u{1b}[37m┴───╯\u{1b}[39m" + "╭───┬───┬───╮│ a │ b │ c │ ─── ─── ─── │ 1 │ 2 │ 3 │ ─── ─── ─── │ 4 │ 5 │ 1 ││ │ ─── │ │ │ 2 ││ │ ─── │ │ │ 3 │╰───┴───┴───╯" ); } @@ -208,6 +208,6 @@ fn table_pagging_row_offset_overlap() { let actual = nu!(r#"0..1000"#); assert_eq!( actual.out, - "╭─────┬─────╮│ 0 │ 0 ││ 1 │ 1 ││ 2 │ 2 ││ 3 │ 3 ││ 4 │ 4 ││ 5 │ 5 ││ 6 │ 6 ││ 7 │ 7 ││ 8 │ 8 ││ 9 │ 9 ││ 10 │ 10 ││ 11 │ 11 ││ 12 │ 12 ││ 13 │ 13 ││ 14 │ 14 ││ 15 │ 15 ││ 16 │ 16 ││ 17 │ 17 ││ 18 │ 18 ││ 19 │ 19 ││ 20 │ 20 ││ 21 │ 21 ││ 22 │ 22 ││ 23 │ 23 ││ 24 │ 24 ││ 25 │ 25 ││ 26 │ 26 ││ 27 │ 27 ││ 28 │ 28 ││ 29 │ 29 ││ 30 │ 30 ││ 31 │ 31 ││ 32 │ 32 ││ 33 │ 33 ││ 34 │ 34 ││ 35 │ 35 ││ 36 │ 36 ││ 37 │ 37 ││ 38 │ 38 ││ 39 │ 39 ││ 40 │ 40 ││ 41 │ 41 ││ 42 │ 42 ││ 43 │ 43 ││ 44 │ 44 ││ 45 │ 45 ││ 46 │ 46 ││ 47 │ 47 ││ 48 │ 48 ││ 49 │ 49 ││ 50 │ 50 ││ 51 │ 51 ││ 52 │ 52 ││ 53 │ 53 ││ 54 │ 54 ││ 55 │ 55 ││ 56 │ 56 ││ 57 │ 57 ││ 58 │ 58 ││ 59 │ 59 ││ 60 │ 60 ││ 61 │ 61 ││ 62 │ 62 ││ 63 │ 63 ││ 64 │ 64 ││ 65 │ 65 ││ 66 │ 66 ││ 67 │ 67 ││ 68 │ 68 ││ 69 │ 69 ││ 70 │ 70 ││ 71 │ 71 ││ 72 │ 72 ││ 73 │ 73 ││ 74 │ 74 ││ 75 │ 75 ││ 76 │ 76 ││ 77 │ 77 ││ 78 │ 78 ││ 79 │ 79 ││ 80 │ 80 ││ 81 │ 81 ││ 82 │ 82 ││ 83 │ 83 ││ 84 │ 84 ││ 85 │ 85 ││ 86 │ 86 ││ 87 │ 87 ││ 88 │ 88 ││ 89 │ 89 ││ 90 │ 90 ││ 91 │ 91 ││ 92 │ 92 ││ 93 │ 93 ││ 94 │ 94 ││ 95 │ 95 ││ 96 │ 96 ││ 97 │ 97 ││ 98 │ 98 ││ 99 │ 99 ││ 100 │ 100 ││ 101 │ 101 ││ 102 │ 102 ││ 103 │ 103 ││ 104 │ 104 ││ 105 │ 105 ││ 106 │ 106 ││ 107 │ 107 ││ 108 │ 108 ││ 109 │ 109 ││ 110 │ 110 ││ 111 │ 111 ││ 112 │ 112 ││ 113 │ 113 ││ 114 │ 114 ││ 115 │ 115 ││ 116 │ 116 ││ 117 │ 117 ││ 118 │ 118 ││ 119 │ 119 ││ 120 │ 120 ││ 121 │ 121 ││ 122 │ 122 ││ 123 │ 123 ││ 124 │ 124 ││ 125 │ 125 ││ 126 │ 126 ││ 127 │ 127 ││ 128 │ 128 ││ 129 │ 129 ││ 130 │ 130 ││ 131 │ 131 ││ 132 │ 132 ││ 133 │ 133 ││ 134 │ 134 ││ 135 │ 135 ││ 136 │ 136 ││ 137 │ 137 ││ 138 │ 138 ││ 139 │ 139 ││ 140 │ 140 ││ 141 │ 141 ││ 142 │ 142 ││ 143 │ 143 ││ 144 │ 144 ││ 145 │ 145 ││ 146 │ 146 ││ 147 │ 147 ││ 148 │ 148 ││ 149 │ 149 ││ 150 │ 150 ││ 151 │ 151 ││ 152 │ 152 ││ 153 │ 153 ││ 154 │ 154 ││ 155 │ 155 ││ 156 │ 156 ││ 157 │ 157 ││ 158 │ 158 ││ 159 │ 159 ││ 160 │ 160 ││ 161 │ 161 ││ 162 │ 162 ││ 163 │ 163 ││ 164 │ 164 ││ 165 │ 165 ││ 166 │ 166 ││ 167 │ 167 ││ 168 │ 168 ││ 169 │ 169 ││ 170 │ 170 ││ 171 │ 171 ││ 172 │ 172 ││ 173 │ 173 ││ 174 │ 174 ││ 175 │ 175 ││ 176 │ 176 ││ 177 │ 177 ││ 178 │ 178 ││ 179 │ 179 ││ 180 │ 180 ││ 181 │ 181 ││ 182 │ 182 ││ 183 │ 183 ││ 184 │ 184 ││ 185 │ 185 ││ 186 │ 186 ││ 187 │ 187 ││ 188 │ 188 ││ 189 │ 189 ││ 190 │ 190 ││ 191 │ 191 ││ 192 │ 192 ││ 193 │ 193 ││ 194 │ 194 ││ 195 │ 195 ││ 196 │ 196 ││ 197 │ 197 ││ 198 │ 198 ││ 199 │ 199 ││ 200 │ 200 ││ 201 │ 201 ││ 202 │ 202 ││ 203 │ 203 ││ 204 │ 204 ││ 205 │ 205 ││ 206 │ 206 ││ 207 │ 207 ││ 208 │ 208 ││ 209 │ 209 ││ 210 │ 210 ││ 211 │ 211 ││ 212 │ 212 ││ 213 │ 213 ││ 214 │ 214 ││ 215 │ 215 ││ 216 │ 216 ││ 217 │ 217 ││ 218 │ 218 ││ 219 │ 219 ││ 220 │ 220 ││ 221 │ 221 ││ 222 │ 222 ││ 223 │ 223 ││ 224 │ 224 ││ 225 │ 225 ││ 226 │ 226 ││ 227 │ 227 ││ 228 │ 228 ││ 229 │ 229 ││ 230 │ 230 ││ 231 │ 231 ││ 232 │ 232 ││ 233 │ 233 ││ 234 │ 234 ││ 235 │ 235 ││ 236 │ 236 ││ 237 │ 237 ││ 238 │ 238 ││ 239 │ 239 ││ 240 │ 240 ││ 241 │ 241 ││ 242 │ 242 ││ 243 │ 243 ││ 244 │ 244 ││ 245 │ 245 ││ 246 │ 246 ││ 247 │ 247 ││ 248 │ 248 ││ 249 │ 249 ││ 250 │ 250 ││ 251 │ 251 ││ 252 │ 252 ││ 253 │ 253 ││ 254 │ 254 ││ 255 │ 255 ││ 256 │ 256 ││ 257 │ 257 ││ 258 │ 258 ││ 259 │ 259 ││ 260 │ 260 ││ 261 │ 261 ││ 262 │ 262 ││ 263 │ 263 ││ 264 │ 264 ││ 265 │ 265 ││ 266 │ 266 ││ 267 │ 267 ││ 268 │ 268 ││ 269 │ 269 ││ 270 │ 270 ││ 271 │ 271 ││ 272 │ 272 ││ 273 │ 273 ││ 274 │ 274 ││ 275 │ 275 ││ 276 │ 276 ││ 277 │ 277 ││ 278 │ 278 ││ 279 │ 279 ││ 280 │ 280 ││ 281 │ 281 ││ 282 │ 282 ││ 283 │ 283 ││ 284 │ 284 ││ 285 │ 285 ││ 286 │ 286 ││ 287 │ 287 ││ 288 │ 288 ││ 289 │ 289 ││ 290 │ 290 ││ 291 │ 291 ││ 292 │ 292 ││ 293 │ 293 ││ 294 │ 294 ││ 295 │ 295 ││ 296 │ 296 ││ 297 │ 297 ││ 298 │ 298 ││ 299 │ 299 ││ 300 │ 300 ││ 301 │ 301 ││ 302 │ 302 ││ 303 │ 303 ││ 304 │ 304 ││ 305 │ 305 ││ 306 │ 306 ││ 307 │ 307 ││ 308 │ 308 ││ 309 │ 309 ││ 310 │ 310 ││ 311 │ 311 ││ 312 │ 312 ││ 313 │ 313 ││ 314 │ 314 ││ 315 │ 315 ││ 316 │ 316 ││ 317 │ 317 ││ 318 │ 318 ││ 319 │ 319 ││ 320 │ 320 ││ 321 │ 321 ││ 322 │ 322 ││ 323 │ 323 ││ 324 │ 324 ││ 325 │ 325 ││ 326 │ 326 ││ 327 │ 327 ││ 328 │ 328 ││ 329 │ 329 ││ 330 │ 330 ││ 331 │ 331 ││ 332 │ 332 ││ 333 │ 333 ││ 334 │ 334 ││ 335 │ 335 ││ 336 │ 336 ││ 337 │ 337 ││ 338 │ 338 ││ 339 │ 339 ││ 340 │ 340 ││ 341 │ 341 ││ 342 │ 342 ││ 343 │ 343 ││ 344 │ 344 ││ 345 │ 345 ││ 346 │ 346 ││ 347 │ 347 ││ 348 │ 348 ││ 349 │ 349 ││ 350 │ 350 ││ 351 │ 351 ││ 352 │ 352 ││ 353 │ 353 ││ 354 │ 354 ││ 355 │ 355 ││ 356 │ 356 ││ 357 │ 357 ││ 358 │ 358 ││ 359 │ 359 ││ 360 │ 360 ││ 361 │ 361 ││ 362 │ 362 ││ 363 │ 363 ││ 364 │ 364 ││ 365 │ 365 ││ 366 │ 366 ││ 367 │ 367 ││ 368 │ 368 ││ 369 │ 369 ││ 370 │ 370 ││ 371 │ 371 ││ 372 │ 372 ││ 373 │ 373 ││ 374 │ 374 ││ 375 │ 375 ││ 376 │ 376 ││ 377 │ 377 ││ 378 │ 378 ││ 379 │ 379 ││ 380 │ 380 ││ 381 │ 381 ││ 382 │ 382 ││ 383 │ 383 ││ 384 │ 384 ││ 385 │ 385 ││ 386 │ 386 ││ 387 │ 387 ││ 388 │ 388 ││ 389 │ 389 ││ 390 │ 390 ││ 391 │ 391 ││ 392 │ 392 ││ 393 │ 393 ││ 394 │ 394 ││ 395 │ 395 ││ 396 │ 396 ││ 397 │ 397 ││ 398 │ 398 ││ 399 │ 399 ││ 400 │ 400 ││ 401 │ 401 ││ 402 │ 402 ││ 403 │ 403 ││ 404 │ 404 ││ 405 │ 405 ││ 406 │ 406 ││ 407 │ 407 ││ 408 │ 408 ││ 409 │ 409 ││ 410 │ 410 ││ 411 │ 411 ││ 412 │ 412 ││ 413 │ 413 ││ 414 │ 414 ││ 415 │ 415 ││ 416 │ 416 ││ 417 │ 417 ││ 418 │ 418 ││ 419 │ 419 ││ 420 │ 420 ││ 421 │ 421 ││ 422 │ 422 ││ 423 │ 423 ││ 424 │ 424 ││ 425 │ 425 ││ 426 │ 426 ││ 427 │ 427 ││ 428 │ 428 ││ 429 │ 429 ││ 430 │ 430 ││ 431 │ 431 ││ 432 │ 432 ││ 433 │ 433 ││ 434 │ 434 ││ 435 │ 435 ││ 436 │ 436 ││ 437 │ 437 ││ 438 │ 438 ││ 439 │ 439 ││ 440 │ 440 ││ 441 │ 441 ││ 442 │ 442 ││ 443 │ 443 ││ 444 │ 444 ││ 445 │ 445 ││ 446 │ 446 ││ 447 │ 447 ││ 448 │ 448 ││ 449 │ 449 ││ 450 │ 450 ││ 451 │ 451 ││ 452 │ 452 ││ 453 │ 453 ││ 454 │ 454 ││ 455 │ 455 ││ 456 │ 456 ││ 457 │ 457 ││ 458 │ 458 ││ 459 │ 459 ││ 460 │ 460 ││ 461 │ 461 ││ 462 │ 462 ││ 463 │ 463 ││ 464 │ 464 ││ 465 │ 465 ││ 466 │ 466 ││ 467 │ 467 ││ 468 │ 468 ││ 469 │ 469 ││ 470 │ 470 ││ 471 │ 471 ││ 472 │ 472 ││ 473 │ 473 ││ 474 │ 474 ││ 475 │ 475 ││ 476 │ 476 ││ 477 │ 477 ││ 478 │ 478 ││ 479 │ 479 ││ 480 │ 480 ││ 481 │ 481 ││ 482 │ 482 ││ 483 │ 483 ││ 484 │ 484 ││ 485 │ 485 ││ 486 │ 486 ││ 487 │ 487 ││ 488 │ 488 ││ 489 │ 489 ││ 490 │ 490 ││ 491 │ 491 ││ 492 │ 492 ││ 493 │ 493 ││ 494 │ 494 ││ 495 │ 495 ││ 496 │ 496 ││ 497 │ 497 ││ 498 │ 498 ││ 499 │ 499 ││ 500 │ 500 ││ 501 │ 501 ││ 502 │ 502 ││ 503 │ 503 ││ 504 │ 504 ││ 505 │ 505 ││ 506 │ 506 ││ 507 │ 507 ││ 508 │ 508 ││ 509 │ 509 ││ 510 │ 510 ││ 511 │ 511 ││ 512 │ 512 ││ 513 │ 513 ││ 514 │ 514 ││ 515 │ 515 ││ 516 │ 516 ││ 517 │ 517 ││ 518 │ 518 ││ 519 │ 519 ││ 520 │ 520 ││ 521 │ 521 ││ 522 │ 522 ││ 523 │ 523 ││ 524 │ 524 ││ 525 │ 525 ││ 526 │ 526 ││ 527 │ 527 ││ 528 │ 528 ││ 529 │ 529 ││ 530 │ 530 ││ 531 │ 531 ││ 532 │ 532 ││ 533 │ 533 ││ 534 │ 534 ││ 535 │ 535 ││ 536 │ 536 ││ 537 │ 537 ││ 538 │ 538 ││ 539 │ 539 ││ 540 │ 540 ││ 541 │ 541 ││ 542 │ 542 ││ 543 │ 543 ││ 544 │ 544 ││ 545 │ 545 ││ 546 │ 546 ││ 547 │ 547 ││ 548 │ 548 ││ 549 │ 549 ││ 550 │ 550 ││ 551 │ 551 ││ 552 │ 552 ││ 553 │ 553 ││ 554 │ 554 ││ 555 │ 555 ││ 556 │ 556 ││ 557 │ 557 ││ 558 │ 558 ││ 559 │ 559 ││ 560 │ 560 ││ 561 │ 561 ││ 562 │ 562 ││ 563 │ 563 ││ 564 │ 564 ││ 565 │ 565 ││ 566 │ 566 ││ 567 │ 567 ││ 568 │ 568 ││ 569 │ 569 ││ 570 │ 570 ││ 571 │ 571 ││ 572 │ 572 ││ 573 │ 573 ││ 574 │ 574 ││ 575 │ 575 ││ 576 │ 576 ││ 577 │ 577 ││ 578 │ 578 ││ 579 │ 579 ││ 580 │ 580 ││ 581 │ 581 ││ 582 │ 582 ││ 583 │ 583 ││ 584 │ 584 ││ 585 │ 585 ││ 586 │ 586 ││ 587 │ 587 ││ 588 │ 588 ││ 589 │ 589 ││ 590 │ 590 ││ 591 │ 591 ││ 592 │ 592 ││ 593 │ 593 ││ 594 │ 594 ││ 595 │ 595 ││ 596 │ 596 ││ 597 │ 597 ││ 598 │ 598 ││ 599 │ 599 ││ 600 │ 600 ││ 601 │ 601 ││ 602 │ 602 ││ 603 │ 603 ││ 604 │ 604 ││ 605 │ 605 ││ 606 │ 606 ││ 607 │ 607 ││ 608 │ 608 ││ 609 │ 609 ││ 610 │ 610 ││ 611 │ 611 ││ 612 │ 612 ││ 613 │ 613 ││ 614 │ 614 ││ 615 │ 615 ││ 616 │ 616 ││ 617 │ 617 ││ 618 │ 618 ││ 619 │ 619 ││ 620 │ 620 ││ 621 │ 621 ││ 622 │ 622 ││ 623 │ 623 ││ 624 │ 624 ││ 625 │ 625 ││ 626 │ 626 ││ 627 │ 627 ││ 628 │ 628 ││ 629 │ 629 ││ 630 │ 630 ││ 631 │ 631 ││ 632 │ 632 ││ 633 │ 633 ││ 634 │ 634 ││ 635 │ 635 ││ 636 │ 636 ││ 637 │ 637 ││ 638 │ 638 ││ 639 │ 639 ││ 640 │ 640 ││ 641 │ 641 ││ 642 │ 642 ││ 643 │ 643 ││ 644 │ 644 ││ 645 │ 645 ││ 646 │ 646 ││ 647 │ 647 ││ 648 │ 648 ││ 649 │ 649 ││ 650 │ 650 ││ 651 │ 651 ││ 652 │ 652 ││ 653 │ 653 ││ 654 │ 654 ││ 655 │ 655 ││ 656 │ 656 ││ 657 │ 657 ││ 658 │ 658 ││ 659 │ 659 ││ 660 │ 660 ││ 661 │ 661 ││ 662 │ 662 ││ 663 │ 663 ││ 664 │ 664 ││ 665 │ 665 ││ 666 │ 666 ││ 667 │ 667 ││ 668 │ 668 ││ 669 │ 669 ││ 670 │ 670 ││ 671 │ 671 ││ 672 │ 672 ││ 673 │ 673 ││ 674 │ 674 ││ 675 │ 675 ││ 676 │ 676 ││ 677 │ 677 ││ 678 │ 678 ││ 679 │ 679 ││ 680 │ 680 ││ 681 │ 681 ││ 682 │ 682 ││ 683 │ 683 ││ 684 │ 684 ││ 685 │ 685 ││ 686 │ 686 ││ 687 │ 687 ││ 688 │ 688 ││ 689 │ 689 ││ 690 │ 690 ││ 691 │ 691 ││ 692 │ 692 ││ 693 │ 693 ││ 694 │ 694 ││ 695 │ 695 ││ 696 │ 696 ││ 697 │ 697 ││ 698 │ 698 ││ 699 │ 699 ││ 700 │ 700 ││ 701 │ 701 ││ 702 │ 702 ││ 703 │ 703 ││ 704 │ 704 ││ 705 │ 705 ││ 706 │ 706 ││ 707 │ 707 ││ 708 │ 708 ││ 709 │ 709 ││ 710 │ 710 ││ 711 │ 711 ││ 712 │ 712 ││ 713 │ 713 ││ 714 │ 714 ││ 715 │ 715 ││ 716 │ 716 ││ 717 │ 717 ││ 718 │ 718 ││ 719 │ 719 ││ 720 │ 720 ││ 721 │ 721 ││ 722 │ 722 ││ 723 │ 723 ││ 724 │ 724 ││ 725 │ 725 ││ 726 │ 726 ││ 727 │ 727 ││ 728 │ 728 ││ 729 │ 729 ││ 730 │ 730 ││ 731 │ 731 ││ 732 │ 732 ││ 733 │ 733 ││ 734 │ 734 ││ 735 │ 735 ││ 736 │ 736 ││ 737 │ 737 ││ 738 │ 738 ││ 739 │ 739 ││ 740 │ 740 ││ 741 │ 741 ││ 742 │ 742 ││ 743 │ 743 ││ 744 │ 744 ││ 745 │ 745 ││ 746 │ 746 ││ 747 │ 747 ││ 748 │ 748 ││ 749 │ 749 ││ 750 │ 750 ││ 751 │ 751 ││ 752 │ 752 ││ 753 │ 753 ││ 754 │ 754 ││ 755 │ 755 ││ 756 │ 756 ││ 757 │ 757 ││ 758 │ 758 ││ 759 │ 759 ││ 760 │ 760 ││ 761 │ 761 ││ 762 │ 762 ││ 763 │ 763 ││ 764 │ 764 ││ 765 │ 765 ││ 766 │ 766 ││ 767 │ 767 ││ 768 │ 768 ││ 769 │ 769 ││ 770 │ 770 ││ 771 │ 771 ││ 772 │ 772 ││ 773 │ 773 ││ 774 │ 774 ││ 775 │ 775 ││ 776 │ 776 ││ 777 │ 777 ││ 778 │ 778 ││ 779 │ 779 ││ 780 │ 780 ││ 781 │ 781 ││ 782 │ 782 ││ 783 │ 783 ││ 784 │ 784 ││ 785 │ 785 ││ 786 │ 786 ││ 787 │ 787 ││ 788 │ 788 ││ 789 │ 789 ││ 790 │ 790 ││ 791 │ 791 ││ 792 │ 792 ││ 793 │ 793 ││ 794 │ 794 ││ 795 │ 795 ││ 796 │ 796 ││ 797 │ 797 ││ 798 │ 798 ││ 799 │ 799 ││ 800 │ 800 ││ 801 │ 801 ││ 802 │ 802 ││ 803 │ 803 ││ 804 │ 804 ││ 805 │ 805 ││ 806 │ 806 ││ 807 │ 807 ││ 808 │ 808 ││ 809 │ 809 ││ 810 │ 810 ││ 811 │ 811 ││ 812 │ 812 ││ 813 │ 813 ││ 814 │ 814 ││ 815 │ 815 ││ 816 │ 816 ││ 817 │ 817 ││ 818 │ 818 ││ 819 │ 819 ││ 820 │ 820 ││ 821 │ 821 ││ 822 │ 822 ││ 823 │ 823 ││ 824 │ 824 ││ 825 │ 825 ││ 826 │ 826 ││ 827 │ 827 ││ 828 │ 828 ││ 829 │ 829 ││ 830 │ 830 ││ 831 │ 831 ││ 832 │ 832 ││ 833 │ 833 ││ 834 │ 834 ││ 835 │ 835 ││ 836 │ 836 ││ 837 │ 837 ││ 838 │ 838 ││ 839 │ 839 ││ 840 │ 840 ││ 841 │ 841 ││ 842 │ 842 ││ 843 │ 843 ││ 844 │ 844 ││ 845 │ 845 ││ 846 │ 846 ││ 847 │ 847 ││ 848 │ 848 ││ 849 │ 849 ││ 850 │ 850 ││ 851 │ 851 ││ 852 │ 852 ││ 853 │ 853 ││ 854 │ 854 ││ 855 │ 855 ││ 856 │ 856 ││ 857 │ 857 ││ 858 │ 858 ││ 859 │ 859 ││ 860 │ 860 ││ 861 │ 861 ││ 862 │ 862 ││ 863 │ 863 ││ 864 │ 864 ││ 865 │ 865 ││ 866 │ 866 ││ 867 │ 867 ││ 868 │ 868 ││ 869 │ 869 ││ 870 │ 870 ││ 871 │ 871 ││ 872 │ 872 ││ 873 │ 873 ││ 874 │ 874 ││ 875 │ 875 ││ 876 │ 876 ││ 877 │ 877 ││ 878 │ 878 ││ 879 │ 879 ││ 880 │ 880 ││ 881 │ 881 ││ 882 │ 882 ││ 883 │ 883 ││ 884 │ 884 ││ 885 │ 885 ││ 886 │ 886 ││ 887 │ 887 ││ 888 │ 888 ││ 889 │ 889 ││ 890 │ 890 ││ 891 │ 891 ││ 892 │ 892 ││ 893 │ 893 ││ 894 │ 894 ││ 895 │ 895 ││ 896 │ 896 ││ 897 │ 897 ││ 898 │ 898 ││ 899 │ 899 ││ 900 │ 900 ││ 901 │ 901 ││ 902 │ 902 ││ 903 │ 903 ││ 904 │ 904 ││ 905 │ 905 ││ 906 │ 906 ││ 907 │ 907 ││ 908 │ 908 ││ 909 │ 909 ││ 910 │ 910 ││ 911 │ 911 ││ 912 │ 912 ││ 913 │ 913 ││ 914 │ 914 ││ 915 │ 915 ││ 916 │ 916 ││ 917 │ 917 ││ 918 │ 918 ││ 919 │ 919 ││ 920 │ 920 ││ 921 │ 921 ││ 922 │ 922 ││ 923 │ 923 ││ 924 │ 924 ││ 925 │ 925 ││ 926 │ 926 ││ 927 │ 927 ││ 928 │ 928 ││ 929 │ 929 ││ 930 │ 930 ││ 931 │ 931 ││ 932 │ 932 ││ 933 │ 933 ││ 934 │ 934 ││ 935 │ 935 ││ 936 │ 936 ││ 937 │ 937 ││ 938 │ 938 ││ 939 │ 939 ││ 940 │ 940 ││ 941 │ 941 ││ 942 │ 942 ││ 943 │ 943 ││ 944 │ 944 ││ 945 │ 945 ││ 946 │ 946 ││ 947 │ 947 ││ 948 │ 948 ││ 949 │ 949 ││ 950 │ 950 ││ 951 │ 951 ││ 952 │ 952 ││ 953 │ 953 ││ 954 │ 954 ││ 955 │ 955 ││ 956 │ 956 ││ 957 │ 957 ││ 958 │ 958 ││ 959 │ 959 ││ 960 │ 960 ││ 961 │ 961 ││ 962 │ 962 ││ 963 │ 963 ││ 964 │ 964 ││ 965 │ 965 ││ 966 │ 966 ││ 967 │ 967 ││ 968 │ 968 ││ 969 │ 969 ││ 970 │ 970 ││ 971 │ 971 ││ 972 │ 972 ││ 973 │ 973 ││ 974 │ 974 ││ 975 │ 975 ││ 976 │ 976 ││ 977 │ 977 ││ 978 │ 978 ││ 979 │ 979 ││ 980 │ 980 ││ 981 │ 981 ││ 982 │ 982 ││ 983 │ 983 ││ 984 │ 984 ││ 985 │ 985 ││ 986 │ 986 ││ 987 │ 987 ││ 988 │ 988 ││ 989 │ 989 ││ 990 │ 990 ││ 991 │ 991 ││ 992 │ 992 ││ 993 │ 993 ││ 994 │ 994 ││ 995 │ 995 ││ 996 │ 996 ││ 997 │ 997 ││ 998 │ 998 ││ 999 │ 999 │╰─────┴─────╯╭──────┬──────╮│ 1000 │ 1000 │╰──────┴──────╯" + "╭─────┬─────╮│ 0 │ 0 │├─────┼─────┤│ 1 │ 1 ││ 2 │ 2 ││ 3 │ 3 ││ 4 │ 4 ││ 5 │ 5 ││ 6 │ 6 ││ 7 │ 7 ││ 8 │ 8 ││ 9 │ 9 ││ 10 │ 10 ││ 11 │ 11 ││ 12 │ 12 ││ 13 │ 13 ││ 14 │ 14 ││ 15 │ 15 ││ 16 │ 16 ││ 17 │ 17 ││ 18 │ 18 ││ 19 │ 19 ││ 20 │ 20 ││ 21 │ 21 ││ 22 │ 22 ││ 23 │ 23 ││ 24 │ 24 ││ 25 │ 25 ││ 26 │ 26 ││ 27 │ 27 ││ 28 │ 28 ││ 29 │ 29 ││ 30 │ 30 ││ 31 │ 31 ││ 32 │ 32 ││ 33 │ 33 ││ 34 │ 34 ││ 35 │ 35 ││ 36 │ 36 ││ 37 │ 37 ││ 38 │ 38 ││ 39 │ 39 ││ 40 │ 40 ││ 41 │ 41 ││ 42 │ 42 ││ 43 │ 43 ││ 44 │ 44 ││ 45 │ 45 ││ 46 │ 46 ││ 47 │ 47 ││ 48 │ 48 ││ 49 │ 49 ││ 50 │ 50 ││ 51 │ 51 ││ 52 │ 52 ││ 53 │ 53 ││ 54 │ 54 ││ 55 │ 55 ││ 56 │ 56 ││ 57 │ 57 ││ 58 │ 58 ││ 59 │ 59 ││ 60 │ 60 ││ 61 │ 61 ││ 62 │ 62 ││ 63 │ 63 ││ 64 │ 64 ││ 65 │ 65 ││ 66 │ 66 ││ 67 │ 67 ││ 68 │ 68 ││ 69 │ 69 ││ 70 │ 70 ││ 71 │ 71 ││ 72 │ 72 ││ 73 │ 73 ││ 74 │ 74 ││ 75 │ 75 ││ 76 │ 76 ││ 77 │ 77 ││ 78 │ 78 ││ 79 │ 79 ││ 80 │ 80 ││ 81 │ 81 ││ 82 │ 82 ││ 83 │ 83 ││ 84 │ 84 ││ 85 │ 85 ││ 86 │ 86 ││ 87 │ 87 ││ 88 │ 88 ││ 89 │ 89 ││ 90 │ 90 ││ 91 │ 91 ││ 92 │ 92 ││ 93 │ 93 ││ 94 │ 94 ││ 95 │ 95 ││ 96 │ 96 ││ 97 │ 97 ││ 98 │ 98 ││ 99 │ 99 ││ 100 │ 100 ││ 101 │ 101 ││ 102 │ 102 ││ 103 │ 103 ││ 104 │ 104 ││ 105 │ 105 ││ 106 │ 106 ││ 107 │ 107 ││ 108 │ 108 ││ 109 │ 109 ││ 110 │ 110 ││ 111 │ 111 ││ 112 │ 112 ││ 113 │ 113 ││ 114 │ 114 ││ 115 │ 115 ││ 116 │ 116 ││ 117 │ 117 ││ 118 │ 118 ││ 119 │ 119 ││ 120 │ 120 ││ 121 │ 121 ││ 122 │ 122 ││ 123 │ 123 ││ 124 │ 124 ││ 125 │ 125 ││ 126 │ 126 ││ 127 │ 127 ││ 128 │ 128 ││ 129 │ 129 ││ 130 │ 130 ││ 131 │ 131 ││ 132 │ 132 ││ 133 │ 133 ││ 134 │ 134 ││ 135 │ 135 ││ 136 │ 136 ││ 137 │ 137 ││ 138 │ 138 ││ 139 │ 139 ││ 140 │ 140 ││ 141 │ 141 ││ 142 │ 142 ││ 143 │ 143 ││ 144 │ 144 ││ 145 │ 145 ││ 146 │ 146 ││ 147 │ 147 ││ 148 │ 148 ││ 149 │ 149 ││ 150 │ 150 ││ 151 │ 151 ││ 152 │ 152 ││ 153 │ 153 ││ 154 │ 154 ││ 155 │ 155 ││ 156 │ 156 ││ 157 │ 157 ││ 158 │ 158 ││ 159 │ 159 ││ 160 │ 160 ││ 161 │ 161 ││ 162 │ 162 ││ 163 │ 163 ││ 164 │ 164 ││ 165 │ 165 ││ 166 │ 166 ││ 167 │ 167 ││ 168 │ 168 ││ 169 │ 169 ││ 170 │ 170 ││ 171 │ 171 ││ 172 │ 172 ││ 173 │ 173 ││ 174 │ 174 ││ 175 │ 175 ││ 176 │ 176 ││ 177 │ 177 ││ 178 │ 178 ││ 179 │ 179 ││ 180 │ 180 ││ 181 │ 181 ││ 182 │ 182 ││ 183 │ 183 ││ 184 │ 184 ││ 185 │ 185 ││ 186 │ 186 ││ 187 │ 187 ││ 188 │ 188 ││ 189 │ 189 ││ 190 │ 190 ││ 191 │ 191 ││ 192 │ 192 ││ 193 │ 193 ││ 194 │ 194 ││ 195 │ 195 ││ 196 │ 196 ││ 197 │ 197 ││ 198 │ 198 ││ 199 │ 199 ││ 200 │ 200 ││ 201 │ 201 ││ 202 │ 202 ││ 203 │ 203 ││ 204 │ 204 ││ 205 │ 205 ││ 206 │ 206 ││ 207 │ 207 ││ 208 │ 208 ││ 209 │ 209 ││ 210 │ 210 ││ 211 │ 211 ││ 212 │ 212 ││ 213 │ 213 ││ 214 │ 214 ││ 215 │ 215 ││ 216 │ 216 ││ 217 │ 217 ││ 218 │ 218 ││ 219 │ 219 ││ 220 │ 220 ││ 221 │ 221 ││ 222 │ 222 ││ 223 │ 223 ││ 224 │ 224 ││ 225 │ 225 ││ 226 │ 226 ││ 227 │ 227 ││ 228 │ 228 ││ 229 │ 229 ││ 230 │ 230 ││ 231 │ 231 ││ 232 │ 232 ││ 233 │ 233 ││ 234 │ 234 ││ 235 │ 235 ││ 236 │ 236 ││ 237 │ 237 ││ 238 │ 238 ││ 239 │ 239 ││ 240 │ 240 ││ 241 │ 241 ││ 242 │ 242 ││ 243 │ 243 ││ 244 │ 244 ││ 245 │ 245 ││ 246 │ 246 ││ 247 │ 247 ││ 248 │ 248 ││ 249 │ 249 ││ 250 │ 250 ││ 251 │ 251 ││ 252 │ 252 ││ 253 │ 253 ││ 254 │ 254 ││ 255 │ 255 ││ 256 │ 256 ││ 257 │ 257 ││ 258 │ 258 ││ 259 │ 259 ││ 260 │ 260 ││ 261 │ 261 ││ 262 │ 262 ││ 263 │ 263 ││ 264 │ 264 ││ 265 │ 265 ││ 266 │ 266 ││ 267 │ 267 ││ 268 │ 268 ││ 269 │ 269 ││ 270 │ 270 ││ 271 │ 271 ││ 272 │ 272 ││ 273 │ 273 ││ 274 │ 274 ││ 275 │ 275 ││ 276 │ 276 ││ 277 │ 277 ││ 278 │ 278 ││ 279 │ 279 ││ 280 │ 280 ││ 281 │ 281 ││ 282 │ 282 ││ 283 │ 283 ││ 284 │ 284 ││ 285 │ 285 ││ 286 │ 286 ││ 287 │ 287 ││ 288 │ 288 ││ 289 │ 289 ││ 290 │ 290 ││ 291 │ 291 ││ 292 │ 292 ││ 293 │ 293 ││ 294 │ 294 ││ 295 │ 295 ││ 296 │ 296 ││ 297 │ 297 ││ 298 │ 298 ││ 299 │ 299 ││ 300 │ 300 ││ 301 │ 301 ││ 302 │ 302 ││ 303 │ 303 ││ 304 │ 304 ││ 305 │ 305 ││ 306 │ 306 ││ 307 │ 307 ││ 308 │ 308 ││ 309 │ 309 ││ 310 │ 310 ││ 311 │ 311 ││ 312 │ 312 ││ 313 │ 313 ││ 314 │ 314 ││ 315 │ 315 ││ 316 │ 316 ││ 317 │ 317 ││ 318 │ 318 ││ 319 │ 319 ││ 320 │ 320 ││ 321 │ 321 ││ 322 │ 322 ││ 323 │ 323 ││ 324 │ 324 ││ 325 │ 325 ││ 326 │ 326 ││ 327 │ 327 ││ 328 │ 328 ││ 329 │ 329 ││ 330 │ 330 ││ 331 │ 331 ││ 332 │ 332 ││ 333 │ 333 ││ 334 │ 334 ││ 335 │ 335 ││ 336 │ 336 ││ 337 │ 337 ││ 338 │ 338 ││ 339 │ 339 ││ 340 │ 340 ││ 341 │ 341 ││ 342 │ 342 ││ 343 │ 343 ││ 344 │ 344 ││ 345 │ 345 ││ 346 │ 346 ││ 347 │ 347 ││ 348 │ 348 ││ 349 │ 349 ││ 350 │ 350 ││ 351 │ 351 ││ 352 │ 352 ││ 353 │ 353 ││ 354 │ 354 ││ 355 │ 355 ││ 356 │ 356 ││ 357 │ 357 ││ 358 │ 358 ││ 359 │ 359 ││ 360 │ 360 ││ 361 │ 361 ││ 362 │ 362 ││ 363 │ 363 ││ 364 │ 364 ││ 365 │ 365 ││ 366 │ 366 ││ 367 │ 367 ││ 368 │ 368 ││ 369 │ 369 ││ 370 │ 370 ││ 371 │ 371 ││ 372 │ 372 ││ 373 │ 373 ││ 374 │ 374 ││ 375 │ 375 ││ 376 │ 376 ││ 377 │ 377 ││ 378 │ 378 ││ 379 │ 379 ││ 380 │ 380 ││ 381 │ 381 ││ 382 │ 382 ││ 383 │ 383 ││ 384 │ 384 ││ 385 │ 385 ││ 386 │ 386 ││ 387 │ 387 ││ 388 │ 388 ││ 389 │ 389 ││ 390 │ 390 ││ 391 │ 391 ││ 392 │ 392 ││ 393 │ 393 ││ 394 │ 394 ││ 395 │ 395 ││ 396 │ 396 ││ 397 │ 397 ││ 398 │ 398 ││ 399 │ 399 ││ 400 │ 400 ││ 401 │ 401 ││ 402 │ 402 ││ 403 │ 403 ││ 404 │ 404 ││ 405 │ 405 ││ 406 │ 406 ││ 407 │ 407 ││ 408 │ 408 ││ 409 │ 409 ││ 410 │ 410 ││ 411 │ 411 ││ 412 │ 412 ││ 413 │ 413 ││ 414 │ 414 ││ 415 │ 415 ││ 416 │ 416 ││ 417 │ 417 ││ 418 │ 418 ││ 419 │ 419 ││ 420 │ 420 ││ 421 │ 421 ││ 422 │ 422 ││ 423 │ 423 ││ 424 │ 424 ││ 425 │ 425 ││ 426 │ 426 ││ 427 │ 427 ││ 428 │ 428 ││ 429 │ 429 ││ 430 │ 430 ││ 431 │ 431 ││ 432 │ 432 ││ 433 │ 433 ││ 434 │ 434 ││ 435 │ 435 ││ 436 │ 436 ││ 437 │ 437 ││ 438 │ 438 ││ 439 │ 439 ││ 440 │ 440 ││ 441 │ 441 ││ 442 │ 442 ││ 443 │ 443 ││ 444 │ 444 ││ 445 │ 445 ││ 446 │ 446 ││ 447 │ 447 ││ 448 │ 448 ││ 449 │ 449 ││ 450 │ 450 ││ 451 │ 451 ││ 452 │ 452 ││ 453 │ 453 ││ 454 │ 454 ││ 455 │ 455 ││ 456 │ 456 ││ 457 │ 457 ││ 458 │ 458 ││ 459 │ 459 ││ 460 │ 460 ││ 461 │ 461 ││ 462 │ 462 ││ 463 │ 463 ││ 464 │ 464 ││ 465 │ 465 ││ 466 │ 466 ││ 467 │ 467 ││ 468 │ 468 ││ 469 │ 469 ││ 470 │ 470 ││ 471 │ 471 ││ 472 │ 472 ││ 473 │ 473 ││ 474 │ 474 ││ 475 │ 475 ││ 476 │ 476 ││ 477 │ 477 ││ 478 │ 478 ││ 479 │ 479 ││ 480 │ 480 ││ 481 │ 481 ││ 482 │ 482 ││ 483 │ 483 ││ 484 │ 484 ││ 485 │ 485 ││ 486 │ 486 ││ 487 │ 487 ││ 488 │ 488 ││ 489 │ 489 ││ 490 │ 490 ││ 491 │ 491 ││ 492 │ 492 ││ 493 │ 493 ││ 494 │ 494 ││ 495 │ 495 ││ 496 │ 496 ││ 497 │ 497 ││ 498 │ 498 ││ 499 │ 499 ││ 500 │ 500 ││ 501 │ 501 ││ 502 │ 502 ││ 503 │ 503 ││ 504 │ 504 ││ 505 │ 505 ││ 506 │ 506 ││ 507 │ 507 ││ 508 │ 508 ││ 509 │ 509 ││ 510 │ 510 ││ 511 │ 511 ││ 512 │ 512 ││ 513 │ 513 ││ 514 │ 514 ││ 515 │ 515 ││ 516 │ 516 ││ 517 │ 517 ││ 518 │ 518 ││ 519 │ 519 ││ 520 │ 520 ││ 521 │ 521 ││ 522 │ 522 ││ 523 │ 523 ││ 524 │ 524 ││ 525 │ 525 ││ 526 │ 526 ││ 527 │ 527 ││ 528 │ 528 ││ 529 │ 529 ││ 530 │ 530 ││ 531 │ 531 ││ 532 │ 532 ││ 533 │ 533 ││ 534 │ 534 ││ 535 │ 535 ││ 536 │ 536 ││ 537 │ 537 ││ 538 │ 538 ││ 539 │ 539 ││ 540 │ 540 ││ 541 │ 541 ││ 542 │ 542 ││ 543 │ 543 ││ 544 │ 544 ││ 545 │ 545 ││ 546 │ 546 ││ 547 │ 547 ││ 548 │ 548 ││ 549 │ 549 ││ 550 │ 550 ││ 551 │ 551 ││ 552 │ 552 ││ 553 │ 553 ││ 554 │ 554 ││ 555 │ 555 ││ 556 │ 556 ││ 557 │ 557 ││ 558 │ 558 ││ 559 │ 559 ││ 560 │ 560 ││ 561 │ 561 ││ 562 │ 562 ││ 563 │ 563 ││ 564 │ 564 ││ 565 │ 565 ││ 566 │ 566 ││ 567 │ 567 ││ 568 │ 568 ││ 569 │ 569 ││ 570 │ 570 ││ 571 │ 571 ││ 572 │ 572 ││ 573 │ 573 ││ 574 │ 574 ││ 575 │ 575 ││ 576 │ 576 ││ 577 │ 577 ││ 578 │ 578 ││ 579 │ 579 ││ 580 │ 580 ││ 581 │ 581 ││ 582 │ 582 ││ 583 │ 583 ││ 584 │ 584 ││ 585 │ 585 ││ 586 │ 586 ││ 587 │ 587 ││ 588 │ 588 ││ 589 │ 589 ││ 590 │ 590 ││ 591 │ 591 ││ 592 │ 592 ││ 593 │ 593 ││ 594 │ 594 ││ 595 │ 595 ││ 596 │ 596 ││ 597 │ 597 ││ 598 │ 598 ││ 599 │ 599 ││ 600 │ 600 ││ 601 │ 601 ││ 602 │ 602 ││ 603 │ 603 ││ 604 │ 604 ││ 605 │ 605 ││ 606 │ 606 ││ 607 │ 607 ││ 608 │ 608 ││ 609 │ 609 ││ 610 │ 610 ││ 611 │ 611 ││ 612 │ 612 ││ 613 │ 613 ││ 614 │ 614 ││ 615 │ 615 ││ 616 │ 616 ││ 617 │ 617 ││ 618 │ 618 ││ 619 │ 619 ││ 620 │ 620 ││ 621 │ 621 ││ 622 │ 622 ││ 623 │ 623 ││ 624 │ 624 ││ 625 │ 625 ││ 626 │ 626 ││ 627 │ 627 ││ 628 │ 628 ││ 629 │ 629 ││ 630 │ 630 ││ 631 │ 631 ││ 632 │ 632 ││ 633 │ 633 ││ 634 │ 634 ││ 635 │ 635 ││ 636 │ 636 ││ 637 │ 637 ││ 638 │ 638 ││ 639 │ 639 ││ 640 │ 640 ││ 641 │ 641 ││ 642 │ 642 ││ 643 │ 643 ││ 644 │ 644 ││ 645 │ 645 ││ 646 │ 646 ││ 647 │ 647 ││ 648 │ 648 ││ 649 │ 649 ││ 650 │ 650 ││ 651 │ 651 ││ 652 │ 652 ││ 653 │ 653 ││ 654 │ 654 ││ 655 │ 655 ││ 656 │ 656 ││ 657 │ 657 ││ 658 │ 658 ││ 659 │ 659 ││ 660 │ 660 ││ 661 │ 661 ││ 662 │ 662 ││ 663 │ 663 ││ 664 │ 664 ││ 665 │ 665 ││ 666 │ 666 ││ 667 │ 667 ││ 668 │ 668 ││ 669 │ 669 ││ 670 │ 670 ││ 671 │ 671 ││ 672 │ 672 ││ 673 │ 673 ││ 674 │ 674 ││ 675 │ 675 ││ 676 │ 676 ││ 677 │ 677 ││ 678 │ 678 ││ 679 │ 679 ││ 680 │ 680 ││ 681 │ 681 ││ 682 │ 682 ││ 683 │ 683 ││ 684 │ 684 ││ 685 │ 685 ││ 686 │ 686 ││ 687 │ 687 ││ 688 │ 688 ││ 689 │ 689 ││ 690 │ 690 ││ 691 │ 691 ││ 692 │ 692 ││ 693 │ 693 ││ 694 │ 694 ││ 695 │ 695 ││ 696 │ 696 ││ 697 │ 697 ││ 698 │ 698 ││ 699 │ 699 ││ 700 │ 700 ││ 701 │ 701 ││ 702 │ 702 ││ 703 │ 703 ││ 704 │ 704 ││ 705 │ 705 ││ 706 │ 706 ││ 707 │ 707 ││ 708 │ 708 ││ 709 │ 709 ││ 710 │ 710 ││ 711 │ 711 ││ 712 │ 712 ││ 713 │ 713 ││ 714 │ 714 ││ 715 │ 715 ││ 716 │ 716 ││ 717 │ 717 ││ 718 │ 718 ││ 719 │ 719 ││ 720 │ 720 ││ 721 │ 721 ││ 722 │ 722 ││ 723 │ 723 ││ 724 │ 724 ││ 725 │ 725 ││ 726 │ 726 ││ 727 │ 727 ││ 728 │ 728 ││ 729 │ 729 ││ 730 │ 730 ││ 731 │ 731 ││ 732 │ 732 ││ 733 │ 733 ││ 734 │ 734 ││ 735 │ 735 ││ 736 │ 736 ││ 737 │ 737 ││ 738 │ 738 ││ 739 │ 739 ││ 740 │ 740 ││ 741 │ 741 ││ 742 │ 742 ││ 743 │ 743 ││ 744 │ 744 ││ 745 │ 745 ││ 746 │ 746 ││ 747 │ 747 ││ 748 │ 748 ││ 749 │ 749 ││ 750 │ 750 ││ 751 │ 751 ││ 752 │ 752 ││ 753 │ 753 ││ 754 │ 754 ││ 755 │ 755 ││ 756 │ 756 ││ 757 │ 757 ││ 758 │ 758 ││ 759 │ 759 ││ 760 │ 760 ││ 761 │ 761 ││ 762 │ 762 ││ 763 │ 763 ││ 764 │ 764 ││ 765 │ 765 ││ 766 │ 766 ││ 767 │ 767 ││ 768 │ 768 ││ 769 │ 769 ││ 770 │ 770 ││ 771 │ 771 ││ 772 │ 772 ││ 773 │ 773 ││ 774 │ 774 ││ 775 │ 775 ││ 776 │ 776 ││ 777 │ 777 ││ 778 │ 778 ││ 779 │ 779 ││ 780 │ 780 ││ 781 │ 781 ││ 782 │ 782 ││ 783 │ 783 ││ 784 │ 784 ││ 785 │ 785 ││ 786 │ 786 ││ 787 │ 787 ││ 788 │ 788 ││ 789 │ 789 ││ 790 │ 790 ││ 791 │ 791 ││ 792 │ 792 ││ 793 │ 793 ││ 794 │ 794 ││ 795 │ 795 ││ 796 │ 796 ││ 797 │ 797 ││ 798 │ 798 ││ 799 │ 799 ││ 800 │ 800 ││ 801 │ 801 ││ 802 │ 802 ││ 803 │ 803 ││ 804 │ 804 ││ 805 │ 805 ││ 806 │ 806 ││ 807 │ 807 ││ 808 │ 808 ││ 809 │ 809 ││ 810 │ 810 ││ 811 │ 811 ││ 812 │ 812 ││ 813 │ 813 ││ 814 │ 814 ││ 815 │ 815 ││ 816 │ 816 ││ 817 │ 817 ││ 818 │ 818 ││ 819 │ 819 ││ 820 │ 820 ││ 821 │ 821 ││ 822 │ 822 ││ 823 │ 823 ││ 824 │ 824 ││ 825 │ 825 ││ 826 │ 826 ││ 827 │ 827 ││ 828 │ 828 ││ 829 │ 829 ││ 830 │ 830 ││ 831 │ 831 ││ 832 │ 832 ││ 833 │ 833 ││ 834 │ 834 ││ 835 │ 835 ││ 836 │ 836 ││ 837 │ 837 ││ 838 │ 838 ││ 839 │ 839 ││ 840 │ 840 ││ 841 │ 841 ││ 842 │ 842 ││ 843 │ 843 ││ 844 │ 844 ││ 845 │ 845 ││ 846 │ 846 ││ 847 │ 847 ││ 848 │ 848 ││ 849 │ 849 ││ 850 │ 850 ││ 851 │ 851 ││ 852 │ 852 ││ 853 │ 853 ││ 854 │ 854 ││ 855 │ 855 ││ 856 │ 856 ││ 857 │ 857 ││ 858 │ 858 ││ 859 │ 859 ││ 860 │ 860 ││ 861 │ 861 ││ 862 │ 862 ││ 863 │ 863 ││ 864 │ 864 ││ 865 │ 865 ││ 866 │ 866 ││ 867 │ 867 ││ 868 │ 868 ││ 869 │ 869 ││ 870 │ 870 ││ 871 │ 871 ││ 872 │ 872 ││ 873 │ 873 ││ 874 │ 874 ││ 875 │ 875 ││ 876 │ 876 ││ 877 │ 877 ││ 878 │ 878 ││ 879 │ 879 ││ 880 │ 880 ││ 881 │ 881 ││ 882 │ 882 ││ 883 │ 883 ││ 884 │ 884 ││ 885 │ 885 ││ 886 │ 886 ││ 887 │ 887 ││ 888 │ 888 ││ 889 │ 889 ││ 890 │ 890 ││ 891 │ 891 ││ 892 │ 892 ││ 893 │ 893 ││ 894 │ 894 ││ 895 │ 895 ││ 896 │ 896 ││ 897 │ 897 ││ 898 │ 898 ││ 899 │ 899 ││ 900 │ 900 ││ 901 │ 901 ││ 902 │ 902 ││ 903 │ 903 ││ 904 │ 904 ││ 905 │ 905 ││ 906 │ 906 ││ 907 │ 907 ││ 908 │ 908 ││ 909 │ 909 ││ 910 │ 910 ││ 911 │ 911 ││ 912 │ 912 ││ 913 │ 913 ││ 914 │ 914 ││ 915 │ 915 ││ 916 │ 916 ││ 917 │ 917 ││ 918 │ 918 ││ 919 │ 919 ││ 920 │ 920 ││ 921 │ 921 ││ 922 │ 922 ││ 923 │ 923 ││ 924 │ 924 ││ 925 │ 925 ││ 926 │ 926 ││ 927 │ 927 ││ 928 │ 928 ││ 929 │ 929 ││ 930 │ 930 ││ 931 │ 931 ││ 932 │ 932 ││ 933 │ 933 ││ 934 │ 934 ││ 935 │ 935 ││ 936 │ 936 ││ 937 │ 937 ││ 938 │ 938 ││ 939 │ 939 ││ 940 │ 940 ││ 941 │ 941 ││ 942 │ 942 ││ 943 │ 943 ││ 944 │ 944 ││ 945 │ 945 ││ 946 │ 946 ││ 947 │ 947 ││ 948 │ 948 ││ 949 │ 949 ││ 950 │ 950 ││ 951 │ 951 ││ 952 │ 952 ││ 953 │ 953 ││ 954 │ 954 ││ 955 │ 955 ││ 956 │ 956 ││ 957 │ 957 ││ 958 │ 958 ││ 959 │ 959 ││ 960 │ 960 ││ 961 │ 961 ││ 962 │ 962 ││ 963 │ 963 ││ 964 │ 964 ││ 965 │ 965 ││ 966 │ 966 ││ 967 │ 967 ││ 968 │ 968 ││ 969 │ 969 ││ 970 │ 970 ││ 971 │ 971 ││ 972 │ 972 ││ 973 │ 973 ││ 974 │ 974 ││ 975 │ 975 ││ 976 │ 976 ││ 977 │ 977 ││ 978 │ 978 ││ 979 │ 979 ││ 980 │ 980 ││ 981 │ 981 ││ 982 │ 982 ││ 983 │ 983 ││ 984 │ 984 ││ 985 │ 985 ││ 986 │ 986 ││ 987 │ 987 ││ 988 │ 988 ││ 989 │ 989 ││ 990 │ 990 ││ 991 │ 991 ││ 992 │ 992 ││ 993 │ 993 ││ 994 │ 994 ││ 995 │ 995 ││ 996 │ 996 ││ 997 │ 997 ││ 998 │ 998 ││ 999 │ 999 │├─────┼─────┤│ 0 │ 0 │╰─────┴─────╯╭──────┬──────╮│ 1000 │ 1000 │╰──────┴──────╯" ); } diff --git a/crates/nu-explore/src/nu_common/table.rs b/crates/nu-explore/src/nu_common/table.rs index 10d5d9c2a0..3d3f06b801 100644 --- a/crates/nu-explore/src/nu_common/table.rs +++ b/crates/nu-explore/src/nu_common/table.rs @@ -1,7 +1,8 @@ use nu_color_config::{get_color_config, style_primitive}; use nu_engine::column::get_columns; +use nu_protocol::FooterMode; use nu_protocol::{ast::PathMember, Config, ShellError, Span, TableIndexMode, Value}; -use nu_table::{string_width, Alignment, Alignments, Table as NuTable, TableTheme, TextStyle}; +use nu_table::{string_width, Alignment, Table as NuTable, TableConfig, TableTheme, TextStyle}; use std::sync::Arc; use std::{ cmp::max, @@ -21,10 +22,8 @@ pub fn try_build_table( color_hm: &NuStyleTable, value: Value, ) -> String { - let theme = load_theme_from_config(config); - match value { - Value::List { vals, span } => try_build_list(vals, &ctrlc, config, span, color_hm, theme), + Value::List { vals, span } => try_build_list(vals, &ctrlc, config, span, color_hm), Value::Record { cols, vals, span } => { try_build_map(cols, vals, span, ctrlc, config, color_hm) } @@ -65,7 +64,6 @@ fn try_build_list( config: &NuConfig, span: Span, color_hm: &HashMap, - theme: TableTheme, ) -> String { let table = convert_to_table2( 0, @@ -74,23 +72,24 @@ fn try_build_list( config, span, color_hm, - &theme, None, false, "", usize::MAX, ); match table { - Ok(Some(table)) => { - let val = table.draw_table( + Ok(Some((table, with_header, with_index))) => { + let table_config = create_table_config( config, color_hm, - Alignments::default(), - &theme, - usize::MAX, + table.count_rows(), + with_header, + with_index, false, ); + let val = table.draw(table_config, usize::MAX); + match val { Some(result) => result, None => value_to_styled_string(&Value::List { vals, span }, config, color_hm).0, @@ -104,7 +103,7 @@ fn try_build_list( } #[allow(clippy::too_many_arguments)] -pub fn build_expanded_table( +fn build_expanded_table( cols: Vec, vals: Vec, span: Span, @@ -115,16 +114,18 @@ pub fn build_expanded_table( flatten: bool, flatten_sep: &str, ) -> Result, ShellError> { - let theme = load_theme_from_config(config); let color_hm = get_color_config(config); - let alignments = Alignments::default(); + let theme = load_theme_from_config(config); // calculate the width of a key part + the rest of table so we know the rest of the table width available for value. let key_width = cols.iter().map(|col| string_width(col)).max().unwrap_or(0); let key = NuTable::create_cell(" ".repeat(key_width), TextStyle::default()); - let key_table = NuTable::new(vec![vec![key]], (1, 2), term_width, false, false); + let key_table = NuTable::new(vec![vec![key]], (1, 2)); let key_width = key_table - .draw_table(config, &color_hm, alignments, &theme, usize::MAX, false) + .draw( + create_table_config(config, &color_hm, 1, false, false, false), + usize::MAX, + ) .map(|table| string_width(&table)) .unwrap_or(0); @@ -161,7 +162,6 @@ pub fn build_expanded_table( config, span, &color_hm, - &theme, deep, flatten, flatten_sep, @@ -169,21 +169,23 @@ pub fn build_expanded_table( )?; match table { - Some(mut table) => { + Some((mut table, with_header, with_index)) => { // controll width via removing table columns. let theme = load_theme_from_config(config); table.truncate(remaining_width, &theme); is_expanded = true; - let val = table.draw_table( + let table_config = create_table_config( config, &color_hm, - alignments, - &theme, - remaining_width, + table.count_rows(), + with_header, + with_index, false, ); + + let val = table.draw(table_config, remaining_width); match val { Some(result) => result, None => return Ok(None), @@ -247,12 +249,12 @@ pub fn build_expanded_table( data.push(row); } - let data_len = data.len(); - let table = NuTable::new(data, (data_len, 2), term_width, false, false); + let table_config = create_table_config(config, &color_hm, data.len(), false, false, false); - let table_s = table - .clone() - .draw_table(config, &color_hm, alignments, &theme, term_width, false); + let data_len = data.len(); + let table = NuTable::new(data, (data_len, 2)); + + let table_s = table.clone().draw(table_config.clone(), term_width); let table = match table_s { Some(s) => { @@ -265,7 +267,8 @@ pub fn build_expanded_table( let used_percent = width as f32 / term_width as f32; if width < term_width && used_percent > EXPAND_TREASHHOLD { - table.draw_table(config, &color_hm, alignments, &theme, term_width, true) + let table_config = table_config.expand(); + table.draw(table_config, term_width) } else { Some(s) } @@ -285,12 +288,11 @@ fn convert_to_table2<'a>( config: &Config, head: Span, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, available_width: usize, -) -> Result, ShellError> { +) -> Result, ShellError> { const PADDING_SPACE: usize = 2; const SPLIT_LINE_SPACE: usize = 1; const ADDITIONAL_CELL_SPACE: usize = PADDING_SPACE + SPLIT_LINE_SPACE; @@ -338,8 +340,6 @@ fn convert_to_table2<'a>( } for (row, item) in input.clone().into_iter().enumerate() { - let row = if with_header { row + 1 } else { row }; - if let Some(ctrlc) = &ctrlc { if ctrlc.load(Ordering::SeqCst) { return Ok(None); @@ -361,6 +361,8 @@ fn convert_to_table2<'a>( column_width = max(column_width, width); let value = NuTable::create_cell(value.0, value.1); + + let row = if with_header { row + 1 } else { row }; data[row].push(value); } @@ -388,7 +390,6 @@ fn convert_to_table2<'a>( config, &ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -401,9 +402,10 @@ fn convert_to_table2<'a>( let count_columns = if with_index { 2 } else { 1 }; let size = (data.len(), count_columns); - let table = NuTable::new(data, size, usize::MAX, with_header, with_index); - return Ok(Some(table)); + let table = NuTable::new(data, size); + + return Ok(Some((table, with_header, with_index))); } let mut widths = Vec::new(); @@ -449,7 +451,6 @@ fn convert_to_table2<'a>( config, &ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -566,9 +567,9 @@ fn convert_to_table2<'a>( let count_rows = data.len(); let size = (count_rows, count_columns); - let table = NuTable::new(data, size, usize::MAX, with_header, with_index); + let table = NuTable::new(data, size); - Ok(Some(table)) + Ok(Some((table, with_header, with_index))) } fn lookup_index_value(item: &Value, config: &Config) -> Option { @@ -614,7 +615,6 @@ fn create_table2_entry( config: &Config, ctrlc: &Option>, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, @@ -632,7 +632,6 @@ fn create_table2_entry( config, ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -646,7 +645,6 @@ fn create_table2_entry( config, ctrlc, color_hm, - theme, deep, flatten, flatten_sep, @@ -670,7 +668,6 @@ fn convert_to_table2_entry( config: &Config, ctrlc: &Option>, color_hm: &NuColorMap, - theme: &TableTheme, deep: Option, flatten: bool, flatten_sep: &str, @@ -693,7 +690,6 @@ fn convert_to_table2_entry( config, *span, color_hm, - theme, deep.map(|i| i - 1), flatten, flatten_sep, @@ -701,9 +697,17 @@ fn convert_to_table2_entry( ); let inner_table = table.map(|table| { - table.and_then(|table| { - let alignments = Alignments::default(); - table.draw_table(config, color_hm, alignments, theme, usize::MAX, false) + table.and_then(|(table, with_header, with_index)| { + let table_config = create_table_config( + config, + color_hm, + table.count_rows(), + with_header, + with_index, + false, + ); + + table.draw(table_config, usize::MAX) }) }); @@ -733,7 +737,6 @@ fn convert_to_table2_entry( config, *span, color_hm, - theme, deep.map(|i| i - 1), flatten, flatten_sep, @@ -741,11 +744,20 @@ fn convert_to_table2_entry( ); let inner_table = table.map(|table| { - table.and_then(|table| { - let alignments = Alignments::default(); - table.draw_table(config, color_hm, alignments, theme, usize::MAX, false) + table.and_then(|(table, with_header, with_index)| { + let table_config = create_table_config( + config, + color_hm, + table.count_rows(), + with_header, + with_index, + false, + ); + + table.draw(table_config, usize::MAX) }) }); + if let Ok(Some(table)) = inner_table { (table, TextStyle::default()) } else { @@ -842,3 +854,43 @@ fn load_theme_from_config(config: &Config) -> TableTheme { _ => nu_table::TableTheme::rounded(), } } + +fn create_table_config( + config: &Config, + color_hm: &HashMap, + count_records: usize, + with_header: bool, + with_index: bool, + expand: bool, +) -> TableConfig { + let theme = load_theme_from_config(config); + let append_footer = with_footer(config, with_header, count_records); + + let mut table_cfg = TableConfig::new(theme, with_header, with_index, append_footer); + + let sep_color = lookup_separator_color(color_hm); + if let Some(color) = sep_color { + table_cfg = table_cfg.splitline_style(color); + } + + if expand { + table_cfg = table_cfg.expand(); + } + + table_cfg.trim(config.trim_strategy.clone()) +} + +fn lookup_separator_color( + color_hm: &HashMap, +) -> Option { + color_hm.get("separator").cloned() +} + +fn with_footer(config: &Config, with_header: bool, count_records: usize) -> bool { + with_header && need_footer(config, count_records as u64) +} + +fn need_footer(config: &Config, count_records: u64) -> bool { + matches!(config.footer_mode, FooterMode::RowCount(limit) if count_records > limit) + || matches!(config.footer_mode, FooterMode::Always) +} diff --git a/crates/nu-protocol/src/config.rs b/crates/nu-protocol/src/config.rs index 2d3d798972..0729080aea 100644 --- a/crates/nu-protocol/src/config.rs +++ b/crates/nu-protocol/src/config.rs @@ -185,6 +185,18 @@ pub enum TrimStrategy { }, } +impl TrimStrategy { + pub fn wrap(dont_split_words: bool) -> Self { + Self::Wrap { + try_to_keep_words: dont_split_words, + } + } + + pub fn truncate(suffix: Option) -> Self { + Self::Truncate { suffix } + } +} + #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ExploreConfig { pub color_config: HashMap, diff --git a/crates/nu-table/Cargo.toml b/crates/nu-table/Cargo.toml index 405b060bd4..bcf3850d64 100644 --- a/crates/nu-table/Cargo.toml +++ b/crates/nu-table/Cargo.toml @@ -11,7 +11,6 @@ version = "0.72.2" nu-ansi-term = "0.46.0" nu-protocol = { path = "../nu-protocol", version = "0.72.2" } nu-utils = { path = "../nu-utils", version = "0.72.2" } -atty = "0.2.14" tabled = { version = "0.10.0", features = ["color"], default-features = false } -json_to_table = { version = "0.2.0", features = ["color"] } +json_to_table = { version = "0.3.1", features = ["color"] } serde_json = "1" diff --git a/crates/nu-table/examples/table_demo.rs b/crates/nu-table/examples/table_demo.rs index c217e2c5b6..bc5671f6ed 100644 --- a/crates/nu-table/examples/table_demo.rs +++ b/crates/nu-table/examples/table_demo.rs @@ -1,6 +1,4 @@ -use nu_protocol::Config; -use nu_table::{Alignments, Table, TableTheme, TextStyle}; -use std::collections::HashMap; +use nu_table::{Table, TableConfig, TableTheme, TextStyle}; use tabled::papergrid::records::{cell_info::CellInfo, tcell::TCell}; fn main() { @@ -19,30 +17,28 @@ fn main() { // The mocked up table data let (table_headers, row_data) = make_table_data(); + // The table headers let headers = vec_of_str_to_vec_of_styledstr(&table_headers, true); + // The table rows let rows = vec_of_str_to_vec_of_styledstr(&row_data, false); + // The table itself let count_cols = std::cmp::max(rows.len(), headers.len()); let mut rows = vec![rows; 3]; rows.insert(0, headers); - let table = Table::new(rows, (3, count_cols), width, true, false); - // FIXME: Config isn't available from here so just put these here to compile - let color_hm: HashMap = HashMap::new(); - // get the default config - let config = Config::default(); + + let theme = TableTheme::rounded(); + let table_cfg = TableConfig::new(theme, true, false, false); + + let table = Table::new(rows, (3, count_cols)); + // Capture the table as a string let output_table = table - .draw_table( - &config, - &color_hm, - Alignments::default(), - &TableTheme::rounded(), - width, - false, - ) + .draw(table_cfg, width) .unwrap_or_else(|| format!("Couldn't fit table into {} columns!", width)); + // Draw the table println!("{}", output_table) } diff --git a/crates/nu-table/src/lib.rs b/crates/nu-table/src/lib.rs index 574b4c8873..82a8f51393 100644 --- a/crates/nu-table/src/lib.rs +++ b/crates/nu-table/src/lib.rs @@ -2,54 +2,10 @@ mod nu_protocol_table; mod table; mod table_theme; mod textstyle; +mod util; pub use nu_protocol_table::NuTable; -pub use table::{Alignments, Table}; +pub use table::{Alignments, Table, TableConfig}; pub use table_theme::TableTheme; pub use textstyle::{Alignment, TextStyle}; - -use tabled::{Padding, Style, Width}; - -pub fn string_width(text: &str) -> usize { - tabled::papergrid::util::string_width_multiline_tab(text, 4) -} - -pub fn wrap_string(text: &str, width: usize) -> String { - // well... it's not effitient to build a table to wrap a string, - // but ... it's better than a copy paste - tabled::builder::Builder::from_iter([[text]]) - .build() - .with(Padding::zero()) - .with(Style::empty()) - .with(Width::wrap(width)) - .to_string() -} - -pub fn string_truncate(text: &str, width: usize) -> String { - // todo: change me... - - match text.lines().next() { - Some(first_line) => tabled::builder::Builder::from_iter([[first_line]]) - .build() - .with(tabled::Style::empty()) - .with(tabled::Padding::zero()) - .with(tabled::Width::truncate(width)) - .to_string(), - None => String::new(), - } -} - -pub fn string_wrap(text: &str, width: usize) -> String { - // todo: change me... - - if text.is_empty() { - return String::new(); - } - - tabled::builder::Builder::from_iter([[text]]) - .build() - .with(tabled::Style::empty()) - .with(tabled::Padding::zero()) - .with(tabled::Width::wrap(width)) - .to_string() -} +pub use util::*; diff --git a/crates/nu-table/src/nu_protocol_table.rs b/crates/nu-table/src/nu_protocol_table.rs index f170d0ff72..688150864a 100644 --- a/crates/nu-table/src/nu_protocol_table.rs +++ b/crates/nu-table/src/nu_protocol_table.rs @@ -1,9 +1,12 @@ use std::collections::HashMap; use nu_protocol::{Config, Span, Value}; -use tabled::{color::Color, papergrid::records::Records, Table}; +use tabled::{ + color::Color, formatting::AlignmentStrategy, object::Segment, papergrid::records::Records, + Alignment, Modify, Table, +}; -use crate::{table::TrimStrategyModifier, TableTheme}; +use crate::{table::TrimStrategyModifier, Alignments, TableTheme}; /// NuTable has a recursive table representation of nu_prorocol::Value. /// @@ -215,4 +218,10 @@ fn load_theme( table.with(color); } } + + table.with( + Modify::new(Segment::all()) + .with(Alignment::Horizontal(Alignments::default().data)) + .with(AlignmentStrategy::PerLine), + ); } diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index 4b9d78a116..e57da5c56a 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -1,6 +1,7 @@ -use std::{collections::HashMap, fmt::Display}; +use std::{cmp::min, collections::HashMap, fmt::Display}; -use nu_protocol::{Config, FooterMode, TrimStrategy}; +use nu_ansi_term::Style; +use nu_protocol::TrimStrategy; use tabled::{ alignment::AlignmentHorizontal, builder::Builder, @@ -12,8 +13,11 @@ use tabled::{ records::{ cell_info::CellInfo, tcell::TCell, vec_records::VecRecords, Records, RecordsMut, }, + util::string_width_multiline, width::CfgWidthFunction, + Estimate, }, + peaker::Peaker, Alignment, Modify, ModifyObject, TableOption, Width, }; @@ -23,9 +27,6 @@ use crate::{table_theme::TableTheme, TextStyle}; #[derive(Debug, Clone)] pub struct Table { data: Data, - is_empty: bool, - with_header: bool, - with_index: bool, } type Data = VecRecords, TextStyle>>; @@ -34,33 +35,22 @@ impl Table { /// Creates a [Table] instance. /// /// If `headers.is_empty` then no headers will be rendered. - pub fn new( - mut data: Vec, TextStyle>>>, - size: (usize, usize), - termwidth: usize, - with_header: bool, - with_index: bool, - ) -> Table { + pub fn new(data: Vec, TextStyle>>>, size: (usize, usize)) -> Table { // it's not guaranted that data will have all rows with the same number of columns. // but VecRecords::with_hint require this constrain. - for row in &mut data { - if row.len() < size.1 { - row.extend( - std::iter::repeat(Self::create_cell(String::default(), TextStyle::default())) - .take(size.1 - row.len()), - ); - } - } + // + // so we do a check to make it certainly true - let mut data = VecRecords::with_hint(data, size.1); - let is_empty = maybe_truncate_columns(&mut data, size.1, termwidth); + let mut data = data; + make_data_consistent(&mut data, size); - Table { - data, - is_empty, - with_header, - with_index, - } + let data = VecRecords::with_hint(data, size.1); + + Table { data } + } + + pub fn count_rows(&self) -> usize { + self.data.count_rows() } pub fn create_cell( @@ -70,29 +60,15 @@ impl Table { TCell::new(CellInfo::new(text.into(), CfgWidthFunction::new(4)), style) } - pub fn is_empty(&self) -> bool { - self.is_empty - } - - pub fn size(&self) -> (usize, usize) { - (self.data.count_rows(), self.data.count_columns()) - } - - pub fn is_with_index(&self) -> bool { - self.with_index - } - pub fn truncate(&mut self, width: usize, theme: &TableTheme) -> bool { let mut truncated = false; while self.data.count_rows() > 0 && self.data.count_columns() > 0 { - let mut table = Builder::custom(self.data.clone()).build(); - load_theme(&mut table, &HashMap::new(), theme, false, false); - let total = table.total_width(); - - // println!("{}", table); - // println!("width={:?} total={:?}", width, total); - - drop(table); + let total; + { + let mut table = Builder::custom(self.data.clone()).build(); + load_theme(&mut table, theme, false, false, None); + total = table.total_width(); + } if total > width { truncated = true; @@ -117,19 +93,69 @@ impl Table { false } - /// Draws a trable on a String. + /// Converts a table to 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, - alignments: Alignments, - theme: &TableTheme, - termwidth: usize, - expand: bool, - ) -> Option { - draw_table(self, config, color_hm, alignments, theme, termwidth, expand) + pub fn draw(self, config: TableConfig, termwidth: usize) -> Option { + build_table(self.data, config, termwidth) + } +} + +fn make_data_consistent(data: &mut Vec>>, size: (usize, usize)) { + for row in data { + if row.len() < size.1 { + row.extend( + std::iter::repeat(Table::create_cell(String::default(), TextStyle::default())) + .take(size.1 - row.len()), + ); + } + } +} + +#[derive(Debug, Clone)] +pub struct TableConfig { + theme: TableTheme, + alignments: Alignments, + trim: TrimStrategy, + split_color: Option