Merge branch 'jc/color-attrs'
authorJunio C Hamano <gitster@pobox.com>
Sat, 20 Mar 2010 18:29:36 +0000 (11:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 20 Mar 2010 18:29:36 +0000 (11:29 -0700)
* jc/color-attrs:
color: allow multiple attributes

1  2 
color.c
color.h
t/t4026-color.sh
diff --combined color.c
index 8f07fc9547efdf37cf44ab0b880f6c26970b3e95,90268fb3c63d340e615f8c54af009e347a654e8b..bcf4e2c192c31136729aabcc2575a94f809d2980
+++ b/color.c
@@@ -1,6 -1,8 +1,6 @@@
  #include "cache.h"
  #include "color.h"
  
 -#define COLOR_RESET "\033[m"
 -
  int git_use_color_default = 0;
  
  static int parse_color(const char *name, int len)
@@@ -47,16 -49,16 +47,16 @@@ void color_parse_mem(const char *value
  {
        const char *ptr = value;
        int len = value_len;
-       int attr = -1;
+       unsigned int attr = 0;
        int fg = -2;
        int bg = -2;
  
        if (!strncasecmp(value, "reset", len)) {
 -              strcpy(dst, "\033[m");
 +              strcpy(dst, GIT_COLOR_RESET);
                return;
        }
  
-       /* [fg [bg]] [attr] */
+       /* [fg [bg]] [attr]... */
        while (len > 0) {
                const char *word = ptr;
                int val, wordlen = 0;
                        goto bad;
                }
                val = parse_attr(word, wordlen);
-               if (val < 0 || attr != -1)
+               if (0 <= val)
+                       attr |= (1 << val);
+               else
                        goto bad;
-               attr = val;
        }
  
-       if (attr >= 0 || fg >= 0 || bg >= 0) {
+       if (attr || fg >= 0 || bg >= 0) {
                int sep = 0;
+               int i;
  
                *dst++ = '\033';
                *dst++ = '[';
-               if (attr >= 0) {
-                       *dst++ = '0' + attr;
-                       sep++;
+               for (i = 0; attr; i++) {
+                       unsigned bit = (1 << i);
+                       if (!(attr & bit))
+                               continue;
+                       attr &= ~bit;
+                       if (sep++)
+                               *dst++ = ';';
+                       *dst++ = '0' + i;
                }
                if (fg >= 0) {
                        if (sep++)
@@@ -138,9 -148,6 +146,9 @@@ int git_config_colorbool(const char *va
                        goto auto_color;
        }
  
 +      if (!var)
 +              return -1;
 +
        /* Missing or explicit false to turn off colorization */
        if (!git_config_bool(var, value))
                return 0;
@@@ -176,7 -183,7 +184,7 @@@ static int color_vfprintf(FILE *fp, con
                r += fprintf(fp, "%s", color);
        r += vfprintf(fp, fmt, args);
        if (*color)
 -              r += fprintf(fp, "%s", COLOR_RESET);
 +              r += fprintf(fp, "%s", GIT_COLOR_RESET);
        if (trail)
                r += fprintf(fp, "%s", trail);
        return r;
@@@ -218,7 -225,7 +226,7 @@@ int color_fwrite_lines(FILE *fp, const 
                char *p = memchr(buf, '\n', count);
                if (p != buf && (fputs(color, fp) < 0 ||
                                fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
 -                              fputs(COLOR_RESET, fp) < 0))
 +                              fputs(GIT_COLOR_RESET, fp) < 0))
                        return -1;
                if (!p)
                        return 0;
diff --combined color.h
index 3cb4b7fc890880b0fcf19a11c6bc7de6b10d6e8d,e2988f4e93f95ece2a1b0721fa8a17aa3f030756..bcb28cf10f2cbef11d9dba0e5a7f3f0515cbbd70
+++ b/color.h
@@@ -1,25 -1,21 +1,37 @@@
  #ifndef COLOR_H
  #define COLOR_H
  
- /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
- #define COLOR_MAXLEN 24
+ /*  2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */
+ /* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */
+ /*
+  * The maximum length of ANSI color sequence we would generate:
+  * - leading ESC '['            2
+  * - attr + ';'                 2 * 8 (e.g. "1;")
+  * - fg color + ';'             9 (e.g. "38;5;2xx;")
+  * - fg color + ';'             9 (e.g. "48;5;2xx;")
+  * - terminating 'm' NUL        2
+  *
+  * The above overcounts attr (we only use 5 not 8) and one semicolon
+  * but it is close enough.
+  */
+ #define COLOR_MAXLEN 40
  
 +/*
 + * IMPORTANT: Due to the way these color codes are emulated on Windows,
 + * write them only using printf(), fprintf(), and fputs(). In particular,
 + * do not use puts() or write().
 + */
 +#define GIT_COLOR_NORMAL      ""
 +#define GIT_COLOR_RESET               "\033[m"
 +#define GIT_COLOR_BOLD                "\033[1m"
 +#define GIT_COLOR_RED         "\033[31m"
 +#define GIT_COLOR_GREEN               "\033[32m"
 +#define GIT_COLOR_YELLOW      "\033[33m"
 +#define GIT_COLOR_BLUE                "\033[34m"
 +#define GIT_COLOR_MAGENTA     "\033[35m"
 +#define GIT_COLOR_CYAN                "\033[36m"
 +#define GIT_COLOR_BG_RED      "\033[41m"
 +
  /*
   * This variable stores the value of color.ui
   */
@@@ -34,9 -30,7 +46,9 @@@ int git_color_default_config(const cha
  int git_config_colorbool(const char *var, const char *value, int stdout_is_tty);
  void color_parse(const char *value, const char *var, char *dst);
  void color_parse_mem(const char *value, int len, const char *var, char *dst);
 +__attribute__((format (printf, 3, 4)))
  int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
 +__attribute__((format (printf, 3, 4)))
  int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
  int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
  
diff --combined t/t4026-color.sh
index 5ade44c043ca6577b2e331b152515359128dbd32,49eced20e7f9346ac6d52891c271ab3ef6d0982b..d5ccdd0cf8061e797e88185bfddb0864f73291dd
@@@ -8,14 -8,13 +8,13 @@@ test_description='Test diff/status colo
  
  color()
  {
-       git config diff.color.new "$1" &&
-       test "`git config --get-color diff.color.new`" = "\e$2"
+       actual=$(git config --get-color no.such.slot "$1") &&
+       test "$actual" = "\e$2"
  }
  
  invalid_color()
  {
-       git config diff.color.new "$1" &&
-       test -z "`git config --get-color diff.color.new 2>/dev/null`"
+       test_must_fail git config --get-color no.such.slot "$1"
  }
  
  test_expect_success 'reset' '
@@@ -42,6 -41,14 +41,14 @@@ test_expect_success 'fg bg attr' 
        color "blue red ul" "[4;34;41m"
  '
  
+ test_expect_success 'fg bg attr...' '
+       color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
+ '
+ test_expect_success 'long color specification' '
+       color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m"
+ '
  test_expect_success '256 colors' '
        color "254 bold 255" "[1;38;5;254;48;5;255m"
  '
@@@ -66,21 -73,4 +73,21 @@@ test_expect_success 'extra character af
        invalid_color "dimX"
  '
  
 +test_expect_success 'unknown color slots are ignored (diff)' '
 +      git config --unset diff.color.new
 +      git config color.diff.nosuchslotwilleverbedefined white &&
 +      git diff --color
 +'
 +
 +test_expect_success 'unknown color slots are ignored (branch)' '
 +      git config color.branch.nosuchslotwilleverbedefined white &&
 +      git branch -a
 +'
 +
 +test_expect_success 'unknown color slots are ignored (status)' '
 +      git config color.status.nosuchslotwilleverbedefined white || exit
 +      git status
 +      case $? in 0|1) : ok ;; *) false ;; esac
 +'
 +
  test_done