mirror of
https://github.com/git/git.git
synced 2024-11-23 18:05:29 +08:00
Merge branch 'jk/ref-filter-colors' into maint
"%C(color name)" in the pretty print format always produced ANSI color escape codes, which was an early design mistake. They now honor the configuration (e.g. "color.ui = never") and also tty-ness of the output medium. * jk/ref-filter-colors: ref-filter: consult want_color() before emitting colors pretty: respect color settings for %C placeholders rev-list: pass diffopt->use_colors through to pretty-print for-each-ref: load config earlier color: check color.ui in git_default_config() ref-filter: pass ref_format struct to atom parsers ref-filter: factor out the parsing of sorting atoms ref-filter: make parse_ref_filter_atom a private function ref-filter: provide a function for parsing sort options ref-filter: move need_color_reset_at_eol into ref_format ref-filter: abstract ref format into its own struct ref-filter: simplify automatic color reset t: use test_decode_color rather than literal ANSI codes docs/for-each-ref: update pointer to color syntax check return value of verify_ref_format()
This commit is contained in:
commit
447f80f508
@ -156,8 +156,10 @@ HEAD::
|
||||
otherwise.
|
||||
|
||||
color::
|
||||
Change output color. Followed by `:<colorname>`, where names
|
||||
are described in `color.branch.*`.
|
||||
Change output color. Followed by `:<colorname>`, where color
|
||||
names are described under Values in the "CONFIGURATION FILE"
|
||||
section of linkgit:git-config[1]. For example,
|
||||
`%(color:bold red)`.
|
||||
|
||||
align::
|
||||
Left-, middle-, or right-align the content between
|
||||
|
@ -173,13 +173,17 @@ endif::git-rev-list[]
|
||||
- '%Cblue': switch color to blue
|
||||
- '%Creset': reset color
|
||||
- '%C(...)': color specification, as described under Values in the
|
||||
"CONFIGURATION FILE" section of linkgit:git-config[1];
|
||||
adding `auto,` at the beginning (e.g. `%C(auto,red)`) will emit
|
||||
color only when colors are enabled for log output (by `color.diff`,
|
||||
`color.ui`, or `--color`, and respecting the `auto` settings of the
|
||||
former if we are going to a terminal). `auto` alone (i.e.
|
||||
`%C(auto)`) will turn on auto coloring on the next placeholders
|
||||
until the color is switched again.
|
||||
"CONFIGURATION FILE" section of linkgit:git-config[1].
|
||||
By default, colors are shown only when enabled for log output (by
|
||||
`color.diff`, `color.ui`, or `--color`, and respecting the `auto`
|
||||
settings of the former if we are going to a terminal). `%C(auto,...)`
|
||||
is accepted as a historical synonym for the default (e.g.,
|
||||
`%C(auto,red)`). Specifying `%C(always,...) will show the colors
|
||||
even when color is not otherwise enabled (though consider
|
||||
just using `--color=always` to enable color for the whole output,
|
||||
including this format and anything else git might color). `auto`
|
||||
alone (i.e. `%C(auto)`) will turn on auto coloring on the next
|
||||
placeholders until the color is switched again.
|
||||
- '%m': left (`<`), right (`>`) or boundary (`-`) mark
|
||||
- '%n': newline
|
||||
- '%%': a raw '%'
|
||||
|
@ -92,7 +92,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)
|
||||
return config_error_nonbool(var);
|
||||
return color_parse(value, branch_colors[slot]);
|
||||
}
|
||||
return git_color_default_config(var, value, cb);
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static const char *branch_get_color(enum color_branch ix)
|
||||
@ -383,7 +383,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
|
||||
return strbuf_detach(&fmt, NULL);
|
||||
}
|
||||
|
||||
static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
|
||||
static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format)
|
||||
{
|
||||
int i;
|
||||
struct ref_array array;
|
||||
@ -407,14 +407,17 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
|
||||
if (filter->verbose)
|
||||
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
|
||||
|
||||
if (!format)
|
||||
format = to_free = build_format(filter, maxwidth, remote_prefix);
|
||||
verify_ref_format(format);
|
||||
if (!format->format)
|
||||
format->format = to_free = build_format(filter, maxwidth, remote_prefix);
|
||||
format->use_color = branch_use_color;
|
||||
|
||||
if (verify_ref_format(format))
|
||||
die(_("unable to parse format string"));
|
||||
|
||||
ref_array_sort(sorting, &array);
|
||||
|
||||
for (i = 0; i < array.nr; i++) {
|
||||
format_ref_array_item(array.items[i], format, 0, &out);
|
||||
format_ref_array_item(array.items[i], format, &out);
|
||||
if (column_active(colopts)) {
|
||||
assert(!filter->verbose && "--column and --verbose are incompatible");
|
||||
/* format to a string_list to let print_columns() do its job */
|
||||
@ -549,7 +552,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
struct ref_filter filter;
|
||||
int icase = 0;
|
||||
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
const char *format = NULL;
|
||||
struct ref_format format = REF_FORMAT_INIT;
|
||||
|
||||
struct option options[] = {
|
||||
OPT_GROUP(N_("Generic options")),
|
||||
@ -593,7 +596,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
N_("print only branches of the object"), 0, parse_opt_object_name
|
||||
},
|
||||
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
|
||||
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
|
||||
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
@ -667,7 +670,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
sorting->ignore_case = icase;
|
||||
print_ref_list(&filter, sorting, format);
|
||||
print_ref_list(&filter, sorting, &format);
|
||||
print_columns(&output, colopts, NULL);
|
||||
string_list_clear(&output, 0);
|
||||
return 0;
|
||||
|
@ -125,8 +125,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* inspect the color.ui config variable and others */
|
||||
return git_color_default_config(var, value, cb);
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static const char *clean_get_color(enum color_clean ix)
|
||||
|
@ -17,25 +17,25 @@ static char const * const for_each_ref_usage[] = {
|
||||
int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
const char *format = "%(objectname) %(objecttype)\t%(refname)";
|
||||
struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
int maxcount = 0, quote_style = 0, icase = 0;
|
||||
int maxcount = 0, icase = 0;
|
||||
struct ref_array array;
|
||||
struct ref_filter filter;
|
||||
struct ref_format format = REF_FORMAT_INIT;
|
||||
|
||||
struct option opts[] = {
|
||||
OPT_BIT('s', "shell", "e_style,
|
||||
OPT_BIT('s', "shell", &format.quote_style,
|
||||
N_("quote placeholders suitably for shells"), QUOTE_SHELL),
|
||||
OPT_BIT('p', "perl", "e_style,
|
||||
OPT_BIT('p', "perl", &format.quote_style,
|
||||
N_("quote placeholders suitably for perl"), QUOTE_PERL),
|
||||
OPT_BIT(0 , "python", "e_style,
|
||||
OPT_BIT(0 , "python", &format.quote_style,
|
||||
N_("quote placeholders suitably for python"), QUOTE_PYTHON),
|
||||
OPT_BIT(0 , "tcl", "e_style,
|
||||
OPT_BIT(0 , "tcl", &format.quote_style,
|
||||
N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
|
||||
|
||||
OPT_GROUP(""),
|
||||
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
|
||||
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
|
||||
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
|
||||
OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
|
||||
N_("field name to sort on"), &parse_opt_ref_sorting),
|
||||
OPT_CALLBACK(0, "points-at", &filter.points_at,
|
||||
@ -52,16 +52,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
memset(&array, 0, sizeof(array));
|
||||
memset(&filter, 0, sizeof(filter));
|
||||
|
||||
format.format = "%(objectname) %(objecttype)\t%(refname)";
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
|
||||
if (maxcount < 0) {
|
||||
error("invalid --count argument: `%d'", maxcount);
|
||||
usage_with_options(for_each_ref_usage, opts);
|
||||
}
|
||||
if (HAS_MULTI_BITS(quote_style)) {
|
||||
if (HAS_MULTI_BITS(format.quote_style)) {
|
||||
error("more than one quoting style?");
|
||||
usage_with_options(for_each_ref_usage, opts);
|
||||
}
|
||||
if (verify_ref_format(format))
|
||||
if (verify_ref_format(&format))
|
||||
usage_with_options(for_each_ref_usage, opts);
|
||||
|
||||
if (!sorting)
|
||||
@ -69,9 +73,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
sorting->ignore_case = icase;
|
||||
filter.ignore_case = icase;
|
||||
|
||||
/* for warn_ambiguous_refs */
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
filter.name_patterns = argv;
|
||||
filter.match_as_path = 1;
|
||||
filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
|
||||
@ -80,7 +81,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||
if (!maxcount || array.nr < maxcount)
|
||||
maxcount = array.nr;
|
||||
for (i = 0; i < maxcount; i++)
|
||||
show_ref_array_item(array.items[i], format, quote_style);
|
||||
show_ref_array_item(array.items[i], &format);
|
||||
ref_array_clear(&array);
|
||||
return 0;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ static int wait_all(void)
|
||||
static int grep_cmd_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
int st = grep_config(var, value, cb);
|
||||
if (git_color_default_config(var, value, cb) < 0)
|
||||
if (git_default_config(var, value, cb) < 0)
|
||||
st = -1;
|
||||
|
||||
if (!strcmp(var, "grep.threads")) {
|
||||
|
@ -122,6 +122,7 @@ static void show_commit(struct commit *commit, void *data)
|
||||
ctx.date_mode_explicit = revs->date_mode_explicit;
|
||||
ctx.fmt = revs->commit_format;
|
||||
ctx.output_encoding = get_log_output_encoding();
|
||||
ctx.color = revs->diffopt.use_color;
|
||||
pretty_print_commit(&ctx, commit, &buf);
|
||||
if (buf.len) {
|
||||
if (revs->commit_format != CMIT_FMT_ONELINE)
|
||||
|
@ -554,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_color_default_config(var, value, cb);
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
|
||||
|
@ -32,7 +32,8 @@ static const char * const git_tag_usage[] = {
|
||||
static unsigned int colopts;
|
||||
static int force_sign_annotate;
|
||||
|
||||
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
|
||||
static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
|
||||
struct ref_format *format)
|
||||
{
|
||||
struct ref_array array;
|
||||
char *to_free = NULL;
|
||||
@ -43,23 +44,24 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
|
||||
if (filter->lines == -1)
|
||||
filter->lines = 0;
|
||||
|
||||
if (!format) {
|
||||
if (!format->format) {
|
||||
if (filter->lines) {
|
||||
to_free = xstrfmt("%s %%(contents:lines=%d)",
|
||||
"%(align:15)%(refname:lstrip=2)%(end)",
|
||||
filter->lines);
|
||||
format = to_free;
|
||||
format->format = to_free;
|
||||
} else
|
||||
format = "%(refname:lstrip=2)";
|
||||
format->format = "%(refname:lstrip=2)";
|
||||
}
|
||||
|
||||
verify_ref_format(format);
|
||||
if (verify_ref_format(format))
|
||||
die(_("unable to parse format string"));
|
||||
filter->with_commit_tag_algo = 1;
|
||||
filter_refs(&array, filter, FILTER_REFS_TAGS);
|
||||
ref_array_sort(sorting, &array);
|
||||
|
||||
for (i = 0; i < array.nr; i++)
|
||||
show_ref_array_item(array.items[i], format, 0);
|
||||
show_ref_array_item(array.items[i], format);
|
||||
ref_array_clear(&array);
|
||||
free(to_free);
|
||||
|
||||
@ -105,17 +107,17 @@ static int verify_tag(const char *name, const char *ref,
|
||||
const struct object_id *oid, const void *cb_data)
|
||||
{
|
||||
int flags;
|
||||
const char *fmt_pretty = cb_data;
|
||||
const struct ref_format *format = cb_data;
|
||||
flags = GPG_VERIFY_VERBOSE;
|
||||
|
||||
if (fmt_pretty)
|
||||
if (format->format)
|
||||
flags = GPG_VERIFY_OMIT_STATUS;
|
||||
|
||||
if (gpg_verify_tag(oid->hash, name, flags))
|
||||
return -1;
|
||||
|
||||
if (fmt_pretty)
|
||||
pretty_print_ref(name, oid->hash, fmt_pretty);
|
||||
if (format->format)
|
||||
pretty_print_ref(name, oid->hash, format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -134,30 +136,6 @@ static const char tag_template_nocleanup[] =
|
||||
"Lines starting with '%c' will be kept; you may remove them"
|
||||
" yourself if you want to.\n");
|
||||
|
||||
/* Parse arg given and add it the ref_sorting array */
|
||||
static int parse_sorting_string(const char *arg, struct ref_sorting **sorting_tail)
|
||||
{
|
||||
struct ref_sorting *s;
|
||||
int len;
|
||||
|
||||
s = xcalloc(1, sizeof(*s));
|
||||
s->next = *sorting_tail;
|
||||
*sorting_tail = s;
|
||||
|
||||
if (*arg == '-') {
|
||||
s->reverse = 1;
|
||||
arg++;
|
||||
}
|
||||
if (skip_prefix(arg, "version:", &arg) ||
|
||||
skip_prefix(arg, "v:", &arg))
|
||||
s->version = 1;
|
||||
|
||||
len = strlen(arg);
|
||||
s->atom = parse_ref_filter_atom(arg, arg+len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int git_tag_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
int status;
|
||||
@ -166,7 +144,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
|
||||
if (!strcmp(var, "tag.sort")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
parse_sorting_string(value, sorting_tail);
|
||||
parse_ref_sorting(sorting_tail, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -392,7 +370,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct ref_filter filter;
|
||||
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
const char *format = NULL;
|
||||
struct ref_format format = REF_FORMAT_INIT;
|
||||
int icase = 0;
|
||||
struct option options[] = {
|
||||
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
|
||||
@ -431,7 +409,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
|
||||
parse_opt_object_name, (intptr_t) "HEAD"
|
||||
},
|
||||
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
|
||||
OPT_STRING( 0 , "format", &format.format, N_("format"),
|
||||
N_("format to use for the output")),
|
||||
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
|
||||
OPT_END()
|
||||
};
|
||||
@ -483,7 +462,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
run_column_filter(colopts, &copts);
|
||||
}
|
||||
filter.name_patterns = argv;
|
||||
ret = list_tags(&filter, sorting, format);
|
||||
ret = list_tags(&filter, sorting, &format);
|
||||
if (column_active(colopts))
|
||||
stop_column_filter();
|
||||
return ret;
|
||||
@ -501,9 +480,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
if (cmdmode == 'd')
|
||||
return for_each_tag_name(argv, delete_tag, NULL);
|
||||
if (cmdmode == 'v') {
|
||||
if (format)
|
||||
verify_ref_format(format);
|
||||
return for_each_tag_name(argv, verify_tag, format);
|
||||
if (format.format && verify_ref_format(&format))
|
||||
usage_with_options(git_tag_usage, options);
|
||||
return for_each_tag_name(argv, verify_tag, &format);
|
||||
}
|
||||
|
||||
if (msg.given || msgfile) {
|
||||
|
@ -32,11 +32,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i = 1, verbose = 0, had_error = 0;
|
||||
unsigned flags = 0;
|
||||
char *fmt_pretty = NULL;
|
||||
struct ref_format format = REF_FORMAT_INIT;
|
||||
const struct option verify_tag_options[] = {
|
||||
OPT__VERBOSE(&verbose, N_("print tag contents")),
|
||||
OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
|
||||
OPT_STRING( 0 , "format", &fmt_pretty, N_("format"), N_("format to use for the output")),
|
||||
OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -50,8 +50,10 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
|
||||
if (verbose)
|
||||
flags |= GPG_VERIFY_VERBOSE;
|
||||
|
||||
if (fmt_pretty) {
|
||||
verify_ref_format(fmt_pretty);
|
||||
if (format.format) {
|
||||
if (verify_ref_format(&format))
|
||||
usage_with_options(verify_tag_usage,
|
||||
verify_tag_options);
|
||||
flags |= GPG_VERIFY_OMIT_STATUS;
|
||||
}
|
||||
|
||||
@ -68,8 +70,8 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fmt_pretty)
|
||||
pretty_print_ref(name, sha1, fmt_pretty);
|
||||
if (format.format)
|
||||
pretty_print_ref(name, sha1, &format);
|
||||
}
|
||||
return had_error;
|
||||
}
|
||||
|
8
color.c
8
color.c
@ -361,14 +361,6 @@ int git_color_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_color_default_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (git_color_config(var, value, cb) < 0)
|
||||
return -1;
|
||||
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
|
||||
{
|
||||
if (*color)
|
||||
|
4
config.c
4
config.c
@ -16,6 +16,7 @@
|
||||
#include "string-list.h"
|
||||
#include "utf8.h"
|
||||
#include "dir.h"
|
||||
#include "color.h"
|
||||
|
||||
struct config_source {
|
||||
struct config_source *prev;
|
||||
@ -1350,6 +1351,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
|
||||
if (starts_with(var, "advice."))
|
||||
return git_default_advice_config(var, value);
|
||||
|
||||
if (git_color_config(var, value, dummy) < 0)
|
||||
return -1;
|
||||
|
||||
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
|
||||
pager_use_color = git_config_bool(var,value);
|
||||
return 0;
|
||||
|
3
diff.c
3
diff.c
@ -299,9 +299,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (git_color_config(var, value, cb) < 0)
|
||||
return -1;
|
||||
|
||||
return git_diff_basic_config(var, value, cb);
|
||||
}
|
||||
|
||||
|
27
pretty.c
27
pretty.c
@ -947,6 +947,7 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
|
||||
struct format_commit_context *c)
|
||||
{
|
||||
const char *rest = placeholder;
|
||||
const char *basic_color = NULL;
|
||||
|
||||
if (placeholder[1] == '(') {
|
||||
const char *begin = placeholder + 2;
|
||||
@ -955,23 +956,41 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
|
||||
|
||||
if (!end)
|
||||
return 0;
|
||||
|
||||
if (skip_prefix(begin, "auto,", &begin)) {
|
||||
if (!want_color(c->pretty_ctx->color))
|
||||
return end - placeholder + 1;
|
||||
} else if (skip_prefix(begin, "always,", &begin)) {
|
||||
/* nothing to do; we do not respect want_color at all */
|
||||
} else {
|
||||
/* the default is the same as "auto" */
|
||||
if (!want_color(c->pretty_ctx->color))
|
||||
return end - placeholder + 1;
|
||||
}
|
||||
|
||||
if (color_parse_mem(begin, end - begin, color) < 0)
|
||||
die(_("unable to parse --pretty format"));
|
||||
strbuf_addstr(sb, color);
|
||||
return end - placeholder + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle things like "%C(red)" above; for historical reasons, there
|
||||
* are a few colors that can be specified without parentheses (and
|
||||
* they cannot support things like "auto" or "always" at all).
|
||||
*/
|
||||
if (skip_prefix(placeholder + 1, "red", &rest))
|
||||
strbuf_addstr(sb, GIT_COLOR_RED);
|
||||
basic_color = GIT_COLOR_RED;
|
||||
else if (skip_prefix(placeholder + 1, "green", &rest))
|
||||
strbuf_addstr(sb, GIT_COLOR_GREEN);
|
||||
basic_color = GIT_COLOR_GREEN;
|
||||
else if (skip_prefix(placeholder + 1, "blue", &rest))
|
||||
strbuf_addstr(sb, GIT_COLOR_BLUE);
|
||||
basic_color = GIT_COLOR_BLUE;
|
||||
else if (skip_prefix(placeholder + 1, "reset", &rest))
|
||||
strbuf_addstr(sb, GIT_COLOR_RESET);
|
||||
basic_color = GIT_COLOR_RESET;
|
||||
|
||||
if (basic_color && want_color(c->pretty_ctx->color))
|
||||
strbuf_addstr(sb, basic_color);
|
||||
|
||||
return rest - placeholder;
|
||||
}
|
||||
|
||||
|
108
ref-filter.c
108
ref-filter.c
@ -97,14 +97,19 @@ static struct used_atom {
|
||||
} u;
|
||||
} *used_atom;
|
||||
static int used_atom_cnt, need_tagged, need_symref;
|
||||
static int need_color_reset_at_eol;
|
||||
|
||||
static void color_atom_parser(struct used_atom *atom, const char *color_value)
|
||||
static void color_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *color_value)
|
||||
{
|
||||
if (!color_value)
|
||||
die(_("expected format: %%(color:<color>)"));
|
||||
if (color_parse(color_value, atom->u.color) < 0)
|
||||
die(_("unrecognized color: %%(color:%s)"), color_value);
|
||||
/*
|
||||
* We check this after we've parsed the color, which lets us complain
|
||||
* about syntactically bogus color names even if they won't be used.
|
||||
*/
|
||||
if (!want_color(format->use_color))
|
||||
color_parse("", atom->u.color);
|
||||
}
|
||||
|
||||
static void refname_atom_parser_internal(struct refname_atom *atom,
|
||||
@ -127,7 +132,7 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
|
||||
die(_("unrecognized %%(%s) argument: %s"), name, arg);
|
||||
}
|
||||
|
||||
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
struct string_list params = STRING_LIST_INIT_DUP;
|
||||
int i;
|
||||
@ -161,28 +166,28 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
|
||||
string_list_clear(¶ms, 0);
|
||||
}
|
||||
|
||||
static void body_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void body_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (arg)
|
||||
die(_("%%(body) does not take arguments"));
|
||||
atom->u.contents.option = C_BODY_DEP;
|
||||
}
|
||||
|
||||
static void subject_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void subject_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (arg)
|
||||
die(_("%%(subject) does not take arguments"));
|
||||
atom->u.contents.option = C_SUB;
|
||||
}
|
||||
|
||||
static void trailers_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void trailers_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (arg)
|
||||
die(_("%%(trailers) does not take arguments"));
|
||||
atom->u.contents.option = C_TRAILERS;
|
||||
}
|
||||
|
||||
static void contents_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void contents_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (!arg)
|
||||
atom->u.contents.option = C_BARE;
|
||||
@ -202,7 +207,7 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
|
||||
die(_("unrecognized %%(contents) argument: %s"), arg);
|
||||
}
|
||||
|
||||
static void objectname_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void objectname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (!arg)
|
||||
atom->u.objectname.option = O_FULL;
|
||||
@ -219,7 +224,7 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
|
||||
die(_("unrecognized %%(objectname) argument: %s"), arg);
|
||||
}
|
||||
|
||||
static void refname_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void refname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
|
||||
}
|
||||
@ -235,7 +240,7 @@ static align_type parse_align_position(const char *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void align_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void align_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
struct align *align = &atom->u.align;
|
||||
struct string_list params = STRING_LIST_INIT_DUP;
|
||||
@ -274,7 +279,7 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
|
||||
string_list_clear(¶ms, 0);
|
||||
}
|
||||
|
||||
static void if_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void if_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
if (!arg) {
|
||||
atom->u.if_then_else.cmp_status = COMPARE_NONE;
|
||||
@ -288,7 +293,7 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void head_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static void head_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
|
||||
{
|
||||
struct object_id unused;
|
||||
|
||||
@ -298,7 +303,7 @@ static void head_atom_parser(struct used_atom *atom, const char *arg)
|
||||
static struct {
|
||||
const char *name;
|
||||
cmp_type cmp_type;
|
||||
void (*parser)(struct used_atom *atom, const char *arg);
|
||||
void (*parser)(const struct ref_format *format, struct used_atom *atom, const char *arg);
|
||||
} valid_atom[] = {
|
||||
{ "refname" , FIELD_STR, refname_atom_parser },
|
||||
{ "objecttype" },
|
||||
@ -365,7 +370,8 @@ struct atom_value {
|
||||
/*
|
||||
* Used to parse format string and sort specifiers
|
||||
*/
|
||||
int parse_ref_filter_atom(const char *atom, const char *ep)
|
||||
static int parse_ref_filter_atom(const struct ref_format *format,
|
||||
const char *atom, const char *ep)
|
||||
{
|
||||
const char *sp;
|
||||
const char *arg;
|
||||
@ -413,7 +419,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
|
||||
arg = used_atom[at].name + (arg - atom) + 1;
|
||||
memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
|
||||
if (valid_atom[i].parser)
|
||||
valid_atom[i].parser(&used_atom[at], arg);
|
||||
valid_atom[i].parser(format, &used_atom[at], arg);
|
||||
if (*atom == '*')
|
||||
need_tagged = 1;
|
||||
if (!strcmp(valid_atom[i].name, "symref"))
|
||||
@ -657,24 +663,26 @@ static const char *find_next(const char *cp)
|
||||
* Make sure the format string is well formed, and parse out
|
||||
* the used atoms.
|
||||
*/
|
||||
int verify_ref_format(const char *format)
|
||||
int verify_ref_format(struct ref_format *format)
|
||||
{
|
||||
const char *cp, *sp;
|
||||
|
||||
need_color_reset_at_eol = 0;
|
||||
for (cp = format; *cp && (sp = find_next(cp)); ) {
|
||||
format->need_color_reset_at_eol = 0;
|
||||
for (cp = format->format; *cp && (sp = find_next(cp)); ) {
|
||||
const char *color, *ep = strchr(sp, ')');
|
||||
int at;
|
||||
|
||||
if (!ep)
|
||||
return error(_("malformed format string %s"), sp);
|
||||
/* sp points at "%(" and ep points at the closing ")" */
|
||||
at = parse_ref_filter_atom(sp + 2, ep);
|
||||
at = parse_ref_filter_atom(format, sp + 2, ep);
|
||||
cp = ep + 1;
|
||||
|
||||
if (skip_prefix(used_atom[at].name, "color:", &color))
|
||||
need_color_reset_at_eol = !!strcmp(color, "reset");
|
||||
format->need_color_reset_at_eol = !!strcmp(color, "reset");
|
||||
}
|
||||
if (format->need_color_reset_at_eol && !want_color(format->use_color))
|
||||
format->need_color_reset_at_eol = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2060,35 +2068,34 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
|
||||
}
|
||||
}
|
||||
|
||||
void format_ref_array_item(struct ref_array_item *info, const char *format,
|
||||
int quote_style, struct strbuf *final_buf)
|
||||
void format_ref_array_item(struct ref_array_item *info,
|
||||
const struct ref_format *format,
|
||||
struct strbuf *final_buf)
|
||||
{
|
||||
const char *cp, *sp, *ep;
|
||||
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
|
||||
|
||||
state.quote_style = quote_style;
|
||||
state.quote_style = format->quote_style;
|
||||
push_stack_element(&state.stack);
|
||||
|
||||
for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
|
||||
for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
|
||||
struct atom_value *atomv;
|
||||
|
||||
ep = strchr(sp, ')');
|
||||
if (cp < sp)
|
||||
append_literal(cp, sp, &state);
|
||||
get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
|
||||
get_ref_atom_value(info,
|
||||
parse_ref_filter_atom(format, sp + 2, ep),
|
||||
&atomv);
|
||||
atomv->handler(atomv, &state);
|
||||
}
|
||||
if (*cp) {
|
||||
sp = cp + strlen(cp);
|
||||
append_literal(cp, sp, &state);
|
||||
}
|
||||
if (need_color_reset_at_eol) {
|
||||
if (format->need_color_reset_at_eol) {
|
||||
struct atom_value resetv;
|
||||
char color[COLOR_MAXLEN] = "";
|
||||
|
||||
if (color_parse("reset", color) < 0)
|
||||
die("BUG: couldn't parse 'reset' as a color");
|
||||
resetv.s = color;
|
||||
resetv.s = GIT_COLOR_RESET;
|
||||
append_atom(&resetv, &state);
|
||||
}
|
||||
if (state.stack->prev)
|
||||
@ -2097,26 +2104,38 @@ void format_ref_array_item(struct ref_array_item *info, const char *format,
|
||||
pop_stack_element(&state.stack);
|
||||
}
|
||||
|
||||
void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
|
||||
void show_ref_array_item(struct ref_array_item *info,
|
||||
const struct ref_format *format)
|
||||
{
|
||||
struct strbuf final_buf = STRBUF_INIT;
|
||||
|
||||
format_ref_array_item(info, format, quote_style, &final_buf);
|
||||
format_ref_array_item(info, format, &final_buf);
|
||||
fwrite(final_buf.buf, 1, final_buf.len, stdout);
|
||||
strbuf_release(&final_buf);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void pretty_print_ref(const char *name, const unsigned char *sha1,
|
||||
const char *format)
|
||||
const struct ref_format *format)
|
||||
{
|
||||
struct ref_array_item *ref_item;
|
||||
ref_item = new_ref_array_item(name, sha1, 0);
|
||||
ref_item->kind = ref_kind_from_refname(name);
|
||||
show_ref_array_item(ref_item, format, 0);
|
||||
show_ref_array_item(ref_item, format);
|
||||
free_array_item(ref_item);
|
||||
}
|
||||
|
||||
static int parse_sorting_atom(const char *atom)
|
||||
{
|
||||
/*
|
||||
* This parses an atom using a dummy ref_format, since we don't
|
||||
* actually care about the formatting details.
|
||||
*/
|
||||
struct ref_format dummy = REF_FORMAT_INIT;
|
||||
const char *end = atom + strlen(atom);
|
||||
return parse_ref_filter_atom(&dummy, atom, end);
|
||||
}
|
||||
|
||||
/* If no sorting option is given, use refname to sort as default */
|
||||
struct ref_sorting *ref_default_sorting(void)
|
||||
{
|
||||
@ -2125,18 +2144,13 @@ struct ref_sorting *ref_default_sorting(void)
|
||||
struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
|
||||
|
||||
sorting->next = NULL;
|
||||
sorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));
|
||||
sorting->atom = parse_sorting_atom(cstr_name);
|
||||
return sorting;
|
||||
}
|
||||
|
||||
int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
|
||||
void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
|
||||
{
|
||||
struct ref_sorting **sorting_tail = opt->value;
|
||||
struct ref_sorting *s;
|
||||
int len;
|
||||
|
||||
if (!arg) /* should --no-sort void the list ? */
|
||||
return -1;
|
||||
|
||||
s = xcalloc(1, sizeof(*s));
|
||||
s->next = *sorting_tail;
|
||||
@ -2149,8 +2163,14 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
|
||||
if (skip_prefix(arg, "version:", &arg) ||
|
||||
skip_prefix(arg, "v:", &arg))
|
||||
s->version = 1;
|
||||
len = strlen(arg);
|
||||
s->atom = parse_ref_filter_atom(arg, arg+len);
|
||||
s->atom = parse_sorting_atom(arg);
|
||||
}
|
||||
|
||||
int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
if (!arg) /* should --no-sort void the list ? */
|
||||
return -1;
|
||||
parse_ref_sorting(opt->value, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
30
ref-filter.h
30
ref-filter.h
@ -72,6 +72,21 @@ struct ref_filter {
|
||||
verbose;
|
||||
};
|
||||
|
||||
struct ref_format {
|
||||
/*
|
||||
* Set these to define the format; make sure you call
|
||||
* verify_ref_format() afterwards to finalize.
|
||||
*/
|
||||
const char *format;
|
||||
int quote_style;
|
||||
int use_color;
|
||||
|
||||
/* Internal state to ref-filter */
|
||||
int need_color_reset_at_eol;
|
||||
};
|
||||
|
||||
#define REF_FORMAT_INIT { NULL, 0, -1 }
|
||||
|
||||
/* Macros for checking --merged and --no-merged options */
|
||||
#define _OPT_MERGED_NO_MERGED(option, filter, h) \
|
||||
{ OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \
|
||||
@ -90,17 +105,18 @@ struct ref_filter {
|
||||
int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);
|
||||
/* Clear all memory allocated to ref_array */
|
||||
void ref_array_clear(struct ref_array *array);
|
||||
/* Parse format string and sort specifiers */
|
||||
int parse_ref_filter_atom(const char *atom, const char *ep);
|
||||
/* Used to verify if the given format is correct and to parse out the used atoms */
|
||||
int verify_ref_format(const char *format);
|
||||
int verify_ref_format(struct ref_format *format);
|
||||
/* Sort the given ref_array as per the ref_sorting provided */
|
||||
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
|
||||
/* Based on the given format and quote_style, fill the strbuf */
|
||||
void format_ref_array_item(struct ref_array_item *info, const char *format,
|
||||
int quote_style, struct strbuf *final_buf);
|
||||
void format_ref_array_item(struct ref_array_item *info,
|
||||
const struct ref_format *format,
|
||||
struct strbuf *final_buf);
|
||||
/* Print the ref using the given format and quote_style */
|
||||
void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);
|
||||
void show_ref_array_item(struct ref_array_item *info, const struct ref_format *format);
|
||||
/* Parse a single sort specifier and add it to the list */
|
||||
void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *atom);
|
||||
/* Callback function for parsing the sort option */
|
||||
int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
|
||||
/* Default sort option based on refname */
|
||||
@ -117,6 +133,6 @@ void setup_ref_filter_porcelain_msg(void);
|
||||
* name must be a fully qualified refname.
|
||||
*/
|
||||
void pretty_print_ref(const char *name, const unsigned char *sha1,
|
||||
const char *format);
|
||||
const struct ref_format *format);
|
||||
|
||||
#endif /* REF_FILTER_H */
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
test_description='git branch display tests'
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-terminal.sh
|
||||
|
||||
test_expect_success 'make commits' '
|
||||
echo content >file &&
|
||||
@ -239,4 +240,34 @@ test_expect_success 'git branch --format option' '
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "set up color tests" '
|
||||
echo "<RED>master<RESET>" >expect.color &&
|
||||
echo "master" >expect.bare &&
|
||||
color_args="--format=%(color:red)%(refname:short) --list master"
|
||||
'
|
||||
|
||||
test_expect_success '%(color) omitted without tty' '
|
||||
TERM=vt100 git branch $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.bare actual
|
||||
'
|
||||
|
||||
test_expect_success TTY '%(color) present with tty' '
|
||||
test_terminal env TERM=vt100 git branch $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.color actual
|
||||
'
|
||||
|
||||
test_expect_success 'color.branch=always overrides auto-color' '
|
||||
git -c color.branch=always branch $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.color actual
|
||||
'
|
||||
|
||||
test_expect_success '--color overrides auto-color' '
|
||||
git branch --color $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.color actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -7,11 +7,6 @@ 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 &&
|
||||
@ -20,14 +15,14 @@ test_expect_success setup '
|
||||
git config color.decorate.stash magenta &&
|
||||
git config color.decorate.HEAD cyan &&
|
||||
|
||||
c_reset=$(get_color reset) &&
|
||||
c_reset="<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) &&
|
||||
c_commit="<YELLOW>" &&
|
||||
c_branch="<GREEN>" &&
|
||||
c_remoteBranch="<RED>" &&
|
||||
c_tag="<BOLD;REVERSE;YELLOW>" &&
|
||||
c_stash="<MAGENTA>" &&
|
||||
c_HEAD="<CYAN>" &&
|
||||
|
||||
test_commit A &&
|
||||
git clone . other &&
|
||||
@ -59,7 +54,8 @@ EOF
|
||||
# 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 &&
|
||||
sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" |
|
||||
test_decode_color >out &&
|
||||
test_cmp expected out
|
||||
'
|
||||
|
||||
|
@ -59,10 +59,14 @@ test_format () {
|
||||
}
|
||||
|
||||
# Feed to --format to provide predictable colored sequences.
|
||||
BASIC_COLOR='%Credfoo%Creset'
|
||||
COLOR='%C(red)foo%C(reset)'
|
||||
AUTO_COLOR='%C(auto,red)foo%C(auto,reset)'
|
||||
ALWAYS_COLOR='%C(always,red)foo%C(always,reset)'
|
||||
has_color () {
|
||||
printf '\033[31mfoo\033[m\n' >expect &&
|
||||
test_cmp expect "$1"
|
||||
test_decode_color <"$1" >decoded &&
|
||||
echo "<RED>foo<RESET>" >expect &&
|
||||
test_cmp expect decoded
|
||||
}
|
||||
|
||||
has_no_color () {
|
||||
@ -170,62 +174,84 @@ $added
|
||||
|
||||
EOF
|
||||
|
||||
test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF
|
||||
commit $head2
|
||||
[31mfoo[32mbar[34mbaz[mxyzzy
|
||||
commit $head1
|
||||
[31mfoo[32mbar[34mbaz[mxyzzy
|
||||
EOF
|
||||
|
||||
test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF
|
||||
commit $head2
|
||||
[1;31;43mfoo[m
|
||||
commit $head1
|
||||
[1;31;43mfoo[m
|
||||
EOF
|
||||
|
||||
test_expect_success '%C(auto,...) does not enable color by default' '
|
||||
git log --format=$AUTO_COLOR -1 >actual &&
|
||||
has_no_color actual
|
||||
test_expect_success 'basic colors' '
|
||||
cat >expect <<-EOF &&
|
||||
commit $head2
|
||||
<RED>foo<GREEN>bar<BLUE>baz<RESET>xyzzy
|
||||
EOF
|
||||
format="%Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy" &&
|
||||
git rev-list --color --format="$format" -1 master >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto,...) enables colors for color.diff' '
|
||||
git -c color.diff=always log --format=$AUTO_COLOR -1 >actual &&
|
||||
has_color actual
|
||||
test_expect_success 'advanced colors' '
|
||||
cat >expect <<-EOF &&
|
||||
commit $head2
|
||||
<BOLD;RED;BYELLOW>foo<RESET>
|
||||
EOF
|
||||
format="%C(red yellow bold)foo%C(reset)" &&
|
||||
git rev-list --color --format="$format" -1 master >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto,...) enables colors for color.ui' '
|
||||
git -c color.ui=always log --format=$AUTO_COLOR -1 >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto,...) respects --color' '
|
||||
git log --format=$AUTO_COLOR -1 --color >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto,...) respects --no-color' '
|
||||
git -c color.ui=always log --format=$AUTO_COLOR -1 --no-color >actual &&
|
||||
has_no_color actual
|
||||
'
|
||||
|
||||
test_expect_success TTY '%C(auto,...) respects --color=auto (stdout is tty)' '
|
||||
test_terminal env TERM=vt100 \
|
||||
git log --format=$AUTO_COLOR -1 --color=auto >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto,...) respects --color=auto (stdout not tty)' '
|
||||
(
|
||||
TERM=vt100 && export TERM &&
|
||||
git log --format=$AUTO_COLOR -1 --color=auto >actual &&
|
||||
for spec in \
|
||||
"%Cred:$BASIC_COLOR" \
|
||||
"%C(...):$COLOR" \
|
||||
"%C(auto,...):$AUTO_COLOR"
|
||||
do
|
||||
desc=${spec%%:*}
|
||||
color=${spec#*:}
|
||||
test_expect_success "$desc does not enable color by default" '
|
||||
git log --format=$color -1 >actual &&
|
||||
has_no_color actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success "$desc enables colors for color.diff" '
|
||||
git -c color.diff=always log --format=$color -1 >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success "$desc enables colors for color.ui" '
|
||||
git -c color.ui=always log --format=$color -1 >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success "$desc respects --color" '
|
||||
git log --format=$color -1 --color >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success "$desc respects --no-color" '
|
||||
git -c color.ui=always log --format=$color -1 --no-color >actual &&
|
||||
has_no_color actual
|
||||
'
|
||||
|
||||
test_expect_success TTY "$desc respects --color=auto (stdout is tty)" '
|
||||
test_terminal env TERM=vt100 \
|
||||
git log --format=$color -1 --color=auto >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success "$desc respects --color=auto (stdout not tty)" '
|
||||
(
|
||||
TERM=vt100 && export TERM &&
|
||||
git log --format=$color -1 --color=auto >actual &&
|
||||
has_no_color actual
|
||||
)
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success '%C(always,...) enables color even without tty' '
|
||||
git log --format=$ALWAYS_COLOR -1 >actual &&
|
||||
has_color actual
|
||||
'
|
||||
|
||||
test_expect_success '%C(auto) respects --color' '
|
||||
git log --color --format="%C(auto)%H" -1 >actual &&
|
||||
printf "\\033[33m%s\\033[m\\n" $(git rev-parse HEAD) >expect &&
|
||||
git log --color --format="%C(auto)%H" -1 >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
echo "<YELLOW>$(git rev-parse HEAD)<RESET>" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
@ -235,6 +261,17 @@ test_expect_success '%C(auto) respects --no-color' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'rev-list %C(auto,...) respects --color' '
|
||||
git rev-list --color --format="%C(auto,green)foo%C(auto,reset)" \
|
||||
-1 HEAD >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
cat >expect <<-EOF &&
|
||||
commit $(git rev-parse HEAD)
|
||||
<GREEN>foo<RESET>
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
iconv -f utf-8 -t $test_encoding > commit-msg <<EOF
|
||||
Test printing of complex bodies
|
||||
|
||||
|
@ -7,6 +7,7 @@ test_description='for-each-ref test'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-gpg.sh
|
||||
. "$TEST_DIRECTORY"/lib-terminal.sh
|
||||
|
||||
# Mon Jul 3 23:18:43 2006 +0000
|
||||
datestamp=1151968723
|
||||
@ -412,21 +413,33 @@ test_expect_success 'Check for invalid refname format' '
|
||||
test_must_fail git for-each-ref --format="%(refname:INVALID)"
|
||||
'
|
||||
|
||||
get_color ()
|
||||
{
|
||||
git config --get-color no.such.slot "$1"
|
||||
}
|
||||
test_expect_success 'set up color tests' '
|
||||
cat >expected.color <<-EOF &&
|
||||
$(git rev-parse --short refs/heads/master) <GREEN>master<RESET>
|
||||
$(git rev-parse --short refs/remotes/origin/master) <GREEN>origin/master<RESET>
|
||||
$(git rev-parse --short refs/tags/testtag) <GREEN>testtag<RESET>
|
||||
$(git rev-parse --short refs/tags/two) <GREEN>two<RESET>
|
||||
EOF
|
||||
sed "s/<[^>]*>//g" <expected.color >expected.bare &&
|
||||
color_format="%(objectname:short) %(color:green)%(refname:short)"
|
||||
'
|
||||
|
||||
cat >expected <<EOF
|
||||
$(git rev-parse --short refs/heads/master) $(get_color green)master$(get_color reset)
|
||||
$(git rev-parse --short refs/remotes/origin/master) $(get_color green)origin/master$(get_color reset)
|
||||
$(git rev-parse --short refs/tags/testtag) $(get_color green)testtag$(get_color reset)
|
||||
$(git rev-parse --short refs/tags/two) $(get_color green)two$(get_color reset)
|
||||
EOF
|
||||
test_expect_success TTY '%(color) shows color with a tty' '
|
||||
test_terminal env TERM=vt100 \
|
||||
git for-each-ref --format="$color_format" >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expected.color actual
|
||||
'
|
||||
|
||||
test_expect_success 'Check %(color:...) ' '
|
||||
git for-each-ref --format="%(objectname:short) %(color:green)%(refname:short)" >actual &&
|
||||
test_cmp expected actual
|
||||
test_expect_success '%(color) does not show color without tty' '
|
||||
TERM=vt100 git for-each-ref --format="$color_format" >actual &&
|
||||
test_cmp expected.bare actual
|
||||
'
|
||||
|
||||
test_expect_success 'color.ui=always can override tty check' '
|
||||
git -c color.ui=always for-each-ref --format="$color_format" >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expected.color actual
|
||||
'
|
||||
|
||||
cat >expected <<\EOF
|
||||
|
@ -9,6 +9,7 @@ Tests for operations with tags.'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-gpg.sh
|
||||
. "$TEST_DIRECTORY"/lib-terminal.sh
|
||||
|
||||
# creating and listing lightweight tags:
|
||||
|
||||
@ -1900,6 +1901,30 @@ test_expect_success '--format should list tags as per format given' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "set up color tests" '
|
||||
echo "<RED>v1.0<RESET>" >expect.color &&
|
||||
echo "v1.0" >expect.bare &&
|
||||
color_args="--format=%(color:red)%(refname:short) --list v1.0"
|
||||
'
|
||||
|
||||
test_expect_success '%(color) omitted without tty' '
|
||||
TERM=vt100 git tag $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.bare actual
|
||||
'
|
||||
|
||||
test_expect_success TTY '%(color) present with tty' '
|
||||
test_terminal env TERM=vt100 git tag $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.color actual
|
||||
'
|
||||
|
||||
test_expect_success 'color.ui=always overrides auto-color' '
|
||||
git -c color.ui=always tag $color_args >actual.raw &&
|
||||
test_decode_color <actual.raw >actual &&
|
||||
test_cmp expect.color actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup --merged test tags' '
|
||||
git tag mergetest-1 HEAD~2 &&
|
||||
git tag mergetest-2 HEAD~1 &&
|
||||
|
@ -42,6 +42,7 @@ test_decode_color () {
|
||||
function name(n) {
|
||||
if (n == 0) return "RESET";
|
||||
if (n == 1) return "BOLD";
|
||||
if (n == 7) return "REVERSE";
|
||||
if (n == 30) return "BLACK";
|
||||
if (n == 31) return "RED";
|
||||
if (n == 32) return "GREEN";
|
||||
|
Loading…
Reference in New Issue
Block a user