Merge branch 'ar/decorate-color'

* ar/decorate-color:
  Add test for correct coloring of git log --decoration
  Allow customizable commit decorations colors
  log --decorate: Colorize commit decorations
  log-tree.c: Use struct name_decoration's type for classifying decoration
  commit.h: add 'type' to struct name_decoration
This commit is contained in:
Junio C Hamano 2010-06-30 11:55:40 -07:00
commit 2927a507bf
6 changed files with 176 additions and 8 deletions

View File

@ -690,6 +690,11 @@ color.diff.<slot>::
(highlighting whitespace errors). The values of these variables may be
specified as in color.branch.<slot>.
color.decorate.<slot>::
Use customized color for 'git log --decorate' output. `<slot>` is one
of `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local
branches, remote tracking branches, tags, stash and HEAD, respectively.
color.grep::
When set to `always`, always highlight matches. When `false` (or
`never`), never. When set to `true` or `auto`, use color only

View File

@ -296,6 +296,9 @@ static int git_log_config(const char *var, const char *value, void *cb)
default_show_root = git_config_bool(var, value);
return 0;
}
if (!prefixcmp(var, "color.decorate."))
return parse_decorate_color_config(var, 15, value);
return git_diff_ui_config(var, value, cb);
}

View File

@ -28,6 +28,7 @@ extern const char *commit_type;
extern struct decoration name_decoration;
struct name_decoration {
struct name_decoration *next;
int type;
char name[1];
};

View File

@ -7,32 +7,113 @@
#include "reflog-walk.h"
#include "refs.h"
#include "string-list.h"
#include "color.h"
struct decoration name_decoration = { "object names" };
static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
enum decoration_type {
DECORATION_NONE = 0,
DECORATION_REF_LOCAL,
DECORATION_REF_REMOTE,
DECORATION_REF_TAG,
DECORATION_REF_STASH,
DECORATION_REF_HEAD,
};
static char decoration_colors[][COLOR_MAXLEN] = {
GIT_COLOR_RESET,
GIT_COLOR_BOLD_GREEN, /* REF_LOCAL */
GIT_COLOR_BOLD_RED, /* REF_REMOTE */
GIT_COLOR_BOLD_YELLOW, /* REF_TAG */
GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
GIT_COLOR_BOLD_CYAN, /* REF_HEAD */
};
static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
{
if (decorate_use_color)
return decoration_colors[ix];
return "";
}
static int parse_decorate_color_slot(const char *slot)
{
/*
* We're comparing with 'ignore-case' on
* (because config.c sets them all tolower),
* but let's match the letters in the literal
* string values here with how they are
* documented in Documentation/config.txt, for
* consistency.
*
* We love being consistent, don't we?
*/
if (!strcasecmp(slot, "branch"))
return DECORATION_REF_LOCAL;
if (!strcasecmp(slot, "remoteBranch"))
return DECORATION_REF_REMOTE;
if (!strcasecmp(slot, "tag"))
return DECORATION_REF_TAG;
if (!strcasecmp(slot, "stash"))
return DECORATION_REF_STASH;
if (!strcasecmp(slot, "HEAD"))
return DECORATION_REF_HEAD;
return -1;
}
int parse_decorate_color_config(const char *var, const int ofs, const char *value)
{
int slot = parse_decorate_color_slot(var + ofs);
if (slot < 0)
return 0;
if (!value)
return config_error_nonbool(var);
color_parse(value, var, decoration_colors[slot]);
return 0;
}
/*
* log-tree.c uses DIFF_OPT_TST for determining whether to use color
* for showing the commit sha1, use the same check for --decorate
*/
#define decorate_get_color_opt(o, ix) \
decorate_get_color(DIFF_OPT_TST((o), COLOR_DIFF), ix)
static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
{
int plen = strlen(prefix);
int nlen = strlen(name);
struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);
memcpy(res->name, prefix, plen);
memcpy(res->name + plen, name, nlen + 1);
struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
memcpy(res->name, name, nlen + 1);
res->type = type;
res->next = add_decoration(&name_decoration, obj, res);
}
static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct object *obj = parse_object(sha1);
enum decoration_type type = DECORATION_NONE;
if (!obj)
return 0;
if (!prefixcmp(refname, "refs/heads"))
type = DECORATION_REF_LOCAL;
else if (!prefixcmp(refname, "refs/remotes"))
type = DECORATION_REF_REMOTE;
else if (!prefixcmp(refname, "refs/tags"))
type = DECORATION_REF_TAG;
else if (!prefixcmp(refname, "refs/stash"))
type = DECORATION_REF_STASH;
else if (!prefixcmp(refname, "HEAD"))
type = DECORATION_REF_HEAD;
if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
refname = prettify_refname(refname);
add_name_decoration("", refname, obj);
add_name_decoration(type, refname, obj);
while (obj->type == OBJ_TAG) {
obj = ((struct tag *)obj)->tagged;
if (!obj)
break;
add_name_decoration("tag: ", refname, obj);
add_name_decoration(DECORATION_REF_TAG, refname, obj);
}
return 0;
}
@ -60,6 +141,10 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
{
const char *prefix;
struct name_decoration *decoration;
const char *color_commit =
diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
const char *color_reset =
decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
if (opt->show_source && commit->util)
printf("\t%s", (char *) commit->util);
@ -70,7 +155,14 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
return;
prefix = " (";
while (decoration) {
printf("%s%s", prefix, decoration->name);
printf("%s", prefix);
fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
stdout);
if (decoration->type == DECORATION_REF_TAG)
fputs("tag: ", stdout);
printf("%s", decoration->name);
fputs(color_reset, stdout);
fputs(color_commit, stdout);
prefix = ", ";
decoration = decoration->next;
}

View File

@ -7,6 +7,7 @@ struct log_info {
struct commit *commit, *parent;
};
int parse_decorate_color_config(const char *var, const int ofs, const char *value);
void init_log_tree_opt(struct rev_info *);
int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);

View File

@ -0,0 +1,66 @@
#!/bin/sh
#
# Copyright (c) 2010 Nazri Ramliy
#
test_description='Test for "git log --decorate" colors'
. ./test-lib.sh
get_color ()
{
git config --get-color no.such.slot "$1"
}
test_expect_success setup '
git config diff.color.commit yellow &&
git config color.decorate.branch green &&
git config color.decorate.remoteBranch red &&
git config color.decorate.tag "reverse bold yellow" &&
git config color.decorate.stash magenta &&
git config color.decorate.HEAD cyan &&
c_reset=$(get_color reset) &&
c_commit=$(get_color yellow) &&
c_branch=$(get_color green) &&
c_remoteBranch=$(get_color red) &&
c_tag=$(get_color "reverse bold yellow") &&
c_stash=$(get_color magenta) &&
c_HEAD=$(get_color cyan) &&
test_commit A &&
git clone . other &&
(
cd other &&
test_commit A1
) &&
git remote add -f other ./other &&
test_commit B &&
git tag v1.0 &&
echo >>A.t &&
git stash save Changes to A.t
'
cat >expected <<EOF
${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
${c_tag}tag: v1.0${c_reset}${c_commit},\
${c_tag}tag: B${c_reset}${c_commit},\
${c_branch}master${c_reset}${c_commit})${c_reset} B
${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
On master: Changes to A.t
${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
EOF
# We want log to show all, but the second parent to refs/stash is irrelevant
# to this test since it does not contain any decoration, hence --first-parent
test_expect_success 'Commit Decorations Colored Correctly' '
git log --first-parent --abbrev=10 --all --decorate --oneline --color=always |
sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" >out &&
test_cmp expected out
'
test_done