]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- trim trailing spaces in number columns if possible 886/head
authorArvin Schnell <aschnell@suse.de>
Thu, 14 Mar 2024 13:29:21 +0000 (14:29 +0100)
committerArvin Schnell <aschnell@suse.de>
Thu, 14 Mar 2024 13:29:21 +0000 (14:29 +0100)
client/cmd-list.cc
client/utils/Table.cc
client/utils/Table.h
client/utils/TableFormatter.cc
client/utils/TableFormatter.h
testsuite/table.cc

index 96e6e51a7414c164bf92cad57b7ce8f988e01bd1..5f5030741153f46a456a8f77bbe52cd9cf4ab642 100644 (file)
@@ -615,8 +615,12 @@ namespace snapper
 
                            formatter.header().push_back(header_for(list_mode, column));
 
+                           formatter.trim().push_back(Id::NUMBER);
+                           formatter.trim().push_back(Id::PRE_NUMBER);
+                           formatter.trim().push_back(Id::POST_NUMBER);
+
                            if (global_options.abbreviate())
-                               formatter.abbrev().push_back(Id::DESCRIPTION);
+                               formatter.abbreviate().push_back(Id::DESCRIPTION);
                        }
 
                        for (const ProxySnapshot& snapshot : output_helper.snapshots)
index c83aef5556b63d9a0507b7619cc94477fc505ddd..7eb8e56eb350469a1ef5cf6ac7cd608cf653065f 100644 (file)
@@ -39,14 +39,18 @@ namespace snapper
        OutputInfo(const Table& table);
 
        void calculate_hidden(const Table& table, const Table::Row& row);
-       void calculate_widths(const Table& table, const Table::Row& row, unsigned indent);
+       void calculate_trims(const Table& table, const Table::Row& row);
+       void calculate_widths(const Table& table, const Table::Row& row, bool is_header, unsigned indent);
        size_t calculate_total_width(const Table& table) const;
        void calculate_abbriviated_widths(const Table& table);
 
+       string trimmed(const string& s, Align align, size_t trim) const;
+
        struct ColumnVars
        {
            bool hidden = false;
            size_t width = 0;
+           size_t trim = -1;
        };
 
        vector<ColumnVars> column_vars;
@@ -71,16 +75,21 @@ namespace snapper
        for (const Table::Row& row : table.rows)
            calculate_hidden(table, row);
 
+       // calculate trims
+
+       for (const Table::Row& row : table.rows)
+           calculate_trims(table, row);
+
        // calculate widths
 
        for (size_t idx = 0; idx < table.column_params.size(); ++idx)
            column_vars[idx].width = table.column_params[idx].min_width;
 
        if (table.show_header)
-           calculate_widths(table, table.header, 0);
+           calculate_widths(table, table.header, true, 0);
 
        for (const Table::Row& row : table.rows)
-           calculate_widths(table, row, 0);
+           calculate_widths(table, row, false, 0);
 
        calculate_abbriviated_widths(table);
     }
@@ -106,7 +115,67 @@ namespace snapper
 
 
     void
-    Table::OutputInfo::calculate_widths(const Table& table, const Table::Row& row, unsigned indent)
+    Table::OutputInfo::calculate_trims(const Table& table, const Table::Row& row)
+    {
+       const vector<string>& columns = row.get_columns();
+
+       for (size_t idx = 0; idx < columns.size(); ++idx)
+       {
+           if (!table.column_params[idx].trim || column_vars[idx].hidden)
+               continue;
+
+           if (column_vars[idx].trim == 0)
+               continue;
+
+           const string& column = columns[idx];
+           if (column.empty())
+               continue;
+
+           size_t trim = 0;
+
+           switch (table.column_params[idx].align)
+           {
+               case Align::RIGHT:
+                   trim = column.size() - column.find_last_not_of(" ") - 1;
+                   break;
+
+               case Align::LEFT:
+                   trim = column.find_first_not_of(" ");
+                   break;
+           }
+
+           column_vars[idx].trim = min(column_vars[idx].trim, trim);
+       }
+
+       for (const Table::Row& subrow : row.get_subrows())
+           calculate_trims(table, subrow);
+    }
+
+
+    string
+    Table::OutputInfo::trimmed(const string& s, Align align, size_t trim) const
+    {
+       string ret = s;
+
+       switch (align)
+       {
+           case Align::RIGHT:
+               if (ret.size() >= trim)
+                   ret.erase(ret.size() - trim, trim);
+               break;
+
+           case Align::LEFT:
+               if (ret.size() >= trim)
+                   ret.erase(0, trim);
+               break;
+       }
+
+       return ret;
+    }
+
+
+    void
+    Table::OutputInfo::calculate_widths(const Table& table, const Table::Row& row, bool is_header, unsigned indent)
     {
        const vector<string>& columns = row.get_columns();
 
@@ -115,7 +184,12 @@ namespace snapper
            if (column_vars[idx].hidden)
                continue;
 
-           size_t width = mbs_width(columns[idx]);
+           string column = columns[idx];
+
+           if (!is_header && table.column_params[idx].trim)
+               column = trimmed(column, table.column_params[idx].align, column_vars[idx].trim);
+
+           size_t width = mbs_width(column);
 
            if (idx == table.tree_idx)
                width += 2 * indent;
@@ -124,7 +198,7 @@ namespace snapper
        }
 
        for (const Table::Row& subrow : row.get_subrows())
