@@ -6122,8 +6122,9 @@ inline int get_wcswidth(const std::string &string, const std::string &locale,
61226122 if (string.size () == 0 )
61236123 return 0 ;
61246124
6125- // The behavior of wcswidth() depends on the LC_CTYPE category of the current locale.
6126- // Set the current locale based on cell properties before computing width
6125+ // The behavior of wcswidth() depends on the LC_CTYPE category of the current
6126+ // locale. Set the current locale based on cell properties before computing
6127+ // width
61276128 auto old_locale = std::locale::global (std::locale (locale));
61286129
61296130 // Convert from narrow std::string to wide string
@@ -6147,7 +6148,7 @@ inline size_t get_sequence_length(const std::string &text, const std::string &lo
61476148 return text.length ();
61486149
61496150#if defined(_WIN32) || defined(_WIN64)
6150- (void ) locale; // unused parameter
6151+ (void )locale; // unused parameter
61516152 return (text.length () - std::count_if (text.begin (), text.end (),
61526153 [](char c) -> bool { return (c & 0xC0 ) == 0x80 ; }));
61536154#elif defined(__unix__) || defined(__unix) || defined(__APPLE__)
@@ -6723,15 +6724,16 @@ class Format {
67236724 current_line_length = 0 ;
67246725 }
67256726
6726- // If the current word is too long to fit on a line even on it's own then
6727- // split the word up.
6727+ // If the current word is too long to fit on a line even on it's own
6728+ // then split the word up.
67286729 while (get_sequence_length (word, locale, is_multi_byte_character_support_enabled) > width) {
67296730 result += word.substr (0 , width - 1 ) + " -" ;
67306731 word = word.substr (width - 1 );
67316732 result += ' \n ' ;
67326733 }
67336734
6734- // Remove leading whitespace from the word so the new line starts flush to the left.
6735+ // Remove leading whitespace from the word so the new line starts flush
6736+ // to the left.
67356737 word = trim_left (word);
67366738 }
67376739 result += word;
@@ -7090,7 +7092,8 @@ class Format {
70907092
70917093 std::string word = input.substr (start_index, index - start_index);
70927094 char next_character = input.substr (index, 1 )[0 ];
7093- // Unlike whitespace, dashes and the like should stick to the word occurring before it.
7095+ // Unlike whitespace, dashes and the like should stick to the word
7096+ // occurring before it.
70947097 if (isspace (next_character)) {
70957098 result.push_back (word);
70967099 result.push_back (std::string (1 , next_character));
@@ -7930,7 +7933,8 @@ class Printer {
79307933 static void print_row_in_cell (std::ostream &stream, TableInternal &table,
79317934 const std::pair<size_t , size_t > &index,
79327935 const std::pair<size_t , size_t > &dimension, size_t num_columns,
7933- size_t row_index);
7936+ size_t row_index,
7937+ const std::vector<std::string> &splitted_cell_text);
79347938
79357939 static bool print_cell_border_top (std::ostream &stream, TableInternal &table,
79367940 const std::pair<size_t , size_t > &index,
@@ -8328,6 +8332,44 @@ inline void Printer::print_table(std::ostream &stream, TableInternal &table) {
83288332 auto dimensions = compute_cell_dimensions (table);
83298333 auto row_heights = dimensions.first ;
83308334 auto column_widths = dimensions.second ;
8335+ auto splitted_cells_text = std::vector<std::vector<std::vector<std::string>>>(
8336+ num_rows, std::vector<std::vector<std::string>>(num_columns, std::vector<std::string>{}));
8337+
8338+ // Pre-compute the cells' content and split them into lines before actually
8339+ // iterating the cells.
8340+ for (size_t i = 0 ; i < num_rows; ++i) {
8341+ Row row = table[i];
8342+ for (size_t j = 0 ; j < num_columns; ++j) {
8343+ Cell cell = row.cell (j);
8344+ const std::string &text = cell.get_text ();
8345+ auto padding_left = *cell.format ().padding_left_ ;
8346+ auto padding_right = *cell.format ().padding_right_ ;
8347+
8348+ // Check if input text has embedded \n that are to be respected
8349+ bool has_new_line = text.find_first_of (' \n ' ) != std::string::npos;
8350+
8351+ if (has_new_line) {
8352+ // Respect to the embedded '\n' characters
8353+ splitted_cells_text[i][j] = Format::split_lines (
8354+ text, " \n " , cell.locale (), cell.is_multi_byte_character_support_enabled ());
8355+ } else {
8356+ // If there are no embedded \n characters, then apply word wrap.
8357+ //
8358+ // Configured column width cannot be lower than (padding_left +
8359+ // padding_right) This is a bad configuration E.g., the user is trying
8360+ // to force the column width to be 5 when padding_left and padding_right
8361+ // are each configured to 3 (padding_left + padding_right) = 6 >
8362+ // column_width
8363+ auto content_width = column_widths[j] > padding_left + padding_right
8364+ ? column_widths[j] - padding_left - padding_right
8365+ : column_widths[j];
8366+ auto word_wrapped_text = Format::word_wrap (text, content_width, cell.locale (),
8367+ cell.is_multi_byte_character_support_enabled ());
8368+ splitted_cells_text[i][j] = Format::split_lines (
8369+ word_wrapped_text, " \n " , cell.locale (), cell.is_multi_byte_character_support_enabled ());
8370+ }
8371+ }
8372+ }
83318373
83328374 // For each row,
83338375 for (size_t i = 0 ; i < num_rows; ++i) {
@@ -8344,8 +8386,8 @@ inline void Printer::print_table(std::ostream &stream, TableInternal &table) {
83448386 // Print row contents with word wrapping
83458387 for (size_t k = 0 ; k < row_heights[i]; ++k) {
83468388 for (size_t j = 0 ; j < num_columns; ++j) {
8347- print_row_in_cell (stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns,
8348- k );
8389+ print_row_in_cell (stream, table, {i, j}, {row_heights[i], column_widths[j]}, num_columns, k,
8390+ splitted_cells_text[i][j] );
83498391 }
83508392 if (k + 1 < row_heights[i])
83518393 stream << termcolor::reset << " \n " ;
@@ -8382,17 +8424,15 @@ inline void Printer::print_table(std::ostream &stream, TableInternal &table) {
83828424inline void Printer::print_row_in_cell (std::ostream &stream, TableInternal &table,
83838425 const std::pair<size_t , size_t > &index,
83848426 const std::pair<size_t , size_t > &dimension,
8385- size_t num_columns, size_t row_index) {
8427+ size_t num_columns, size_t row_index,
8428+ const std::vector<std::string> &splitted_cell_text) {
83868429 auto column_width = dimension.second ;
83878430 auto cell = table[index.first ][index.second ];
83888431 auto locale = cell.locale ();
83898432 auto is_multi_byte_character_support_enabled = cell.is_multi_byte_character_support_enabled ();
83908433 auto old_locale = std::locale::global (std::locale (locale));
83918434 auto format = cell.format ();
8392- auto text = cell.get_text ();
8393- auto word_wrapped_text =
8394- Format::word_wrap (text, column_width, locale, is_multi_byte_character_support_enabled);
8395- auto text_height = std::count (word_wrapped_text.begin (), word_wrapped_text.end (), ' \n ' ) + 1 ;
8435+ auto text_height = splitted_cell_text.size ();
83968436 auto padding_top = *format.padding_top_ ;
83978437
83988438 if (*format.show_border_left_ ) {
@@ -8407,53 +8447,22 @@ inline void Printer::print_row_in_cell(std::ostream &stream, TableInternal &tabl
84078447 // Padding top
84088448 stream << std::string (column_width, ' ' );
84098449 } else if (row_index >= padding_top && (row_index <= (padding_top + text_height))) {
8410- // // Row contents
8411-
84128450 // Retrieve padding left and right
84138451 // (column_width - padding_left - padding_right) is the amount of space
84148452 // available for cell text - Use this to word wrap cell contents
84158453 auto padding_left = *format.padding_left_ ;
84168454 auto padding_right = *format.padding_right_ ;
84178455
8418- // Check if input text has embedded \n that are to be respected
8419- auto newlines_in_input = Format::split_lines (text, " \n " , cell.locale (),
8420- cell.is_multi_byte_character_support_enabled ())
8421- .size () -
8422- 1 ;
8423- std::string word_wrapped_text;
8424-
8425- // If there are no embedded \n characters, then apply word wrap
8426- if (newlines_in_input == 0 ) {
8427- // Apply word wrapping to input text
8428- // Then display one word-wrapped line at a time within cell
8429- if (column_width > (padding_left + padding_right))
8430- word_wrapped_text =
8431- Format::word_wrap (text, column_width - padding_left - padding_right, cell.locale (),
8432- cell.is_multi_byte_character_support_enabled ());
8433- else {
8434- // Configured column width cannot be lower than (padding_left + padding_right)
8435- // This is a bad configuration
8436- // E.g., the user is trying to force the column width to be 5
8437- // when padding_left and padding_right are each configured to 3
8438- // (padding_left + padding_right) = 6 > column_width
8439- }
8440- } else {
8441- word_wrapped_text = text; // repect the embedded '\n' characters
8442- }
8443-
8444- auto lines = Format::split_lines (word_wrapped_text, " \n " , cell.locale (),
8445- cell.is_multi_byte_character_support_enabled ());
8446-
8447- if (row_index - padding_top < lines.size ()) {
8448- auto line = lines[row_index - padding_top];
8456+ if (row_index - padding_top < text_height) {
8457+ auto line = splitted_cell_text[row_index - padding_top];
84498458
84508459 // Print left padding characters
84518460 stream << std::string (padding_left, ' ' );
84528461
84538462 // Print word-wrapped line
84548463 line = Format::trim (line);
84558464 auto line_with_padding_size =
8456- get_sequence_length (line, cell.locale (), cell. is_multi_byte_character_support_enabled () ) +
8465+ get_sequence_length (line, cell.locale (), is_multi_byte_character_support_enabled) +
84578466 padding_left + padding_right;
84588467 switch (*format.font_align_ ) {
84598468 case FontAlign::left:
@@ -8640,8 +8649,7 @@ class Table {
86408649public:
86418650 Table () : table_(TableInternal::create()) {}
86428651
8643- using Row_t =
8644- std::vector<variant<std::string, const char *, string_view, Table>>;
8652+ using Row_t = std::vector<variant<std::string, const char *, string_view, Table>>;
86458653
86468654 Table &add_row (const Row_t &cells) {
86478655
@@ -8703,8 +8711,7 @@ class Table {
87038711
87048712 class RowIterator {
87058713 public:
8706- explicit RowIterator (std::vector<std::shared_ptr<Row>>::iterator ptr)
8707- : ptr(ptr) {}
8714+ explicit RowIterator (std::vector<std::shared_ptr<Row>>::iterator ptr) : ptr(ptr) {}
87088715
87098716 RowIterator operator ++() {
87108717 ++ptr;
@@ -9236,7 +9243,7 @@ SOFTWARE.
92369243
92379244// Project version
92389245#define TABULATE_VERSION_MAJOR 1
9239- #define TABULATE_VERSION_MINOR 4
9246+ #define TABULATE_VERSION_MINOR 5
92409247#define TABULATE_VERSION_PATCH 0
92419248
92429249// Composing the protocol version string from major, and minor
0 commit comments