]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libsmartcols: fix colors use
authorKarel Zak <kzak@redhat.com>
Fri, 12 Mar 2021 15:14:39 +0000 (16:14 +0100)
committerKarel Zak <kzak@redhat.com>
Fri, 12 Mar 2021 15:15:16 +0000 (16:15 +0100)
* use color for all cell
* always switch back to line color

Signed-off-by: Karel Zak <kzak@redhat.com>
Documentation/TODO
libsmartcols/samples/Makemodule.am
libsmartcols/samples/colors.c [new file with mode: 0644]
libsmartcols/src/print.c
libsmartcols/src/smartcolsP.h

index e7e867e87d2759c24e726f232b3bdc40d6f212fc..129f658a12928c4a506f9de81e8e83651bd2f8cf 100644 (file)
@@ -122,8 +122,6 @@ login-utils:
 
 libsmartcols / column -t
 ------------------------
-  - fix color use, color has to be used for all cell, line and column. Now it's
-    used only for text, but no for padding chars and cell separators (line color).
   - add column --table-header-color
   - add support for border of table
     * extend 'struct libscols_symbols', use box-drawing chars UTF8/ASCII
index d6ab25c131e8fc999200445d5b85a27c045347ae..c0130b9e0a0fab8591390ead275649638c3ea3d6 100644 (file)
@@ -1,5 +1,6 @@
 
 check_PROGRAMS += \
+       sample-scols-colors \
        sample-scols-title \
        sample-scols-wrap \
        sample-scols-continuous \
@@ -19,6 +20,10 @@ sample_scols_tree_LDADD = $(sample_scols_ldadd) libcommon.la
 sample_scols_tree_CFLAGS = $(sample_scols_cflags)
 endif
 
+sample_scols_colors_SOURCES = libsmartcols/samples/colors.c
+sample_scols_colors_LDADD = $(sample_scols_ldadd) libcommon.la
+sample_scols_colors_CFLAGS = $(sample_scols_cflags)
+
 sample_scols_title_SOURCES = libsmartcols/samples/title.c
 sample_scols_title_LDADD = $(sample_scols_ldadd) libcommon.la
 sample_scols_title_CFLAGS = $(sample_scols_cflags)
