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..90d23e0269 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -3,33 +3,30 @@ 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, records::{ vec_records::{Cell, Text, VecRecords}, - ExactRecords, Records, Resizable, + ExactRecords, Records, }, }, settings::{ - format::FormatContent, formatting::AlignmentStrategy, - object::{Columns, Row, Rows}, + object::{Columns, Rows}, peaker::Priority, themes::ColumnNames, width::Truncate, - Alignment, Color, Format, Modify, ModifyList, Padding, Settings, TableOption, Width, + Alignment, Color, Modify, Padding, TableOption, Width, }, Table, }; -use crate::{convert_style, is_color_empty, table_theme::TableTheme}; +use crate::{convert_style, is_color_empty, string_width, table_theme::TableTheme}; pub type NuRecords = VecRecords; pub type NuRecordsValue = Text; @@ -244,14 +241,41 @@ impl TableStructure { } } +#[derive(Debug, Clone)] +struct HeadInfo { + values: Vec, + align: AlignmentHorizontal, + color: Option, +} + 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 mut head = None; + if is_header_on_border(&t) { + head = Some(remove_header(&mut t)); + } else { + table_insert_footer(&mut t); + } + + let widths = table_truncate(&mut t, head.clone(), termwidth)?; + if let Some(head) = head.as_mut() { + if head.values.len() > widths.len() { + head.values[widths.len() - 1] = String::from("..."); + } + } + + draw_table(t, widths, head, termwidth) +} + +fn is_header_on_border(t: &NuTable) -> bool { + let structure = get_table_structure(&t.data, &t.config); + let is_configured = 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(t: &mut NuTable) { @@ -260,9 +284,8 @@ fn table_insert_footer(t: &mut NuTable) { } } -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); +fn table_truncate(t: &mut NuTable, head: Option, termwidth: usize) -> Option> { + let widths = maybe_truncate_columns(&mut t.data, &t.config, head, termwidth); if widths.is_empty() { return None; } @@ -270,10 +293,52 @@ fn table_truncate(t: &mut NuTable, termwidth: usize) -> Option> { 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 = is_color_empty(&t.styles.header).then(|| 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(); + + // 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(); + + HeadInfo { + values: head, + align, + color, + } +} + +fn draw_table( + t: NuTable, + widths: Vec, + head: Option, + termwidth: usize, +) -> Option { + let mut structure = get_table_structure(&t.data, &t.config); let sep_color = t.config.border_color; - let border_header = structure.with_header && t.config.header_on_border; + if head.is_some() { + structure.with_header = false; + } let data: Vec> = t.data.into(); let mut table = Builder::from_vec(data).build(); @@ -282,15 +347,51 @@ fn draw_table(t: NuTable, widths: Vec, termwidth: usize) -> Option, + theme: &TableTheme, + structure: TableStructure, +) { + let head = match head { + Some(head) => head, + None => return, + }; + + let mut widths = GetDims(Vec::new()); + table.with(&mut widths); + + 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 structure.with_footer { + let last_row = table.count_rows(); + table + .get_config_mut() + .insert_horizontal_line(last_row, line); + } + }; + } + + if structure.with_footer { + let last_row = table.count_rows(); + table.with(SetLineHeaders::new(last_row, head.clone())); + } + + table.with(SetLineHeaders::new(0, head)); +} + +fn truncate_table(table: &mut Table, cfg: TableConfig, widths: Vec, termwidth: usize) { + table.with(WidthCtrl::new(widths, cfg, termwidth)); +} + fn indent_sum(indent: TableIndent) -> usize { indent.left + indent.right } @@ -303,75 +404,10 @@ fn get_table_structure(data: &VecRecords>, cfg: &TableConfig) -> Ta 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(); @@ -387,16 +423,14 @@ struct WidthCtrl { width: Vec, cfg: TableConfig, width_max: usize, - pad: usize, } impl WidthCtrl { - fn new(width: Vec, cfg: TableConfig, max: usize, pad: usize) -> Self { + fn new(width: Vec, cfg: TableConfig, max: usize) -> Self { Self { width, cfg, width_max: max, - pad, } } } @@ -414,8 +448,9 @@ impl TableOption> for 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 pad = indent_sum(self.cfg.indent); - let trim = TableTrim::new(self.width, self.width_max, self.cfg.trim, as_head, self.pad); + let trim = TableTrim::new(self.width, self.width_max, self.cfg.trim, as_head, pad); trim.change(rec, cfg, dim); return; } @@ -663,24 +698,22 @@ fn load_theme( fn maybe_truncate_columns( data: &mut NuRecords, cfg: &TableConfig, + head: Option, termwidth: usize, - pad: usize, ) -> Vec { const TERMWIDTH_THRESHOLD: usize = 120; + let pad = cfg.indent.left + cfg.indent.right; + let preserve_content = termwidth > TERMWIDTH_THRESHOLD; - let has_header = cfg.structure.with_header && data.count_rows() > 1; - let is_header_on_border = has_header && cfg.header_on_border; - let truncate = if is_header_on_border { - truncate_columns_by_head + if let Some(head) = head { + truncate_columns_by_head(data, &cfg.theme, head, pad, termwidth) } else if preserve_content { - truncate_columns_by_columns + truncate_columns_by_columns(data, &cfg.theme, pad, termwidth) } else { - truncate_columns_by_content - }; - - truncate(data, &cfg.theme, pad, termwidth) + truncate_columns_by_content(data, &cfg.theme, pad, termwidth) + } } // VERSION where we are showing AS LITTLE COLUMNS AS POSSIBLE but WITH AS MUCH CONTENT AS POSSIBLE. @@ -835,51 +868,76 @@ fn truncate_columns_by_columns( widths } -// VERSION where we are showing AS LITTLE COLUMNS AS POSSIBLE but WITH AS MUCH CONTENT AS POSSIBLE. +// VERSION where we are showing AS LITTLE COLUMNS AS POSSIBLE but +// WITH AS MUCH CONTENT AS POSSIBLE BY ACCOUNTED BY HEADERS. fn truncate_columns_by_head( data: &mut NuRecords, theme: &TableTheme, + head: HeadInfo, pad: usize, termwidth: usize, ) -> Vec { + const MIN_ACCEPTABLE_WIDTH: usize = 3; const TRAILING_COLUMN_WIDTH: usize = 5; - let config = create_config(theme, false, None); - let mut widths = build_width(&*data, pad); - let total_width = get_total_width2(&widths, &config); - if total_width <= termwidth { - return widths; - } - if data.is_empty() { - return widths; + return vec![0; data.count_columns()]; } - let head = &data[0]; + let mut widths = build_width(data, pad); + let config = create_config(theme, false, None); let borders = config.get_borders(); let has_vertical = borders.has_vertical(); let mut width = borders.has_left() as usize + borders.has_right() as usize; let mut truncate_pos = 0; - for (i, column_header) in head.iter().enumerate() { - let column_header_width = Cell::width(column_header); - width += column_header_width + pad; + for (i, head) in head.values.iter().enumerate() { + let head_width = string_width(head); + let col_width = widths[i]; + if head_width + pad <= col_width { + let move_width = head_width + pad + (i > 0 && has_vertical) as usize; + if width + move_width >= termwidth { + break; + } - if i > 0 { - width += has_vertical as usize; + width += move_width; + truncate_pos += 1; + continue; } - if width >= termwidth { - width -= column_header_width + (i > 0 && has_vertical) as usize + pad; + // NOTE: So header is bigger then a column + // Therefore we must try to expand the column to head text width as much as possible. + // + // The kicker is that we will truncate the header if we can't fit it totally. + // Therefore it's not guaranteed that the column will be expanded to exactly head width. + widths[i] = head_width + pad; + let col_width = widths[i]; + + let move_width = col_width + (i > 0 && has_vertical) as usize; + if width + move_width >= termwidth { + let mut used_width = width + pad + (i > 0 && has_vertical) as usize; + if i + 1 != widths.len() { + used_width += TRAILING_COLUMN_WIDTH; + } + + let available = termwidth.saturating_sub(used_width); + + if available > MIN_ACCEPTABLE_WIDTH { + width += available; + widths[i] = available; + truncate_pos += 1; + } + break; } + width += move_width; truncate_pos += 1; } // we don't need any truncation then (is it possible?) - if truncate_pos == head.len() { + if truncate_pos == head.values.len() { return widths; } @@ -991,63 +1049,16 @@ fn build_width(records: &NuRecords, pad: usize) -> Vec { widths } -struct GetRow(usize, Vec); - -impl TableOption> for &mut GetRow { - fn change( - self, - recs: &mut NuRecords, - _: &mut ColoredConfig, - _: &mut CompleteDimensionVecRecords<'_>, - ) { - let row = self.0; - self.1 = recs[row].iter().map(|c| c.as_ref().to_owned()).collect(); - } -} - -struct GetRowSettings(usize, AlignmentHorizontal, Option); - -impl TableOption> - for &mut GetRowSettings -{ - fn change( - self, - _: &mut NuRecords, - cfg: &mut ColoredConfig, - _: &mut CompleteDimensionVecRecords<'_>, - ) { - let row = self.0; - self.1 = *cfg.get_alignment_horizontal(Entity::Row(row)); - self.2 = cfg - .get_colors() - .get_color((row, 0)) - .cloned() - .map(Color::from); - } -} - // It's laverages a use of guuaranted cached widths before hand // to speed up things a bit. struct SetLineHeaders { line: usize, - columns: Vec, - alignment: AlignmentHorizontal, - color: Option, + head: HeadInfo, } impl SetLineHeaders { - fn new( - line: usize, - columns: Vec, - alignment: AlignmentHorizontal, - color: Option, - ) -> Self { - Self { - line, - columns, - alignment, - color, - } + fn new(line: usize, head: HeadInfo) -> Self { + Self { line, head } } } @@ -1071,7 +1082,8 @@ impl TableOption> for }; let columns: Vec<_> = self - .columns + .head + .values .into_iter() .zip(widths.iter().cloned()) // it must be always safe to do .map(|(s, width)| Truncate::truncate(&s, width).into_owned()) @@ -1079,8 +1091,8 @@ impl TableOption> for let mut names = ColumnNames::new(columns) .line(self.line) - .alignment(Alignment::from(self.alignment)); - if let Some(color) = self.color { + .alignment(Alignment::from(self.head.align)); + if let Some(color) = self.head.color { names = names.color(color); } @@ -1092,163 +1104,25 @@ impl TableOption> for } } -struct MoveRowNext { - row: usize, - line: usize, -} - -impl MoveRowNext { - fn new(row: usize, line: usize) -> Self { - Self { row, line } - } -} - -struct MoveRowPrev { - row: usize, - line: usize, -} - -impl MoveRowPrev { - fn new(row: usize, line: usize) -> Self { - Self { row, line } - } -} - -impl TableOption> for MoveRowNext { - fn change( - self, - recs: &mut NuRecords, - cfg: &mut ColoredConfig, - _: &mut CompleteDimensionVecRecords<'_>, - ) { - row_shift_next(recs, cfg, self.row, self.line); - } - - fn hint_change(&self) -> Option { - None - } -} - -impl TableOption> for MoveRowPrev { - fn change( - self, - recs: &mut NuRecords, - cfg: &mut ColoredConfig, - _: &mut CompleteDimensionVecRecords<'_>, - ) { - row_shift_prev(recs, cfg, self.row, self.line); - } - - fn hint_change(&self) -> Option { - None - } -} - -fn row_shift_next(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, line: usize) { - let count_rows = recs.count_rows(); - let count_columns = recs.count_columns(); - let has_line = cfg.has_horizontal(line, count_rows); - let has_next_line = cfg.has_horizontal(line + 1, count_rows); - if !has_line && !has_next_line { - return; - } - - recs.remove_row(row); - let count_rows = recs.count_rows(); - - shift_alignments_down(cfg, row, count_rows, count_columns); - shift_colors_down(cfg, row, count_rows, count_columns); - - if !has_line { - shift_lines_up(cfg, count_rows, &[line + 1]); - } else { - remove_lines(cfg, count_rows, &[line + 1]); - } - - shift_lines_up(cfg, count_rows, &[count_rows]); -} - -fn row_shift_prev(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, line: usize) { - let mut count_rows = recs.count_rows(); - let count_columns = recs.count_columns(); - let has_line = cfg.has_horizontal(line, count_rows); - let has_prev_line = cfg.has_horizontal(line - 1, count_rows); - if !has_line && !has_prev_line { - return; - } - - recs.remove_row(row); - - if !has_line { - return; - } - - count_rows -= 1; - - shift_alignments_down(cfg, row, count_rows, count_columns); - shift_colors_down(cfg, row, count_rows, count_columns); - remove_lines(cfg, count_rows, &[line - 1]); -} - -fn remove_lines(cfg: &mut ColoredConfig, count_rows: usize, line: &[usize]) { - for &line in line { - cfg.remove_horizontal_line(line, count_rows) - } -} - -fn shift_alignments_down( - cfg: &mut ColoredConfig, - row: usize, - count_rows: usize, - count_columns: usize, -) { - for row in row..count_rows { - for col in 0..count_columns { - let pos = (row + 1, col).into(); - let posn = (row, col).into(); - let align = *cfg.get_alignment_horizontal(pos); - cfg.set_alignment_horizontal(posn, align); - } - - let align = *cfg.get_alignment_horizontal(Entity::Row(row + 1)); - cfg.set_alignment_horizontal(Entity::Row(row), align); - } -} - -fn shift_colors_down(cfg: &mut ColoredConfig, row: usize, count_rows: usize, count_columns: usize) { - for row in row..count_rows { - for col in 0..count_columns { - let pos = (row + 1, col); - let posn = (row, col).into(); - let color = cfg.get_colors().get_color(pos).cloned(); - if let Some(color) = color { - cfg.set_color(posn, color); - } - } - } -} - -fn shift_lines_up(cfg: &mut ColoredConfig, count_rows: usize, lines: &[usize]) { - for &i in lines { - let line = cfg.get_horizontal_line(i).cloned(); - if let Some(line) = line { - cfg.insert_horizontal_line(i - 1, line); - cfg.remove_horizontal_line(i, count_rows); - } - } -} - fn theme_copy_horizontal_line(theme: &mut tabled::settings::Theme, from: usize, to: usize) { if let Some(line) = theme.get_horizontal_line(from) { theme.insert_horizontal_line(to, *line); } } -#[allow(clippy::type_complexity)] -fn strip_color_from_row(row: usize) -> ModifyList String>> { - fn foo(s: &str) -> String { - strip_ansi_unlikely(s).into_owned() +struct GetDims(Vec); + +impl TableOption> for &mut GetDims { + fn change( + self, + _: &mut NuRecords, + _: &mut ColoredConfig, + dims: &mut CompleteDimensionVecRecords<'_>, + ) { + self.0 = dims.get_widths().expect("expected to get it").to_vec(); } - Modify::new(Rows::single(row)).with(Format::content(foo)) + fn hint_change(&self) -> Option { + None + } } diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index 393a381646..c93832fc19 100644 --- a/crates/nu-table/src/types/expanded.rs +++ b/crates/nu-table/src/types/expanded.rs @@ -240,7 +240,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { } let mut available = available_width - pad_space; - let mut column_width = string_width(&header); + let mut column_width = 0; if !is_last_column { // we need to make sure that we have a space for a next column if we use available width @@ -293,9 +293,18 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { column_rows = column_rows.saturating_add(cell.size); } + let mut head_width = string_width(&header); + let mut header = header; + if head_width > available { + header = wrap_text(&header, available, cfg.opts.config); + head_width = available; + } + let head_cell = NuRecordsValue::new(header); data[0].push(head_cell); + column_width = max(column_width, head_width); + if column_width > available { // remove the column we just inserted for row in &mut data { diff --git a/crates/nu-table/src/util.rs b/crates/nu-table/src/util.rs index 8384ef144f..8784454cfb 100644 --- a/crates/nu-table/src/util.rs +++ b/crates/nu-table/src/util.rs @@ -31,6 +31,27 @@ pub fn string_wrap(text: &str, width: usize, keep_words: bool) -> String { Wrap::wrap(text, width, keep_words) } +pub fn string_expand(text: &str, width: usize) -> String { + use std::{borrow::Cow, iter::repeat}; + use tabled::grid::util::string::{get_line_width, get_lines}; + + get_lines(text) + .map(|line| { + let length = get_line_width(&line); + + if length < width { + let mut line = line.into_owned(); + let remain = width - length; + line.extend(repeat(' ').take(remain)); + Cow::Owned(line) + } else { + line + } + }) + .collect::>() + .join("\n") +} + pub fn string_truncate(text: &str, width: usize) -> String { let line = match text.lines().next() { Some(line) => line, diff --git a/typos.toml b/typos.toml index 14baa39811..76d8b8959a 100644 --- a/typos.toml +++ b/typos.toml @@ -1,6 +1,7 @@ [files] extend-exclude = [ ".git/", + "crates/nu-command/tests/commands/table.rs", "crates/nu-cmd-extra/assets/228_themes.json", "tests/fixtures/formats/", ]