From 949226fe77beb1027bd5ac7be56fe002236d6cad Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 14:19:24 -0700 Subject: diff: pass the whole diff_options to diffcore_apply_filter() The --diff-filter= option given by the user is kept as a string, and passed to the underlying diffcore_apply_filter() function as a string for each resulting path we run number of strchr() to see if each class of change among ACDMRTXUB is meant to be given. Change the function signature to pass the whole diff_options, so that we can pre-parse this string in the next patch. Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 649ec86..41c64f2 100644 --- a/diff.c +++ b/diff.c @@ -4509,11 +4509,13 @@ free_queue: } } -static void diffcore_apply_filter(const char *filter) +static void diffcore_apply_filter(struct diff_options *options) { int i; struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; + const char *filter = options->filter; + DIFF_QUEUE_CLEAR(&outq); if (!filter) @@ -4661,7 +4663,7 @@ void diffcore_std(struct diff_options *options) if (!options->found_follow) /* See try_to_follow_renames() in tree-diff.c */ diff_resolve_rename_copy(); - diffcore_apply_filter(options->filter); + diffcore_apply_filter(options); if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) DIFF_OPT_SET(options, HAS_CHANGES); -- cgit v0.10.2-6-g49f6 From 08578fa13eeec7079101f7ac52208aec83d54c62 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 15:09:34 -0700 Subject: diff: factor out match_filter() diffcore_apply_filter() checks if a filepair matches the filter given with the "--diff-filter" option for each input filepairs with a fairly complex expression in two places. Create a helper function and call it. Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 41c64f2..0220c19 100644 --- a/diff.c +++ b/diff.c @@ -4509,6 +4509,17 @@ free_queue: } } +static int match_filter(const struct diff_options *options, const struct diff_filepair *p) +{ + return (((p->status == DIFF_STATUS_MODIFIED) && + ((p->score && + strchr(options->filter, DIFF_STATUS_FILTER_BROKEN)) || + (!p->score && + strchr(options->filter, DIFF_STATUS_MODIFIED)))) || + ((p->status != DIFF_STATUS_MODIFIED) && + strchr(options->filter, p->status))); +} + static void diffcore_apply_filter(struct diff_options *options) { int i; @@ -4524,14 +4535,7 @@ static void diffcore_apply_filter(struct diff_options *options) if (strchr(filter, DIFF_STATUS_FILTER_AON)) { int found; for (i = found = 0; !found && i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - if (((p->status == DIFF_STATUS_MODIFIED) && - ((p->score && - strchr(filter, DIFF_STATUS_FILTER_BROKEN)) || - (!p->score && - strchr(filter, DIFF_STATUS_MODIFIED)))) || - ((p->status != DIFF_STATUS_MODIFIED) && - strchr(filter, p->status))) + if (match_filter(options, q->queue[i])) found++; } if (found) @@ -4549,14 +4553,7 @@ static void diffcore_apply_filter(struct diff_options *options) /* Only the matching ones */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - - if (((p->status == DIFF_STATUS_MODIFIED) && - ((p->score && - strchr(filter, DIFF_STATUS_FILTER_BROKEN)) || - (!p->score && - strchr(filter, DIFF_STATUS_MODIFIED)))) || - ((p->status != DIFF_STATUS_MODIFIED) && - strchr(filter, p->status))) + if (match_filter(options, p)) diff_q(&outq, p); else diff_free_filepair(p); -- cgit v0.10.2-6-g49f6 From 1ecc1cbd3a7642c4f517d086d7b45d6341172dfe Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 15:05:46 -0700 Subject: diff: preparse --diff-filter string argument Instead of running strchr() on the list of status characters over and over again, parse the --diff-filter option into bitfields and use the bits to see if the change to the filepair matches the status requested. Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 0220c19..03f10e6 100644 --- a/diff.c +++ b/diff.c @@ -3496,6 +3496,53 @@ static int parse_submodule_opt(struct diff_options *options, const char *value) return 1; } +static const char diff_status_letters[] = { + DIFF_STATUS_ADDED, + DIFF_STATUS_COPIED, + DIFF_STATUS_DELETED, + DIFF_STATUS_MODIFIED, + DIFF_STATUS_RENAMED, + DIFF_STATUS_TYPE_CHANGED, + DIFF_STATUS_UNKNOWN, + DIFF_STATUS_UNMERGED, + DIFF_STATUS_FILTER_AON, + DIFF_STATUS_FILTER_BROKEN, + '\0', +}; + +static unsigned int filter_bit['Z' + 1]; + +static void prepare_filter_bits(void) +{ + int i; + + if (!filter_bit[DIFF_STATUS_ADDED]) { + for (i = 0; diff_status_letters[i]; i++) + filter_bit[(int) diff_status_letters[i]] = (1 << i); + } +} + +static unsigned filter_bit_tst(char status, const struct diff_options *opt) +{ + return opt->filter & filter_bit[(int) status]; +} + +static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) +{ + int i, optch; + + prepare_filter_bits(); + for (i = 0; (optch = optarg[i]) != '\0'; i++) { + unsigned int bit; + + bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0; + if (!bit) + continue; /* ignore unknown ones, like we always have */ + opt->filter |= bit; + } + return 0; +} + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; @@ -3717,7 +3764,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) return argcount; } else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { - options->filter = optarg; + int offending = parse_diff_filter_opt(optarg, options); + if (offending) + die("unknown change class '%c' in --diff-filter=%s", + offending, optarg); return argcount; } else if (!strcmp(arg, "--abbrev")) @@ -4513,11 +4563,11 @@ static int match_filter(const struct diff_options *options, const struct diff_fi { return (((p->status == DIFF_STATUS_MODIFIED) && ((p->score && - strchr(options->filter, DIFF_STATUS_FILTER_BROKEN)) || + filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) || (!p->score && - strchr(options->filter, DIFF_STATUS_MODIFIED)))) || + filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) || ((p->status != DIFF_STATUS_MODIFIED) && - strchr(options->filter, p->status))); + filter_bit_tst(p->status, options))); } static void diffcore_apply_filter(struct diff_options *options) @@ -4525,14 +4575,13 @@ static void diffcore_apply_filter(struct diff_options *options) int i; struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct outq; - const char *filter = options->filter; DIFF_QUEUE_CLEAR(&outq); - if (!filter) + if (!options->filter) return; - if (strchr(filter, DIFF_STATUS_FILTER_AON)) { + if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) { int found; for (i = found = 0; !found && i < q->nr; i++) { if (match_filter(options, q->queue[i])) diff --git a/diff.h b/diff.h index 78b4091..a367207 100644 --- a/diff.h +++ b/diff.h @@ -103,12 +103,15 @@ enum diff_words_type { }; struct diff_options { - const char *filter; const char *orderfile; const char *pickaxe; const char *single_follow; const char *a_prefix, *b_prefix; unsigned flags; + + /* diff-filter bits */ + unsigned int filter; + int use_color; int context; int interhunkcontext; -- cgit v0.10.2-6-g49f6 From bf142ec4346385553918bc53f203b205091aa362 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 15:27:19 -0700 Subject: diff: reject unknown change class given to --diff-filter We used to accept "git diff --diff-filter=Q" (note that there is no such change class 'Q') silently and showed no output (because there is no such change class 'Q'). Error out when such an input is given. Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 03f10e6..3d37b56 100644 --- a/diff.c +++ b/diff.c @@ -3537,7 +3537,7 @@ static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0; if (!bit) - continue; /* ignore unknown ones, like we always have */ + return optarg[i]; opt->filter |= bit; } return 0; -- cgit v0.10.2-6-g49f6 From 7f2ea5f0f2fb056314092cce23202096ca70f076 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 16:19:19 -0700 Subject: diff: allow lowercase letter to specify what change class to exclude In order to express "we do not care about deletions", we had to say "--diff-filter=ACMRTXUB", giving all the possible change class except for the one we do not want, "D". This is cumbersome. As all the change classes are in uppercase, allow their lowercase counterpart to selectively exclude the class from the output. When such a negated change class is in the input, start the filter option with the full bits set. This would allow us to express the old "show-diff -q" with "git diff-files --diff-filter=d". Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 3d37b56..2d0b5e3 100644 --- a/diff.c +++ b/diff.c @@ -3532,13 +3532,40 @@ static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) int i, optch; prepare_filter_bits(); + + /* + * If there is a negation e.g. 'd' in the input, and we haven't + * initialized the filter field with another --diff-filter, start + * from full set of bits, except for AON. + */ + if (!opt->filter) { + for (i = 0; (optch = optarg[i]) != '\0'; i++) { + if (optch < 'a' || 'z' < optch) + continue; + opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1; + opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON]; + break; + } + } + for (i = 0; (optch = optarg[i]) != '\0'; i++) { unsigned int bit; + int negate; + + if ('a' <= optch && optch <= 'z') { + negate = 1; + optch = toupper(optch); + } else { + negate = 0; + } bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0; if (!bit) return optarg[i]; - opt->filter |= bit; + if (negate) + opt->filter &= ~bit; + else + opt->filter |= bit; } return 0; } -- cgit v0.10.2-6-g49f6 From 95a7c546b02a962b9e458f7fd2d0ed9b657c0ca6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 Jul 2013 17:18:32 -0700 Subject: diff: deprecate -q option to diff-files This reimplements the ancient "-q" option to "git diff-files" that was inherited from "show-diff -q" in terms of "--diff-filter=d". We will be deprecating the "-q" option, so let's issue a warning when we do so. Incidentally this also tentatively fixes "git diff --no-index" to honor "-q" and hide deletions; the use will get the same warning. We should remove the support for "-q" in a future version but it is not that urgent. Signed-off-by: Junio C Hamano diff --git a/diff-lib.c b/diff-lib.c index f35de0f..4634b29 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -86,10 +86,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option) { int entries, i; int diff_unmerged_stage = revs->max_count; - int silent_on_removed = option & DIFF_SILENT_ON_REMOVED; unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) ? CE_MATCH_RACY_IS_DIRTY : 0); + if (option & DIFF_SILENT_ON_REMOVED) + handle_deprecated_show_diff_q(&revs->diffopt); + diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); if (diff_unmerged_stage < 0) @@ -136,8 +138,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option) perror(ce->name); continue; } - if (silent_on_removed) - continue; wt_mode = 0; } dpath->mode = wt_mode; @@ -203,8 +203,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option) perror(ce->name); continue; } - if (silent_on_removed) - continue; diff_addremove(&revs->diffopt, '-', ce->ce_mode, ce->sha1, !is_null_sha1(ce->sha1), ce->name, 0); diff --git a/diff-no-index.c b/diff-no-index.c index 74da659..a788a5f 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -187,7 +187,7 @@ void diff_no_index(struct rev_info *revs, { int i, prefixlen; int no_index = 0; - unsigned options = 0; + unsigned deprecated_show_diff_q_option_used = 0; const char *paths[2]; /* Were we asked to do --no-index explicitly? */ @@ -225,7 +225,7 @@ void diff_no_index(struct rev_info *revs, if (!strcmp(argv[i], "--no-index")) i++; else if (!strcmp(argv[i], "-q")) { - options |= DIFF_SILENT_ON_REMOVED; + deprecated_show_diff_q_option_used = 1; i++; } else if (!strcmp(argv[i], "--")) @@ -260,6 +260,9 @@ void diff_no_index(struct rev_info *revs, revs->max_count = -2; diff_setup_done(&revs->diffopt); + if (deprecated_show_diff_q_option_used) + handle_deprecated_show_diff_q(&revs->diffopt); + setup_diff_pager(&revs->diffopt); DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); diff --git a/diff.c b/diff.c index 2d0b5e3..78819ba 100644 --- a/diff.c +++ b/diff.c @@ -3570,6 +3570,14 @@ static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt) return 0; } +/* Used only by "diff-files" and "diff --no-index" */ +void handle_deprecated_show_diff_q(struct diff_options *opt) +{ + warning("'diff -q' and 'diff-files -q' are deprecated."); + warning("Use 'diff --diff-filter=d' instead to ignore deleted filepairs."); + parse_diff_filter_opt("d", opt); +} + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; diff --git a/diff.h b/diff.h index a367207..5237d63 100644 --- a/diff.h +++ b/diff.h @@ -341,6 +341,8 @@ extern int parse_rename_score(const char **cp_p); extern long parse_algorithm_value(const char *value); +extern void handle_deprecated_show_diff_q(struct diff_options *); + extern int print_stat_summary(FILE *fp, int files, int insertions, int deletions); extern void setup_diff_pager(struct diff_options *); -- cgit v0.10.2-6-g49f6