-           calculate_widths(table, subrow, indent + 1);
+           calculate_widths(table, subrow, false, indent + 1);
     }
 
 
@@ -180,7 +254,8 @@ namespace snapper
 
 
     void
-    Table::output(std::ostream& s, const OutputInfo& output_info, const Table::Row& row, const vector<bool>& lasts) const
+    Table::output(std::ostream& s, const OutputInfo& output_info, const Table::Row& row, bool is_header,
+                 const vector<bool>& lasts) const
     {
        s << string(global_indent, ' ');
 
@@ -193,6 +268,9 @@ namespace snapper
 
            string column = idx < columns.size() ? columns[idx] : "";
 
+           if (!is_header && column_params[idx].trim)
+               column = output_info.trimmed(column, column_params[idx].align, output_info.column_vars[idx].trim);
+
            bool first = idx == 0;
            bool last = idx == output_info.column_vars.size() - 1;
 
@@ -254,7 +332,7 @@ namespace snapper
        {
            vector<bool> sub_lasts = lasts;
            sub_lasts.push_back(i == subrows.size() - 1);
-           output(s, output_info, subrows[i], sub_lasts);
+           output(s, output_info, subrows[i], false, sub_lasts);
        }
     }
 
@@ -379,6 +457,14 @@ namespace snapper
     }
 
 
+    void
+    Table::set_trim(Id id, bool trim)
+    {
+       size_t idx = id_to_idx(id);
+       column_params[idx].trim = trim;
+    }
+
+
     void
     Table::set_tree_id(Id id)
     {
@@ -396,13 +482,13 @@ namespace snapper
        // output header and rows
 
        if (table.show_header)
-           table.output(s, output_info, table.header, {});
+           table.output(s, output_info, table.header, true, {});
 
        if (table.show_header && table.show_grid)
            table.output(s, output_info);
 
        for (const Table::Row& row : table.rows)
-           table.output(s, output_info, row, {});
+           table.output(s, output_info, row, false, {});
 
        return s;
     }
index 2570955f23a57eb19b36cf07b53a96ee9d5443aa..ac7ad197da221a6f8361b2b1122b8055da615c60 100644 (file)
@@ -148,9 +148,17 @@ namespace snapper
        void set_style(Style style) { Table::style = style; }
        void set_global_indent(size_t global_indent) { Table::global_indent = global_indent; }
        void set_screen_width(size_t screen_width) { Table::screen_width = screen_width; }
+
        void set_min_width(Id id, size_t min_width);
        void set_visibility(Id id, Visibility visibility);
        void set_abbreviate(Id id, bool abbreviate);
+
+       /**
+        * Allow to trim a column without breaking alignment by removing the same amount of
+        * spaces from all rols (excluding the header).
+        */
+       void set_trim(Id id, bool trim);
+
        void set_tree_id(Id id);
 
        friend std::ostream& operator<<(std::ostream& s, const Table& Table);
@@ -178,6 +186,7 @@ namespace snapper
            size_t min_width = 0;
            Visibility visibility = Visibility::ON;
            bool abbreviate = false;
+           bool trim = false;
        };
 
        vector<ColumnParams> column_params;
@@ -186,7 +195,7 @@ namespace snapper
 
        struct OutputInfo;
 
