diff options
-rw-r--r-- | include/tt.h | 14 | ||||
-rw-r--r-- | lib/tt.c | 165 | ||||
-rw-r--r-- | misc-utils/findmnt.c | 4 | ||||
-rw-r--r-- | misc-utils/lsblk.c | 2 |
4 files changed, 136 insertions, 49 deletions
diff --git a/include/tt.h b/include/tt.h index 1ae71337d..9b5f15a9c 100644 --- a/include/tt.h +++ b/include/tt.h @@ -23,10 +23,11 @@ enum { /* * Column flags */ - TT_FL_TRUNC = (1 << 5), - TT_FL_TREE = (1 << 6), - TT_FL_RIGHT = (1 << 7), - TT_FL_STRICTWIDTH = (1 << 8) + TT_FL_TRUNC = (1 << 5), /* truncate fields data if necessary */ + TT_FL_TREE = (1 << 6), /* use tree "ascii art" */ + TT_FL_RIGHT = (1 << 7), /* align to the right */ + TT_FL_STRICTWIDTH = (1 << 8), /* don't reduce width if column is empty */ + TT_FL_NOEXTREMES = (1 << 9) /* ignore extreme fields when count column width*/ }; struct tt { @@ -46,10 +47,13 @@ struct tt_column { size_t seqnum; size_t width; /* real column width */ - size_t width_min; /* minimal width (width of header) */ + size_t width_min; /* minimal width (usually header width) */ + size_t width_max; /* maximal width */ + size_t width_avg; /* average width, used to detect extreme fields */ double width_hint; /* hint (N < 1 is in percent of termwidth) */ int flags; + int is_extreme; struct list_head cl_columns; }; @@ -326,6 +326,10 @@ static char *line_get_data(struct tt_line *ln, struct tt_column *cl, buf[bufsz - 1] = '\0'; return buf; } + + /* + * Tree stuff + */ if (ln->parent) { p = line_get_ascii_art(ln->parent, buf, &bufsz); if (!p) @@ -344,63 +348,138 @@ static char *line_get_data(struct tt_line *ln, struct tt_column *cl, return buf; } -static void recount_widths(struct tt *tb, char *buf, size_t bufsz) +/* + * This function counts column width. + * + * For the TT_FL_NOEXTREMES columns is possible to call this function two + * times. The first pass counts width and average width. If the column + * contains too large fields (width greater than 2 * average) then the column + * is marked as "extreme". In the second pass all extreme fields are ignored + * and column width is counted from non-extreme fields only. + */ +static size_t count_column_width(struct tt *tb, struct tt_column *cl, + char *buf, size_t bufsz) { - struct list_head *p; - size_t width = 0; - int trunc_only; + struct list_head *lp; + int count = 0; + size_t sum = 0; - /* set width according to the size of data - */ - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - struct list_head *lp; + cl->width = 0; - list_for_each(lp, &tb->tb_lines) { - struct tt_line *ln = - list_entry(lp, struct tt_line, ln_lines); + list_for_each(lp, &tb->tb_lines) { + struct tt_line *ln = list_entry(lp, struct tt_line, ln_lines); + char *data = line_get_data(ln, cl, buf, bufsz); + size_t len = data ? mbs_width(data) : 0; - char *data = line_get_data(ln, cl, buf, bufsz); - size_t len = data ? mbs_width(data) : 0; + if (len > cl->width_max) + cl->width_max = len; - if (cl->width < len) - cl->width = len; + if (cl->is_extreme && len > cl->width_avg * 2) + continue; + else if (cl->flags & TT_FL_NOEXTREMES) { + sum += len; + count++; } + if (len > cl->width) + cl->width = len; + } + + if (count && cl->width_avg == 0) { + cl->width_avg = sum / count; + + if (cl->width_max > cl->width_avg * 2) + cl->is_extreme = 1; } - /* set minimal width (= size of column header) + /* check and set minimal column width */ + if (cl->name) + cl->width_min = mbs_width(cl->name); + + /* enlarge to minimal width */ + if (cl->width < cl->width_min && !(cl->flags & TT_FL_STRICTWIDTH)) + cl->width = cl->width_min; + + /* use relative size for large columns */ + else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint && + cl->width_min < (size_t) cl->width_hint) + + cl->width = (size_t) cl->width_hint; +} + +/* + * This is core of the tt_* voodo... + */ +static void recount_widths(struct tt *tb, char *buf, size_t bufsz) +{ + struct list_head *p; + size_t width = 0; /* output width */ + int trunc_only; + int extremes = 0; + + /* set basic columns width */ list_for_each(p, &tb->tb_columns) { struct tt_column *cl = list_entry(p, struct tt_column, cl_columns); - if (cl->name) - cl->width_min = mbs_width(cl->name); + count_column_width(tb, cl, buf, bufsz); + width += cl->width + (is_last_column(tb, cl) ? 0 : 1); + extremes += cl->is_extreme; + } - if (cl->width < cl->width_min && - !(cl->flags & TT_FL_STRICTWIDTH)) - cl->width = cl->width_min; + /* reduce columns with extreme fields + */ + if (width > tb->termwidth && extremes) { + list_for_each(p, &tb->tb_columns) { + struct tt_column *cl = list_entry(p, struct tt_column, cl_columns); + size_t org_width; - else if (cl->width_hint >= 1 && - cl->width < (size_t) cl->width_hint && - cl->width_min < (size_t) cl->width_hint) + if (!cl->is_extreme) + continue; - cl->width = (size_t) cl->width_hint; + org_width = cl->width; + count_column_width(tb, cl, buf, bufsz); - width += cl->width + (is_last_column(tb, cl) ? 0 : 1); + if (org_width > cl->width) + width -= org_width - cl->width; + else + extremes--; /* hmm... nothing reduced */ + } } - if (width == tb->termwidth) - goto leave; if (width < tb->termwidth) { - /* cool, use the extra space for the last column */ - struct tt_column *cl = list_entry( - tb->tb_columns.prev, struct tt_column, cl_columns); - - if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0) - cl->width += tb->termwidth - width; - goto leave; + /* cool, use the extra space for the extreme columns or/and last column + */ + if (extremes) { + /* enlarge the first extreme column */ + list_for_each(p, &tb->tb_columns) { + struct tt_column *cl = + list_entry(p, struct tt_column, cl_columns); + size_t add; + + if (!cl->is_extreme) + continue; + add = tb->termwidth - width; + if (add && cl->width + add > cl->width_max) + add = cl->width_max - cl->width; + + cl->width += add; + width += add; + + if (width == tb->termwidth) + break; + } + } + if (width < tb->termwidth) { + /* enalarge the last column */ + struct tt_column *cl = list_entry( + tb->tb_columns.prev, struct tt_column, cl_columns); + + if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0) { + cl->width += tb->termwidth - width; + width = tb->termwidth; + } + } } /* bad, we have to reduce output width, this is done in two steps: @@ -408,7 +487,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz) * 2) reduce columns with a relative width without truncate flag */ trunc_only = 1; - while(width > tb->termwidth) { + while (width > tb->termwidth) { size_t org = width; list_for_each(p, &tb->tb_columns) { @@ -438,6 +517,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz) cl->width--; width--; } + } if (org == width) { if (trunc_only) @@ -446,7 +526,7 @@ static void recount_widths(struct tt *tb, char *buf, size_t bufsz) break; } } -leave: + /* fprintf(stderr, "terminal: %d, output: %d\n", tb->termwidth, width); @@ -454,10 +534,13 @@ leave: struct tt_column *cl = list_entry(p, struct tt_column, cl_columns); - fprintf(stderr, "width: %s=%zd [hint=%d]\n", + fprintf(stderr, "width: %s=%zd [hint=%d, avg=%zd, max=%zd, extreme=%s]\n", cl->name, cl->width, cl->width_hint > 1 ? (int) cl->width_hint : - (int) (cl->width_hint * tb->termwidth)); + (int) (cl->width_hint * tb->termwidth), + cl->width_avg, + cl->width_max, + cl->is_extreme ? "yes" : "not"); } */ return; diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c index 2c1b20c45..9c2b9fc6b 100644 --- a/misc-utils/findmnt.c +++ b/misc-utils/findmnt.c @@ -80,8 +80,8 @@ struct colinfo { /* columns descriptions (don't use const, this is writable) */ static struct colinfo infos[FINDMNT_NCOLUMNS] = { - [COL_SOURCE] = { "SOURCE", 0.25, 0, N_("source device") }, - [COL_TARGET] = { "TARGET", 0.30, TT_FL_TREE, N_("mountpoint") }, + [COL_SOURCE] = { "SOURCE", 0.25, TT_FL_NOEXTREMES, N_("source device") }, + [COL_TARGET] = { "TARGET", 0.30, TT_FL_TREE | TT_FL_NOEXTREMES, N_("mountpoint") }, [COL_FSTYPE] = { "FSTYPE", 0.10, TT_FL_TRUNC, N_("filesystem type") }, [COL_OPTIONS] = { "OPTIONS", 0.10, TT_FL_TRUNC, N_("all mount options") }, [COL_VFS_OPTIONS] = { "VFS-OPTIONS", 0.20, TT_FL_TRUNC, N_("VFS specific mount options") }, diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c index f8bf26590..4fd7189e2 100644 --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@ -100,7 +100,7 @@ struct colinfo { /* columns descriptions */ static struct colinfo infos[] = { - [COL_NAME] = { "NAME", 0.25, TT_FL_TREE, N_("device name") }, + [COL_NAME] = { "NAME", 0.25, TT_FL_TREE | TT_FL_NOEXTREMES, N_("device name") }, [COL_KNAME] = { "KNAME", 0.3, 0, N_("internal kernel device name") }, [COL_MAJMIN] = { "MAJ:MIN", 6, 0, N_("major:minor device number") }, [COL_FSTYPE] = { "FSTYPE", 0.1, TT_FL_TRUNC, N_("filesystem type") }, |