From: Junio C Hamano Date: Mon, 29 Aug 2011 04:19:16 +0000 (-0700) Subject: Merge branch 'jk/color-and-pager' X-Git-Tag: v1.7.7-rc1~39 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/f946b465d7fa13a235dd5653d37c7babb1ceb233?ds=inline;hp=-c Merge branch 'jk/color-and-pager' * jk/color-and-pager: want_color: automatically fallback to color.ui diff: don't load color config in plumbing config: refactor get_colorbool function color: delay auto-color decision until point of use git_config_colorbool: refactor stdout_is_tty handling diff: refactor COLOR_DIFF from a flag into an int setup_pager: set GIT_PAGER_IN_USE t7006: use test_config helpers test-lib: add helper functions for config t7006: modernize calls to unset Conflicts: builtin/commit.c parse-options.c --- f946b465d7fa13a235dd5653d37c7babb1ceb233 diff --combined builtin/branch.c index 953bc1ca9b,73d41700d1..f7da69c932 --- a/builtin/branch.c +++ b/builtin/branch.c @@@ -71,7 -71,7 +71,7 @@@ static int parse_branch_color_slot(cons static int git_branch_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "color.branch")) { - branch_use_color = git_config_colorbool(var, value, -1); + branch_use_color = git_config_colorbool(var, value); return 0; } if (!prefixcmp(var, "color.branch.")) { @@@ -88,7 -88,7 +88,7 @@@ static const char *branch_get_color(enum color_branch ix) { - if (branch_use_color > 0) + if (want_color(branch_use_color)) return branch_colors[ix]; return ""; } @@@ -613,7 -613,7 +613,7 @@@ static int opt_parse_merge_filter(cons int cmd_branch(int argc, const char **argv, const char *prefix) { int delete = 0, rename = 0, force_create = 0; - int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0; + int verbose = 0, abbrev = -1, detached = 0; int reflog = 0; enum branch_track track; int kinds = REF_LOCAL_BRANCH; @@@ -673,9 -673,6 +673,6 @@@ git_config(git_branch_config, NULL); - if (branch_use_color == -1) - branch_use_color = git_use_color_default; - track = git_branch_track; head = resolve_ref("HEAD", head_sha1, 0, NULL); @@@ -696,9 -693,6 +693,9 @@@ if (!!delete + !!rename + !!force_create > 1) usage_with_options(builtin_branch_usage, options); + if (abbrev == -1) + abbrev = DEFAULT_ABBREV; + if (delete) return delete_branches(argc, argv, delete > 1, kinds); else if (argc == 0) diff --combined builtin/commit.c index 05029d40d1,9763146b6f..cbc9613ec6 --- a/builtin/commit.c +++ b/builtin/commit.c @@@ -62,6 -62,8 +62,6 @@@ N_("The previous cherry-pick is now emp "\n" "Otherwise, please use 'git reset'\n"); -static unsigned char head_sha1[20]; - static const char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ @@@ -100,7 -102,7 +100,7 @@@ static enum static char *cleanup_arg; static enum commit_whence whence; -static int use_editor = 1, initial_commit, include_status = 1; +static int use_editor = 1, include_status = 1; static int show_ignored_in_status; static const char *only_include_assumed; static struct strbuf message; @@@ -254,10 -256,8 +254,10 @@@ static int list_paths(struct string_lis ; m = xcalloc(1, i); - if (with_tree) - overlay_tree_on_cache(with_tree, prefix); + if (with_tree) { + const char *max_prefix = pathspec_prefix(prefix, pattern); + overlay_tree_on_cache(with_tree, max_prefix); + } for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; @@@ -272,7 -272,7 +272,7 @@@ item->util = item; /* better a valid pointer than a fake one */ } - return report_path_error(m, pattern, prefix ? strlen(prefix) : 0); + return report_path_error(m, pattern, prefix); } static void add_remove_files(struct string_list *list) @@@ -294,13 -294,13 +294,13 @@@ } } -static void create_base_index(void) +static void create_base_index(const struct commit *current_head) { struct tree *tree; struct unpack_trees_options opts; struct tree_desc t; - if (initial_commit) { + if (!current_head) { discard_cache(); return; } @@@ -313,7 -313,7 +313,7 @@@ opts.dst_index = &the_index; opts.fn = oneway_merge; - tree = parse_tree_indirect(head_sha1); + tree = parse_tree_indirect(current_head->object.sha1); if (!tree) die(_("failed to unpack HEAD tree object")); parse_tree(tree); @@@ -332,8 -332,7 +332,8 @@@ static void refresh_cache_or_die(int re die_resolve_conflict("commit"); } -static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status) +static char *prepare_index(int argc, const char **argv, const char *prefix, + const struct commit *current_head, int is_status) { int fd; struct string_list partial; @@@ -449,7 -448,7 +449,7 @@@ memset(&partial, 0, sizeof(partial)); partial.strdup_strings = 1; - if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec)) + if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec)) exit(1); discard_cache(); @@@ -468,7 -467,7 +468,7 @@@ (uintmax_t) getpid()), LOCK_DIE_ON_ERROR); - create_base_index(); + create_base_index(current_head); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); @@@ -517,9 -516,12 +517,9 @@@ static int run_status(FILE *fp, const c return s->commitable; } -static int is_a_merge(const unsigned char *sha1) +static int is_a_merge(const struct commit *current_head) { - struct commit *commit = lookup_commit(sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - return !!(commit->parents && commit->parents->next); + return !!(current_head->parents && current_head->parents->next); } static const char sign_off_header[] = "Signed-off-by: "; @@@ -623,7 -625,6 +623,7 @@@ static char *cut_ident_timestamp_part(c } static int prepare_to_commit(const char *index_file, const char *prefix, + struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { @@@ -845,7 -846,7 +845,7 @@@ * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && - !(amend && is_a_merge(head_sha1))) { + !(amend && is_a_merge(current_head))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); @@@ -1003,7 -1004,6 +1003,7 @@@ static const char *read_commit_message( static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, + struct commit *current_head, struct wt_status *s) { int f = 0; @@@ -1024,8 -1024,11 +1024,8 @@@ if (!use_editor) setenv("GIT_EDITOR", ":", 1); - if (get_sha1("HEAD", head_sha1)) - initial_commit = 1; - /* Sanity check options */ - if (amend && initial_commit) + if (amend && !current_head) die(_("You have nothing to amend.")); if (amend && whence != FROM_COMMIT) die(_("You are in the middle of a %s -- cannot amend."), whence_s()); @@@ -1097,12 -1100,12 +1097,12 @@@ } static int dry_run_commit(int argc, const char **argv, const char *prefix, - struct wt_status *s) + const struct commit *current_head, struct wt_status *s) { int commitable; const char *index_file; - index_file = prepare_index(argc, argv, prefix, 1); + index_file = prepare_index(argc, argv, prefix, current_head, 1); commitable = run_status(stdout, index_file, prefix, 0, s); rollback_index_files(); @@@ -1141,7 -1144,7 +1141,7 @@@ static int git_status_config(const cha return 0; } if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { - s->use_color = git_config_colorbool(k, v, -1); + s->use_color = git_config_colorbool(k, v); return 0; } if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { @@@ -1234,10 -1237,6 +1234,6 @@@ int cmd_status(int argc, const char **a if (s.relative_paths) s.prefix = prefix; - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; switch (status_format) { case STATUS_FORMAT_SHORT: @@@ -1255,8 -1254,7 +1251,8 @@@ return 0; } -static void print_summary(const char *prefix, const unsigned char *sha1) +static void print_summary(const char *prefix, const unsigned char *sha1, + int initial_commit) { struct rev_info rev; struct commit *commit; @@@ -1378,13 -1376,12 +1374,13 @@@ int cmd_commit(int argc, const char **a struct strbuf author_ident = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; - unsigned char commit_sha1[20]; + unsigned char sha1[20]; struct ref_lock *ref_lock; struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; struct wt_status s; + struct commit *current_head = NULL; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@@ -1393,43 -1390,35 +1389,38 @@@ git_config(git_commit_config, &s); determine_whence(&s); - if (s.use_color == -1) - s.use_color = git_use_color_default; + if (get_sha1("HEAD", sha1)) + current_head = NULL; + else { + current_head = lookup_commit(sha1); + if (!current_head || parse_commit(current_head)) + die(_("could not parse HEAD commit")); + } argc = parse_and_validate_options(argc, argv, builtin_commit_usage, - prefix, &s); + prefix, current_head, &s); - if (dry_run) { - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; + if (dry_run) - return dry_run_commit(argc, argv, prefix, &s); - index_file = prepare_index(argc, argv, prefix, 0); + return dry_run_commit(argc, argv, prefix, current_head, &s); - } + index_file = prepare_index(argc, argv, prefix, current_head, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ - if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) { + if (!prepare_to_commit(index_file, prefix, + current_head, &s, &author_ident)) { rollback_index_files(); return 1; } /* Determine parents */ reflog_msg = getenv("GIT_REFLOG_ACTION"); - if (initial_commit) { + if (!current_head) { if (!reflog_msg) reflog_msg = "commit (initial)"; } else if (amend) { struct commit_list *c; - struct commit *commit; if (!reflog_msg) reflog_msg = "commit (amend)"; - commit = lookup_commit(head_sha1); - if (!commit || parse_commit(commit)) - die(_("could not parse HEAD commit")); - - for (c = commit->parents; c; c = c->next) + for (c = current_head->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (whence == FROM_MERGE) { struct strbuf m = STRBUF_INIT; @@@ -1437,7 -1426,7 +1428,7 @@@ if (!reflog_msg) reflog_msg = "commit (merge)"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die_errno(_("could not open '%s' for reading"), @@@ -1463,7 -1452,7 +1454,7 @@@ reflog_msg = (whence == FROM_CHERRY_PICK) ? "commit (cherry-pick)" : "commit"; - pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; + pptr = &commit_list_insert(current_head, pptr)->next; } /* Finally, get the commit message */ @@@ -1489,7 -1478,7 +1480,7 @@@ exit(1); } - if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1, + if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1, author_ident.buf)) { rollback_index_files(); die(_("failed to write commit object")); @@@ -1497,9 -1486,7 +1488,9 @@@ strbuf_release(&author_ident); ref_lock = lock_any_ref_for_update("HEAD", - initial_commit ? NULL : head_sha1, + !current_head + ? NULL + : current_head->object.sha1, 0); nl = strchr(sb.buf, '\n'); @@@ -1514,7 -1501,7 +1505,7 @@@ rollback_index_files(); die(_("cannot lock HEAD ref")); } - if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) { + if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) { rollback_index_files(); die(_("cannot update HEAD ref")); } @@@ -1536,14 -1523,13 +1527,14 @@@ struct notes_rewrite_cfg *cfg; cfg = init_copy_notes_for_rewrite("amend"); if (cfg) { - copy_note_for_rewrite(cfg, head_sha1, commit_sha1); + /* we are amending, so current_head is not NULL */ + copy_note_for_rewrite(cfg, current_head->object.sha1, sha1); finish_copy_notes_for_rewrite(cfg); } - run_rewrite_hook(head_sha1, commit_sha1); + run_rewrite_hook(current_head->object.sha1, sha1); } if (!quiet) - print_summary(prefix, commit_sha1); + print_summary(prefix, sha1, !current_head); return 0; } diff --combined builtin/grep.c index 1851797540,18522cab75..1c359c2671 --- a/builtin/grep.c +++ b/builtin/grep.c @@@ -93,7 -93,8 +93,7 @@@ static pthread_cond_t cond_write /* Signalled when we are finished with everything. */ static pthread_cond_t cond_result; -static int print_hunk_marks_between_files; -static int printed_something; +static int skip_first_line; static void add_work(enum work_type type, char *name, void *id) { @@@ -159,20 -160,10 +159,20 @@@ static void work_done(struct work_item todo_done = (todo_done+1) % ARRAY_SIZE(todo)) { w = &todo[todo_done]; if (w->out.len) { - if (print_hunk_marks_between_files && printed_something) - write_or_die(1, "--\n", 3); - write_or_die(1, w->out.buf, w->out.len); - printed_something = 1; + const char *p = w->out.buf; + size_t len = w->out.len; + + /* Skip the leading hunk mark of the first file. */ + if (skip_first_line) { + while (len) { + len--; + if (*p++ == '\n') + break; + } + skip_first_line = 0; + } + + write_or_die(1, p, len); } free(w->name); free(w->identifier); @@@ -325,7 -316,7 +325,7 @@@ static int grep_config(const char *var } if (!strcmp(var, "color.grep")) - opt->color = git_config_colorbool(var, value, -1); + opt->color = git_config_colorbool(var, value); else if (!strcmp(var, "color.grep.context")) color = opt->color_context; else if (!strcmp(var, "color.grep.filename")) @@@ -822,24 -813,18 +822,24 @@@ int cmd_grep(int argc, const char **arg OPT_BOOLEAN('c', "count", &opt.count, "show the number of matches instead of matching lines"), OPT__COLOR(&opt.color, "highlight matches"), + OPT_BOOLEAN(0, "break", &opt.file_break, + "print empty line between matches from different files"), + OPT_BOOLEAN(0, "heading", &opt.heading, + "show filename only once above matches from same file"), OPT_GROUP(""), - OPT_CALLBACK('C', NULL, &opt, "n", + OPT_CALLBACK('C', "context", &opt, "n", "show context lines before and after matches", context_callback), - OPT_INTEGER('B', NULL, &opt.pre_context, + OPT_INTEGER('B', "before-context", &opt.pre_context, "show context lines before matches"), - OPT_INTEGER('A', NULL, &opt.post_context, + OPT_INTEGER('A', "after-context", &opt.post_context, "show context lines after matches"), OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, "show a line with the function name before matches"), + OPT_BOOLEAN('W', "function-context", &opt.funcbody, + "show the surrounding function"), OPT_GROUP(""), OPT_CALLBACK('f', NULL, &opt, "file", "read patterns from file", file_callback), @@@ -898,8 -883,6 +898,6 @@@ strcpy(opt.color_sep, GIT_COLOR_CYAN); opt.color = -1; git_config(grep_config, &opt); - if (opt.color == -1) - opt.color = git_use_color_default; /* * If there is no -- then the paths must exist in the working @@@ -982,9 -965,8 +980,9 @@@ use_threads = 0; if (use_threads) { - if (opt.pre_context || opt.post_context) - print_hunk_marks_between_files = 1; + if (opt.pre_context || opt.post_context || opt.file_break || + opt.funcbody) + skip_first_line = 1; start_threads(&opt); } #else diff --combined builtin/merge.c index f32c5c6432,b75ae0193c..ab4077f272 --- a/builtin/merge.c +++ b/builtin/merge.c @@@ -390,8 -390,6 +390,6 @@@ static void finish(const unsigned char opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; - if (diff_use_color_default > 0) - DIFF_OPT_SET(&opts, COLOR_DIFF); if (diff_setup_done(&opts) < 0) die(_("diff_setup_done failed")); diff_tree_sha1(head, new_head, "", &opts); @@@ -903,7 -901,7 +901,7 @@@ static int finish_automerge(struct comm strbuf_addch(&merge_msg, '\n'); run_prepare_commit_msg(); commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); - strbuf_addf(&buf, "Merge made by %s.", wt_strategy); + strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(result_commit, buf.buf); strbuf_release(&buf); drop_save(); @@@ -1033,10 -1031,6 +1031,6 @@@ int cmd_merge(int argc, const char **ar git_config(git_merge_config, NULL); - /* for color.ui */ - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - if (branch_mergeoptions) parse_branch_merge_options(branch_mergeoptions); argc = parse_options(argc, argv, prefix, builtin_merge_options, diff --combined combine-diff.c index 178313bc23,c588c79351..214014dc64 --- a/combine-diff.c +++ b/combine-diff.c @@@ -702,9 -702,8 +702,8 @@@ static void show_combined_header(struc int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV; const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/"; const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/"; - int use_color = DIFF_OPT_TST(opt, COLOR_DIFF); - const char *c_meta = diff_get_color(use_color, DIFF_METAINFO); - const char *c_reset = diff_get_color(use_color, DIFF_RESET); + const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO); + const char *c_reset = diff_get_color_opt(opt, DIFF_RESET); const char *abb; int added = 0; int deleted = 0; @@@ -768,8 -767,7 +767,8 @@@ } static void show_patch_diff(struct combine_diff_path *elem, int num_parent, - int dense, struct rev_info *rev) + int dense, int working_tree_file, + struct rev_info *rev) { struct diff_options *opt = &rev->diffopt; unsigned long result_size, cnt, lno; @@@ -778,6 -776,7 +777,6 @@@ struct sline *sline; /* survived lines */ int mode_differs = 0; int i, show_hunks; - int working_tree_file = is_null_sha1(elem->sha1); mmfile_t result_file; struct userdiff_driver *userdiff; struct userdiff_driver *textconv = NULL; @@@ -964,7 -963,7 +963,7 @@@ show_combined_header(elem, num_parent, dense, rev, mode_differs, 1); dump_sline(sline, cnt, num_parent, - DIFF_OPT_TST(opt, COLOR_DIFF), result_deleted); + opt->use_color, result_deleted); } free(result); @@@ -1028,12 -1027,6 +1027,12 @@@ static void show_raw_diff(struct combin write_name_quoted(p->path, stdout, line_termination); } +/* + * The result (p->elem) is from the working tree and their + * parents are typically from multiple stages during a merge + * (i.e. diff-files) or the state in HEAD and in the index + * (i.e. diff-index). + */ void show_combined_diff(struct combine_diff_path *p, int num_parent, int dense, @@@ -1047,73 -1040,7 +1046,73 @@@ DIFF_FORMAT_NAME_STATUS)) show_raw_diff(p, num_parent, rev); else if (opt->output_format & DIFF_FORMAT_PATCH) - show_patch_diff(p, num_parent, dense, rev); + show_patch_diff(p, num_parent, dense, 1, rev); +} + +static void free_combined_pair(struct diff_filepair *pair) +{ + free(pair->two); + free(pair); +} + +/* + * A combine_diff_path expresses N parents on the LHS against 1 merge + * result. Synthesize a diff_filepair that has N entries on the "one" + * side and 1 entry on the "two" side. + * + * In the future, we might want to add more data to combine_diff_path + * so that we can fill fields we are ignoring (most notably, size) here, + * but currently nobody uses it, so this should suffice for now. + */ +static struct diff_filepair *combined_pair(struct combine_diff_path *p, + int num_parent) +{ + int i; + struct diff_filepair *pair; + struct diff_filespec *pool; + + pair = xmalloc(sizeof(*pair)); + pool = xcalloc(num_parent + 1, sizeof(struct diff_filespec)); + pair->one = pool + 1; + pair->two = pool; + + for (i = 0; i < num_parent; i++) { + pair->one[i].path = p->path; + pair->one[i].mode = p->parent[i].mode; + hashcpy(pair->one[i].sha1, p->parent[i].sha1); + pair->one[i].sha1_valid = !is_null_sha1(p->parent[i].sha1); + pair->one[i].has_more_entries = 1; + } + pair->one[num_parent - 1].has_more_entries = 0; + + pair->two->path = p->path; + pair->two->mode = p->mode; + hashcpy(pair->two->sha1, p->sha1); + pair->two->sha1_valid = !is_null_sha1(p->sha1); + return pair; +} + +static void handle_combined_callback(struct diff_options *opt, + struct combine_diff_path *paths, + int num_parent, + int num_paths) +{ + struct combine_diff_path *p; + struct diff_queue_struct q; + int i; + + q.queue = xcalloc(num_paths, sizeof(struct diff_filepair *)); + q.alloc = num_paths; + q.nr = num_paths; + for (i = 0, p = paths; p; p = p->next) { + if (!p->len) + continue; + q.queue[i++] = combined_pair(p, num_parent); + } + opt->format_callback(&q, opt, opt->format_callback_data); + for (i = 0; i < num_paths; i++) + free_combined_pair(q.queue[i]); + free(q.queue); } void diff_tree_combined(const unsigned char *sha1, @@@ -1175,16 -1102,13 +1174,16 @@@ else if (opt->output_format & (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)) needsep = 1; + else if (opt->output_format & DIFF_FORMAT_CALLBACK) + handle_combined_callback(opt, paths, num_parent, num_paths); + if (opt->output_format & DIFF_FORMAT_PATCH) { if (needsep) putchar(opt->line_termination); for (p = paths; p; p = p->next) { if (p->len) show_patch_diff(p, num_parent, dense, - rev); + 0, rev); } } } diff --combined diff.c index d3d8daec77,052e42adf0..fcc0078074 --- a/diff.c +++ b/diff.c @@@ -137,7 -137,7 +137,7 @@@ static int git_config_rename(const cha int git_diff_ui_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { - diff_use_color_default = git_config_colorbool(var, value, -1); + diff_use_color_default = git_config_colorbool(var, value); return 0; } if (!strcmp(var, "diff.renames")) { @@@ -164,6 -164,9 +164,9 @@@ if (!strcmp(var, "diff.ignoresubmodules")) handle_ignore_submodules_arg(&default_diff_options, value); + if (git_color_config(var, value, cb) < 0) + return -1; + return git_diff_basic_config(var, value, cb); } @@@ -212,7 -215,7 +215,7 @@@ int git_diff_basic_config(const char *v if (!prefixcmp(var, "submodule.")) return parse_submodule_config_option(var, value); - return git_color_default_config(var, value, cb); + return git_default_config(var, value, cb); } static char *quote_two(const char *one, const char *two) @@@ -583,11 -586,10 +586,10 @@@ static void emit_rewrite_diff(const cha struct diff_options *o) { int lc_a, lc_b; - int color_diff = DIFF_OPT_TST(o, COLOR_DIFF); const char *name_a_tab, *name_b_tab; - const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO); - const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO); - const char *reset = diff_get_color(color_diff, DIFF_RESET); + const char *metainfo = diff_get_color(o->use_color, DIFF_METAINFO); + const char *fraginfo = diff_get_color(o->use_color, DIFF_FRAGINFO); + const char *reset = diff_get_color(o->use_color, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; const char *a_prefix, *b_prefix; char *data_one, *data_two; @@@ -623,7 -625,7 +625,7 @@@ size_two = fill_textconv(textconv_two, two, &data_two); memset(&ecbdata, 0, sizeof(ecbdata)); - ecbdata.color_diff = color_diff; + ecbdata.color_diff = want_color(o->use_color); ecbdata.found_changesp = &o->found_changes; ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); ecbdata.opt = o; @@@ -1004,7 -1006,7 +1006,7 @@@ static void free_diff_words_data(struc const char *diff_get_color(int diff_use_color, enum color_diff ix) { - if (diff_use_color) + if (want_color(diff_use_color)) return diff_colors[ix]; return ""; } @@@ -1316,10 -1318,9 +1318,10 @@@ static void show_stats(struct diffstat_ int i, len, add, del, adds = 0, dels = 0; uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; - int width, name_width; + int width, name_width, count; const char *reset, *add_c, *del_c; const char *line_prefix = ""; + int extra_shown = 0; struct strbuf *msg = NULL; if (data->nr == 0) @@@ -1332,7 -1333,6 +1334,7 @@@ width = options->stat_width ? options->stat_width : 80; name_width = options->stat_name_width ? options->stat_name_width : 50; + count = options->stat_count ? options->stat_count : data->nr; /* Sanity: give at least 5 columns to the graph, * but leave at least 10 columns for the name. @@@ -1349,14 -1349,9 +1351,14 @@@ add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); - for (i = 0; i < data->nr; i++) { + for (i = 0; (i < count) && (i < data->nr); i++) { struct diffstat_file *file = data->files[i]; uintmax_t change = file->added + file->deleted; + if (!data->files[i]->is_renamed && + (change == 0)) { + count++; /* not shown == room for one more */ + continue; + } fill_print_name(file); len = strlen(file->print_name); if (max_len < len) @@@ -1367,7 -1362,6 +1369,7 @@@ if (max_change < change) max_change = change; } + count = i; /* min(count, data->nr) */ /* Compute the width of the graph part; * 10 is for one blank at the beginning of the line plus @@@ -1382,18 -1376,13 +1384,18 @@@ else width = max_change; - for (i = 0; i < data->nr; i++) { + for (i = 0; i < count; i++) { const char *prefix = ""; char *name = data->files[i]->print_name; uintmax_t added = data->files[i]->added; uintmax_t deleted = data->files[i]->deleted; int name_len; + if (!data->files[i]->is_renamed && + (added + deleted == 0)) { + total_files--; + continue; + } /* * "scale" the filename */ @@@ -1428,6 -1417,11 +1430,6 @@@ fprintf(options->file, " Unmerged\n"); continue; } - else if (!data->files[i]->is_renamed && - (added + deleted == 0)) { - total_files--; - continue; - } /* * scale the add/delete @@@ -1449,20 -1443,6 +1451,20 @@@ show_graph(options->file, '-', del, del_c, reset); fprintf(options->file, "\n"); } + for (i = count; i < data->nr; i++) { + uintmax_t added = data->files[i]->added; + uintmax_t deleted = data->files[i]->deleted; + if (!data->files[i]->is_renamed && + (added + deleted == 0)) { + total_files--; + continue; + } + adds += added; + dels += deleted; + if (!extra_shown) + fprintf(options->file, "%s ...\n", line_prefix); + extra_shown = 1; + } fprintf(options->file, "%s", line_prefix); fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n", @@@ -1808,11 -1788,10 +1810,10 @@@ static int is_conflict_marker(const cha static void checkdiff_consume(void *priv, char *line, unsigned long len) { struct checkdiff_t *data = priv; - int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF); int marker_size = data->conflict_marker_size; - const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE); - const char *reset = diff_get_color(color_diff, DIFF_RESET); - const char *set = diff_get_color(color_diff, DIFF_FILE_NEW); + const char *ws = diff_get_color(data->o->use_color, DIFF_WHITESPACE); + const char *reset = diff_get_color(data->o->use_color, DIFF_RESET); + const char *set = diff_get_color(data->o->use_color, DIFF_FILE_NEW); char *err; char *line_prefix = ""; struct strbuf *msgbuf; @@@ -2157,7 -2136,7 +2158,7 @@@ static void builtin_diff(const char *na memset(&xecfg, 0, sizeof(xecfg)); memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; - ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF); + ecbdata.color_diff = want_color(o->use_color); ecbdata.found_changesp = &o->found_changes; ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) @@@ -2205,7 -2184,7 +2206,7 @@@ break; } } - if (DIFF_OPT_TST(o, COLOR_DIFF)) { + if (want_color(o->use_color)) { struct diff_words_style *st = ecbdata.diff_words->style; st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD); st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW); @@@ -2855,7 -2834,7 +2856,7 @@@ static void run_diff_cmd(const char *pg */ fill_metainfo(msg, name, other, one, two, o, p, &must_show_header, - DIFF_OPT_TST(o, COLOR_DIFF) && !pgm); + want_color(o->use_color) && !pgm); xfrm_msg = msg->len ? msg->buf : NULL; } @@@ -3021,8 -3000,7 +3022,7 @@@ void diff_setup(struct diff_options *op options->change = diff_change; options->add_remove = diff_addremove; - if (diff_use_color_default > 0) - DIFF_OPT_SET(options, COLOR_DIFF); + options->use_color = diff_use_color_default; options->detect_rename = diff_detect_rename_default; if (diff_no_prefix) { @@@ -3230,7 -3208,6 +3230,7 @@@ static int stat_opt(struct diff_option char *end; int width = options->stat_width; int name_width = options->stat_name_width; + int count = options->stat_count; int argcount = 1; arg += strlen("--stat"); @@@ -3258,24 -3235,12 +3258,24 @@@ name_width = strtoul(av[1], &end, 10); argcount = 2; } + } else if (!prefixcmp(arg, "-count")) { + arg += strlen("-count"); + if (*arg == '=') + count = strtoul(arg + 1, &end, 10); + else if (!*arg && !av[1]) + die("Option '--stat-count' requires a value"); + else if (!*arg) { + count = strtoul(av[1], &end, 10); + argcount = 2; + } } break; case '=': width = strtoul(arg+1, &end, 10); if (*end == ',') name_width = strtoul(end+1, &end, 10); + if (*end == ',') + count = strtoul(end+1, &end, 10); } /* Important! This checks all the error cases! */ @@@ -3284,7 -3249,6 +3284,7 @@@ options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; options->stat_width = width; + options->stat_count = count; return argcount; } @@@ -3349,7 -3313,7 +3349,7 @@@ int diff_opt_parse(struct diff_options else if (!strcmp(arg, "-s")) options->output_format |= DIFF_FORMAT_NO_OUTPUT; else if (!prefixcmp(arg, "--stat")) - /* --stat, --stat-width, or --stat-name-width */ + /* --stat, --stat-width, --stat-name-width, or --stat-count */ return stat_opt(options, av); /* renames options */ @@@ -3393,8 -3357,6 +3393,8 @@@ DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); else if (!strcmp(arg, "--patience")) DIFF_XDL_SET(options, PATIENCE_DIFF); + else if (!strcmp(arg, "--histogram")) + DIFF_XDL_SET(options, HISTOGRAM_DIFF); /* flags options */ else if (!strcmp(arg, "--binary")) { @@@ -3412,24 -3374,21 +3412,21 @@@ else if (!strcmp(arg, "--follow")) DIFF_OPT_SET(options, FOLLOW_RENAMES); else if (!strcmp(arg, "--color")) - DIFF_OPT_SET(options, COLOR_DIFF); + options->use_color = 1; else if (!prefixcmp(arg, "--color=")) { - int value = git_config_colorbool(NULL, arg+8, -1); - if (value == 0) - DIFF_OPT_CLR(options, COLOR_DIFF); - else if (value > 0) - DIFF_OPT_SET(options, COLOR_DIFF); - else + int value = git_config_colorbool(NULL, arg+8); + if (value < 0) return error("option `color' expects \"always\", \"auto\", or \"never\""); + options->use_color = value; } else if (!strcmp(arg, "--no-color")) - DIFF_OPT_CLR(options, COLOR_DIFF); + options->use_color = 0; else if (!strcmp(arg, "--color-words")) { - DIFF_OPT_SET(options, COLOR_DIFF); + options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } else if (!prefixcmp(arg, "--color-words=")) { - DIFF_OPT_SET(options, COLOR_DIFF); + options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; options->word_regex = arg + 14; } @@@ -3442,7 -3401,7 +3439,7 @@@ if (!strcmp(type, "plain")) options->word_diff = DIFF_WORDS_PLAIN; else if (!strcmp(type, "color")) { - DIFF_OPT_SET(options, COLOR_DIFF); + options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } else if (!strcmp(type, "porcelain")) diff --combined diff.h index b920a20f80,04a9ad781b..8c66b59517 --- a/diff.h +++ b/diff.h @@@ -58,7 -58,7 +58,7 @@@ typedef struct strbuf *(*diff_prefix_fn #define DIFF_OPT_SILENT_ON_REMOVE (1 << 5) #define DIFF_OPT_FIND_COPIES_HARDER (1 << 6) #define DIFF_OPT_FOLLOW_RENAMES (1 << 7) - #define DIFF_OPT_COLOR_DIFF (1 << 8) + /* (1 << 8) unused */ /* (1 << 9) unused */ #define DIFF_OPT_HAS_CHANGES (1 << 10) #define DIFF_OPT_QUICK (1 << 11) @@@ -101,6 -101,7 +101,7 @@@ struct diff_options const char *single_follow; const char *a_prefix, *b_prefix; unsigned flags; + int use_color; int context; int interhunkcontext; int break_opt; @@@ -125,7 -126,6 +126,7 @@@ int stat_width; int stat_name_width; + int stat_count; const char *word_regex; enum diff_words_type word_diff; @@@ -160,7 -160,7 +161,7 @@@ enum color_diff }; const char *diff_get_color(int diff_use_color, enum color_diff ix); #define diff_get_color_opt(o, ix) \ - diff_get_color(DIFF_OPT_TST((o), COLOR_DIFF), ix) + diff_get_color((o)->use_color, ix) extern const char mime_boundary_leader[]; diff --combined grep.c index 26e8d8ec4c,e52654b20b..2dd2a25ad7 --- a/grep.c +++ b/grep.c @@@ -430,7 -430,7 +430,7 @@@ static int word_char(char ch static void output_color(struct grep_opt *opt, const void *data, size_t size, const char *color) { - if (opt->color && color && color[0]) { + if (want_color(opt->color) && color && color[0]) { opt->output(opt, color, strlen(color)); opt->output(opt, data, size); opt->output(opt, GIT_COLOR_RESET, strlen(GIT_COLOR_RESET)); @@@ -721,10 -721,7 +721,10 @@@ static void show_line(struct grep_opt * int rest = eol - bol; char *line_color = NULL; - if (opt->pre_context || opt->post_context) { + if (opt->file_break && opt->last_shown == 0) { + if (opt->show_hunk_mark) + opt->output(opt, "\n", 1); + } else if (opt->pre_context || opt->post_context || opt->funcbody) { if (opt->last_shown == 0) { if (opt->show_hunk_mark) { output_color(opt, "--", 2, opt->color_sep); @@@ -735,13 -732,9 +735,13 @@@ opt->output(opt, "\n", 1); } } + if (opt->heading && opt->last_shown == 0) { + output_color(opt, name, strlen(name), opt->color_filename); + opt->output(opt, "\n", 1); + } opt->last_shown = lno; - if (opt->pathname) { + if (!opt->heading && opt->pathname) { output_color(opt, name, strlen(name), opt->color_filename); output_sep(opt, sign); } @@@ -819,13 -812,10 +819,13 @@@ static void show_funcname_line(struct g } static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, - char *bol, unsigned lno) + char *bol, char *end, unsigned lno) { unsigned cur = lno, from = 1, funcname_lno = 0; - int funcname_needed = opt->funcname; + int funcname_needed = !!opt->funcname; + + if (opt->funcbody && !match_funcname(opt, bol, end)) + funcname_needed = 2; if (opt->pre_context < lno) from = lno - opt->pre_context; @@@ -833,8 -823,7 +833,8 @@@ from = opt->last_shown + 1; /* Rewind. */ - while (bol > buf && cur > from) { + while (bol > buf && + cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) { char *eol = --bol; while (bol > buf && bol[-1] != '\n') @@@ -946,26 -935,15 +946,26 @@@ static int grep_buffer_1(struct grep_op int binary_match_only = 0; unsigned count = 0; int try_lookahead = 0; + int show_function = 0; enum grep_context ctx = GREP_CONTEXT_HEAD; xdemitconf_t xecfg; if (!opt->output) opt->output = std_output; - if (opt->last_shown && (opt->pre_context || opt->post_context) && - opt->output == std_output) - opt->show_hunk_mark = 1; + if (opt->pre_context || opt->post_context || opt->file_break || + opt->funcbody) { + /* Show hunk marks, except for the first file. */ + if (opt->last_shown) + opt->show_hunk_mark = 1; + /* + * If we're using threads then we can't easily identify + * the first file. Always put hunk marks in that case + * and skip the very first one later in work_done(). + */ + if (opt->output != std_output) + opt->show_hunk_mark = 1; + } opt->last_shown = 0; switch (opt->binary) { @@@ -1010,8 -988,7 +1010,8 @@@ */ if (try_lookahead && !(last_hit - && lno <= last_hit + opt->post_context) + && (show_function || + lno <= last_hit + opt->post_context)) && look_ahead(opt, &left, &lno, &bol)) break; eol = end_of_line(bol, &left); @@@ -1058,20 -1035,15 +1058,20 @@@ /* Hit at this line. If we haven't shown the * pre-context lines, we would need to show them. */ - if (opt->pre_context) - show_pre_context(opt, name, buf, bol, lno); + if (opt->pre_context || opt->funcbody) + show_pre_context(opt, name, buf, bol, eol, lno); else if (opt->funcname) show_funcname_line(opt, name, buf, bol, lno); show_line(opt, bol, eol, name, lno, ':'); last_hit = lno; + if (opt->funcbody) + show_function = 1; + goto next_line; } - else if (last_hit && - lno <= last_hit + opt->post_context) { + if (show_function && match_funcname(opt, bol, eol)) + show_function = 0; + if (show_function || + (last_hit && lno <= last_hit + opt->post_context)) { /* If the last hit is within the post context, * we need to show this line. */ diff --combined parse-options-cb.c index c248f667c1,0000000000..6db0921fc1 mode 100644,000000..100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@@ -1,125 -1,0 +1,125 @@@ +#include "git-compat-util.h" +#include "parse-options.h" +#include "cache.h" +#include "commit.h" +#include "color.h" +#include "string-list.h" + +/*----- some often used options -----*/ + +int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) +{ + int v; + + if (!arg) { + v = unset ? 0 : DEFAULT_ABBREV; + } else { + v = strtol(arg, (char **)&arg, 10); + if (*arg) + return opterror(opt, "expects a numerical value", 0); + if (v && v < MINIMUM_ABBREV) + v = MINIMUM_ABBREV; + else if (v > 40) + v = 40; + } + *(int *)(opt->value) = v; + return 0; +} + +int parse_opt_approxidate_cb(const struct option *opt, const char *arg, + int unset) +{ + *(unsigned long *)(opt->value) = approxidate(arg); + return 0; +} + +int parse_opt_color_flag_cb(const struct option *opt, const char *arg, + int unset) +{ + int value; + + if (!arg) + arg = unset ? "never" : (const char *)opt->defval; - value = git_config_colorbool(NULL, arg, -1); ++ value = git_config_colorbool(NULL, arg); + if (value < 0) + return opterror(opt, + "expects \"always\", \"auto\", or \"never\"", 0); + *(int *)opt->value = value; + return 0; +} + +int parse_opt_verbosity_cb(const struct option *opt, const char *arg, + int unset) +{ + int *target = opt->value; + + if (unset) + /* --no-quiet, --no-verbose */ + *target = 0; + else if (opt->short_name == 'v') { + if (*target >= 0) + (*target)++; + else + *target = 1; + } else { + if (*target <= 0) + (*target)--; + else + *target = -1; + } + return 0; +} + +int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) +{ + unsigned char sha1[20]; + struct commit *commit; + + if (!arg) + return -1; + if (get_sha1(arg, sha1)) + return error("malformed object name %s", arg); + commit = lookup_commit_reference(sha1); + if (!commit) + return error("no such commit %s", arg); + commit_list_insert(commit, opt->value); + return 0; +} + +int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) +{ + int *target = opt->value; + *target = unset ? 2 : 1; + return 0; +} + +int parse_options_concat(struct option *dst, size_t dst_size, struct option *src) +{ + int i, j; + + for (i = 0; i < dst_size; i++) + if (dst[i].type == OPTION_END) + break; + for (j = 0; i < dst_size; i++, j++) { + dst[i] = src[j]; + if (src[j].type == OPTION_END) + return 0; + } + return -1; +} + +int parse_opt_string_list(const struct option *opt, const char *arg, int unset) +{ + struct string_list *v = opt->value; + + if (unset) { + string_list_clear(v, 0); + return 0; + } + + if (!arg) + return -1; + + string_list_append(v, xstrdup(arg)); + return 0; +} diff --combined t/test-lib.sh index e27422217d,395bf609ad..d7dfc8b0b1 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@@ -92,10 -92,6 +92,10 @@@ _x40="$_x05$_x05$_x05$_x05$_x05$_x05$_x # Zero SHA-1 _z40=0000000000000000000000000000000000000000 +# Line feed +LF=' +' + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... @@@ -361,6 -357,24 +361,24 @@@ test_chmod () git update-index --add "--chmod=$@" } + # Unset a configuration variable, but don't fail if it doesn't exist. + test_unconfig () { + git config --unset-all "$@" + config_status=$? + case "$config_status" in + 5) # ok, nothing to unset + config_status=0 + ;; + esac + return $config_status + } + + # Set git config, automatically unsetting it after the test is over. + test_config () { + test_when_finished "test_unconfig '$1'" && + git config "$@" + } + # Use test_set_prereq to tell that a particular prerequisite is available. # The prerequisite can later be checked for in two ways: # @@@ -448,26 -462,20 +466,26 @@@ test_debug () test "$debug" = "" || eval "$1" } +test_eval_ () { + # This is a separate function because some tests use + # "return" to end a test_expect_success block early. + eval >&3 2>&4 "$*" +} + test_run_ () { test_cleanup=: expecting_failure=$2 - eval >&3 2>&4 "$1" + test_eval_ "$1" eval_ret=$? if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure" then - eval >&3 2>&4 "$test_cleanup" + test_eval_ "$test_cleanup" fi if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then echo "" fi - return 0 + return "$eval_ret" } test_skip () { @@@ -512,7 -520,8 +530,7 @@@ test_expect_failure () if ! test_skip "$@" then say >&3 "checking known breakage: $2" - test_run_ "$2" expecting_failure - if [ "$?" = 0 -a "$eval_ret" = 0 ] + if test_run_ "$2" expecting_failure then test_known_broken_ok_ "$1" else @@@ -530,7 -539,8 +548,7 @@@ test_expect_success () if ! test_skip "$@" then say >&3 "expecting success: $2" - test_run_ "$2" - if [ "$?" = 0 -a "$eval_ret" = 0 ] + if test_run_ "$2" then test_ok_ "$1" else diff --combined wt-status.c index 02377729c4,f2016dcdcc..8836a527d0 --- a/wt-status.c +++ b/wt-status.c @@@ -26,7 -26,9 +26,9 @@@ static char default_wt_status_colors[][ static const char *color(int slot, struct wt_status *s) { - const char *c = s->use_color > 0 ? s->color_palette[slot] : ""; + const char *c = ""; + if (want_color(s->use_color)) + c = s->color_palette[slot]; if (slot == WT_STATUS_ONBRANCH && color_is_nil(c)) c = s->color_palette[WT_STATUS_HEADER]; return c; @@@ -642,7 -644,7 +644,7 @@@ static void wt_status_print_other(struc int i; struct strbuf buf = STRBUF_INIT; - if (!s->untracked.nr) + if (!l->nr) return; wt_status_print_other_header(s, what, how); @@@ -681,7 -683,7 +683,7 @@@ static void wt_status_print_verbose(str * will have checked isatty on stdout). */ if (s->fp != stdout) - DIFF_OPT_CLR(&rev.diffopt, COLOR_DIFF); + rev.diffopt.use_color = 0; run_diff_index(&rev, 1); }