diff: introduce a hunk provider interface
To learn which line ranges changed between two blobs, every consumer in the diff machinery loads both blobs and runs xdiff. There is no other way to supply that answer, even when it is known elsewhere: a cache may hold the ranges from the last time the pair was diffed, and a format-aware process may have its own idea of which lines changed. Either could answer from the blob object ids alone, but the loading and computing are hard-wired into each consumer, so such an answer has no place to enter. Introduce the hunk provider interface, diff-provider.h, between asking the question and computing the answer. A provider answers a request made of the pair's identity, its blob object ids and the parameters that determine the diff. A provider is either authoritative, so its answer may deliberately differ from the builtin diff, or not, so its answer must reproduce the builtin result exactly. Every answer served from identity passes diff_provider_check_hunk() before a consumer sees it: coordinates fit int32, hunks are ordered and non-overlapping, and the unchanged runs between them match on both sides. A failing answer is discarded and the pair falls through as unanswered. Providers are repository-lifecycle objects. Each repository owns a chain of them, built on first consultation and released from repo_clear(), so a submodule gets its own providers and no provider state outlives the repository it serves. The chain has a fixed composition, and each provider gates itself per request, passing when it does not apply. Chain order is the authority: the first answer wins. A provider may instead refuse a pair whose request is shaped by parameters its recording key cannot express. After a refusal, no later provider answers the pair from identity, and the consumer must not record what it computes for it. The last provider is the builtin computation, the only one that computes rather than answering from identity, so a walk given a fill callback always ends in an answer, refusal or not. The walk in diff-provider.c maps a provider's four dispositions (answer, pass, fail, refuse) onto the consumer-facing outcomes, and checks with BUG() that only the computing provider fails and that it passes on a walk with no fill callback. The implementor contract, the provider struct, its dispositions, and the shared check, lives in diff-provider-internal.h, as refs/refs-internal.h is to refs.h; consumers see only diff-provider.h. The consumer surface is two types. struct diff_provider_request names what is diffed and under which parameters; each later commit that consults on more state adds the field it keys on (the object ids and diff options, then the path). enum diff_provider_outcome flattens two dependent axes into four points: the response state (answered, unanswered, failed) and, only when unanswered, whether the caller may record what it computes. The record rule rides in the outcome, not a separate flag, so -Wswitch forces every consumer to place the no-record arm. A provider added later maps onto these values inside the walk, so consumer code is written once. diff_provider_emit_hunks() is the consumer entry: the caller states the request, a hunk callback, and a content-loading callback that reaches the terminal provider only when the ranges are computed. Blame's pass_blame_to_parent() is the first consumer, since it knows both blob ids before reading either blob; its loads move into the fill callback. With only the terminal provider registered, every request still computes, so behavior is unchanged. (Blame's -C/-M split detection diffs partial buffers with no blob identity and stays on xdi_diff().) Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>