diff --git a/libsmartcols/samples/colors.c b/libsmartcols/samples/colors.c
new file mode 100644 (file)
index 0000000..0e9ab66
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <getopt.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+#include "xalloc.h"
+
+#include "libsmartcols.h"
+
+
+enum { COL_NAME, COL_FOO, COL_BAR };
+
+/* add columns to the @tb */
+static void setup_columns(struct libscols_table *tb)
+{
+       if (!scols_table_new_column(tb, "NAME", 0, 0))
+               goto fail;
+       if (!scols_table_new_column(tb, "BAR", 0, 0))
+               goto fail;
+       if (!scols_table_new_column(tb, "FOO", 0, 0))
+               goto fail;
+       return;
+fail:
+       scols_unref_table(tb);
+       err(EXIT_FAILURE, "failed to create output columns");
+}
+
+static struct libscols_line *add_line(struct libscols_table *tb, const char *name, const char *data)
+{
+       struct libscols_line *ln = scols_table_new_line(tb, NULL);
+       if (!ln)
+               err(EXIT_FAILURE, "failed to create output line");
+
+       if (scols_line_set_data(ln, COL_NAME, name))
+               goto fail;
+       if (scols_line_set_data(ln, COL_FOO, data))
+               goto fail;
+       if (scols_line_set_data(ln, COL_BAR, data))
+               goto fail;
+       return ln;
+fail:
+       scols_unref_table(tb);
+       err(EXIT_FAILURE, "failed to create output line");
+}
+
+int main(int argc, char *argv[])
+{
+       struct libscols_table *tb;
+       struct libscols_column *cl;
+       struct libscols_line *ln;
+       struct libscols_cell *ce;
+       int c;
+
+       static const struct option longopts[] = {
+               { "maxout", 0, NULL, 'm' },
+               { "width",  1, NULL, 'w' },
+               { "help",   1, NULL, 'h' },
+
+               { NULL, 0, NULL, 0 },
+       };
+
+       setlocale(LC_ALL, "");  /* just to have enable UTF8 chars */
+
+       scols_init_debug(0);
+
+       tb = scols_new_table();
+       if (!tb)
+               err(EXIT_FAILURE, "failed to create output table");
+
+       while((c = getopt_long(argc, argv, "hmw:", longopts, NULL)) != -1) {
+               switch(c) {
+               case 'h':
+                       printf("%s [--help | --maxout | --width <num>]\n", program_invocation_short_name);
+                       break;
+               case 'm':
+                       scols_table_enable_maxout(tb, TRUE);
+                       break;
+               case 'w':
+                       scols_table_set_termforce(tb, SCOLS_TERMFORCE_ALWAYS);
+                       scols_table_set_termwidth(tb, strtou32_or_err(optarg, "failed to parse terminal width"));
+                       break;
+               }
+       }
+
+       scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
+       setup_columns(tb);
+       add_line(tb, "AAA", "bla bla bla");
+       add_line(tb, "BB", "b");
+       add_line(tb, "CCCC", "fooo");
+       add_line(tb, "D",   "baaar");
+       add_line(tb, "EE", "eee");
+
+       cl = scols_table_get_column(tb, 1);
+       scols_column_set_color(cl, "red");              /* red column */
+
+       cl = scols_table_get_column(tb, 2);
+       scols_column_set_color(cl, "reverse");          /* reverse column */
+
+       ln = scols_table_get_line(tb, 0);
+       scols_line_set_color(ln, "\033[37;41m");        /* line with red bg */
+       ce = scols_line_get_cell(ln, 0);
+       scols_cell_set_color(ce, "\033[37;45m");        /* cell with purple bg */
+
+       ln = scols_table_get_line(tb, 3);
+       scols_line_set_color(ln, "\033[37;41m");        /* line with red bg */
+       ce = scols_line_get_cell(ln, 2);
+       scols_cell_set_color(ce, "\033[37;44m");        /* cell with blue bg */
+
+       scols_print_table(tb);
+       scols_unref_table(tb);
+       return EXIT_SUCCESS;
+}
index 918ec5c64d31f21a29a0a34aa6f4b199ae855a7a..d35445d07c26815b58d9c9a8adf6bbcefc64a06e 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * table.c - functions handling the data at the table level
+ /* print.c - functions to print table
  *
  * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
  * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
@@ -217,16 +216,94 @@ static int has_pending_data(struct libscols_table *tb)
        return 0;
 }
 
+static void fputs_color_reset(struct libscols_table *tb)
+{
+       if (tb->cur_color) {
+               fputs(UL_COLOR_RESET, tb->out);
+               tb->cur_color = NULL;
+       }
+}
+
+static void fputs_color(struct libscols_table *tb, const char *color)
+{
+       if (tb->cur_color)
+               fputs_color_reset(tb);
+
+       tb->cur_color = color;
+       if (color)
+               fputs(color, tb->out);
+}
+
+static const char *get_cell_color(struct libscols_table *tb,
+                               struct libscols_column *cl,
+                               struct libscols_line *ln,
+                               struct libscols_cell *ce)
+{
+       const char *color = NULL;
+
+       if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN)
+               return NULL;
+       if (ce)
+               color = ce->color;
+       if (!color && (!ln || !ln->color) && cl)
+               color = cl->color;
+       return color;
+}
+
+/* switch from line color to cell/column color */
+static void fputs_color_cell_open(struct libscols_table *tb,
+                               struct libscols_column *cl,
+                               struct libscols_line *ln,
+                               struct libscols_cell *ce)
+{
+       const char *color = get_cell_color(tb, cl, ln, ce);
+
+       if (color)
+               fputs_color(tb, color);
+}
+
+/* switch from cell/column color to line color or reset */
+static void fputs_color_cell_close(struct libscols_table *tb,
+                               struct libscols_column *cl,
+                               struct libscols_line *ln,
+                               struct libscols_cell *ce)
+{
+       const char *color = get_cell_color(tb, cl, ln, ce);
+
+       if (color)
+               fputs_color(tb, ln ? ln->color : NULL);
+}
+
+/* switch to line color */
+static void fputs_color_line_open(struct libscols_table *tb,
+                               struct libscols_line *ln)
+{
+       if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN)
+               return;
+       fputs_color(tb, ln ? ln->color : NULL);
+}
+
+/* switch off all colors */
+static void fputs_color_line_close(struct libscols_table *tb)
+{
+       if (!tb || !tb->colors_wanted || tb->format != SCOLS_FMT_HUMAN)
+               return;
+       fputs_color_reset(tb);
+}
+
 /* print padding or ASCII-art instead of data of @cl */
 static void print_empty_cell(struct libscols_table *tb,
                          struct libscols_column *cl,
                          struct libscols_line *ln,     /* optional */
+                         struct libscols_cell *ce,
                          size_t bufsz)
 {
        size_t len_pad = 0;             /* in screen cells as opposed to bytes */
 
        DBG(COL, ul_debugobj(cl, " printing empty cell"));
 
+       fputs_color_cell_open(tb, cl, ln, ce);
+
        /* generate tree ASCII-art rather than padding */
        if (ln && scols_column_is_tree(cl)) {
                if (!ln->parent) {
@@ -256,39 +333,28 @@ static void print_empty_cell(struct libscols_table *tb,
        }
 
        /* minout -- don't fill */
-       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return;
+       }
 
        /* default -- fill except last column */
-       if (!scols_table_is_maxout(tb) && is_last_column(cl))
+       if (!scols_table_is_maxout(tb) && is_last_column(cl)) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return;
+       }
 
        /* fill rest of cell with space */
        for(; len_pad < cl->width; ++len_pad)
                fputs(cellpadding_symbol(tb), tb->out);
 
+       fputs_color_cell_close(tb, cl, ln, ce);
+
        if (!is_last_column(cl))
                fputs(colsep(tb), tb->out);
 }
 
 