-       void output(std::ostream& s, const OutputInfo& output_info, const Table::Row& row,
+       void output(std::ostream& s, const OutputInfo& output_info, const Table::Row& row, bool is_header,
                    const vector<bool>& lasts) const;
 
        void output(std::ostream& s, const OutputInfo& output_info) const;
index 435d28f1cefcd0ddb9ffe4c98992c50a343c0686..d7c69ea7c960a30904267a43c74bd4ff7d25e967 100644 (file)
@@ -36,10 +36,14 @@ namespace snapper
 
        table.set_style(table_formatter.style);
 
-       for (Id id : table_formatter._abbrev)
+       for (Id id : table_formatter._abbreviate)
            if (table.has_id(id))
                table.set_abbreviate(id, true);
 
+       for (Id id : table_formatter._trim)
+           if (table.has_id(id))
+               table.set_trim(id, true);
+
        for (const vector<string>& row : table_formatter._rows)
        {
            Table::Row table_row(table);
index cd02d9b0aba866ddf424e548f35c33d98b458e69..3cbada30762d043f5b5555dc137ec51e620e2c69 100644 (file)
@@ -50,7 +50,8 @@ namespace snapper
        TableFormatter& operator=(const TableFormatter&) = delete;
 
        vector<Cell>& header() { return _header; }
-       vector<Id>& abbrev() { return _abbrev; }
+       vector<Id>& abbreviate() { return _abbreviate; }
+       vector<Id>& trim() { return _trim; }
        vector<vector<string>>& rows() { return _rows; }
 
        friend ostream& operator<<(ostream& stream, const TableFormatter& table_formatter);
@@ -60,7 +61,8 @@ namespace snapper
        const Style style;
 
        vector<Cell> _header;
-       vector<Id> _abbrev;
+       vector<Id> _abbreviate;
+       vector<Id> _trim;
        vector<vector<string>> _rows;
 
     };
index 3dd548f1f6afdcab631a4ddedd0035d0ea6444d3..0efb67067039c8cfdb6352bc9db411f7a25b617a 100644 (file)
@@ -128,3 +128,80 @@ BOOST_AUTO_TEST_CASE(test4)
 
     check(table, output);
 }
+
+
+BOOST_AUTO_TEST_CASE(test5)
+{
+    Table table({ Cell("#", Id::NUMBER, Align::RIGHT), Cell("Description", Id::DESCRIPTION) });
+
+    table.set_style(Style::LIGHT);
+    table.set_trim(Id::NUMBER, true);
+
+    Table::Row row1(table, { "1 ", "boot" });
+    table.add(row1);
+
+    Table::Row row2(table, { "2 " });
+    table.add(row2);
+
+    Table::Row row3(table, { "3 " });
+    table.add(row3);
+
+    vector<string> output = {
+       "# │ Description",
+       "──┼────────────",
+       "1 │ boot",
+       "2 │",
+       "3 │"
+    };
+
+    check(table, output);
+}
+
+
+BOOST_AUTO_TEST_CASE(test6)
+{
+    Table table({ Cell("#", Id::NUMBER, Align::RIGHT), Cell("Description", Id::DESCRIPTION) });
+
+    table.set_style(Style::LIGHT);
+    table.set_trim(Id::NUMBER, true);
+
+    Table::Row row1(table, { "1 ", "boot" });
+    table.add(row1);
+
+    Table::Row row2(table, { "2+" });
+    table.add(row2);
+
+    Table::Row row3(table, { "3 " });
+    table.add(row3);
+
+    vector<string> output = {
+       " # │ Description",
+       "───┼────────────",
+       "1  │ boot",
+       "2+ │",
+       "3  │"
+    };
+
+    check(table, output);
+}
+
+
+BOOST_AUTO_TEST_CASE(test7)
+{
+    Table table({ Cell("#", Id::NUMBER, Align::RIGHT), Cell("Description", Id::DESCRIPTION) });
+
+    table.set_style(Style::LIGHT);
+    table.set_trim(Id::NUMBER, true);
+    table.set_trim(Id::DESCRIPTION, true);
+
+    Table::Row row1(table, { "" });
+    table.add(row1);
+
+    vector<string> output = {
+       "# │ Description",
+       "──┼────────────",
+       "  │",
+    };
+
+    check(table, output);
+}