46 columns_.push_back(col);
50 void AddRow(
const std::vector<std::string> &cells) { rows_.push_back(cells); }
53 [[nodiscard]] std::string
Render()
const {
54 if (columns_.empty()) {
59 std::vector<std::size_t> widths = CalculateWidths();
61 std::ostringstream oss;
64 oss << RenderTopBorder(widths) <<
"\n";
67 oss << RenderHeaderRow(GetHeaders(), widths) <<
"\n";
70 oss << RenderHeaderSeparator(widths) <<
"\n";
73 for (
const auto &row : rows_) {
74 oss << RenderRow(row, widths) <<
"\n";
78 oss << RenderBottomBorder(widths) <<
"\n";
93 std::vector<Column> columns_;
94 std::vector<std::vector<std::string>> rows_;
96 [[nodiscard]] std::vector<std::string> GetHeaders()
const {
97 std::vector<std::string> headers;
98 headers.reserve(columns_.size());
99 for (
const auto &col : columns_) {
100 headers.push_back(col.header);
105 [[nodiscard]] std::vector<std::size_t> CalculateWidths()
const {
106 std::vector<std::size_t> widths;
107 widths.reserve(columns_.size());
109 for (std::size_t i = 0; i < columns_.size(); ++i) {
110 std::size_t width = columns_[i].width;
113 width = columns_[i].header.size();
114 for (
const auto &row : rows_) {
115 if (i < row.size()) {
116 width = std::max(width, row[i].size());
120 widths.push_back(width);
125 [[nodiscard]] std::string RenderTopBorder(
const std::vector<std::size_t> &widths)
const {
126 std::ostringstream oss;
128 for (std::size_t i = 0; i < widths.size(); ++i) {
129 for (std::size_t j = 0; j < widths[i] + 2; ++j) {
132 if (i < widths.size() - 1) {
140 [[nodiscard]] std::string RenderHeaderSeparator(
const std::vector<std::size_t> &widths)
const {
141 std::ostringstream oss;
143 for (std::size_t i = 0; i < widths.size(); ++i) {
144 for (std::size_t j = 0; j < widths[i] + 2; ++j) {
147 if (i < widths.size() - 1) {
155 [[nodiscard]] std::string RenderBottomBorder(
const std::vector<std::size_t> &widths)
const {
156 std::ostringstream oss;
158 for (std::size_t i = 0; i < widths.size(); ++i) {
159 for (std::size_t j = 0; j < widths[i] + 2; ++j) {
162 if (i < widths.size() - 1) {
170 [[nodiscard]] std::string RenderRow(
const std::vector<std::string> &cells,
171 const std::vector<std::size_t> &widths)
const {
172 std::ostringstream oss;
174 for (std::size_t i = 0; i < widths.size(); ++i) {
175 std::string cell = (i < cells.size()) ? cells[i] :
"";
177 oss <<
" " << AlignCell(cell, widths[i], align) <<
" ";
184 [[nodiscard]] std::string RenderHeaderRow(
const std::vector<std::string> &cells,
185 const std::vector<std::size_t> &widths)
const {
186 std::ostringstream oss;
188 for (std::size_t i = 0; i < widths.size(); ++i) {
189 std::string cell = (i < cells.size()) ? cells[i] :
"";
190 oss <<
" " << AlignCell(cell, widths[i],
Align::Left) <<
" ";
197 [[nodiscard]]
static std::size_t DisplayWidth(
const std::string &text) {
198 std::size_t width = 0;
199 for (std::size_t i = 0; i < text.size(); ++i) {
200 unsigned char c =
static_cast<unsigned char>(text[i]);
202 if ((c & 0xC0) != 0x80) {
209 [[nodiscard]]
static std::string AlignCell(
const std::string &text, std::size_t width,
211 std::size_t display_width = DisplayWidth(text);
212 if (display_width >= width) {
213 return text.substr(0, width);
216 std::size_t padding = width - display_width;
219 return text + std::string(padding,
' ');
221 return std::string(padding,
' ') + text;
223 std::size_t left = padding / 2;
224 std::size_t right = padding - left;
225 return std::string(left,
' ') + text + std::string(right,
' ');