From: Joel Rosdahl Date: Sat, 14 Aug 2021 19:44:51 +0000 (+0200) Subject: enhance: Add TextTable support for cells spanning several columns X-Git-Tag: v4.4~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1110df8ac673f46e98af63b6e193f0662c3a292;p=thirdparty%2Fccache.git enhance: Add TextTable support for cells spanning several columns --- diff --git a/src/util/TextTable.cpp b/src/util/TextTable.cpp index c4006da50..6bc6171ab 100644 --- a/src/util/TextTable.cpp +++ b/src/util/TextTable.cpp @@ -18,6 +18,8 @@ #include "TextTable.hpp" +#include + #include #include @@ -35,33 +37,74 @@ TextTable::add_heading(const std::string& text) void TextTable::add_row(const std::initializer_list cells) { - m_rows.emplace_back(cells); + m_rows.emplace_back(); + for (const auto& cell : cells) { + for (size_t i = 0; i < cell.m_colspan - 1; ++i) { + Cell dummy(""); + dummy.m_colspan = 0; + m_rows.back().push_back(dummy); + } + m_rows.back().push_back(cell); + + m_columns = std::max(m_columns, m_rows.back().size()); + } } -std::string -TextTable::render() const +std::vector +TextTable::compute_column_widths() const { - std::vector column_widths; + std::vector result(m_columns, 0); - for (const auto& row : m_rows) { - column_widths.resize(std::max(column_widths.size(), row.size())); - for (size_t i = 0; i < row.size(); ++i) { - if (!row[i].m_heading) { - column_widths[i] = std::max(column_widths[i], row[i].m_text.size()); + for (size_t column_index = 0; column_index < m_columns; ++column_index) { + for (const auto row : m_rows) { + if (column_index >= row.size()) { + continue; + } + const auto& cell = row[column_index]; + if (cell.m_heading || cell.m_colspan == 0) { + continue; + } + + size_t width_of_left_cols_in_span = 0; + for (size_t i = 0; i < cell.m_colspan - 1; ++i) { + width_of_left_cols_in_span += 1 + result[column_index - i - 1]; } + result[column_index] = std::max( + result[column_index], + cell.m_text.length() + - std::min(width_of_left_cols_in_span, cell.m_text.length())); } } + return result; +} + +std::string +TextTable::render() const +{ + auto column_widths = compute_column_widths(); + std::string result; for (const auto& row : m_rows) { std::string r; + bool first = true; for (size_t i = 0; i < row.size(); ++i) { - if (i > 0) { + const auto& cell = row[i]; + if (cell.m_colspan == 0) { + continue; + } + if (first) { + first = false; + } else { r += ' '; } - r += fmt::format((row[i].m_right_align ? "{:>{}}" : "{:<{}}"), - row[i].m_text, - column_widths[i]); + + size_t width = 0; + for (size_t j = i + 1 - cell.m_colspan; j <= i; ++j) { + width += column_widths[j] + (j == i ? 0 : 1); + } + r += fmt::format( + (cell.m_right_align ? "{:>{}}" : "{:<{}}"), cell.m_text, width); } result.append(r, 0, r.find_last_not_of(' ') + 1); result += '\n'; @@ -92,6 +135,14 @@ TextTable::Cell::left_align() return *this; } +TextTable::Cell& +TextTable::Cell::colspan(const size_t columns) +{ + ASSERT(columns >= 1); + m_colspan = columns; + return *this; +} + TextTable::Cell& TextTable::Cell::right_align() { diff --git a/src/util/TextTable.hpp b/src/util/TextTable.hpp index 8017a6250..b3c38a4b9 100644 --- a/src/util/TextTable.hpp +++ b/src/util/TextTable.hpp @@ -34,6 +34,7 @@ public: Cell(const char* text); Cell(uint64_t number); + Cell& colspan(size_t columns); Cell& left_align(); Cell& right_align(); @@ -43,6 +44,7 @@ public: const std::string m_text; bool m_right_align = false; bool m_heading = false; + size_t m_colspan = 1; }; void add_heading(const std::string& text); @@ -51,6 +53,9 @@ public: private: std::vector> m_rows; + size_t m_columns = 0; + + std::vector compute_column_widths() const; }; } // namespace util diff --git a/unittest/test_util_TextTable.cpp b/unittest/test_util_TextTable.cpp index a504790f2..36240731f 100644 --- a/unittest/test_util_TextTable.cpp +++ b/unittest/test_util_TextTable.cpp @@ -105,4 +105,17 @@ TEST_CASE("TextTable") "DDDDDD\n" "aaa bbb ccc\n")); } + + SUBCASE("colspan") + { + table.add_row({C("22").colspan(2), C("2r").colspan(2).right_align()}); + table.add_row({C("1").colspan(1), C("22222").colspan(2), "1"}); + table.add_row({"1", "1", "1", "1", "1"}); + table.add_row({"1", C("3333333333").colspan(3), "1"}); + CHECK(table.render() + == ("22 2r\n" // 4 columns + "1 22222 1\n" // 4 columns + "1 1 1 1 1\n" // 5 columns + "1 3333333333 1\n")); // 5 columns + } }