]> granicus.if.org Git - procps-ng/commitdiff
watch: enhancing ANSI color & style support
authorJaromir Capik <jcapik@redhat.com>
Sat, 6 Sep 2014 08:46:27 +0000 (10:46 +0200)
committerJaromir Capik <jcapik@redhat.com>
Sat, 6 Sep 2014 08:52:38 +0000 (10:52 +0200)
This commit adds support for background colors
and additional ANSI styles (faint, italic,
underlined, blinking, inversed).

watch.1
watch.c

diff --git a/watch.1 b/watch.1
index e31f642dcec06ee07d56777ee06ee541abfaa688..34f604aaf96491ccb470c21ff63c98494c53db73 100644 (file)
--- a/watch.1
+++ b/watch.1
@@ -53,7 +53,7 @@ Exit when the output of
 changes.
 .TP
 \fB\-c\fR, \fB\-\-color\fR
-Interpret ANSI color sequences.
+Interpret ANSI color and style sequences.
 .TP
 \fB\-x\fR, \fB\-\-exec\fR
 .I command
diff --git a/watch.c b/watch.c
index 5bd4d2696852c8aa123880fe1628e39b3c18261c..e734165904b5affdd5615a4c08422bc6a428929a 100644 (file)
--- a/watch.c
+++ b/watch.c
@@ -89,7 +89,7 @@ static void __attribute__ ((__noreturn__))
               _(" %s [options] command\n"), program_invocation_short_name);
        fputs(USAGE_OPTIONS, out);
        fputs(_("  -b, --beep             beep if command has a non-zero exit\n"), out);
-       fputs(_("  -c, --color            interpret ANSI color sequences\n"), out);
+       fputs(_("  -c, --color            interpret ANSI color and style sequences\n"), out);
        fputs(_("  -d, --differences[=<permanent>]\n"
                 "                         highlight changes between updates\n"), out);
        fputs(_("  -e, --errexit          exit if command has a non-zero exit\n"), out);
@@ -106,34 +106,90 @@ static void __attribute__ ((__noreturn__))
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
+static int nr_of_colors;
+static int attributes;
+static int fg_col;
+static int bg_col;
+
 static void init_ansi_colors(void)
 {
-       int i;
        short ncurses_colors[] = {
                COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
                COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
        };
 
-       for (i = 0; i < 8; i++)
-               init_pair(i + 1, ncurses_colors[i], -1);
+       nr_of_colors = sizeof(ncurses_colors) / sizeof(short);
+
+       for (bg_col = 0; bg_col < nr_of_colors; bg_col++)
+               for (fg_col = 0; fg_col < nr_of_colors; fg_col++)
+                       init_pair(bg_col * nr_of_colors + fg_col + 1, ncurses_colors[fg_col], ncurses_colors[bg_col]);
+
+       /* default settings */
+       attributes = A_NORMAL;
+       fg_col = COLOR_WHITE;
+       bg_col = COLOR_BLACK;
 }
 
