1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 module libgit2_d.diff;
8 
9 
10 private static import libgit2_d.buffer;
11 private static import libgit2_d.oid;
12 private static import libgit2_d.strarray;
13 private static import libgit2_d.types;
14 
15 /**
16  * @file git2/diff.h
17  * @brief Git tree and file differencing routines.
18  * @ingroup Git
19  * @{
20  */
21 extern (C):
22 nothrow @nogc:
23 public:
24 
25 /**
26  * Flags for diff options.  A combination of these flags can be passed
27  * in via the `flags` value in the `git_diff_options`.
28  */
29 enum git_diff_option_t
30 {
31 	/**
32 	 * Normal diff, the default
33 	 */
34 	GIT_DIFF_NORMAL = 0,
35 
36 	/*
37 	 * Options controlling which files will be in the diff
38 	 */
39 
40 	/**
41 	 * Reverse the sides of the diff
42 	 */
43 	GIT_DIFF_REVERSE = 1u << 0,
44 
45 	/**
46 	 * Include ignored files in the diff
47 	 */
48 	GIT_DIFF_INCLUDE_IGNORED = 1u << 1,
49 
50 	/**
51 	 * Even with GIT_DIFF_INCLUDE_IGNORED, an entire ignored directory
52 	 *  will be marked with only a single entry in the diff; this flag
53 	 *  adds all files under the directory as IGNORED entries, too.
54 	 */
55 	GIT_DIFF_RECURSE_IGNORED_DIRS = 1u << 2,
56 
57 	/**
58 	 * Include untracked files in the diff
59 	 */
60 	GIT_DIFF_INCLUDE_UNTRACKED = 1u << 3,
61 
62 	/**
63 	 * Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked
64 	 *  directory will be marked with only a single entry in the diff
65 	 *  (a la what core Git does in `git status`); this flag adds *all*
66 	 *  files under untracked directories as UNTRACKED entries, too.
67 	 */
68 	GIT_DIFF_RECURSE_UNTRACKED_DIRS = 1u << 4,
69 
70 	/**
71 	 * Include unmodified files in the diff
72 	 */
73 	GIT_DIFF_INCLUDE_UNMODIFIED = 1u << 5,
74 
75 	/**
76 	 * Normally, a type change between files will be converted into a
77 	 *  DELETED record for the old and an ADDED record for the new; this
78 	 *  options enabled the generation of TYPECHANGE delta records.
79 	 */
80 	GIT_DIFF_INCLUDE_TYPECHANGE = 1u << 6,
81 
82 	/**
83 	 * Even with GIT_DIFF_INCLUDE_TYPECHANGE, blob->tree changes still
84 	 *  generally show as a DELETED blob.  This flag tries to correctly
85 	 *  label blob->tree transitions as TYPECHANGE records with new_file's
86 	 *  mode set to tree.  Note: the tree SHA will not be available.
87 	 */
88 	GIT_DIFF_INCLUDE_TYPECHANGE_TREES = 1u << 7,
89 
90 	/**
91 	 * Ignore file mode changes
92 	 */
93 	GIT_DIFF_IGNORE_FILEMODE = 1u << 8,
94 
95 	/**
96 	 * Treat all submodules as unmodified
97 	 */
98 	GIT_DIFF_IGNORE_SUBMODULES = 1u << 9,
99 
100 	/**
101 	 * Use case insensitive filename comparisons
102 	 */
103 	GIT_DIFF_IGNORE_CASE = 1u << 10,
104 
105 	/**
106 	 * May be combined with `GIT_DIFF_IGNORE_CASE` to specify that a file
107 	 *  that has changed case will be returned as an add/delete pair.
108 	 */
109 	GIT_DIFF_INCLUDE_CASECHANGE = 1u << 11,
110 
111 	/**
112 	 * If the pathspec is set in the diff options, this flags indicates
113 	 *  that the paths will be treated as literal paths instead of
114 	 *  fnmatch patterns.  Each path in the list must either be a full
115 	 *  path to a file or a directory.  (A trailing slash indicates that
116 	 *  the path will _only_ match a directory).  If a directory is
117 	 *  specified, all children will be included.
118 	 */
119 	GIT_DIFF_DISABLE_PATHSPEC_MATCH = 1u << 12,
120 
121 	/**
122 	 * Disable updating of the `binary` flag in delta records.  This is
123 	 *  useful when iterating over a diff if you don't need hunk and data
124 	 *  callbacks and want to avoid having to load file completely.
125 	 */
126 	GIT_DIFF_SKIP_BINARY_CHECK = 1u << 13,
127 
128 	/**
129 	 * When diff finds an untracked directory, to match the behavior of
130 	 *  core Git, it scans the contents for IGNORED and UNTRACKED files.
131 	 *  If *all* contents are IGNORED, then the directory is IGNORED; if
132 	 *  any contents are not IGNORED, then the directory is UNTRACKED.
133 	 *  This is extra work that may not matter in many cases.  This flag
134 	 *  turns off that scan and immediately labels an untracked directory
135 	 *  as UNTRACKED (changing the behavior to not match core Git).
136 	 */
137 	GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS = 1u << 14,
138 
139 	/**
140 	 * When diff finds a file in the working directory with stat
141 	 * information different from the index, but the OID ends up being the
142 	 * same, write the correct stat information into the index.  Note:
143 	 * without this flag, diff will always leave the index untouched.
144 	 */
145 	GIT_DIFF_UPDATE_INDEX = 1u << 15,
146 
147 	/**
148 	 * Include unreadable files in the diff
149 	 */
150 	GIT_DIFF_INCLUDE_UNREADABLE = 1u << 16,
151 
152 	/**
153 	 * Include unreadable files in the diff
154 	 */
155 	GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED = 1u << 17,
156 
157 	/*
158 	 * Options controlling how output will be generated
159 	 */
160 
161 	/**
162 	 * Use a heuristic that takes indentation and whitespace into account
163 	 * which generally can produce better diffs when dealing with ambiguous
164 	 * diff hunks.
165 	 */
166 	GIT_DIFF_INDENT_HEURISTIC = 1u << 18,
167 
168 	/**
169 	 * Treat all files as text, disabling binary attributes & detection
170 	 */
171 	GIT_DIFF_FORCE_TEXT = 1u << 20,
172 
173 	/**
174 	 * Treat all files as binary, disabling text diffs
175 	 */
176 	GIT_DIFF_FORCE_BINARY = 1u << 21,
177 
178 	/**
179 	 * Ignore all whitespace
180 	 */
181 	GIT_DIFF_IGNORE_WHITESPACE = 1u << 22,
182 
183 	/**
184 	 * Ignore changes in amount of whitespace
185 	 */
186 	GIT_DIFF_IGNORE_WHITESPACE_CHANGE = 1u << 23,
187 
188 	/**
189 	 * Ignore whitespace at end of line
190 	 */
191 	GIT_DIFF_IGNORE_WHITESPACE_EOL = 1u << 24,
192 
193 	/**
194 	 * When generating patch text, include the content of untracked
195 	 *  files.  This automatically turns on GIT_DIFF_INCLUDE_UNTRACKED but
196 	 *  it does not turn on GIT_DIFF_RECURSE_UNTRACKED_DIRS.  Add that
197 	 *  flag if you want the content of every single UNTRACKED file.
198 	 */
199 	GIT_DIFF_SHOW_UNTRACKED_CONTENT = 1u << 25,
200 
201 	/**
202 	 * When generating output, include the names of unmodified files if
203 	 *  they are included in the git_diff.  Normally these are skipped in
204 	 *  the formats that list files (e.g. name-only, name-status, raw).
205 	 *  Even with this, these will not be included in patch format.
206 	 */
207 	GIT_DIFF_SHOW_UNMODIFIED = 1u << 26,
208 
209 	/**
210 	 * Use the "patience diff" algorithm
211 	 */
212 	GIT_DIFF_PATIENCE = 1u << 28,
213 
214 	/**
215 	 * Take extra time to find minimal diff
216 	 */
217 	GIT_DIFF_MINIMAL = 1u << 29,
218 
219 	/**
220 	 * Include the necessary deflate / delta information so that `git-apply`
221 	 *  can apply given diff information to binary files.
222 	 */
223 	GIT_DIFF_SHOW_BINARY = 1u << 30,
224 }
225 
226 /**
227  * The diff object that contains all individual file deltas.
228  *
229  * A `diff` represents the cumulative list of differences between two
230  * snapshots of a repository (possibly filtered by a set of file name
231  * patterns).
232  *
233  * Calculating diffs is generally done in two phases: building a list of
234  * diffs then traversing it. This makes is easier to share logic across
235  * the various types of diffs (tree vs tree, workdir vs index, etc.), and
236  * also allows you to insert optional diff post-processing phases,
237  * such as rename detection, in between the steps. When you are done with
238  * a diff object, it must be freed.
239  *
240  * This is an opaque structure which will be allocated by one of the diff
241  * generator functions below (such as `git_diff_tree_to_tree`). You are
242  * responsible for releasing the object memory when done, using the
243  * `git_diff_free()` function.
244  */
245 struct git_diff;
246 
247 /**
248  * Flags for the delta object and the file objects on each side.
249  *
250  * These flags are used for both the `flags` value of the `git_diff_delta`
251  * and the flags for the `git_diff_file` objects representing the old and
252  * new sides of the delta.  Values outside of this public range should be
253  * considered reserved for internal or future use.
254  */
255 enum git_diff_flag_t
256 {
257 	/**
258 	 * file(s) treated as binary data
259 	 */
260 	GIT_DIFF_FLAG_BINARY = 1u << 0,
261 
262 	/**
263 	 * file(s) treated as text data
264 	 */
265 	GIT_DIFF_FLAG_NOT_BINARY = 1u << 1,
266 
267 	/**
268 	 * `id` value is known correct
269 	 */
270 	GIT_DIFF_FLAG_VALID_ID = 1u << 2,
271 
272 	/**
273 	 * file exists at this side of the delta
274 	 */
275 	GIT_DIFF_FLAG_EXISTS = 1u << 3,
276 }
277 
278 /**
279  * What type of change is described by a git_diff_delta?
280  *
281  * `GIT_DELTA_RENAMED` and `GIT_DELTA_COPIED` will only show up if you run
282  * `git_diff_find_similar()` on the diff object.
283  *
284  * `GIT_DELTA_TYPECHANGE` only shows up given `GIT_DIFF_INCLUDE_TYPECHANGE`
285  * in the option flags (otherwise type changes will be split into ADDED /
286  * DELETED pairs).
287  */
288 enum git_delta_t
289 {
290 	/**
291 	 * no changes
292 	 */
293 	GIT_DELTA_UNMODIFIED = 0,
294 
295 	/**
296 	 * entry does not exist in old version
297 	 */
298 	GIT_DELTA_ADDED = 1,
299 
300 	/**
301 	 * entry does not exist in new version
302 	 */
303 	GIT_DELTA_DELETED = 2,
304 
305 	/**
306 	 * entry content changed between old and new
307 	 */
308 	GIT_DELTA_MODIFIED = 3,
309 
310 	/**
311 	 * entry was renamed between old and new
312 	 */
313 	GIT_DELTA_RENAMED = 4,
314 
315 	/**
316 	 * entry was copied from another old entry
317 	 */
318 	GIT_DELTA_COPIED = 5,
319 
320 	/**
321 	 * entry is ignored item in workdir
322 	 */
323 	GIT_DELTA_IGNORED = 6,
324 
325 	/**
326 	 * entry is untracked item in workdir
327 	 */
328 	GIT_DELTA_UNTRACKED = 7,
329 
330 	/**
331 	 * type of entry changed between old and new
332 	 */
333 	GIT_DELTA_TYPECHANGE = 8,
334 
335 	/**
336 	 * entry is unreadable
337 	 */
338 	GIT_DELTA_UNREADABLE = 9,
339 
340 	/**
341 	 * entry in the index is conflicted
342 	 */
343 	GIT_DELTA_CONFLICTED = 10,
344 }
345 
346 /**
347  * Description of one side of a delta.
348  *
349  * Although this is called a "file", it could represent a file, a symbolic
350  * link, a submodule commit id, or even a tree (although that only if you
351  * are tracking type changes or ignored/untracked directories).
352  *
353  * The `id` is the `git_oid` of the item.  If the entry represents an
354  * absent side of a diff (e.g. the `old_file` of a `git_delta_t.GIT_DELTA_ADDED` delta),
355  * then the oid will be zeroes.
356  *
357  * `path` is the NUL-terminated path to the entry relative to the working
358  * directory of the repository.
359  *
360  * `size` is the size of the entry in bytes.
361  *
362  * `flags` is a combination of the `git_diff_flag_t` types
363  *
364  * `mode` is, roughly, the stat() `st_mode` value for the item.  This will
365  * be restricted to one of the `libgit2_d.types.git_filemode_t` values.
366  *
367  * The `id_abbrev` represents the known length of the `id` field, when
368  * converted to a hex string.  It is generally `GIT_OID_HEXSZ`, unless this
369  * delta was created from reading a patch file, in which case it may be
370  * abbreviated to something reasonable, like 7 characters.
371  */
372 struct git_diff_file
373 {
374 	libgit2_d.oid.git_oid id;
375 	const (char)* path;
376 	libgit2_d.types.git_object_size_t size;
377 	uint flags;
378 	ushort mode;
379 	ushort id_abbrev;
380 }
381 
382 /**
383  * Description of changes to one entry.
384  *
385  * A `delta` is a file pair with an old and new revision.  The old version
386  * may be absent if the file was just created and the new version may be
387  * absent if the file was deleted.  A diff is mostly just a list of deltas.
388  *
389  * When iterating over a diff, this will be passed to most callbacks and
390  * you can use the contents to understand exactly what has changed.
391  *
392  * The `old_file` represents the "from" side of the diff and the `new_file`
393  * represents to "to" side of the diff.  What those means depend on the
394  * function that was used to generate the diff and will be documented below.
395  * You can also use the `git_diff_option_t.GIT_DIFF_REVERSE` flag to flip it around.
396  *
397  * Although the two sides of the delta are named "old_file" and "new_file",
398  * they actually may correspond to entries that represent a file, a symbolic
399  * link, a submodule commit id, or even a tree (if you are tracking type
400  * changes or ignored/untracked directories).
401  *
402  * Under some circumstances, in the name of efficiency, not all fields will
403  * be filled in, but we generally try to fill in as much as possible.  One
404  * example is that the "flags" field may not have either the `BINARY` or the
405  * `NOT_BINARY` flag set to avoid examining file contents if you do not pass
406  * in hunk and/or line callbacks to the diff foreach iteration function.  It
407  * will just use the git attributes for those files.
408  *
409  * The similarity score is zero unless you call `git_diff_find_similar()`
410  * which does a similarity analysis of files in the diff.  Use that
411  * function to do rename and copy detection, and to split heavily modified
412  * files in add/delete pairs.  After that call, deltas with a status of
413  * GIT_DELTA_RENAMED or GIT_DELTA_COPIED will have a similarity score
414  * between 0 and 100 indicating how similar the old and new sides are.
415  *
416  * If you ask `git_diff_find_similar` to find heavily modified files to
417  * break, but to not *actually* break the records, then GIT_DELTA_MODIFIED
418  * records may have a non-zero similarity score if the self-similarity is
419  * below the split threshold.  To display this value like core Git, invert
420  * the score (a la `printf("M%03d", 100 - delta->similarity)`).
421  */
422 struct git_diff_delta
423 {
424 	.git_delta_t status;
425 
426 	/**
427 	 * git_diff_flag_t values
428 	 */
429 	uint flags;
430 
431 	/**
432 	 * for RENAMED and COPIED, value 0-100
433 	 */
434 	ushort similarity;
435 
436 	/**
437 	 * number of files in this delta
438 	 */
439 	ushort nfiles;
440 
441 	.git_diff_file old_file;
442 	.git_diff_file new_file;
443 }
444 
445 /**
446  * Diff notification callback function.
447  *
448  * The callback will be called for each file, just before the `git_diff_delta`
449  * gets inserted into the diff.
450  *
451  * When the callback:
452  * - returns < 0, the diff process will be aborted.
453  * - returns > 0, the delta will not be inserted into the diff, but the
454  *		diff process continues.
455  * - returns 0, the delta is inserted into the diff, and the diff process
456  *		continues.
457  */
458 alias git_diff_notify_cb = int function(const (.git_diff)* diff_so_far, const (.git_diff_delta)* delta_to_add, const (char)* matched_pathspec, void* payload);
459 
460 /**
461  * Diff progress callback.
462  *
463  * Called before each file comparison.
464  *
465  * Params:
466  *      diff_so_far = The diff being generated.
467  *      old_path = The path to the old file or null.
468  *      new_path = The path to the new file or null.
469  *
470  * Returns: Non-zero to abort the diff.
471  */
472 alias git_diff_progress_cb = int function(const (.git_diff)* diff_so_far, const (char)* old_path, const (char)* new_path, void* payload);
473 
474 /**
475  * Structure describing options about how the diff should be executed.
476  *
477  * Setting all values of the structure to zero will yield the default
478  * values.  Similarly, passing null for the options structure will
479  * give the defaults.  The default values are marked below.
480  */
481 struct git_diff_options
482 {
483 	/**
484 	 * version for the struct
485 	 */
486 	uint version_;
487 
488 	/**
489 	 * A combination of `git_diff_option_t` values above.
490 	 * Defaults to git_diff_option_t.GIT_DIFF_NORMAL
491 	 */
492 	uint flags;
493 
494 	/* options controlling which files are in the diff */
495 
496 	/**
497 	 * Overrides the submodule ignore setting for all submodules in the diff.
498 	 */
499 	libgit2_d.types.git_submodule_ignore_t ignore_submodules;
500 
501 	/**
502 	 * An array of paths / fnmatch patterns to constrain diff.
503 	 * All paths are included by default.
504 	 */
505 	libgit2_d.strarray.git_strarray pathspec;
506 
507 	/**
508 	 * An optional callback function, notifying the consumer of changes to
509 	 * the diff as new deltas are added.
510 	 */
511 	.git_diff_notify_cb notify_cb;
512 
513 	/**
514 	 * An optional callback function, notifying the consumer of which files
515 	 * are being examined as the diff is generated.
516 	 */
517 	.git_diff_progress_cb progress_cb;
518 
519 	/**
520 	 * The payload to pass to the callback functions.
521 	 */
522 	void* payload;
523 
524 	/* options controlling how to diff text is generated */
525 
526 	/**
527 	 * The number of unchanged lines that define the boundary of a hunk
528 	 * (and to display before and after). Defaults to 3.
529 	 */
530 	uint context_lines;
531 
532 	/**
533 	 * The maximum number of unchanged lines between hunk boundaries before
534 	 * the hunks will be merged into one. Defaults to 0.
535 	 */
536 	uint interhunk_lines;
537 
538 	/**
539 	 * The abbreviation length to use when formatting object ids.
540 	 * Defaults to the value of 'core.abbrev' from the config, or 7 if unset.
541 	 */
542 	ushort id_abbrev;
543 
544 	/**
545 	 * A size (in bytes) above which a blob will be marked as binary
546 	 * automatically; pass a negative value to disable.
547 	 * Defaults to 512MB.
548 	 */
549 	libgit2_d.types.git_off_t max_size;
550 
551 	/**
552 	 * The virtual "directory" prefix for old file names in hunk headers.
553 	 * Default is "a".
554 	 */
555 	const (char)* old_prefix;
556 
557 	/**
558 	 * The virtual "directory" prefix for new file names in hunk headers.
559 	 * Defaults to "b".
560 	 */
561 	const (char)* new_prefix;
562 }
563 
564 /**
565  * The current version of the diff options structure
566  */
567 enum GIT_DIFF_OPTIONS_VERSION = 1;
568 
569 /*
570  * Stack initializer for diff options.  Alternatively use
571  * `git_diff_options_init` programmatic initialization.
572  */
573 
574 pragma(inline, true)
575 pure nothrow @safe @nogc
576 .git_diff_options GIT_DIFF_OPTIONS_INIT()
577 
578 	do
579 	{
580 		libgit2_d.strarray.git_strarray PATHSPEC_OPTION =
581 		{
582 			strings: null,
583 			count: 0,
584 		};
585 
586 		.git_diff_options OUTPUT =
587 		{
588 			version_: .GIT_DIFF_OPTIONS_VERSION,
589 			flags: 0,
590 			ignore_submodules: libgit2_d.types.git_submodule_ignore_t.GIT_SUBMODULE_IGNORE_UNSPECIFIED,
591 			pathspec: PATHSPEC_OPTION,
592 			notify_cb: null,
593 			progress_cb: null,
594 			payload: null,
595 			context_lines: 3,
596 		};
597 
598 		return OUTPUT;
599 	}
600 
601 /**
602  * Initialize git_diff_options structure
603  *
604  * Initializes a `git_diff_options` with default values. Equivalent to creating
605  * an instance with GIT_DIFF_OPTIONS_INIT.
606  *
607  * Params:
608  *      opts = The `git_diff_options` struct to initialize.
609  *      version = The struct version; pass `GIT_DIFF_OPTIONS_VERSION`.
610  *
611  * Returns: Zero on success; -1 on failure.
612  */
613 //GIT_EXTERN
614 int git_diff_options_init(.git_diff_options* opts, uint version_);
615 
616 /**
617  * When iterating over a diff, callback that will be made per file.
618  *
619  * Params:
620  *      delta = A pointer to the delta data for the file
621  *      progress = Goes from 0 to 1 over the diff
622  *      payload = User-specified pointer from foreach function
623  */
624 alias git_diff_file_cb = int function(const (.git_diff_delta)* delta, float progress, void* payload);
625 
626 enum GIT_DIFF_HUNK_HEADER_SIZE = 128;
627 
628 /**
629  * Structure describing the binary contents of a diff.
630  *
631  * A `binary` file / delta is a file (or pair) for which no text diffs
632  * should be generated. A diff can contain delta entries that are
633  * binary, but no diff content will be output for those files. There is
634  * a base heuristic for binary detection and you can further tune the
635  * behavior with git attributes or diff flags and option settings.
636  */
637 enum git_diff_binary_t
638 {
639 	/**
640 	 * Whether there is data in this binary structure or not.
641 	 *
642 	 * If this is `1`, then this was produced and included binary content.
643 	 * If this is `0` then this was generated knowing only that a binary
644 	 * file changed but without providing the data, probably from a patch
645 	 * that said `Binary files a/file.txt and b/file.txt differ`.
646 	 */
647 	GIT_DIFF_BINARY_NONE,
648 
649 	/**
650 	 * The binary data is the literal contents of the file.
651 	 */
652 	GIT_DIFF_BINARY_LITERAL,
653 
654 	/**
655 	 * The binary data is the delta from one side to the other.
656 	 */
657 	GIT_DIFF_BINARY_DELTA,
658 }
659 
660 /**
661  * The contents of one of the files in a binary diff.
662  */
663 struct git_diff_binary_file
664 {
665 	/**
666 	 * The type of binary data for this file.
667 	 */
668 	.git_diff_binary_t type;
669 
670 	/**
671 	 * The binary data, deflated.
672 	 */
673 	const (char)* data;
674 
675 	/**
676 	 * The length of the binary data.
677 	 */
678 	size_t datalen;
679 
680 	/**
681 	 * The length of the binary data after inflation.
682 	 */
683 	size_t inflatedlen;
684 }
685 
686 /**
687  * Structure describing the binary contents of a diff.
688  */
689 struct git_diff_binary
690 {
691 	/**
692 	 * Whether there is data in this binary structure or not.  If this
693 	 * is `1`, then this was produced and included binary content.  If
694 	 * this is `0` then this was generated knowing only that a binary
695 	 * file changed but without providing the data, probably from a patch
696 	 * that said `Binary files a/file.txt and b/file.txt differ`.
697 	 */
698 	uint contains_data;
699 
700 	/**
701 	 * The contents of the old file.
702 	 */
703 	.git_diff_binary_file old_file;
704 
705 	/**
706 	 * The contents of the new file.
707 	 */
708 	.git_diff_binary_file new_file;
709 }
710 
711 /**
712  * When iterating over a diff, callback that will be made for
713  * binary content within the diff.
714  */
715 alias git_diff_binary_cb = int function(const (.git_diff_delta)* delta, const (.git_diff_binary)* binary, void* payload);
716 
717 /**
718  * Structure describing a hunk of a diff.
719  *
720  * A `hunk` is a span of modified lines in a delta along with some stable
721  * surrounding context. You can configure the amount of context and other
722  * properties of how hunks are generated. Each hunk also comes with a
723  * header that described where it starts and ends in both the old and new
724  * versions in the delta.
725  */
726 struct git_diff_hunk
727 {
728 	/**
729 	 * Starting line number in old_file
730 	 */
731 	int old_start;
732 
733 	/**
734 	 * Number of lines in old_file
735 	 */
736 	int old_lines;
737 
738 	/**
739 	 * Starting line number in new_file
740 	 */
741 	int new_start;
742 
743 	/**
744 	 * Number of lines in new_file
745 	 */
746 	int new_lines;
747 
748 	/**
749 	 * Number of bytes in header text
750 	 */
751 	size_t header_len;
752 
753 	/**
754 	 * Header text, NUL-byte terminated
755 	 */
756 	char[.GIT_DIFF_HUNK_HEADER_SIZE] header = '\0'; 
757 }
758 
759 /**
760  * When iterating over a diff, callback that will be made per hunk.
761  */
762 alias git_diff_hunk_cb = int function(const (.git_diff_delta)* delta, const (.git_diff_hunk)* hunk, void* payload);
763 
764 /**
765  * Line origin constants.
766  *
767  * These values describe where a line came from and will be passed to
768  * the git_diff_line_cb when iterating over a diff.  There are some
769  * special origin constants at the end that are used for the text
770  * output callbacks to demarcate lines that are actually part of
771  * the file or hunk headers.
772  */
773 enum git_diff_line_t
774 {
775 	/* These values will be sent to `git_diff_line_cb` along with the line */
776 	GIT_DIFF_LINE_CONTEXT = ' ',
777 	GIT_DIFF_LINE_ADDITION = '+',
778 	GIT_DIFF_LINE_DELETION = '-',
779 
780 	/**
781 	 * Both files have no LF at end
782 	 */
783 	GIT_DIFF_LINE_CONTEXT_EOFNL = '=',
784 
785 	/**
786 	 * Old has no LF at end, new does
787 	 */
788 	GIT_DIFF_LINE_ADD_EOFNL = '>',
789 
790 	/**
791 	 * Old has LF at end, new does not
792 	 */
793 	GIT_DIFF_LINE_DEL_EOFNL = '<',
794 
795 	/*
796 	 * The following values will only be sent to a `git_diff_line_cb` when
797 	 * the content of a diff is being formatted through `git_diff_print`.
798 	 */
799 	GIT_DIFF_LINE_FILE_HDR = 'F',
800 	GIT_DIFF_LINE_HUNK_HDR = 'H',
801 
802 	/**
803 	 * For "Binary files x and y differ"
804 	 */
805 	GIT_DIFF_LINE_BINARY = 'B',
806 }
807 
808 /**
809  * Structure describing a line (or data span) of a diff.
810  *
811  * A `line` is a range of characters inside a hunk.  It could be a context
812  * line (i.e. in both old and new versions), an added line (i.e. only in
813  * the new version), or a removed line (i.e. only in the old version).
814  * Unfortunately, we don't know anything about the encoding of data in the
815  * file being diffed, so we cannot tell you much about the line content.
816  * Line data will not be NUL-byte terminated, however, because it will be
817  * just a span of bytes inside the larger file.
818  */
819 struct git_diff_line
820 {
821 	/**
822 	 * A git_diff_line_t value
823 	 */
824 	char origin = '\0';
825 
826 	/**
827 	 * Line number in old file or -1 for added line
828 	 */
829 	int old_lineno;
830 
831 	/**
832 	 * Line number in new file or -1 for deleted line
833 	 */
834 	int new_lineno;
835 
836 	/**
837 	 * Number of newline characters in content
838 	 */
839 	int num_lines;
840 
841 	/**
842 	 * Number of bytes of data
843 	 */
844 	size_t content_len;
845 
846 	/**
847 	 * Offset in the original file to the content
848 	 */
849 	libgit2_d.types.git_off_t content_offset;
850 
851 	/**
852 	 * Pointer to diff text, not NUL-byte terminated
853 	 */
854 	const (char)* content;
855 }
856 
857 /**
858  * When iterating over a diff, callback that will be made per text diff
859  * line. In this context, the provided range will be null.
860  *
861  * When printing a diff, callback that will be made to output each line
862  * of text.  This uses some extra GIT_DIFF_LINE_... constants for output
863  * of lines of file and hunk headers.
864  */
865 alias git_diff_line_cb = int function(
866     const (.git_diff_delta)* delta, /**< delta that contains this data */
867     const (.git_diff_hunk)* hunk,   /**< hunk containing this data */
868     const (.git_diff_line)* line,   /**< line data */
869     void* payload);              /**< user reference data */
870 
871 /**
872  * Flags to control the behavior of diff rename/copy detection.
873  */
874 enum git_diff_find_t
875 {
876 	/**
877 	 * Obey `diff.renames`. Overridden by any other GIT_DIFF_FIND_... flag.
878 	 */
879 	GIT_DIFF_FIND_BY_CONFIG = 0,
880 
881 	/**
882 	 * Look for renames? (`--find-renames`)
883 	 */
884 	GIT_DIFF_FIND_RENAMES = 1u << 0,
885 
886 	/**
887 	 * Consider old side of MODIFIED for renames? (`--break-rewrites=N`)
888 	 */
889 	GIT_DIFF_FIND_RENAMES_FROM_REWRITES = 1u << 1,
890 
891 	/**
892 	 * Look for copies? (a la `--find-copies`).
893 	 */
894 	GIT_DIFF_FIND_COPIES = 1u << 2,
895 
896 	/**
897 	 * Consider UNMODIFIED as copy sources? (`--find-copies-harder`).
898 	 *
899 	 * For this to work correctly, use git_diff_option_t.GIT_DIFF_INCLUDE_UNMODIFIED when
900 	 * the initial `git_diff` is being generated.
901 	 */
902 	GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED = 1u << 3,
903 
904 	/**
905 	 * Mark significant rewrites for split (`--break-rewrites=/M`)
906 	 */
907 	GIT_DIFF_FIND_REWRITES = 1u << 4,
908 
909 	/**
910 	 * Actually split large rewrites into delete/add pairs
911 	 */
912 	GIT_DIFF_BREAK_REWRITES = 1u << 5,
913 
914 	/**
915 	 * Mark rewrites for split and break into delete/add pairs
916 	 */
917 	GIT_DIFF_FIND_AND_BREAK_REWRITES = GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES,
918 
919 	/**
920 	 * Find renames/copies for UNTRACKED items in working directory.
921 	 *
922 	 * For this to work correctly, use git_diff_option_t.GIT_DIFF_INCLUDE_UNTRACKED when the
923 	 * initial `git_diff` is being generated (and obviously the diff must
924 	 * be against the working directory for this to make sense).
925 	 */
926 	GIT_DIFF_FIND_FOR_UNTRACKED = 1u << 6,
927 
928 	/**
929 	 * Turn on all finding features.
930 	 */
931 	GIT_DIFF_FIND_ALL = 0x00FF,
932 
933 	/**
934 	 * Measure similarity ignoring leading whitespace (default)
935 	 */
936 	GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE = 0,
937 
938 	/**
939 	 * Measure similarity ignoring all whitespace
940 	 */
941 	GIT_DIFF_FIND_IGNORE_WHITESPACE = 1u << 12,
942 
943 	/**
944 	 * Measure similarity including all data
945 	 */
946 	GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = 1u << 13,
947 
948 	/**
949 	 * Measure similarity only by comparing SHAs (fast and cheap)
950 	 */
951 	GIT_DIFF_FIND_EXACT_MATCH_ONLY = 1u << 14,
952 
953 	/**
954 	 * Do not break rewrites unless they contribute to a rename.
955 	 *
956 	 * Normally, GIT_DIFF_FIND_AND_BREAK_REWRITES will measure the self-
957 	 * similarity of modified files and split the ones that have changed a
958 	 * lot into a DELETE / ADD pair.  Then the sides of that pair will be
959 	 * considered candidates for rename and copy detection.
960 	 *
961 	 * If you add this flag in and the split pair is *not* used for an
962 	 * actual rename or copy, then the modified record will be restored to
963 	 * a regular MODIFIED record instead of being split.
964 	 */
965 	GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = 1u << 15,
966 
967 	/**
968 	 * Remove any UNMODIFIED deltas after find_similar is done.
969 	 *
970 	 * Using GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED to emulate the
971 	 * --find-copies-harder behavior requires building a diff with the
972 	 * GIT_DIFF_INCLUDE_UNMODIFIED flag.  If you do not want UNMODIFIED
973 	 * records in the final result, pass this flag to have them removed.
974 	 */
975 	GIT_DIFF_FIND_REMOVE_UNMODIFIED = 1u << 16,
976 }
977 
978 /**
979  * Pluggable similarity metric
980  */
981 struct git_diff_similarity_metric
982 {
983 	int function(void** out_, const (.git_diff_file)* file, const (char)* fullpath, void* payload) file_signature;
984 	int function(void** out_, const (.git_diff_file)* file, const (char)* buf, size_t buflen, void* payload) buffer_signature;
985 	void function(void* sig, void* payload) free_signature;
986 	int function(int* score, void* siga, void* sigb, void* payload) similarity;
987 	void* payload;
988 }
989 
990 /**
991  * Control behavior of rename and copy detection
992  *
993  * These options mostly mimic parameters that can be passed to git-diff.
994  */
995 struct git_diff_find_options
996 {
997 	uint version_;
998 
999 	/**
1000 	 * Combination of git_diff_find_t values (default git_diff_find_t.GIT_DIFF_FIND_BY_CONFIG).
1001 	 * NOTE: if you don't explicitly set this, `diff.renames` could be set
1002 	 * to false, resulting in `git_diff_find_similar` doing nothing.
1003 	 */
1004 	uint flags;
1005 
1006 	/**
1007 	 * Threshold above which similar files will be considered renames.
1008 	 * This is equivalent to the -M option. Defaults to 50.
1009 	 */
1010 	ushort rename_threshold;
1011 
1012 	/**
1013 	 * Threshold below which similar files will be eligible to be a rename source.
1014 	 * This is equivalent to the first part of the -B option. Defaults to 50.
1015 	 */
1016 	ushort rename_from_rewrite_threshold;
1017 
1018 	/**
1019 	 * Threshold above which similar files will be considered copies.
1020 	 * This is equivalent to the -C option. Defaults to 50.
1021 	 */
1022 	ushort copy_threshold;
1023 
1024 	/**
1025 	 * Treshold below which similar files will be split into a delete/add pair.
1026 	 * This is equivalent to the last part of the -B option. Defaults to 60.
1027 	 */
1028 	ushort break_rewrite_threshold;
1029 
1030 	/**
1031 	 * Maximum number of matches to consider for a particular file.
1032 	 *
1033 	 * This is a little different from the `-l` option from Git because we
1034 	 * will still process up to this many matches before abandoning the search.
1035 	 * Defaults to 200.
1036 	 */
1037 	size_t rename_limit;
1038 
1039 	/**
1040 	 * The `metric` option allows you to plug in a custom similarity metric.
1041 	 *
1042 	 * Set it to NULL to use the default internal metric.
1043 	 *
1044 	 * The default metric is based on sampling hashes of ranges of data in
1045 	 * the file, which is a pretty good similarity approximation that should
1046 	 * work fairly well for both text and binary data while still being
1047 	 * pretty fast with a fixed memory overhead.
1048 	 */
1049 	.git_diff_similarity_metric* metric;
1050 }
1051 
1052 enum GIT_DIFF_FIND_OPTIONS_VERSION = 1;
1053 
1054 pragma(inline, true)
1055 pure nothrow @safe @nogc
1056 .git_diff_find_options GIT_DIFF_FIND_OPTIONS_INIT()
1057 
1058 	do
1059 	{
1060 		.git_diff_find_options OUTPUT =
1061 		{
1062 			version_: .GIT_DIFF_FIND_OPTIONS_VERSION,
1063 		};
1064 
1065 		return OUTPUT;
1066 	}
1067 
1068 /**
1069  * Initialize git_diff_find_options structure
1070  *
1071  * Initializes a `git_diff_find_options` with default values. Equivalent to creating
1072  * an instance with GIT_DIFF_FIND_OPTIONS_INIT.
1073  *
1074  * Params:
1075  *      opts = The `git_diff_find_options` struct to initialize.
1076  *      version = The struct version; pass `GIT_DIFF_FIND_OPTIONS_VERSION`.
1077  *
1078  * Returns: Zero on success; -1 on failure.
1079  */
1080 //GIT_EXTERN
1081 int git_diff_find_options_init(.git_diff_find_options* opts, uint version_);
1082 
1083 /**
1084  * @name Diff Generator Functions
1085  *
1086  * These are the functions you would use to create (or destroy) a
1087  * git_diff from various objects in a repository.
1088  */
1089 /**@{*/
1090 
1091 /**
1092  * Deallocate a diff.
1093  *
1094  * Params:
1095  *      diff = The previously created diff; cannot be used after free.
1096  */
1097 //GIT_EXTERN
1098 void git_diff_free(.git_diff* diff);
1099 
1100 /**
1101  * Create a diff with the difference between two tree objects.
1102  *
1103  * This is equivalent to `git diff <old-tree> <new-tree>`
1104  *
1105  * The first tree will be used for the "old_file" side of the delta and the
1106  * second tree will be used for the "new_file" side of the delta.  You can
1107  * pass null to indicate an empty tree, although it is an error to pass
1108  * null for both the `old_tree` and `new_tree`.
1109  *
1110  * Params:
1111  *      diff = Output pointer to a git_diff pointer to be allocated.
1112  *      repo = The repository containing the trees.
1113  *      old_tree = A git_tree object to diff from, or null for empty tree.
1114  *      new_tree = A git_tree object to diff to, or null for empty tree.
1115  *      opts = Structure with options to influence diff or null for defaults.
1116  */
1117 //GIT_EXTERN
1118 int git_diff_tree_to_tree(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_tree* old_tree, libgit2_d.types.git_tree* new_tree, const (.git_diff_options)* opts);
1119 
1120 /**
1121  * Create a diff between a tree and repository index.
1122  *
1123  * This is equivalent to `git diff --cached <treeish>` or if you pass
1124  * the HEAD tree, then like `git diff --cached`.
1125  *
1126  * The tree you pass will be used for the "old_file" side of the delta, and
1127  * the index will be used for the "new_file" side of the delta.
1128  *
1129  * If you pass null for the index, then the existing index of the `repo`
1130  * will be used.  In this case, the index will be refreshed from disk
1131  * (if it has changed) before the diff is generated.
1132  *
1133  * Params:
1134  *      diff = Output pointer to a git_diff pointer to be allocated.
1135  *      repo = The repository containing the tree and index.
1136  *      old_tree = A git_tree object to diff from, or null for empty tree.
1137  *      index = The index to diff with; repo index used if null.
1138  *      opts = Structure with options to influence diff or null for defaults.
1139  */
1140 //GIT_EXTERN
1141 int git_diff_tree_to_index(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_tree* old_tree, libgit2_d.types.git_index* index, const (.git_diff_options)* opts);
1142 
1143 /**
1144  * Create a diff between the repository index and the workdir directory.
1145  *
1146  * This matches the `git diff` command.  See the note below on
1147  * `git_diff_tree_to_workdir` for a discussion of the difference between
1148  * `git diff` and `git diff HEAD` and how to emulate a `git diff <treeish>`
1149  * using libgit2.
1150  *
1151  * The index will be used for the "old_file" side of the delta, and the
1152  * working directory will be used for the "new_file" side of the delta.
1153  *
1154  * If you pass null for the index, then the existing index of the `repo`
1155  * will be used.  In this case, the index will be refreshed from disk
1156  * (if it has changed) before the diff is generated.
1157  *
1158  * Params:
1159  *      diff = Output pointer to a git_diff pointer to be allocated.
1160  *      repo = The repository.
1161  *      index = The index to diff from; repo index used if null.
1162  *      opts = Structure with options to influence diff or null for defaults.
1163  */
1164 //GIT_EXTERN
1165 int git_diff_index_to_workdir(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_index* index, const (.git_diff_options)* opts);
1166 
1167 /**
1168  * Create a diff between a tree and the working directory.
1169  *
1170  * The tree you provide will be used for the "old_file" side of the delta,
1171  * and the working directory will be used for the "new_file" side.
1172  *
1173  * This is not the same as `git diff <treeish>` or `git diff-index
1174  * <treeish>`.  Those commands use information from the index, whereas this
1175  * function strictly returns the differences between the tree and the files
1176  * in the working directory, regardless of the state of the index.  Use
1177  * `git_diff_tree_to_workdir_with_index` to emulate those commands.
1178  *
1179  * To see difference between this and `git_diff_tree_to_workdir_with_index`,
1180  * consider the example of a staged file deletion where the file has then
1181  * been put back into the working dir and further modified.  The
1182  * tree-to-workdir diff for that file is 'modified', but `git diff` would
1183  * show status 'deleted' since there is a staged delete.
1184  *
1185  * Params:
1186  *      diff = A pointer to a git_diff pointer that will be allocated.
1187  *      repo = The repository containing the tree.
1188  *      old_tree = A git_tree object to diff from, or null for empty tree.
1189  *      opts = Structure with options to influence diff or null for defaults.
1190  */
1191 //GIT_EXTERN
1192 int git_diff_tree_to_workdir(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_tree* old_tree, const (.git_diff_options)* opts);
1193 
1194 /**
1195  * Create a diff between a tree and the working directory using index data
1196  * to account for staged deletes, tracked files, etc.
1197  *
1198  * This emulates `git diff <tree>` by diffing the tree to the index and
1199  * the index to the working directory and blending the results into a
1200  * single diff that includes staged deleted, etc.
1201  *
1202  * Params:
1203  *      diff = A pointer to a git_diff pointer that will be allocated.
1204  *      repo = The repository containing the tree.
1205  *      old_tree = A git_tree object to diff from, or null for empty tree.
1206  *      opts = Structure with options to influence diff or null for defaults.
1207  */
1208 //GIT_EXTERN
1209 int git_diff_tree_to_workdir_with_index(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_tree* old_tree, const (.git_diff_options)* opts);
1210 
1211 /**
1212  * Create a diff with the difference between two index objects.
1213  *
1214  * The first index will be used for the "old_file" side of the delta and the
1215  * second index will be used for the "new_file" side of the delta.
1216  *
1217  * Params:
1218  *      diff = Output pointer to a git_diff pointer to be allocated.
1219  *      repo = The repository containing the indexes.
1220  *      old_index = A git_index object to diff from.
1221  *      new_index = A git_index object to diff to.
1222  *      opts = Structure with options to influence diff or null for defaults.
1223  */
1224 //GIT_EXTERN
1225 int git_diff_index_to_index(.git_diff** diff, libgit2_d.types.git_repository* repo, libgit2_d.types.git_index* old_index, libgit2_d.types.git_index* new_index, const (.git_diff_options)* opts);
1226 
1227 /**
1228  * Merge one diff into another.
1229  *
1230  * This merges items from the "from" list into the "onto" list.  The
1231  * resulting diff will have all items that appear in either list.
1232  * If an item appears in both lists, then it will be "merged" to appear
1233  * as if the old version was from the "onto" list and the new version
1234  * is from the "from" list (with the exception that if the item has a
1235  * pending DELETE in the middle, then it will show as deleted).
1236  *
1237  * Params:
1238  *      onto = Diff to merge into.
1239  *      from = Diff to merge.
1240  */
1241 //GIT_EXTERN
1242 int git_diff_merge(.git_diff* onto, const (.git_diff)* from);
1243 
1244 /**
1245  * Transform a diff marking file renames, copies, etc.
1246  *
1247  * This modifies a diff in place, replacing old entries that look
1248  * like renames or copies with new entries reflecting those changes.
1249  * This also will, if requested, break modified files into add/remove
1250  * pairs if the amount of change is above a threshold.
1251  *
1252  * Params:
1253  *      diff = diff to run detection algorithms on
1254  *      options = Control how detection should be run, null for defaults
1255  *
1256  * Returns: 0 on success, -1 on failure
1257  */
1258 //GIT_EXTERN
1259 int git_diff_find_similar(.git_diff* diff, const (.git_diff_find_options)* options);
1260 
1261 /**@}*/
1262 
1263 /**
1264  * @name Diff Processor Functions
1265  *
1266  * These are the functions you apply to a diff to process it
1267  * or read it in some way.
1268  */
1269 /**@{*/
1270 
1271 /**
1272  * Query how many diff records are there in a diff.
1273  *
1274  * Params:
1275  *      diff = A git_diff generated by one of the above functions
1276  *
1277  * Returns: Count of number of deltas in the list
1278  */
1279 //GIT_EXTERN
1280 size_t git_diff_num_deltas(const (.git_diff)* diff);
1281 
1282 /**
1283  * Query how many diff deltas are there in a diff filtered by type.
1284  *
1285  * This works just like `git_diff_entrycount()` with an extra parameter
1286  * that is a `git_delta_t` and returns just the count of how many deltas
1287  * match that particular type.
1288  *
1289  * Params:
1290  *      diff = A git_diff generated by one of the above functions
1291  *      type = A git_delta_t value to filter the count
1292  *
1293  * Returns: Count of number of deltas matching delta_t type
1294  */
1295 //GIT_EXTERN
1296 size_t git_diff_num_deltas_of_type(const (.git_diff)* diff, .git_delta_t type);
1297 
1298 /**
1299  * Return the diff delta for an entry in the diff list.
1300  *
1301  * The `git_diff_delta` pointer points to internal data and you do not
1302  * have to release it when you are done with it.  It will go away when
1303  * the * `git_diff` (or any associated `git_patch`) goes away.
1304  *
1305  * Note that the flags on the delta related to whether it has binary
1306  * content or not may not be set if there are no attributes set for the
1307  * file and there has been no reason to load the file data at this point.
1308  * For now, if you need those flags to be up to date, your only option is
1309  * to either use `git_diff_foreach` or create a `git_patch`.
1310  *
1311  * Params:
1312  *      diff = Diff list object
1313  *      idx = Index into diff list
1314  *
1315  * Returns: Pointer to git_diff_delta (or null if `idx` out of range)
1316  */
1317 //GIT_EXTERN
1318 const (.git_diff_delta)* git_diff_get_delta(const (.git_diff)* diff, size_t idx);
1319 
1320 /**
1321  * Check if deltas are sorted case sensitively or insensitively.
1322  *
1323  * Params:
1324  *      diff = diff to check
1325  *
1326  * Returns: 0 if case sensitive, 1 if case is ignored
1327  */
1328 //GIT_EXTERN
1329 int git_diff_is_sorted_icase(const (.git_diff)* diff);
1330 
1331 /**
1332  * Loop over all deltas in a diff issuing callbacks.
1333  *
1334  * This will iterate through all of the files described in a diff.  You
1335  * should provide a file callback to learn about each file.
1336  *
1337  * The "hunk" and "line" callbacks are optional, and the text diff of the
1338  * files will only be calculated if they are not null.  Of course, these
1339  * callbacks will not be invoked for binary files on the diff or for
1340  * files whose only changed is a file mode change.
1341  *
1342  * Returning a non-zero value from any of the callbacks will terminate
1343  * the iteration and return the value to the user.
1344  *
1345  * Params:
1346  *      diff = A git_diff generated by one of the above functions.
1347  *      file_cb = Callback function to make per file in the diff.
1348  *      binary_cb = Optional callback to make for binary files.
1349  *      hunk_cb = Optional callback to make per hunk of text diff.  This callback is called to describe a range of lines in the diff.  It will not be issued for binary files.
1350  *      line_cb = Optional callback to make per line of diff text.  This same callback will be made for context lines, added, and removed lines, and even for a deleted trailing newline.
1351  *      payload = Reference pointer that will be passed to your callbacks.
1352  *
1353  * Returns: 0 on success, non-zero callback return value, or error code
1354  */
1355 //GIT_EXTERN
1356 int git_diff_foreach(.git_diff* diff, .git_diff_file_cb file_cb, .git_diff_binary_cb binary_cb, .git_diff_hunk_cb hunk_cb, .git_diff_line_cb line_cb, void* payload);
1357 
1358 /**
1359  * Look up the single character abbreviation for a delta status code.
1360  *
1361  * When you run `git diff --name-status` it uses single letter codes in
1362  * the output such as 'A' for added, 'D' for deleted, 'M' for modified,
1363  * etc.  This function converts a git_delta_t value into these letters for
1364  * your own purposes.  git_delta_t.GIT_DELTA_UNTRACKED will return a space (i.e. ' ').
1365  *
1366  * Params:
1367  *      status = The git_delta_t value to look up
1368  *
1369  * Returns: The single character label for that code
1370  */
1371 //GIT_EXTERN
1372 char git_diff_status_char(.git_delta_t status);
1373 
1374 /**
1375  * Possible output formats for diff data
1376  */
1377 enum git_diff_format_t
1378 {
1379 	/**
1380 	 * full git diff
1381 	 */
1382 	GIT_DIFF_FORMAT_PATCH = 1u,
1383 
1384 	/**
1385 	 * just the file headers of patch
1386 	 */
1387 	GIT_DIFF_FORMAT_PATCH_HEADER = 2u,
1388 
1389 	/**
1390 	 * like git diff --raw
1391 	 */
1392 	GIT_DIFF_FORMAT_RAW = 3u,
1393 
1394 	/**
1395 	 * like git diff --name-only
1396 	 */
1397 	GIT_DIFF_FORMAT_NAME_ONLY = 4u,
1398 
1399 	/**
1400 	 * like git diff --name-status
1401 	 */
1402 	GIT_DIFF_FORMAT_NAME_STATUS = 5u,
1403 
1404 	/**
1405 	 * git diff as used by git patch-id
1406 	 */
1407 	GIT_DIFF_FORMAT_PATCH_ID = 6u,
1408 }
1409 
1410 /**
1411  * Iterate over a diff generating formatted text output.
1412  *
1413  * Returning a non-zero value from the callbacks will terminate the
1414  * iteration and return the non-zero value to the caller.
1415  *
1416  * Params:
1417  *      diff = A git_diff generated by one of the above functions.
1418  *      format = A git_diff_format_t value to pick the text format.
1419  *      print_cb = Callback to make per line of diff text.
1420  *      payload = Reference pointer that will be passed to your callback.
1421  *
1422  * Returns: 0 on success, non-zero callback return value, or error code
1423  */
1424 //GIT_EXTERN
1425 int git_diff_print(.git_diff* diff, .git_diff_format_t format, .git_diff_line_cb print_cb, void* payload);
1426 
1427 /**
1428  * Produce the complete formatted text output from a diff into a
1429  * buffer.
1430  *
1431  * Params:
1432  *      out_ = A pointer to a user-allocated git_buf that will contain the diff text
1433  *      diff = A git_diff generated by one of the above functions.
1434  *      format = A git_diff_format_t value to pick the text format.
1435  *
1436  * Returns: 0 on success or error code
1437  */
1438 //GIT_EXTERN
1439 int git_diff_to_buf(libgit2_d.buffer.git_buf* out_, .git_diff* diff, .git_diff_format_t format);
1440 
1441 /**@}*/
1442 
1443 /*
1444  * Misc
1445  */
1446 
1447 /**
1448  * Directly run a diff on two blobs.
1449  *
1450  * Compared to a file, a blob lacks some contextual information. As such,
1451  * the `git_diff_file` given to the callback will have some fake data; i.e.
1452  * `mode` will be 0 and `path` will be null.
1453  *
1454  * null is allowed for either `old_blob` or `new_blob` and will be treated
1455  * as an empty blob, with the `oid` set to null in the `git_diff_file` data.
1456  * Passing null for both blobs is a noop; no callbacks will be made at all.
1457  *
1458  * We do run a binary content check on the blob content and if either blob
1459  * looks like binary data, the `git_diff_delta` binary attribute will be set
1460  * to 1 and no call to the hunk_cb nor line_cb will be made (unless you pass
1461  * `git_diff_option_t.GIT_DIFF_FORCE_TEXT` of course).
1462  *
1463  * Params:
1464  *      old_blob = Blob for old side of diff, or null for empty blob
1465  *      old_as_path = Treat old blob as if it had this filename; can be null
1466  *      new_blob = Blob for new side of diff, or null for empty blob
1467  *      new_as_path = Treat new blob as if it had this filename; can be null
1468  *      options = Options for diff, or null for default options
1469  *      file_cb = Callback for "file"; made once if there is a diff; can be null
1470  *      binary_cb = Callback for binary files; can be null
1471  *      hunk_cb = Callback for each hunk in diff; can be null
1472  *      line_cb = Callback for each line in diff; can be null
1473  *      payload = Payload passed to each callback function
1474  *
1475  * Returns: 0 on success, non-zero callback return value, or error code
1476  */
1477 //GIT_EXTERN
1478 int git_diff_blobs(const (libgit2_d.types.git_blob)* old_blob, const (char)* old_as_path, const (libgit2_d.types.git_blob)* new_blob, const (char)* new_as_path, const (.git_diff_options)* options, .git_diff_file_cb file_cb, .git_diff_binary_cb binary_cb, .git_diff_hunk_cb hunk_cb, .git_diff_line_cb line_cb, void* payload);
1479 
1480 /**
1481  * Directly run a diff between a blob and a buffer.
1482  *
1483  * As with `git_diff_blobs`, comparing a blob and buffer lacks some context,
1484  * so the `git_diff_file` parameters to the callbacks will be faked a la the
1485  * rules for `git_diff_blobs()`.
1486  *
1487  * Passing null for `old_blob` will be treated as an empty blob (i.e. the
1488  * `file_cb` will be invoked with git_delta_t.GIT_DELTA_ADDED and the diff will be the
1489  * entire content of the buffer added).  Passing null to the buffer will do
1490  * the reverse, with GIT_DELTA_REMOVED and blob content removed.
1491  *
1492  * Params:
1493  *      old_blob = Blob for old side of diff, or null for empty blob
1494  *      old_as_path = Treat old blob as if it had this filename; can be null
1495  *      buffer = Raw data for new side of diff, or null for empty
1496  *      buffer_len = Length of raw data for new side of diff
1497  *      buffer_as_path = Treat buffer as if it had this filename; can be null
1498  *      options = Options for diff, or null for default options
1499  *      file_cb = Callback for "file"; made once if there is a diff; can be null
1500  *      binary_cb = Callback for binary files; can be null
1501  *      hunk_cb = Callback for each hunk in diff; can be null
1502  *      line_cb = Callback for each line in diff; can be null
1503  *      payload = Payload passed to each callback function
1504  *
1505  * Returns: 0 on success, non-zero callback return value, or error code
1506  */
1507 //GIT_EXTERN
1508 int git_diff_blob_to_buffer(const (libgit2_d.types.git_blob)* old_blob, const (char)* old_as_path, const (char)* buffer, size_t buffer_len, const (char)* buffer_as_path, const (.git_diff_options)* options, .git_diff_file_cb file_cb, .git_diff_binary_cb binary_cb, .git_diff_hunk_cb hunk_cb, .git_diff_line_cb line_cb, void* payload);
1509 
1510 /**
1511  * Directly run a diff between two buffers.
1512  *
1513  * Even more than with `git_diff_blobs`, comparing two buffer lacks
1514  * context, so the `git_diff_file` parameters to the callbacks will be
1515  * faked a la the rules for `git_diff_blobs()`.
1516  *
1517  * Params:
1518  *      old_buffer = Raw data for old side of diff, or null for empty
1519  *      old_len = Length of the raw data for old side of the diff
1520  *      old_as_path = Treat old buffer as if it had this filename; can be null
1521  *      new_buffer = Raw data for new side of diff, or null for empty
1522  *      new_len = Length of raw data for new side of diff
1523  *      new_as_path = Treat buffer as if it had this filename; can be null
1524  *      options = Options for diff, or null for default options
1525  *      file_cb = Callback for "file"; made once if there is a diff; can be null
1526  *      binary_cb = Callback for binary files; can be null
1527  *      hunk_cb = Callback for each hunk in diff; can be null
1528  *      line_cb = Callback for each line in diff; can be null
1529  *      payload = Payload passed to each callback function
1530  *
1531  * Returns: 0 on success, non-zero callback return value, or error code
1532  */
1533 //GIT_EXTERN
1534 int git_diff_buffers(const (void)* old_buffer, size_t old_len, const (char)* old_as_path, const (void)* new_buffer, size_t new_len, const (char)* new_as_path, const (.git_diff_options)* options, .git_diff_file_cb file_cb, .git_diff_binary_cb binary_cb, .git_diff_hunk_cb hunk_cb, .git_diff_line_cb line_cb, void* payload);
1535 
1536 /**
1537  * Read the contents of a git patch file into a `git_diff` object.
1538  *
1539  * The diff object produced is similar to the one that would be
1540  * produced if you actually produced it computationally by comparing
1541  * two trees, however there may be subtle differences.  For example,
1542  * a patch file likely contains abbreviated object IDs, so the
1543  * object IDs in a `git_diff_delta` produced by this function will
1544  * also be abbreviated.
1545  *
1546  * This function will only read patch files created by a git
1547  * implementation, it will not read unified diffs produced by
1548  * the `diff` program, nor any other types of patch files.
1549  *
1550  * Params:
1551  *      out_ = A pointer to a git_diff pointer that will be allocated.
1552  *      content = The contents of a patch file
1553  *      content_len = The length of the patch file contents
1554  *
1555  * Returns: 0 or an error code
1556  */
1557 //GIT_EXTERN
1558 int git_diff_from_buffer(.git_diff** out_, const (char)* content, size_t content_len);
1559 
1560 /**
1561  * This is an opaque structure which is allocated by `git_diff_get_stats`.
1562  * You are responsible for releasing the object memory when done, using the
1563  * `git_diff_stats_free()` function.
1564  */
1565 struct git_diff_stats;
1566 
1567 /**
1568  * Formatting options for diff stats
1569  */
1570 enum git_diff_stats_format_t
1571 {
1572 	/**
1573 	 * No stats
1574 	 */
1575 	GIT_DIFF_STATS_NONE = 0,
1576 
1577 	/**
1578 	 * Full statistics, equivalent of `--stat`
1579 	 */
1580 	GIT_DIFF_STATS_FULL = 1u << 0,
1581 
1582 	/**
1583 	 * Short statistics, equivalent of `--shortstat`
1584 	 */
1585 	GIT_DIFF_STATS_SHORT = 1u << 1,
1586 
1587 	/**
1588 	 * Number statistics, equivalent of `--numstat`
1589 	 */
1590 	GIT_DIFF_STATS_NUMBER = 1u << 2,
1591 
1592 	/**
1593 	 * Extended header information such as creations, renames and mode changes,
1594 	 * equivalent of `--summary`
1595 	 */
1596 	GIT_DIFF_STATS_INCLUDE_SUMMARY = 1u << 3,
1597 }
1598 
1599 /**
1600  * Accumulate diff statistics for all patches.
1601  *
1602  * Params:
1603  *      out_ = Structure containg the diff statistics.
1604  *      diff = A git_diff generated by one of the above functions.
1605  *
1606  * Returns: 0 on success; non-zero on error
1607  */
1608 //GIT_EXTERN
1609 int git_diff_get_stats(.git_diff_stats** out_, .git_diff* diff);
1610 
1611 /**
1612  * Get the total number of files changed in a diff
1613  *
1614  * Params:
1615  *      stats = A `git_diff_stats` generated by one of the above functions.
1616  *
1617  * Returns: total number of files changed in the diff
1618  */
1619 //GIT_EXTERN
1620 size_t git_diff_stats_files_changed(const (.git_diff_stats)* stats);
1621 
1622 /**
1623  * Get the total number of insertions in a diff
1624  *
1625  * Params:
1626  *      stats = A `git_diff_stats` generated by one of the above functions.
1627  *
1628  * Returns: total number of insertions in the diff
1629  */
1630 //GIT_EXTERN
1631 size_t git_diff_stats_insertions(const (.git_diff_stats)* stats);
1632 
1633 /**
1634  * Get the total number of deletions in a diff
1635  *
1636  * Params:
1637  *      stats = A `git_diff_stats` generated by one of the above functions.
1638  *
1639  * Returns: total number of deletions in the diff
1640  */
1641 //GIT_EXTERN
1642 size_t git_diff_stats_deletions(const (.git_diff_stats)* stats);
1643 
1644 /**
1645  * Print diff statistics to a `git_buf`.
1646  *
1647  * Params:
1648  *      out_ = buffer to store the formatted diff statistics in.
1649  *      stats = A `git_diff_stats` generated by one of the above functions.
1650  *      format = Formatting option.
1651  *      width = Target width for output (only affects git_diff_stats_format_t.GIT_DIFF_STATS_FULL)
1652  *
1653  * Returns: 0 on success; non-zero on error
1654  */
1655 //GIT_EXTERN
1656 int git_diff_stats_to_buf(libgit2_d.buffer.git_buf* out_, const (.git_diff_stats)* stats, .git_diff_stats_format_t format, size_t width);
1657 
1658 /**
1659  * Deallocate a `git_diff_stats`.
1660  *
1661  * Params:
1662  *      stats = The previously created statistics object;
1663  * cannot be used after free.
1664  */
1665 //GIT_EXTERN
1666 void git_diff_stats_free(.git_diff_stats* stats);
1667 
1668 /**
1669  * Formatting options for diff e-mail generation
1670  */
1671 enum git_diff_format_email_flags_t
1672 {
1673 	/**
1674 	 * Normal patch, the default
1675 	 */
1676 	GIT_DIFF_FORMAT_EMAIL_NONE = 0,
1677 
1678 	/**
1679 	 * Don't insert "[PATCH]" in the subject header
1680 	 */
1681 	GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = 1 << 0,
1682 }
1683 
1684 /**
1685  * Options for controlling the formatting of the generated e-mail.
1686  */
1687 struct git_diff_format_email_options
1688 {
1689 	uint version_;
1690 
1691 	/**
1692 	 * see `git_diff_format_email_flags_t` above
1693 	 */
1694 	uint flags;
1695 
1696 	/**
1697 	 * This patch number
1698 	 */
1699 	size_t patch_no;
1700 
1701 	/**
1702 	 * Total number of patches in this series
1703 	 */
1704 	size_t total_patches;
1705 
1706 	/**
1707 	 * id to use for the commit
1708 	 */
1709 	const (libgit2_d.oid.git_oid)* id;
1710 
1711 	/**
1712 	 * Summary of the change
1713 	 */
1714 	const (char)* summary;
1715 
1716 	/**
1717 	 * Commit message's body
1718 	 */
1719 	const (char)* body_;
1720 
1721 	/**
1722 	 * Author of the change
1723 	 */
1724 	const (libgit2_d.types.git_signature)* author;
1725 }
1726 
1727 enum GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION = 1;
1728 
1729 pragma(inline, true)
1730 pure nothrow @safe @nogc
1731 .git_diff_format_email_options GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT()
1732 
1733 	do
1734 	{
1735 		.git_diff_format_email_options OUTPUT =
1736 		{
1737 			version_: .GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION,
1738 			flags: .git_diff_format_email_flags_t.GIT_DIFF_FORMAT_EMAIL_NONE,
1739 			patch_no: 1,
1740 			total_patches: 1,
1741 			id: null,
1742 			summary: null,
1743 			body_: null,
1744 			author: null,
1745 		};
1746 
1747 		return OUTPUT;
1748 	}
1749 
1750 /**
1751  * Create an e-mail ready patch from a diff.
1752  *
1753  * Params:
1754  *      out_ = buffer to store the e-mail patch in
1755  *      diff = containing the commit
1756  *      opts = structure with options to influence content and formatting.
1757  *
1758  * Returns: 0 or an error code
1759  */
1760 //GIT_EXTERN
1761 int git_diff_format_email(libgit2_d.buffer.git_buf* out_, .git_diff* diff, const (.git_diff_format_email_options)* opts);
1762 
1763 /**
1764  * Create an e-mail ready patch for a commit.
1765  *
1766  * Does not support creating patches for merge commits (yet).
1767  *
1768  * Params:
1769  *      out_ = buffer to store the e-mail patch in
1770  *      repo = containing the commit
1771  *      commit = pointer to up commit
1772  *      patch_no = patch number of the commit
1773  *      total_patches = total number of patches in the patch set
1774  *      flags = determines the formatting of the e-mail
1775  *      diff_opts = structure with options to influence diff or null for defaults.
1776  *
1777  * Returns: 0 or an error code
1778  */
1779 //GIT_EXTERN
1780 int git_diff_commit_as_email(libgit2_d.buffer.git_buf* out_, libgit2_d.types.git_repository* repo, libgit2_d.types.git_commit* commit, size_t patch_no, size_t total_patches, uint flags, const (.git_diff_options)* diff_opts);
1781 
1782 /**
1783  * Initialize git_diff_format_email_options structure
1784  *
1785  * Initializes a `git_diff_format_email_options` with default values. Equivalent
1786  * to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
1787  *
1788  * Params:
1789  *      opts = The `git_blame_options` struct to initialize.
1790  *      version = The struct version; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`.
1791  *
1792  * Returns: Zero on success; -1 on failure.
1793  */
1794 //GIT_EXTERN
1795 int git_diff_format_email_options_init(.git_diff_format_email_options* opts, uint version_);
1796 
1797 /**
1798  * Patch ID options structure
1799  *
1800  * Initialize with `GIT_PATCHID_OPTIONS_INIT`. Alternatively, you can
1801  * use `git_diff_patchid_options_init`.
1802  */
1803 struct git_diff_patchid_options
1804 {
1805 	uint version_;
1806 }
1807 
1808 enum GIT_DIFF_PATCHID_OPTIONS_VERSION = 1;
1809 
1810 pragma(inline, true)
1811 pure nothrow @safe @nogc
1812 .git_diff_patchid_options GIT_DIFF_PATCHID_OPTIONS_INIT()
1813 
1814 	do
1815 	{
1816 		.git_diff_patchid_options OUTPUT =
1817 		{
1818 			version_: .GIT_DIFF_PATCHID_OPTIONS_VERSION,
1819 		};
1820 
1821 		return OUTPUT;
1822 	}
1823 
1824 /**
1825  * Initialize git_diff_patchid_options structure
1826  *
1827  * Initializes a `git_diff_patchid_options` with default values. Equivalent to
1828  * creating an instance with `GIT_DIFF_PATCHID_OPTIONS_INIT`.
1829  *
1830  * Params:
1831  *      opts = The `git_diff_patchid_options` struct to initialize.
1832  *      version = The struct version; pass `GIT_DIFF_PATCHID_OPTIONS_VERSION`.
1833  *
1834  * Returns: Zero on success; -1 on failure.
1835  */
1836 //GIT_EXTERN
1837 int git_diff_patchid_options_init(.git_diff_patchid_options* opts, uint version_);
1838 
1839 /**
1840  * Calculate the patch ID for the given patch.
1841  *
1842  * Calculate a stable patch ID for the given patch by summing the
1843  * hash of the file diffs, ignoring whitespace and line numbers.
1844  * This can be used to derive whether two diffs are the same with
1845  * a high probability.
1846  *
1847  * Currently, this function only calculates stable patch IDs, as
1848  * defined in git-patch-id(1), and should in fact generate the
1849  * same IDs as the upstream git project does.
1850  *
1851  * Params:
1852  *      out_ = Pointer where the calculated patch ID should be stored
1853  *      diff = The diff to calculate the ID for
1854  *      opts = Options for how to calculate the patch ID. This is intended for future changes, as currently no options are available.
1855  *
1856  * Returns: 0 on success, an error code otherwise.
1857  */
1858 //GIT_EXTERN
1859 int git_diff_patchid(libgit2_d.oid.git_oid* out_, .git_diff* diff, .git_diff_patchid_options* opts);
1860 
1861 /** @} */