665
*/
666
struct line_range_filter {
667
xdiff_emit_line_fn orig_line_fn;
668
+ /*
669
+ * Optional; consumers that report file line numbers (e.g.
670
+ * checkdiff) need the synthetic hunk header to set their
671
+ * post-image position before in-range lines are replayed.
672
+ */
673
+ xdiff_emit_hunk_fn orig_hunk_fn;
674
void *orig_cb_data;
675
const struct range_set *ranges; /* 0-based [start, end) */
676
unsigned int cur_range; /* index into the range_set */
2658
filter->hunk.new_begin, new_count,
2659
filter->func, filter->funclen);
2660
2661
+ /*
2662
+ * Inform a line-numbering consumer of the post-image position
2663
+ * before replaying lines, mirroring the hunk callback xdiff
2664
+ * would have issued for a non-scoped diff.
2665
+ */
2666
+ if (filter->orig_hunk_fn)
2667
+ filter->orig_hunk_fn(filter->orig_cb_data,
2668
+ filter->hunk.old_begin, old_count,
2669
+ filter->hunk.new_begin, new_count,
2670
+ filter->func, filter->funclen);
2671
+
2672
filter->ret = filter->orig_line_fn(filter->orig_cb_data, hdr.buf, hdr.len);
2673
strbuf_release(&hdr);
2674
4347
diff_free_filespec_data(two);
4348
}
4349
4350
+/*
4351
+ * Is the 0-based line index within any of the tracked ranges?
4352
+ * (range_set ranges are 0-based, half-open [start, end).) This is a
4353
+ * one-shot query for a single line and scans; the streaming filter
4354
+ * (line_range_line_fn) uses a forward cursor instead.
4355
+ */
4356
+static int idx_in_ranges(const struct range_set *ranges, long idx)
4357
+{
4358
+ unsigned int i;
4359
+
4360
+ for (i = 0; i < ranges->nr; i++)
4361
+ if (idx >= ranges->ranges[i].start &&
4362
+ idx < ranges->ranges[i].end)
4363
+ return 1;
4364
+ return 0;
4365
+}
4366
+
4367
static void builtin_checkdiff(const char *name_a, const char *name_b,
4368
const char *attr_path,
4369
struct diff_filespec *one,
4370
struct diff_filespec *two,
4337
- struct diff_options *o)
4371
+ struct diff_options *o,
4372
+ const struct range_set *line_ranges)
4373
{
4374
mmfile_t mf1, mf2;
4375
struct checkdiff_t data;
4409
memset(&xecfg, 0, sizeof(xecfg));
4410
xecfg.ctxlen = 1; /* at least one context line */
4411
xpp.flags = 0;
4377
- if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume_hunk,
4412
+
4413
+ if (line_ranges) {
4414
+ struct line_range_filter lr_filter;
4415
+
4416
+ line_range_filter_init(&lr_filter, line_ranges,
4417
+ checkdiff_consume, &data);
4418
+ lr_filter.orig_hunk_fn = checkdiff_consume_hunk;
4419
+
4420
+ if (line_range_filter_diff(&lr_filter, &mf1, &mf2,
4421
+ &xpp, &xecfg))
4422
+ die("unable to generate checkdiff for %s",
4423
+ one->path);
4424
+ } else if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume_hunk,
4425
checkdiff_consume, &data,
4426
&xpp, &xecfg))
4427
die("unable to generate checkdiff for %s", one->path);
4434
check_blank_at_eof(&mf1, &mf2, &ecbdata);
4435
blank_at_eof = ecbdata.blank_at_eof_in_postimage;
4436
4437
+ /*
4438
+ * check_blank_at_eof() scans the whole file; with -L,
4439
+ * keep the report only when its line is in a tracked
4440
+ * range. The error's location is the first trailing
4441
+ * blank line (blank_at_eof, 1-based; ranges 0-based), so
4442
+ * we scope by that line.
4443
+ */
4444
+ if (blank_at_eof && line_ranges &&
4445
+ !idx_in_ranges(line_ranges, blank_at_eof - 1))
4446
+ blank_at_eof = 0;
4447
+
4448
if (blank_at_eof) {
4449
static char *err;
4450
if (!err)
5237
diff_fill_oid_info(p->one, o->repo->index);
5238
diff_fill_oid_info(p->two, o->repo->index);
5239
5182
- builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
5240
+ builtin_checkdiff(name, other, attr_path, p->one, p->two, o,
5241
+ p->line_ranges);
5242
}
5243
5244
void repo_diff_setup(struct repository *r, struct diff_options *options)