diff --git a/crates/nu-command/tests/commands/table.rs b/crates/nu-command/tests/commands/table.rs index cc40a41a74..6bd7dfbc00 100644 --- a/crates/nu-command/tests/commands/table.rs +++ b/crates/nu-command/tests/commands/table.rs @@ -1333,7 +1333,15 @@ fn test_expand_big_0() { "│ target │ {record 3 fields} │", "│ dev-dependencies │ {record 9 fields} │", "│ features │ {record 8 fields} │", - "│ bin │ [table 1 row] │", + "│ │ ╭───┬─────┬─────╮ │", + "│ bin │ │ # │ nam │ pat │ │", + "│ │ │ │ e │ h │ │", + "│ │ ├───┼─────┼─────┤ │", + "│ │ │ 0 │ nu │ src │ │", + "│ │ │ │ │ /ma │ │", + "│ │ │ │ │ in. │ │", + "│ │ │ │ │ rs │ │", + "│ │ ╰───┴─────┴─────╯ │", "│ │ ╭───────────┬───╮ │", "│ patch │ │ crates-io │ { │ │", "│ │ │ │ r │ │", @@ -1352,7 +1360,16 @@ fn test_expand_big_0() { "│ │ │ │ d │ │", "│ │ │ │ } │ │", "│ │ ╰───────────┴───╯ │", - "│ bench │ [table 1 row] │", + "│ │ ╭───┬─────┬─────╮ │", + "│ bench │ │ # │ nam │ har │ │", + "│ │ │ │ e │ nes │ │", + "│ │ │ │ │ s │ │", + "│ │ ├───┼─────┼─────┤ │", + "│ │ │ 0 │ ben │ fal │ │", + "│ │ │ │ chm │ se │ │", + "│ │ │ │ ark │ │ │", + "│ │ │ │ s │ │ │", + "│ │ ╰───┴─────┴─────╯ │", "╰──────────────────┴───────────────────╯", ]); @@ -1366,6 +1383,8 @@ fn table_expande_with_no_header_internally_0() { let actual = nu!(format!("{} | table --expand --width 141", nu_value.trim())); + _print_lines(&actual.out, 141); + assert_eq!( actual.out, join_lines([ @@ -1532,71 +1551,191 @@ fn table_expande_with_no_header_internally_0() { "│ │ │ │ │ │ ╰─────┴──────────╯ │ │ │", "│ │ │ │ │ display_output │ │ │ │", "│ │ │ │ ╰────────────────┴────────────────────╯ │ │", - "│ │ │ │ ╭───┬───────────────────────────┬────────────────────────┬────────┬─────╮ │ │", - "│ │ │ menus │ │ # │ name │ only_buffer_difference │ marker │ ... │ │ │", - "│ │ │ │ ├───┼───────────────────────────┼────────────────────────┼────────┼─────┤ │ │", - "│ │ │ │ │ 0 │ completion_menu │ false │ | │ ... │ │ │", - "│ │ │ │ │ 1 │ history_menu │ true │ ? │ ... │ │ │", - "│ │ │ │ │ 2 │ help_menu │ true │ ? │ ... │ │ │", - "│ │ │ │ │ 3 │ commands_menu │ false │ # │ ... │ │ │", - "│ │ │ │ │ 4 │ vars_menu │ true │ # │ ... │ │ │", - "│ │ │ │ │ 5 │ commands_with_description │ true │ # │ ... │ │ │", - "│ │ │ │ ╰───┴───────────────────────────┴────────────────────────┴────────┴─────╯ │ │", + "│ │ │ │ ╭───┬───────────────────────────┬────────────────────────┬────────┬───┬─────╮ │ │", + "│ │ │ menus │ │ # │ name │ only_buffer_difference │ marker │ t │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ y │ │ │ │", + "│ │ │ │ │ │ │ │ │ p │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ ├───┼───────────────────────────┼────────────────────────┼────────┼───┼─────┤ │ │", + "│ │ │ │ │ 0 │ completion_menu │ false │ | │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 4 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ │ 1 │ history_menu │ true │ ? │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 2 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ │ 2 │ help_menu │ true │ ? │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 6 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ │ 3 │ commands_menu │ false │ # │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 4 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ │ 4 │ vars_menu │ true │ # │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 2 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ │ 5 │ commands_with_description │ true │ # │ { │ ... │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ c │ │ │ │", + "│ │ │ │ │ │ │ │ │ o │ │ │ │", + "│ │ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ 6 │ │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ │ │", + "│ │ │ │ │ │ │ │ │ f │ │ │ │", + "│ │ │ │ │ │ │ │ │ i │ │ │ │", + "│ │ │ │ │ │ │ │ │ e │ │ │ │", + "│ │ │ │ │ │ │ │ │ l │ │ │ │", + "│ │ │ │ │ │ │ │ │ d │ │ │ │", + "│ │ │ │ │ │ │ │ │ s │ │ │ │", + "│ │ │ │ │ │ │ │ │ } │ │ │ │", + "│ │ │ │ ╰───┴───────────────────────────┴────────────────────────┴────────┴───┴─────╯ │ │", "│ │ │ │ ╭────┬───────────────────────────┬──────────┬─────────┬───────────────┬─────╮ │ │", - "│ │ │ keybindings │ │ # │ name │ modifier │ keycode │ mode │ ... │ │ │", + "│ │ │ keybindings │ │ # │ name │ modifier │ keycode │ mode │ eve │ │ │", + "│ │ │ │ │ │ │ │ │ │ nt │ │ │", "│ │ │ │ ├────┼───────────────────────────┼──────────┼─────────┼───────────────┼─────┤ │ │", - "│ │ │ │ │ 0 │ completion_menu │ none │ tab │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 0 │ completion_menu │ none │ tab │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ } │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 1 │ completion_previous │ shift │ backtab │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 1 │ completion_previous │ shift │ backtab │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ } │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 2 │ history_menu │ control │ char_r │ emacs │ ... │ │ │", - "│ │ │ │ │ 3 │ next_page │ control │ char_x │ emacs │ ... │ │ │", - "│ │ │ │ │ 4 │ undo_or_previous_page │ control │ char_z │ emacs │ ... │ │ │", - "│ │ │ │ │ 5 │ yank │ control │ char_y │ emacs │ ... │ │ │", - "│ │ │ │ │ 6 │ unix-line-discard │ control │ char_u │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 2 │ history_menu │ control │ char_r │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ s} │ │ │", + "│ │ │ │ │ 3 │ next_page │ control │ char_x │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 4 │ undo_or_previous_page │ control │ char_z │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 5 │ yank │ control │ char_y │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 6 │ unix-line-discard │ control │ char_u │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ } │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 7 │ kill-line │ control │ char_k │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 7 │ kill-line │ control │ char_k │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ } │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 8 │ commands_menu │ control │ char_t │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 8 │ commands_menu │ control │ char_t │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ s} │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 9 │ vars_menu │ alt │ char_o │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 9 │ vars_menu │ alt │ char_o │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ s} │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", - "│ │ │ │ │ 10 │ commands_with_description │ control │ char_s │ ╭───┬───────╮ │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ │ │ │", - "│ │ │ │ │ │ │ │ │ │ │ sert │ │ │ │ │", + "│ │ │ │ │ 10 │ commands_with_description │ control │ char_s │ ╭───┬───────╮ │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ 0 │ emacs │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ 1 │ vi_no │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ rmal │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ 2 │ vi_in │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ │ sert │ │ s} │ │ │", "│ │ │ │ │ │ │ │ │ ╰───┴───────╯ │ │ │ │", "│ │ │ │ ╰────┴───────────────────────────┴──────────┴─────────┴───────────────┴─────╯ │ │", "│ │ ╰──────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────╯ │", @@ -1611,6 +1750,8 @@ fn table_expande_with_no_header_internally_1() { let actual = nu!(format!("{} | table --expand --width 136", nu_value.trim())); + _print_lines(&actual.out, 136); + assert_eq!( actual.out, join_lines([ @@ -1777,37 +1918,87 @@ fn table_expande_with_no_header_internally_1() { "│ │ │ │ │ │ ╰─────┴──────────╯ │ │ │", "│ │ │ │ │ display_output │ │ │ │", "│ │ │ │ ╰────────────────┴────────────────────╯ │ │", - "│ │ │ │ ╭───┬───────────────────────────┬────────────────────────┬─────╮ │ │", - "│ │ │ menus │ │ # │ name │ only_buffer_difference │ ... │ │ │", - "│ │ │ │ ├───┼───────────────────────────┼────────────────────────┼─────┤ │ │", - "│ │ │ │ │ 0 │ completion_menu │ false │ ... │ │ │", - "│ │ │ │ │ 1 │ history_menu │ true │ ... │ │ │", - "│ │ │ │ │ 2 │ help_menu │ true │ ... │ │ │", - "│ │ │ │ │ 3 │ commands_menu │ false │ ... │ │ │", - "│ │ │ │ │ 4 │ vars_menu │ true │ ... │ │ │", - "│ │ │ │ │ 5 │ commands_with_description │ true │ ... │ │ │", - "│ │ │ │ ╰───┴───────────────────────────┴────────────────────────┴─────╯ │ │", + "│ │ │ │ ╭───┬───────────────────────────┬────────────────────────┬───────┬─────╮ │ │", + "│ │ │ menus │ │ # │ name │ only_buffer_difference │ marke │ ... │ │ │", + "│ │ │ │ │ │ │ │ r │ │ │ │", + "│ │ │ │ ├───┼───────────────────────────┼────────────────────────┼───────┼─────┤ │ │", + "│ │ │ │ │ 0 │ completion_menu │ false │ | │ ... │ │ │", + "│ │ │ │ │ 1 │ history_menu │ true │ ? │ ... │ │ │", + "│ │ │ │ │ 2 │ help_menu │ true │ ? │ ... │ │ │", + "│ │ │ │ │ 3 │ commands_menu │ false │ # │ ... │ │ │", + "│ │ │ │ │ 4 │ vars_menu │ true │ # │ ... │ │ │", + "│ │ │ │ │ 5 │ commands_with_description │ true │ # │ ... │ │ │", + "│ │ │ │ ╰───┴───────────────────────────┴────────────────────────┴───────┴─────╯ │ │", "│ │ │ │ ╭────┬───────────────────────────┬──────────┬─────────┬──────────┬─────╮ │ │", - "│ │ │ keybindings │ │ # │ name │ modifier │ keycode │ mode │ ... │ │ │", + "│ │ │ keybindings │ │ # │ name │ modifier │ keycode │ mode │ eve │ │ │", + "│ │ │ │ │ │ │ │ │ │ nt │ │ │", "│ │ │ │ ├────┼───────────────────────────┼──────────┼─────────┼──────────┼─────┤ │ │", - "│ │ │ │ │ 0 │ completion_menu │ none │ tab │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 1 │ completion_previous │ shift │ backtab │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 2 │ history_menu │ control │ char_r │ emacs │ ... │ │ │", - "│ │ │ │ │ 3 │ next_page │ control │ char_x │ emacs │ ... │ │ │", - "│ │ │ │ │ 4 │ undo_or_previous_page │ control │ char_z │ emacs │ ... │ │ │", - "│ │ │ │ │ 5 │ yank │ control │ char_y │ emacs │ ... │ │ │", - "│ │ │ │ │ 6 │ unix-line-discard │ control │ char_u │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 7 │ kill-line │ control │ char_k │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 8 │ commands_menu │ control │ char_t │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 9 │ vars_menu │ alt │ char_o │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", - "│ │ │ │ │ 10 │ commands_with_description │ control │ char_s │ [list 3 │ ... │ │ │", - "│ │ │ │ │ │ │ │ │ items] │ │ │ │", + "│ │ │ │ │ 0 │ completion_menu │ none │ tab │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 1 │ completion_previous │ shift │ backtab │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 2 │ history_menu │ control │ char_r │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ s} │ │ │", + "│ │ │ │ │ 3 │ next_page │ control │ char_x │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 4 │ undo_or_previous_page │ control │ char_z │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 5 │ yank │ control │ char_y │ emacs │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 6 │ unix-line-discard │ control │ char_u │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 7 │ kill-line │ control │ char_k │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 1 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ } │ │ │", + "│ │ │ │ │ 8 │ commands_menu │ control │ char_t │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ s} │ │ │", + "│ │ │ │ │ 9 │ vars_menu │ alt │ char_o │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ s} │ │ │", + "│ │ │ │ │ 10 │ commands_with_description │ control │ char_s │ [list 3 │ {re │ │ │", + "│ │ │ │ │ │ │ │ │ items] │ cor │ │ │", + "│ │ │ │ │ │ │ │ │ │ d 2 │ │ │", + "│ │ │ │ │ │ │ │ │ │ fi │ │ │", + "│ │ │ │ │ │ │ │ │ │ eld │ │ │", + "│ │ │ │ │ │ │ │ │ │ s} │ │ │", "│ │ │ │ ╰────┴───────────────────────────┴──────────┴─────────┴──────────┴─────╯ │ │", "│ │ ╰──────────────────────────────────┴──────────────────────────────────────────────────────────────────────────╯ │", "╰────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯", @@ -2521,6 +2712,7 @@ fn table_theme_on_border_with_love() { fn table_theme_on_border_thin() { assert_eq!( create_theme_output("thin"), + // ["┌─#─┬a_looooooong_name┬─b─┬─c─┐│ 0 │ 1 │ 2 │ 3 │└─#─┴a_looooooong_name┴─b─┴─c─┘"] [ "┌─#─┬─a─┬─b─┬───────c────────┐│ 0 │ 1 │ 2 │ 3 │├───┼───┼───┼────────────────┤│ 1 │ 4 │ 5 │ [list 3 items] │└───┴───┴───┴────────────────┘", "┌─#─┬─a─┬─b─┬───────c────────┐│ 0 │ 1 │ 2 │ 3 │├───┼───┼───┼────────────────┤│ 1 │ 4 │ 5 │ [list 3 items] │└─#─┴─a─┴─b─┴───────c────────┘", @@ -3149,3 +3341,21 @@ fn table_index_expand() { ╰─────┴─────╯" ); } + +#[test] +fn table_expand_big_header() { + let actual = nu!(" + let column_name = (('' | fill -c 'a' --width 81)) + [{ $column_name: 'contents' }] | table -e --width=80 + "); + + assert_eq!( + actual.out, + "╭───┬──────────────────────────────────────────────────────────────────────────╮\ + │ # │ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │\ + │ │ aaaaaaaaa │\ + ├───┼──────────────────────────────────────────────────────────────────────────┤\ + │ 0 │ contents │\ + ╰───┴──────────────────────────────────────────────────────────────────────────╯" + ); +} diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index b706a41eb2..e37c2180c4 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -1,36 +1,42 @@ +// TODO: Stop building `tabled -e` when it's clear we are out of terminal +// TODO: Stop building `tabled` when it's clear we are out of terminal +// NOTE: TODO the above we could expose something like [`WidthCtrl`] in which case we could also laverage the width list build right away. +// currently it seems like we do recacalculate it for `table -e`? + use std::{cmp::min, collections::HashMap}; use nu_ansi_term::Style; use nu_color_config::TextStyle; use nu_protocol::{TableIndent, TrimStrategy}; -use nu_utils::strip_ansi_unlikely; use tabled::{ builder::Builder, grid::{ ansi::ANSIBuf, - colors::Colors, - config::{AlignmentHorizontal, ColoredConfig, Entity, Position}, - dimension::CompleteDimensionVecRecords, + config::{ + AlignmentHorizontal, ColoredConfig, Entity, Indent, Position, Sides, SpannedConfig, + }, + dimension::{CompleteDimensionVecRecords, SpannedGridDimension}, records::{ - vec_records::{Cell, Text, VecRecords}, - ExactRecords, Records, Resizable, + vec_records::{Text, VecRecords}, + ExactRecords, Records, }, }, settings::{ - format::FormatContent, formatting::AlignmentStrategy, - object::{Columns, Row, Rows}, - peaker::Priority, + object::{Columns, Rows}, themes::ColumnNames, width::Truncate, - Alignment, Color, Format, Modify, ModifyList, Padding, Settings, TableOption, Width, + Alignment, CellOption, Color, Padding, TableOption, Width, }, Table, }; use crate::{convert_style, is_color_empty, table_theme::TableTheme}; +const EMPTY_COLUMN_TEXT: &str = "..."; +const EMPTY_COLUMN_TEXT_WIDTH: usize = 3; + pub type NuRecords = VecRecords; pub type NuRecordsValue = Text; @@ -227,7 +233,7 @@ pub struct TableConfig { indent: TableIndent, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] struct TableStructure { with_index: bool, with_header: bool, @@ -244,36 +250,114 @@ impl TableStructure { } } +#[derive(Debug, Clone)] +struct HeadInfo { + values: Vec, + align: AlignmentHorizontal, + color: Option, +} + +impl HeadInfo { + fn new(values: Vec, align: AlignmentHorizontal, color: Option) -> Self { + Self { + values, + align, + color, + } + } +} + fn build_table(mut t: NuTable, termwidth: usize) -> Option { if t.count_columns() == 0 || t.count_rows() == 0 { return Some(String::new()); } let widths = table_truncate(&mut t, termwidth)?; - table_insert_footer(&mut t); - draw_table(t, widths, termwidth) + let head = remove_header_if(&mut t); + table_insert_footer_if(&mut t); + + draw_table(t, widths, head, termwidth) } -fn table_insert_footer(t: &mut NuTable) { +fn remove_header_if(t: &mut NuTable) -> Option { + if !is_header_on_border(t) { + return None; + } + + let head = remove_header(t); + t.config.structure.with_header = false; + + Some(head) +} + +fn is_header_on_border(t: &NuTable) -> bool { + let is_configured = t.config.structure.with_header && t.config.header_on_border; + let has_horizontal = t.config.theme.as_base().borders_has_top() + || t.config.theme.as_base().get_horizontal_line(1).is_some(); + is_configured && has_horizontal +} + +fn table_insert_footer_if(t: &mut NuTable) { if t.config.structure.with_header && t.config.structure.with_footer { duplicate_row(&mut t.data, 0); } } -fn table_truncate(t: &mut NuTable, termwidth: usize) -> Option> { - let pad = t.config.indent.left + t.config.indent.right; - let widths = maybe_truncate_columns(&mut t.data, &t.config, termwidth, pad); - if widths.is_empty() { +fn table_truncate(t: &mut NuTable, termwidth: usize) -> Option { + let widths = maybe_truncate_columns(&mut t.data, &t.config, termwidth); + if widths.needed.is_empty() { return None; } Some(widths) } -fn draw_table(t: NuTable, widths: Vec, termwidth: usize) -> Option { - let structure = get_table_structure(&t.data, &t.config); +fn remove_header(t: &mut NuTable) -> HeadInfo { + let head: Vec = t + .data + .remove(0) + .into_iter() + .map(|s| s.to_string()) + .collect(); + let align = t.alignments.header; + let color = if is_color_empty(&t.styles.header) { + None + } else { + Some(t.styles.header.clone()) + }; + + // move settings by one row down + t.alignments.cells = t + .alignments + .cells + .drain() + .filter(|(k, _)| k.0 != 0) + .map(|(k, v)| ((k.0 - 1, k.1), v)) + .collect(); + t.alignments.header = AlignmentHorizontal::Center; + + // move settings by one row down + t.styles.cells = t + .styles + .cells + .drain() + .filter(|(k, _)| k.0 != 0) + .map(|(k, v)| ((k.0 - 1, k.1), v)) + .collect(); + t.styles.header = Color::empty(); + + HeadInfo::new(head, align, color) +} + +fn draw_table( + t: NuTable, + width: WidthEstimation, + head: Option, + termwidth: usize, +) -> Option { + let mut structure = t.config.structure; + structure.with_footer = structure.with_footer && head.is_none(); let sep_color = t.config.border_color; - let border_header = structure.with_header && t.config.header_on_border; let data: Vec> = t.data.into(); let mut table = Builder::from_vec(data).build(); @@ -282,96 +366,58 @@ fn draw_table(t: NuTable, widths: Vec, termwidth: usize) -> Option, cfg: &TableConfig) { + let head = match head { + Some(head) => head, + None => return, + }; + + let theme = &cfg.theme; + let with_footer = cfg.structure.with_footer; + let pad = cfg.indent.left + cfg.indent.right; + + if !theme.as_base().borders_has_top() { + let line = theme.as_base().get_horizontal_line(1); + if let Some(line) = line.cloned() { + table.get_config_mut().insert_horizontal_line(0, line); + if with_footer { + let last_row = table.count_rows(); + table + .get_config_mut() + .insert_horizontal_line(last_row, line); + } + }; + } + + if with_footer { + let last_row = table.count_rows(); + table.with(SetLineHeaders::new(head.clone(), last_row, pad)); + } + + table.with(SetLineHeaders::new(head, 0, pad)); +} + +fn truncate_table(table: &mut Table, cfg: &TableConfig, width: WidthEstimation, termwidth: usize) { + let trim = cfg.trim.clone(); + let pad = cfg.indent.left + cfg.indent.right; + let ctrl = WidthCtrl::new(termwidth, width, trim, cfg.expand, pad); + table.with(ctrl); +} + fn indent_sum(indent: TableIndent) -> usize { indent.left + indent.right } -fn get_table_structure(data: &VecRecords>, cfg: &TableConfig) -> TableStructure { - let with_index = cfg.structure.with_index; - let with_header = cfg.structure.with_header && data.count_rows() > 1; - let with_footer = with_header && cfg.structure.with_footer; - - TableStructure::new(with_index, with_header, with_footer) -} - -fn adjust_table(table: &mut Table, width_ctrl: WidthCtrl, border_header: bool, with_footer: bool) { - if border_header { - if with_footer { - set_border_head_with_footer(table, width_ctrl); - } else { - set_border_head(table, width_ctrl); - } - } else { - table.with(width_ctrl); - } -} - fn set_indent(table: &mut Table, indent: TableIndent) { table.with(Padding::new(indent.left, indent.right, 0, 0)); } -fn set_border_head(table: &mut Table, wctrl: WidthCtrl) { - let mut row = GetRow(0, Vec::new()); - let mut row_opts = GetRowSettings(0, AlignmentHorizontal::Left, None); - - table.with(&mut row); - table.with(&mut row_opts); - - table.with( - Settings::default() - .with(strip_color_from_row(0)) - .with(wctrl) - .with(MoveRowNext::new(0, 0)) - .with(SetLineHeaders::new(0, row.1, row_opts.1, row_opts.2)), - ); -} - -fn set_border_head_with_footer(table: &mut Table, wctrl: WidthCtrl) { - // note: funnily last and row must be equal at this point but we do not rely on it just in case. - - let count_rows = table.count_rows(); - let last_row_index = count_rows - 1; - - let mut first_row = GetRow(0, Vec::new()); - let mut head_settings = GetRowSettings(0, AlignmentHorizontal::Left, None); - let mut last_row = GetRow(last_row_index, Vec::new()); - - table.with(&mut first_row); - table.with(&mut head_settings); - table.with(&mut last_row); - - let head = first_row.1; - let footer = last_row.1; - let alignment = head_settings.1; - let head_color = head_settings.2.clone(); - let footer_color = head_settings.2; - - table.with( - Settings::default() - .with(strip_color_from_row(0)) - .with(strip_color_from_row(count_rows - 1)) - .with(wctrl) - .with(MoveRowNext::new(0, 0)) - .with(MoveRowPrev::new(last_row_index - 1, last_row_index)) - .with(SetLineHeaders::new(0, head, alignment, head_color)) - .with(SetLineHeaders::new( - last_row_index - 1, - footer, - alignment, - footer_color, - )), - ); -} - fn table_to_string(table: Table, termwidth: usize) -> Option { let total_width = table.total_width(); @@ -384,186 +430,107 @@ fn table_to_string(table: Table, termwidth: usize) -> Option { } struct WidthCtrl { - width: Vec, - cfg: TableConfig, - width_max: usize, + width: WidthEstimation, + trim_strategy: TrimStrategy, + max_width: usize, + expand: bool, pad: usize, } impl WidthCtrl { - fn new(width: Vec, cfg: TableConfig, max: usize, pad: usize) -> Self { + fn new( + max_width: usize, + width: WidthEstimation, + trim_strategy: TrimStrategy, + expand: bool, + pad: usize, + ) -> Self { Self { width, - cfg, - width_max: max, + trim_strategy, + max_width, + expand, pad, } } } +#[derive(Debug, Clone)] +struct WidthEstimation { + original: Vec, + needed: Vec, + #[allow(dead_code)] + total: usize, + truncate: bool, +} + +impl WidthEstimation { + fn new(original: Vec, needed: Vec, total: usize, truncate: bool) -> Self { + Self { + original, + needed, + total, + truncate, + } + } +} + impl TableOption> for WidthCtrl { - fn change( - self, - rec: &mut NuRecords, - cfg: &mut ColoredConfig, - dim: &mut CompleteDimensionVecRecords<'_>, - ) { - let total_width = get_total_width2(&self.width, cfg); - - let need_truncation = total_width > self.width_max; - if need_truncation { - let has_header = self.cfg.structure.with_header && rec.count_rows() > 1; - let as_head = has_header && self.cfg.header_on_border; - - let trim = TableTrim::new(self.width, self.width_max, self.cfg.trim, as_head, self.pad); - trim.change(rec, cfg, dim); - return; - } - - let need_expansion = self.cfg.expand && self.width_max > total_width; - if need_expansion { - let opt = (SetDimensions(self.width), Width::increase(self.width_max)); - TableOption::, _, _>::change(opt, rec, cfg, dim); - return; - } - - SetDimensions(self.width).change(rec, cfg, dim); - } -} - -struct TableTrim { - width: Vec, - width_max: usize, - strategy: TrimStrategy, - trim_as_head: bool, - pad: usize, -} - -impl TableTrim { - fn new( - width: Vec, - width_max: usize, - strategy: TrimStrategy, - trim_as_head: bool, - pad: usize, - ) -> Self { - Self { - width, - strategy, - pad, - width_max, - trim_as_head, - } - } -} - -impl TableOption> for TableTrim { fn change( self, recs: &mut NuRecords, cfg: &mut ColoredConfig, dims: &mut CompleteDimensionVecRecords<'_>, ) { - // we already must have been estimated that it's safe to do. - // and all dims will be suffitient - if self.trim_as_head { - trim_as_header(recs, cfg, dims, self); + if self.width.truncate { + width_ctrl_truncate(self, recs, cfg, dims); return; } - match self.strategy { - TrimStrategy::Wrap { try_to_keep_words } => { - let wrap = Width::wrap(self.width_max) - .keep_words(try_to_keep_words) - .priority(Priority::max(false)); - - let opt = (SetDimensions(self.width), wrap); - TableOption::::change(opt, recs, cfg, dims); - } - TrimStrategy::Truncate { suffix } => { - let mut truncate = Width::truncate(self.width_max).priority(Priority::max(false)); - if let Some(suffix) = suffix { - truncate = truncate.suffix(suffix).suffix_try_color(true); - } - - let opt = (SetDimensions(self.width), truncate); - TableOption::::change(opt, recs, cfg, dims); - } + if self.expand { + width_ctrl_expand(self, recs, cfg, dims); + return; } + + // NOTE: just an optimization; to not recalculate it internally + SetDimensions(self.width.needed).change(recs, cfg, dims); } } -fn trim_as_header( - recs: &mut VecRecords>, +fn width_ctrl_expand( + ctrl: WidthCtrl, + recs: &mut NuRecords, cfg: &mut ColoredConfig, dims: &mut CompleteDimensionVecRecords, - trim: TableTrim, ) { - if recs.is_empty() { - return; - } + let opt = Width::increase(ctrl.max_width); + TableOption::, _, _>::change(opt, recs, cfg, dims); +} - let headers = recs[0].to_owned(); - let headers_widths = headers +fn width_ctrl_truncate( + ctrl: WidthCtrl, + recs: &mut NuRecords, + cfg: &mut ColoredConfig, + dims: &mut CompleteDimensionVecRecords, +) { + for (col, (&width, width_original)) in ctrl + .width + .needed .iter() - .map(Text::width) - .map(|v| v + trim.pad) - .collect::>(); - let min_width_use = get_total_width2(&headers_widths, cfg); - let mut free_width = trim.width_max.saturating_sub(min_width_use); - - // even though it's safe to trim columns by header there might be left unused space - // so we do use it if possible prioritizing left columns - let mut widths = vec![0; headers_widths.len()]; - for (i, head_width) in headers_widths.into_iter().enumerate() { - let column_width = trim.width[i]; // safe to assume width is bigger then padding - - let mut use_width = head_width; - if free_width > 0 { - // it's safe to assume that column_width is always bigger or equal to head_width - debug_assert!(column_width >= head_width); - - let additional_width = min(free_width, column_width - head_width); - free_width -= additional_width; - use_width += additional_width; + .zip(ctrl.width.original) + .enumerate() + { + if width == width_original { + continue; } - widths[i] = use_width; - } + let width = width - ctrl.pad; - // make sure we are fit in; - // which is might not be the case where we need to truncate columns further then a column head width - let expected_width = get_total_width2(&widths, cfg); - if expected_width > trim.width_max { - let mut diff = expected_width - trim.width_max; - 'out: loop { - let (biggest_column, &value) = widths - .iter() - .enumerate() - .max_by_key(|(_, &value)| value) - .expect("ok"); - if value <= trim.pad { - unreachable!("theoretically must never happen at this point") - } - - widths[biggest_column] -= 1; - diff -= 1; - - if diff == 0 { - break 'out; - } - } - } - - for (i, width) in widths.iter().cloned().enumerate() { - let width = width - trim.pad; - - match &trim.strategy { + match &ctrl.trim_strategy { TrimStrategy::Wrap { try_to_keep_words } => { let wrap = Width::wrap(width).keep_words(*try_to_keep_words); - let opt = Modify::new(Columns::single(i)).with(wrap); - TableOption::, _, _>::change(opt, recs, cfg, dims); + CellOption::::change(wrap, recs, cfg, Entity::Column(col)); } TrimStrategy::Truncate { suffix } => { let mut truncate = Width::truncate(width); @@ -571,13 +538,12 @@ fn trim_as_header( truncate = truncate.suffix(suffix).suffix_try_color(true); } - let opt = Modify::new(Columns::single(i)).with(truncate); - TableOption::, _, _>::change(opt, recs, cfg, dims); + CellOption::::change(truncate, recs, cfg, Entity::Column(col)); } } } - TableOption::change(SetDimensions(widths), recs, cfg, dims); + dims.set_widths(ctrl.width.needed); } fn align_table(table: &mut Table, alignments: Alignments, structure: &TableStructure) { @@ -630,7 +596,7 @@ fn colorize_table(table: &mut Table, styles: Styles, structure: &TableStructure) table.modify(Rows::first(), styles.header.clone()); } - if structure.with_footer && !is_color_empty(&styles.header) { + if structure.with_header && structure.with_footer && !is_color_empty(&styles.header) { table.modify(Rows::last(), styles.header); } } @@ -641,13 +607,15 @@ fn load_theme( structure: &TableStructure, sep_color: Option