]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
enhance: Add TextTable support for cells spanning several columns
authorJoel Rosdahl <joel@rosdahl.net>
Sat, 14 Aug 2021 19:44:51 +0000 (21:44 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 16 Aug 2021 18:12:02 +0000 (20:12 +0200)
src/util/TextTable.cpp
src/util/TextTable.hpp
unittest/test_util_TextTable.cpp

index c4006da509c1a64ac9e8d17d128f04bd7044793f..6bc6171abbfa749b46435911c1c47cc59986b4d8 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "TextTable.hpp"
 
+#include <assertions.hpp>
+
 #include <third_party/fmt/core.h>
 
 #include <algorithm>
@@ -35,33 +37,74 @@ TextTable::add_heading(const std::string& text)
 void
 TextTable::add_row(const std::initializer_list<Cell> 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<size_t>
+TextTable::compute_column_widths() const
 {
-  std::vector<size_t> column_widths;
+  std::vector<size_t> 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()
 {
index 8017a6250a3da2e1b4a02981bf0913d2f710dcb6..b3c38a4b91198c8c15dbdb6f9bbe40d99dd17a40 100644 (file)
@@ -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<std::vector<Cell>> m_rows;
+  size_t m_columns = 0;
+
+  std::vector<size_t> compute_column_widths() const;
 };
 
 } // namespace util
index a504790f2944c1111eb06d0dbd3fb413bc7d05c8..36240731f1e2dff033d15067a53a09e25a79716c 100644 (file)
@@ -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
+  }
 }