Skip to content

Commit 95433ee

Browse files
newrengitster
authored andcommitted
diff: add ability to insert additional headers for paths
When additional headers are provided, we need to * add diff_filepairs to diff_queued_diff for each paths in the additional headers map which, unless that path is part of another diff_filepair already found in diff_queued_diff * format the headers (colorization, line_prefix for --graph) * make sure the various codepaths that attempt to return early if there are "no changes" take into account the headers that need to be shown. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6054d1a commit 95433ee

File tree

3 files changed

+123
-6
lines changed

3 files changed

+123
-6
lines changed

diff.c

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "help.h"
2828
#include "promisor-remote.h"
2929
#include "dir.h"
30+
#include "strmap.h"
3031

3132
#ifdef NO_FAST_WORKING_DIRECTORY
3233
#define FAST_WORKING_DIRECTORY 0
@@ -3406,6 +3407,31 @@ struct userdiff_driver *get_textconv(struct repository *r,
34063407
return userdiff_get_textconv(r, one->driver);
34073408
}
34083409

3410+
static struct strbuf *additional_headers(struct diff_options *o,
3411+
const char *path)
3412+
{
3413+
if (!o->additional_path_headers)
3414+
return NULL;
3415+
return strmap_get(o->additional_path_headers, path);
3416+
}
3417+
3418+
static void add_formatted_headers(struct strbuf *msg,
3419+
struct strbuf *more_headers,
3420+
const char *line_prefix,
3421+
const char *meta,
3422+
const char *reset)
3423+
{
3424+
char *next, *newline;
3425+
3426+
for (next = more_headers->buf; *next; next = newline) {
3427+
newline = strchrnul(next, '\n');
3428+
strbuf_addf(msg, "%s%s%.*s%s\n", line_prefix, meta,
3429+
(int)(newline - next), next, reset);
3430+
if (*newline)
3431+
newline++;
3432+
}
3433+
}
3434+
34093435
static void builtin_diff(const char *name_a,
34103436
const char *name_b,
34113437
struct diff_filespec *one,
@@ -3464,6 +3490,17 @@ static void builtin_diff(const char *name_a,
34643490
b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
34653491
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
34663492
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
3493+
if (!DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two)) {
3494+
/*
3495+
* We should only reach this point for pairs from
3496+
* create_filepairs_for_header_only_notifications(). For
3497+
* these, we should avoid the "/dev/null" special casing
3498+
* above, meaning we avoid showing such pairs as either
3499+
* "new file" or "deleted file" below.
3500+
*/
3501+
lbl[0] = a_one;
3502+
lbl[1] = b_two;
3503+
}
34673504
strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset);
34683505
if (lbl[0][0] == '/') {
34693506
/* /dev/null */
@@ -4328,6 +4365,7 @@ static void fill_metainfo(struct strbuf *msg,
43284365
const char *set = diff_get_color(use_color, DIFF_METAINFO);
43294366
const char *reset = diff_get_color(use_color, DIFF_RESET);
43304367
const char *line_prefix = diff_line_prefix(o);
4368+
struct strbuf *more_headers = NULL;
43314369

43324370
*must_show_header = 1;
43334371
strbuf_init(msg, PATH_MAX * 2 + 300);
@@ -4364,6 +4402,11 @@ static void fill_metainfo(struct strbuf *msg,
43644402
default:
43654403
*must_show_header = 0;
43664404
}
4405+
if ((more_headers = additional_headers(o, name))) {
4406+
add_formatted_headers(msg, more_headers,
4407+
line_prefix, set, reset);
4408+
*must_show_header = 1;
4409+
}
43674410
if (one && two && !oideq(&one->oid, &two->oid)) {
43684411
const unsigned hexsz = the_hash_algo->hexsz;
43694412
int abbrev = o->abbrev ? o->abbrev : DEFAULT_ABBREV;
@@ -5852,12 +5895,27 @@ int diff_unmodified_pair(struct diff_filepair *p)
58525895

58535896
static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
58545897
{
5855-
if (diff_unmodified_pair(p))
5898+
int include_conflict_headers =
5899+
(additional_headers(o, p->one->path) &&
5900+
(!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o)));
5901+
5902+
/*
5903+
* Check if we can return early without showing a diff. Note that
5904+
* diff_filepair only stores {oid, path, mode, is_valid}
5905+
* information for each path, and thus diff_unmodified_pair() only
5906+
* considers those bits of info. However, we do not want pairs
5907+
* created by create_filepairs_for_header_only_notifications()
5908+
* (which always look like unmodified pairs) to be ignored, so
5909+
* return early if both p is unmodified AND we don't want to
5910+
* include_conflict_headers.
5911+
*/
5912+
if (diff_unmodified_pair(p) && !include_conflict_headers)
58565913
return;
58575914

5915+
/* Actually, we can also return early to avoid showing tree diffs */
58585916
if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
58595917
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
5860-
return; /* no tree diffs in patch format */
5918+
return;
58615919

58625920
run_diff(p, o);
58635921
}
@@ -5888,10 +5946,17 @@ static void diff_flush_checkdiff(struct diff_filepair *p,
58885946
run_checkdiff(p, o);
58895947
}
58905948

5891-
int diff_queue_is_empty(void)
5949+
int diff_queue_is_empty(struct diff_options *o)
58925950
{
58935951
struct diff_queue_struct *q = &diff_queued_diff;
58945952
int i;
5953+
int include_conflict_headers =
5954+
(o->additional_path_headers &&
5955+
(!o->filter || filter_bit_tst(DIFF_STATUS_UNMERGED, o)));
5956+
5957+
if (include_conflict_headers)
5958+
return 0;
5959+
58955960
for (i = 0; i < q->nr; i++)
58965961
if (!diff_unmodified_pair(q->queue[i]))
58975962
return 0;
@@ -6325,6 +6390,54 @@ void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc)
63256390
warning(_(rename_limit_advice), varname, needed);
63266391
}
63276392

6393+
static void create_filepairs_for_header_only_notifications(struct diff_options *o)
6394+
{
6395+
struct strset present;
6396+
struct diff_queue_struct *q = &diff_queued_diff;
6397+
struct hashmap_iter iter;
6398+
struct strmap_entry *e;
6399+
int i;
6400+
6401+
strset_init_with_options(&present, /*pool*/ NULL, /*strdup*/ 0);
6402+
6403+
/*
6404+
* Find out which paths exist in diff_queued_diff, preferring
6405+
* one->path for any pair that has multiple paths.
6406+
*/
6407+
for (i = 0; i < q->nr; i++) {
6408+
struct diff_filepair *p = q->queue[i];
6409+
char *path = p->one->path ? p->one->path : p->two->path;
6410+
6411+
if (strmap_contains(o->additional_path_headers, path))
6412+
strset_add(&present, path);
6413+
}
6414+
6415+
/*
6416+
* Loop over paths in additional_path_headers; for each NOT already
6417+
* in diff_queued_diff, create a synthetic filepair and insert that
6418+
* into diff_queued_diff.
6419+
*/
6420+
strmap_for_each_entry(o->additional_path_headers, &iter, e) {
6421+
if (!strset_contains(&present, e->key)) {
6422+
struct diff_filespec *one, *two;
6423+
struct diff_filepair *p;
6424+
6425+
one = alloc_filespec(e->key);
6426+
two = alloc_filespec(e->key);
6427+
fill_filespec(one, null_oid(), 0, 0);
6428+
fill_filespec(two, null_oid(), 0, 0);
6429+
p = diff_queue(q, one, two);
6430+
p->status = DIFF_STATUS_MODIFIED;
6431+
}
6432+
}
6433+
6434+
/* Re-sort the filepairs */
6435+
diffcore_fix_diff_index();
6436+
6437+
/* Cleanup */
6438+
strset_clear(&present);
6439+
}
6440+
63286441
static void diff_flush_patch_all_file_pairs(struct diff_options *o)
63296442
{
63306443
int i;
@@ -6337,6 +6450,9 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
63376450
if (o->color_moved)
63386451
o->emitted_symbols = &esm;
63396452

6453+
if (o->additional_path_headers)
6454+
create_filepairs_for_header_only_notifications(o);
6455+
63406456
for (i = 0; i < q->nr; i++) {
63416457
struct diff_filepair *p = q->queue[i];
63426458
if (check_pair_status(p))
@@ -6413,7 +6529,7 @@ void diff_flush(struct diff_options *options)
64136529
* Order: raw, stat, summary, patch
64146530
* or: name/name-status/checkdiff (other bits clear)
64156531
*/
6416-
if (!q->nr)
6532+
if (!q->nr && !options->additional_path_headers)
64176533
goto free_queue;
64186534

64196535
if (output_format & (DIFF_FORMAT_RAW |

diff.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ struct diff_options {
395395

396396
struct repository *repo;
397397
struct option *parseopts;
398+
struct strmap *additional_path_headers;
398399

399400
int no_free;
400401
};
@@ -593,7 +594,7 @@ void diffcore_fix_diff_index(void);
593594
" show all files diff when -S is used and hit is found.\n" \
594595
" -a --text treat all files as text.\n"
595596

596-
int diff_queue_is_empty(void);
597+
int diff_queue_is_empty(struct diff_options *o);
597598
void diff_flush(struct diff_options*);
598599
void diff_free(struct diff_options*);
599600
void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);

log-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ int log_tree_diff_flush(struct rev_info *opt)
852852
opt->shown_dashes = 0;
853853
diffcore_std(&opt->diffopt);
854854

855-
if (diff_queue_is_empty()) {
855+
if (diff_queue_is_empty(&opt->diffopt)) {
856856
int saved_fmt = opt->diffopt.output_format;
857857
opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
858858
diff_flush(&opt->diffopt);

0 commit comments

Comments
 (0)