+
 static void set_ansi_attribute(const int attrib)
 {
        switch (attrib) {
-       case -1:
-               return;
-       case 0:
-               standend();
-               return;
-       case 1:
-               attrset(A_BOLD);
-               return;
-       }
-       if (attrib >= 30 && attrib <= 37) {
-               color_set(attrib - 29, NULL);
-               return;
+       case -1:        /* restore last settings */
+               break;
+       case 0:         /* restore default settings */
+               attributes = A_NORMAL;
+               fg_col = COLOR_WHITE;
+               bg_col = COLOR_BLACK;
+               break;
+       case 1:         /* set bold / increased intensity */
+               attributes |= A_BOLD;
+               break;
+       case 2:         /* set decreased intensity (if supported) */
+               attributes |= A_DIM;
+               break;
+#ifdef A_ITALIC
+       case 3:         /* set italic (if supported) */
+               attributes |= A_ITALIC;
+               break;
+#endif
+       case 4:         /* set underline */
+               attributes |= A_UNDERLINE;
+               break;
+       case 5:         /* set blinking */
+               attributes |= A_BLINK;
+               break;
+       case 7:         /* set inversed */
+               attributes |= A_REVERSE;
+               break;
+       case 21:        /* unset bold / increased intensity */
+               attributes &= ~A_BOLD;
+               break;
+       case 22:        /* unset bold / any intensity modifier */
+               attributes &= ~(A_BOLD | A_DIM);
+               break;
+#ifdef A_ITALIC
+       case 23:        /* unset italic */
+               attributes &= A_ITALIC;
+               break;
+#endif
+       case 24:        /* unset underline */
+               attributes &= ~A_UNDERLINE;
+               break;
+       case 25:        /* unset blinking */
+               attributes &= ~A_BLINK;
+               break;
+       case 27:        /* unset inversed */
+               attributes &= ~A_REVERSE;
+               break;
+       default:
+               if (attrib >= 30 && attrib <= 37) {     /* set foreground color */
+                       fg_col = attrib - 30;
+               } else if (attrib >= 40 && attrib <= 47) { /* set background color */
+                       bg_col = attrib - 40;
+               }
        }
+
+       attrset(attributes | COLOR_PAIR(bg_col * nr_of_colors + fg_col + 1));
 }
 
 static void process_ansi(FILE * fp)
@@ -414,7 +470,8 @@ static int run_command(char *restrict command, char **restrict command_argv)
                xerr(5, _("fdopen"));
 
        for (y = show_title; y < height; y++) {
-               int eolseen = 0, tabpending = 0;
+               int eolseen = 0, tabpending = 0, tabwaspending;
+               set_ansi_attribute(-1);
 #ifdef WITH_WATCH8BIT
                wint_t carry = WEOF;
 #endif
@@ -426,6 +483,10 @@ static int run_command(char *restrict command, char **restrict command_argv)
 #endif
                        int attr = 0;
 
+                       if (tabwaspending && (flags & WATCH_COLOR))
+                               set_ansi_attribute(-1);
+                       tabwaspending = 0;
+
                        if (!eolseen) {
                                /* if there is a tab pending, just
                                 * spit spaces until the next stop
@@ -475,16 +536,25 @@ static int run_command(char *restrict command, char **restrict command_argv)
                                        carry = c;      /* character on the next line */
                                        continue;       /* because it won't fit here */
                                }
-                               if (c == WEOF || c == L'\n' || c == L'\t')
+                               if (c == WEOF || c == L'\n' || c == L'\t') {
                                        c = L' ';
+                                       if (flags & WATCH_COLOR)
+                                               attrset(A_NORMAL);
+                               }
 #else
-                               if (c == EOF || c == '\n' || c == '\t')
+                               if (c == EOF || c == '\n' || c == '\t') {
                                        c = ' ';
+                                       if (flags & WATCH_COLOR)
+                                               attrset(A_NORMAL);
+                               }
 #endif
-                               if (tabpending && (((x + 1) % 8) == 0))
+                               if (tabpending && (((x + 1) % 8) == 0)) {
                                        tabpending = 0;
+                                       tabwaspending = 1;
+                               }
                        }
                        move(y, x);
+
                        if (!first_screen && !exit_early && (flags & WATCH_CHGEXIT)) {
 #ifdef WITH_WATCH8BIT
                                cchar_t oldc;
@@ -538,6 +608,7 @@ static int run_command(char *restrict command, char **restrict command_argv)
 
        fclose(p);
 
+
        /* harvest child process and get status, propagated from command */
        if (waitpid(child, &status, 0) < 0)
                xerr(8, _("waitpid"));
@@ -733,6 +804,8 @@ int main(int argc, char *argv[])
 
                if (run_command(command, command_argv))
                        break;
+
+
                if (precise_timekeeping) {
                        watch_usec_t cur_time = get_time_usec();
                        next_loop += USECS_PER_SEC * interval;