-static const char *get_cell_color(struct libscols_table *tb,
-                                 struct libscols_column *cl,
-                                 struct libscols_line *ln,     /* optional */
-                                 struct libscols_cell *ce)     /* optional */
-{
-       const char *color = NULL;
-
-       if (tb && tb->colors_wanted) {
-               if (ce)
-                       color = ce->color;
-               if (ln && !color)
-                       color = ln->color;
-               if (!color)
-                       color = cl->color;
-       }
-       return color;
-}
 
 /* Fill the start of a line with padding (or with tree ascii-art).
  *
@@ -304,6 +370,7 @@ static const char *get_cell_color(struct libscols_table *tb,
 static void print_newline_padding(struct libscols_table *tb,
                                  struct libscols_column *cl,
                                  struct libscols_line *ln,     /* optional */
+                                 struct libscols_cell *ce,
                                  size_t bufsz)
 {
        size_t i;
@@ -316,9 +383,13 @@ static void print_newline_padding(struct libscols_table *tb,
        fputs(linesep(tb), tb->out);            /* line break */
        tb->termlines_used++;
 
+       fputs_color_line_open(tb, ln);
+
        /* fill cells after line break */
        for (i = 0; i <= (size_t) cl->seqnum; i++)
-               print_empty_cell(tb, scols_table_get_column(tb, i), ln, bufsz);
+               print_empty_cell(tb, scols_table_get_column(tb, i), ln, ce, bufsz);
+
+       fputs_color_line_close(tb);
 }
 
 /*
@@ -374,7 +445,6 @@ static int print_pending_data(
                struct libscols_line *ln,       /* optional */
                struct libscols_cell *ce)
 {
-       const char *color = get_cell_color(tb, cl, ln, ce);
        size_t width = cl->width, bytes;
        size_t len = width, i;
        char *data;
@@ -407,25 +477,29 @@ static int print_pending_data(
        if (bytes)
                step_pending_data(cl, bytes);
 
-       if (color)
-               fputs(color, tb->out);
+       fputs_color_cell_open(tb, cl, ln, ce);
+
        fputs(data, tb->out);
-       if (color)
-               fputs(UL_COLOR_RESET, tb->out);
        free(data);
 
        /* minout -- don't fill */
-       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return 0;
+       }
 
        /* default -- fill except last column */
-       if (!scols_table_is_maxout(tb) && is_last_column(cl))
+       if (!scols_table_is_maxout(tb) && is_last_column(cl)) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return 0;
+       }
 
        /* fill rest of cell with space */
        for(i = len; i < width; i++)
                fputs(cellpadding_symbol(tb), tb->out);
 
+       fputs_color_cell_close(tb, cl, ln, ce);
+
        if (!is_last_column(cl))
                fputs(colsep(tb), tb->out);
 
