]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: column width reduction refactoring
authorKarel Zak <kzak@redhat.com>
Fri, 7 Apr 2017 11:40:14 +0000 (13:40 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 7 Apr 2017 12:34:11 +0000 (14:34 +0200)
The current implementation is unreadable... Let's write it again with
more obvious semantic.

Signed-off-by: Karel Zak <kzak@redhat.com>
libsmartcols/src/table.c
libsmartcols/src/table_print.c

index 3672114b25c73eaf8a10eeff6d66027162ff8927..066a1e9a74801fe73a77e075d6a481351d10ebfe 100644 (file)
@@ -326,6 +326,23 @@ int scols_table_move_column(struct libscols_table *tb,
  * relative width is used as a hint only. It's possible that column will be
  * narrow if the specified size is too large for column data.
  *
+ *
+ * If the width of all columns is greater than terminal width then library
+ * tries to reduce width of the individual columns. It's done in three stages:
+ *
+ * #1 reduce columns with SCOLS_FL_TRUNC flag and with relative width if the
+ *    width is greater than width defined by @whint (@whint * terminal_width)
+ *
+ * #2 reduce all columns with SCOLS_FL_TRUNC flag
+ *
+ * #3 reduce all columns with relative width
+ *
+ * The next stage is always used if the previous stage is unsuccessful. Note
+ * that SCOLS_FL_WRAP is interpreted as SCOLS_FL_TRUNC when calculate column
+ * width (if custom wrap function is not specified), but the final text is not
+ * truncated, but wrapped to multi-line cell.
+ *
+ *
  * The column is necessary to address by sequential number. The first defined
  * column has the colnum = 0. For example:
  *
index 1fe70027393ff8b19d7ae7b4035d451845a99f9e..6b4b727c0d3c4fd96fe864d39aca0287c9e1ec01 100644 (file)
@@ -1090,7 +1090,7 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
        struct libscols_column *cl;
        struct libscols_iter itr;
        size_t width = 0, width_min = 0;        /* output width */
-       int trunc_only, rc = 0;
+       int stage, rc = 0;
        int extremes = 0;
        size_t colsepsz;
 
@@ -1220,60 +1220,91 @@ static int recount_widths(struct libscols_table *tb, struct libscols_buffer *buf
                }
        }
 
-       /* bad, we have to reduce output width, this is done in two steps:
-        * 1) reduce columns with a relative width and with truncate flag
-        * 2) reduce columns with a relative width without truncate flag
+       /* bad, we have to reduce output width, this is done in three stages:
+        *
+        * 1) trunc relative with trunc flag if the column width is greater than
+        *    expected column width (it means "width_hint * terminal_width").
+        *
+        * 2) trunc all with trunc flag
+        *
+        * 3) trunc relative without trunc flag
+        *
+        * Note that SCOLS_FL_WRAP (if no custom wrap function is specified) is
+        * interpreted as SCOLS_FL_TRUNC.
         */
-       trunc_only = 1;
-       while (width > tb->termwidth) {
-               size_t org = width;
+       for (stage = 1; width > tb->termwidth && stage <= 3; ) {
+               size_t org_width = width;
 
-               DBG(TAB, ul_debugobj(tb, " reduce width (current=%zu, "
-                                        "wanted=%zu, mode=%s)",
-                                       width, tb->termwidth,
-                                       trunc_only ? "trunc-only" : "all-relative"));
+               DBG(TAB, ul_debugobj(tb, " reduce width - #%d stage (current=%zu, wanted=%zu)",
+                               stage, width, tb->termwidth));
 
                scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
                while (scols_table_next_column(tb, &itr, &cl) == 0) {
 
-                       DBG(TAB, ul_debugobj(cl, "  checking %s (width=%zu, treeart=%zu)",
+                       int trunc_flag = 0;
+
+                       DBG(TAB, ul_debugobj(cl, "   checking %s (width=%zu, treeart=%zu)",
                                                cl->header.data, cl->width, cl->width_treeart));
                        if (scols_column_is_hidden(cl))
                                continue;
                        if (width <= tb->termwidth)
                                break;
-                       if (cl->width_hint > 1 && !scols_column_is_trunc(cl))
-                               continue;       /* never truncate columns with absolute sizes */
+
+                       /* never truncate if already minimal width */
+                       if (cl->width == cl->width_min)
+                               continue;
+
+                       /* never truncate the tree */
                        if (scols_column_is_tree(cl) && width <= cl->width_treeart)
-                               continue;       /* never truncate the tree */
-                       if (trunc_only && !(scols_column_is_trunc(cl) ||
-                                       (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl))))
                                continue;
-                       if (cl->width == cl->width_min)
+
+                       /* nothing to truncate */
+                       if (cl->width == 0 || width == 0)
                                continue;
 
-                       DBG(TAB, ul_debugobj(tb, "  trying to reduce: %s (width=%zu)", cl->header.data, cl->width));
+                       trunc_flag = scols_column_is_trunc(cl)
+                                   || (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl));
 
-                       /* truncate column with relative sizes */
-                       if (cl->width_hint < 1 && cl->width > 0 && width > 0 &&
-                           cl->width >= (size_t) (cl->width_hint * tb->termwidth)) {
+                       switch (stage) {
+                       /* #1 stage - trunc relative with TRUNC flag */
+                       case 1:
+                               if (!trunc_flag)                /* ignore: missing flag */
+                                       break;
+                               if (cl->width_hint >= 1)        /* ignore: no relative */
+                                       break;
+                               if (cl->width < (size_t) (cl->width_hint * tb->termwidth)) /* ignore: smaller than expected width */
+                                       break;
+
+                               DBG(TAB, ul_debugobj(tb, "     reducing (relative with flag)"));
                                cl->width--;
                                width--;
-                       }
+                               break;
 
-                       /* truncate column with absolute size */
-                       if (cl->width_hint > 1 && cl->width > 0 && width > 0 &&
-                           !trunc_only) {
+                       /* #2 stage - trunc all with TRUNC flag */
+                       case 2:
+                               if (!trunc_flag)                /* ignore: missing flag */
+                                       break;
+
+                               DBG(TAB, ul_debugobj(tb, "     reducing (all with flag)"));
                                cl->width--;
                                width--;
-                       }
-               }
-               if (org == width) {
-                       if (trunc_only)
-                               trunc_only = 0;
-                       else
                                break;
+
+                       /* #3 stage - trunc relative without flag */
+                       case 3:
+                               if (cl->width_hint >= 1)        /* ignore: no relative */
+                                       break;
+
+                               DBG(TAB, ul_debugobj(tb, "     reducing (relative without flag)"));
+                               cl->width--;
+                               width--;
+                               break;
+                       }
                }
+
+               /* the current stage is without effect, go to the next */
+               if (org_width == width)
+                       stage++;
        }
 
        /* ignore last column(s) or force last column to be truncated if