]> granicus.if.org Git - jq/commitdiff
Add JQ_COLORS env var for color config (fix #1252)
authorNico Williams <nico@cryptonector.com>
Sat, 29 Apr 2017 18:00:52 +0000 (13:00 -0500)
committerWilliam Langford <wlangfor@gmail.com>
Sat, 29 Apr 2017 18:00:52 +0000 (14:00 -0400)
docs/content/3.manual/manual.yml
jq.1.prebuilt
src/jq.h
src/jv_print.c
src/main.c
tests/shtest

index f666ceb1b6e96563601e7dd2ed62001ab32bdfc1..fcca8412fb76729ae874569f6c2afbf28bf2f41c 100644 (file)
@@ -160,6 +160,9 @@ sections:
         terminal. You can force it to produce color even if writing to
         a pipe or a file using `-C`, and disable color with `-M`.
 
+        Colors can be configured with the `JQ_COLORS` environment
+        variable (see below).
+
       * `--ascii-output` / `-a`:
 
         jq usually outputs non-ASCII Unicode codepoints as UTF-8, even
@@ -3195,3 +3198,42 @@ sections:
           could then use to, for example, search for, download, and
           install missing dependencies.
 
+  - title: Colors
+    body: |
+
+      To configure alternative colors just set the `JQ_COLORS`
+      environment variable to colon-delimited list of partial terminal
+      escape sequences like `"1;31"`, in this order:
+
+        - color for `null`
+        - color for `false`
+        - color for `true`
+        - color for numbers
+        - color for strings
+        - color for arrays
+        - color for objects
+
+      The default color scheme is the same as setting
+      `"JQ_COLORS=1;30:0;39:0;39:0;39:0;32:1;39:1;39"`.
+
+      This is not a manual for VT100/ANSI escapes.  However, each of
+      these color specifications should consist of two numbers separated
+      by a semi-colon, where the first number is one of these:
+
+        - 1 (bright)
+        - 2 (dim)
+        - 4 (underscore)
+        - 5 (blink)
+        - 7 (reverse)
+        - 8 (hidden)
+
+      and the second is one of these:
+
+        - 30 (black)
+        - 31 (red)
+        - 32 (green)
+        - 33 (yellow)
+        - 34 (blue)
+        - 35 (magenta)
+        - 36 (cyan)
+        - 37 (white)
index ef04d74109f59b7d57c0e32f0af5768223bf5749..21a0fcd0ae9bb15028f2a909dc5b98c449403a4f 100644 (file)
@@ -105,6 +105,9 @@ Use the given number of spaces (no more than 8) for indentation\.
 .IP
 By default, jq outputs colored JSON if writing to a terminal\. You can force it to produce color even if writing to a pipe or a file using \fB\-C\fR, and disable color with \fB\-M\fR\.
 .
+.IP
+Colors can be configured with the \fBJQ_COLORS\fR environment variable (see below)\.
+.
 .IP "\(bu" 4
 \fB\-\-ascii\-output\fR / \fB\-a\fR:
 .
@@ -3373,6 +3376,87 @@ Takes a module name as input and outputs the module\'s metadata as an object, wi
 .P
 Programs can use this to query a module\'s metadata, which they could then use to, for example, search for, download, and install missing dependencies\.
 .
+.SH "COLORS"
+To configure alternative colors just set the \fBJQ_COLORS\fR environment variable to colon\-delimited list of partial terminal escape sequences like \fB"1;31"\fR, in this order:
+.
+.IP "\(bu" 4
+color for \fBnull\fR
+.
+.IP "\(bu" 4
+color for \fBfalse\fR
+.
+.IP "\(bu" 4
+color for \fBtrue\fR
+.
+.IP "\(bu" 4
+color for numbers
+.
+.IP "\(bu" 4
+color for strings
+.
+.IP "\(bu" 4
+color for arrays
+.
+.IP "\(bu" 4
+color for objects
+.
+.IP "" 0
+.
+.P
+The default color scheme is the same as setting \fB"JQ_COLORS=1;30:0;39:0;39:0;39:0;32:1;39:1;39"\fR\.
+.
+.P
+This is not a manual for VT100/ANSI escapes\. However, each of these color specifications should consist of two numbers separated by a semi\-colon, where the first number is one of these:
+.
+.IP "\(bu" 4
+1 (bright)
+.
+.IP "\(bu" 4
+2 (dim)
+.
+.IP "\(bu" 4
+4 (underscore)
+.
+.IP "\(bu" 4
+5 (blink)
+.
+.IP "\(bu" 4
+7 (reverse)
+.
+.IP "\(bu" 4
+8 (hidden)
+.
+.IP "" 0
+.
+.P
+and the second is one of these:
+.
+.IP "\(bu" 4
+30 (black)
+.
+.IP "\(bu" 4
+31 (red)
+.
+.IP "\(bu" 4
+32 (green)
+.
+.IP "\(bu" 4
+33 (yellow)
+.
+.IP "\(bu" 4
+34 (blue)
+.
+.IP "\(bu" 4
+35 (magenta)
+.
+.IP "\(bu" 4
+36 (cyan)
+.
+.IP "\(bu" 4
+37 (white)
+.
+.IP "" 0
+.
 .SH "BUGS"
 Presumably\. Report them or discuss them at:
 .
index 3067d8ae3962b6c41597b7467a7e2d7da183b079..5269de3ff8389cc6b2686878a7bb5aaada22c374 100644 (file)
--- a/src/jq.h
+++ b/src/jq.h
@@ -66,4 +66,6 @@ jv jq_util_input_get_position(jq_state*);
 jv jq_util_input_get_current_filename(jq_state*);
 jv jq_util_input_get_current_line(jq_state*);
 
+int jq_set_colors(const char *);
+
 #endif /* !JQ_H */
index 3fcf8378f56361b493d491154908ab6567a230dd..5ebc01e6283348d181bf15d21ec9e7ef3430da62 100644 (file)
 static const jv_kind color_kinds[] =
   {JV_KIND_NULL,   JV_KIND_FALSE, JV_KIND_TRUE, JV_KIND_NUMBER,
    JV_KIND_STRING, JV_KIND_ARRAY, JV_KIND_OBJECT};
-static const char* const colors[] =
+static char color_bufs[sizeof(color_kinds)/sizeof(color_kinds[0])][16];
+static const char *color_bufps[8];
+static const char* def_colors[] =
   {COL("1;30"),    COL("0;39"),      COL("0;39"),     COL("0;39"),
    COL("0;32"),      COL("1;39"),     COL("1;39")};
 #define FIELD_COLOR COL("34;1")
 
+static const char **colors = def_colors;
+
+int
+jq_set_colors(const char *c)
+{
+  const char *e;
+  size_t i;
+
+  if (c == NULL)
+    return 1;
+  colors = def_colors;
+  memset(color_bufs, 0, sizeof(color_bufs));
+  for (i = 0; i < sizeof(def_colors) / sizeof(def_colors[0]); i++)
+    color_bufps[i] = def_colors[i];
+  for (i = 0; i < sizeof(def_colors) / sizeof(def_colors[0]) && *c != '\0'; i++, c = e) {
+    if ((e = strchr(c, ':')) == NULL)
+      e = c + strlen(c);
+    if ((size_t)(e - c) > sizeof(color_bufs[i]) - 4 /* ESC [ m NUL */)
+      return 0;
+    color_bufs[i][0] = ESC[0];
+    color_bufs[i][1] = '[';
+    (void) strncpy(&color_bufs[i][2], c, e - c);
+    if (strspn(&color_bufs[i][2], "0123456789;") < strlen(&color_bufs[i][2]))
+      return 0;
+    color_bufs[i][2 + (e - c)] = 'm';
+    color_bufps[i] = color_bufs[i];
+    if (e[0] == ':')
+      e++;
+  }
+  colors = color_bufps;
+  return 1;
+}
+
 static void put_buf(const char *s, int len, FILE *fout, jv *strout, int is_tty) {
   if (strout) {
     *strout = jv_string_append_buf(*strout, s, len);
index 3cbf31526a8096b26e8c182087eb4054e735a9f9..a7f50b5135551f54a1db75e8049a44192fbed486 100644 (file)
@@ -525,6 +525,9 @@ int main(int argc, char* argv[]) {
   if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR;
   if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR;
 
+  if (getenv("JQ_COLORS") != NULL && !jq_set_colors(getenv("JQ_COLORS")))
+      fprintf(stderr, "Failed to set $JQ_COLORS\n");
+
   if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) {
     // Default search path list
     lib_search_paths = JV_ARRAY(jv_string("~/.jq"),
index cec1fc59314f453b0a7654ca0cb02af4332121fa..af1b159eb8a2899e5deae6e05c3c154cfaaed34b 100755 (executable)
@@ -244,4 +244,58 @@ if [ "`$VALGRIND $Q $JQ -n '"xyz\n"|halt_error(1)' 2>&1`" != xyz ]; then
     exit 1
 fi
 
+# Check $JQ_COLORS
+$JQ -Ccn . > $d/color
+printf '\033[1;30mnull\033[0m\n' > $d/expect
+cmp $d/color $d/expect
+JQ_COLORS='4;31' $JQ -Ccn . > $d/color
+printf '\033[4;31mnull\033[0m\n' > $d/expect
+cmp $d/color $d/expect
+JQ_COLORS='1;30:0;31:0;32:0;33:0;34:1;35:1;36' \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color
+(
+printf '\033[1;35m[\033[1;36m{'
+printf '\033[0m\033[34;1m"a"\033['
+printf '0m\033[1;36m:\033[0m\033['
+printf '0;32mtrue\033[0m\033[1'
+printf ';36m,\033[0m\033[34;1m'
+printf '"b"\033[0m\033[1;36m:\033'
+printf '[0m\033[0;31mfalse\033'
+printf '[0m\033[1;36m\033[1;36'
+printf 'm}\033[0m\033[1;35m,\033['
+printf '0;33m123\033[0m\033[1;'
+printf '35m,\033[1;30mnull\033'
+printf '[0m\033[1;35m\033[1;35'
+printf 'm]\033[0m\n'
+) > $d/expect
+cmp $d/color $d/expect
+
+# Check garbage in JQ_COLORS.  We write each color sequence into a 16
+# char buffer that needs to hold ESC [ <color> m NUL, so each color
+# sequence can be no more than 12 chars (bytes).  These emit a warning
+# on stderr.
+set -vx
+echo 'Failed to set $JQ_COLORS' > $d/expect_warning
+$JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/expect
+JQ_COLORS='garbage;30:*;31:,;3^:0;$%:0;34:1;35:1;36' \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color 2>$d/warning
+cmp $d/color $d/expect
+cmp $d/warning $d/expect_warning
+JQ_COLORS='1234567890123456789;30:0;31:0;32:0;33:0;34:1;35:1;36' \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color 2>$d/warning
+cmp $d/color $d/expect
+cmp $d/warning $d/expect_warning
+JQ_COLORS='1;31234567890123456789:0;31:0;32:0;33:0;34:1;35:1;36' \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color 2>$d/warning
+cmp $d/color $d/expect
+cmp $d/warning $d/expect_warning
+JQ_COLORS='1234567890123456;1234567890123456:1234567890123456;1234567890123456:1234567890123456;1234567890123456:1234567890123456;1234567890123456:1234567890123456;1234567890123456:1234567890123456;1234567890123456:1234567890123456;1234567890123456' \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color 2>$d/warning
+cmp $d/color $d/expect
+cmp $d/warning $d/expect_warning
+JQ_COLORS="0123456789123:0123456789123:0123456789123:0123456789123:0123456789123:0123456789123:0123456789123:0123456789123:" \
+  $JQ -Ccn '[{"a":true,"b":false},123,null]' > $d/color 2>$d/warning
+cmp $d/color $d/expect
+cmp $d/warning $d/expect_warning
+
 exit 0