@@ -487,7 +561,6 @@ static int print_data(struct libscols_table *tb,
                      struct libscols_buffer *buf)
 {
        size_t len = 0, i, width, bytes;
-       const char *color = NULL;
        char *data, *nextchunk;
        const char *name = NULL;
        int is_last;
@@ -534,8 +607,6 @@ static int print_data(struct libscols_table *tb,
                break;          /* continue below */
        }
 
-       color = get_cell_color(tb, cl, ln, ce);
-
        /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
         */
        data = buffer_get_safe_data(tb, buf, &len, scols_column_get_safechars(cl));
@@ -583,49 +654,39 @@ static int print_data(struct libscols_table *tb,
                data = NULL;
        }
 
+       fputs_color_cell_open(tb, cl, ln, ce);
+
        if (data && *data) {
                if (scols_column_is_right(cl)) {
-                       if (color)
-                               fputs(color, tb->out);
                        for (i = len; i < width; i++)
                                fputs(cellpadding_symbol(tb), tb->out);
-                       fputs(data, tb->out);
-                       if (color)
-                               fputs(UL_COLOR_RESET, tb->out);
                        len = width;
+               }
+               fputs(data, tb->out);
 
-               } else if (color) {
-                       char *p = data;
-                       size_t art = buffer_get_safe_art_size(buf);
-
-                       /* we don't want to colorize tree ascii art */
-                       if (scols_column_is_tree(cl) && art && art < bytes) {
-                               fwrite(p, 1, art, tb->out);
-                               p += art;
-                       }
-
-                       fputs(color, tb->out);
-                       fputs(p, tb->out);
-                       fputs(UL_COLOR_RESET, tb->out);
-               } else
-                       fputs(data, tb->out);
        }
 
        /* minout -- don't fill */
-       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+       if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln)) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return 0;
+       }
 
        /* default -- fill except last column */
-       if (!scols_table_is_maxout(tb) && is_last)
+       if (!scols_table_is_maxout(tb) && is_last) {
+               fputs_color_cell_close(tb, cl, ln, ce);
                return 0;
+       }
 
        /* fill rest of cell with space */
        for(i = len; i < width; i++)
                fputs(cellpadding_symbol(tb), tb->out);
 
+       fputs_color_cell_close(tb, cl, ln, ce);
+
        if (len > width && !scols_column_is_trunc(cl)) {
                DBG(COL, ul_debugobj(cl, "*** data len=%zu > column width=%zu", len, width));
-               print_newline_padding(tb, cl, ln, buffer_get_size(buf));        /* next column starts on next line */
+               print_newline_padding(tb, cl, ln, ce, buffer_get_size(buf));    /* next column starts on next line */
 
        } else if (!is_last)
                fputs(colsep(tb), tb->out);             /* columns separator */
@@ -698,6 +759,8 @@ static int print_line(struct libscols_table *tb,
 
        DBG(LINE, ul_debugobj(ln, "printing line"));
 
+       fputs_color_line_open(tb, ln);
+
        /* regular line */
        scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
        while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
@@ -711,12 +774,14 @@ static int print_line(struct libscols_table *tb,
                if (rc == 0 && cl->pending_data)
                        pending = 1;
        }
+       fputs_color_line_close(tb);
 
        /* extra lines of the multi-line cells */
        while (rc == 0 && pending) {
                DBG(LINE, ul_debugobj(ln, "printing pending data"));
                pending = 0;
                fputs(linesep(tb), tb->out);
+               fputs_color_line_open(tb, ln);
                tb->termlines_used++;
                scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
                while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
@@ -727,8 +792,9 @@ static int print_line(struct libscols_table *tb,
                                if (rc == 0 && cl->pending_data)
                                        pending = 1;
                        } else
-                               print_empty_cell(tb, cl, ln, buffer_get_size(buf));
+                               print_empty_cell(tb, cl, ln, NULL, buffer_get_size(buf));
                }
+               fputs_color_line_close(tb);
        }
 
        return 0;
@@ -736,7 +802,7 @@ static int print_line(struct libscols_table *tb,
 
 int __scols_print_title(struct libscols_table *tb)
 {
-       int rc, color = 0;
+       int rc;
        mbs_align_t align;
        size_t width, len = 0, bufsz, titlesz;
        char *title = NULL, *buf = NULL;
@@ -817,15 +883,11 @@ int __scols_print_title(struct libscols_table *tb)
                goto done;
        }
 
-       if (tb->colors_wanted && tb->title.color)
-               color = 1;
-       if (color)
-               fputs(tb->title.color, tb->out);
+       fputs_color(tb, tb->title.color);
 
        fputs(title, tb->out);
 
-       if (color)
-               fputs(UL_COLOR_RESET, tb->out);
+       fputs_color_reset(tb);
 
        fputc('\n', tb->out);
        rc = 0;
index 2a3b22672f86b939867a3eb79a052757b5069179..076707412cfe9320a0e5aea3fc2377dac57c54f6 100644 (file)
@@ -232,6 +232,8 @@ struct libscols_table {
        size_t  termlines_used; /* printed line counter */
        size_t  header_next;    /* where repeat header */
 
+       const char *cur_color;  /* current active color when printing */
+
        /* flags */
        unsigned int    ascii           :1,     /* don't use unicode */
                        colors_wanted   :1,     /* enable colors */