From b3e36c552b3321a5e317c012d194034d60e363ec Mon Sep 17 00:00:00 2001 From: Jaromir Capik Date: Sat, 6 Sep 2014 10:46:27 +0200 Subject: [PATCH] watch: enhancing ANSI color & style support This commit adds support for background colors and additional ANSI styles (faint, italic, underlined, blinking, inversed). --- watch.1 | 2 +- watch.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 94 insertions(+), 21 deletions(-) diff --git a/watch.1 b/watch.1 index e31f642d..34f604aa 100644 --- 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 5bd4d269..e7341659 100644 --- 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[=]\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;