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  * @param diff_so_far The diff being generated.
466  * @param old_path The path to the old file or null.
467  * @param new_path The path to the new file or null.
468  * @return Non-zero to abort the diff.
469  */
470 alias git_diff_progress_cb = int function(const (.git_diff)* diff_so_far, const (char)* old_path, const (char)* new_path, void* payload);
471 
472 /**
473  * Structure describing options about how the diff should be executed.
474  *
475  * Setting all values of the structure to zero will yield the default
476  * values.  Similarly, passing null for the options structure will
477  * give the defaults.  The default values are marked below.
478  */
479 struct git_diff_options
480 {
481 	/**
482 	 * version for the struct
483 	 */
484 	uint version_;
485 
486 	/**
487 	 * A combination of `git_diff_option_t` values above.
488 	 * Defaults to git_diff_option_t.GIT_DIFF_NORMAL
489 	 */
490 	uint flags;
491 
492 	/* options controlling which files are in the diff */
493 
494 	/**
495 	 * Overrides the submodule ignore setting for all submodules in the diff.
496 	 */
497 	libgit2_d.types.git_submodule_ignore_t ignore_submodules;
498 
499 	/**
500 	 * An array of paths / fnmatch patterns to constrain diff.
501 	 * All paths are included by default.
502 	 */
503 	libgit2_d.strarray.git_strarray pathspec;
504 
505 	/**
506 	 * An optional callback function, notifying the consumer of changes to
507 	 * the diff as new deltas are added.
508 	 */
509 	.git_diff_notify_cb notify_cb;
510 
511 	/**
512 	 * An optional callback function, notifying the consumer of which files
513 	 * are being examined as the diff is generated.
514 	 */
515 	.git_diff_progress_cb progress_cb;
516 
517 	/**
518 	 * The payload to pass to the callback functions.
519 	 */
520 	void* payload;
521 
522 	/* options controlling how to diff text is generated */
523 
524 	/**
525 	 * The number of unchanged lines that define the boundary of a hunk
526 	 * (and to display before and after). Defaults to 3.
527 	 */
528 	uint context_lines;
529 
530 	/**
531 	 * The maximum number of unchanged lines between hunk boundaries before
532 	 * the hunks will be merged into one. Defaults to 0.
533 	 */
534 	uint interhunk_lines;
535 
536 	/**
537 	 * The abbreviation length to use when formatting object ids.
538 	 * Defaults to the value of 'core.abbrev' from the config, or 7 if unset.
539 	 */
540 	ushort id_abbrev;
541 
542 	/**
543 	 * A size (in bytes) above which a blob will be marked as binary
544 	 * automatically; pass a negative value to disable.
545 	 * Defaults to 512MB.
546 	 */
547 	libgit2_d.types.git_off_t max_size;
548 
549 	/**
550 	 * The virtual "directory" prefix for old file names in hunk headers.
551 	 * Default is "a".
552 	 */
553 	const (char)* old_prefix;
554 
555 	/**
556 	 * The virtual "directory" prefix for new file names in hunk headers.
557 	 * Defaults to "b".
558 	 */
559 	const (char)* new_prefix;
560 }
561 
562 /**
563  * The current version of the diff options structure
564  */
565 enum GIT_DIFF_OPTIONS_VERSION = 1;
566 
567 /*
568  * Stack initializer for diff options.  Alternatively use
569  * `git_diff_options_init` programmatic initialization.
570  */
571 
572 pragma(inline, true)
573 pure nothrow @safe @nogc
574 .git_diff_options GIT_DIFF_OPTIONS_INIT()
575 
576 	do
577 	{
578 		libgit2_d.strarray.git_strarray PATHSPEC_OPTION =
579 		{
580 			strings: null,
581 			count: 0,
582 		};
583 
584 		.git_diff_options OUTPUT =
585 		{
586 			version_: .GIT_DIFF_OPTIONS_VERSION,
587 			flags: 0,
588 			ignore_submodules: libgit2_d.types.git_submodule_ignore_t.GIT_SUBMODULE_IGNORE_UNSPECIFIED,
589 			pathspec: PATHSPEC_OPTION,
590 			notify_cb: null,
591 			progress_cb: null,
592 			payload: null,
593 			context_lines: 3,
594 		};
595 
596 		return OUTPUT;
597 	}
598 
599 /**
600  * Initialize git_diff_options structure
601  *
602  * Initializes a `git_diff_options` with default values. Equivalent to creating
603  * an instance with GIT_DIFF_OPTIONS_INIT.
604  *
605  * @param opts The `git_diff_options` struct to initialize.
606  * @param version The struct version; pass `GIT_DIFF_OPTIONS_VERSION`.
607  * @return Zero on success; -1 on failure.
608  */
609 //GIT_EXTERN
610 int git_diff_options_init(.git_diff_options* opts, uint version_);
611 
612 /**
613  * When iterating over a diff, callback that will be made per file.
614  *
615  * @param delta A pointer to the delta data for the file
616  * @param progress Goes from 0 to 1 over the diff
617  * @param payload User-specified pointer from foreach function
618  */
619 alias git_diff_file_cb = int function(const (.git_diff_delta)* delta, float progress, void* payload);
620 
621 enum GIT_DIFF_HUNK_HEADER_SIZE = 128;
622 
623 /**
624  * Structure describing the binary contents of a diff.
625  *
626  * A `binary` file / delta is a file (or pair) for which no text diffs
627  * should be generated. A diff can contain delta entries that are
628  * binary, but no diff content will be output for those files. There is
629  * a base heuristic for binary detection and you can further tune the
630  * behavior with git attributes or diff flags and option settings.
631  */
632 enum git_diff_binary_t
633 {
634 	/**
635 	 * Whether there is data in this binary structure or not.
636 	 *
637 	 * If this is `1`, then this was produced and included binary content.
638 	 * If this is `0` then this was generated knowing only that a binary
639 	 * file changed but without providing the data, probably from a patch
640 	 * that said `Binary files a/file.txt and b/file.txt differ`.
641 	 */
642 	GIT_DIFF_BINARY_NONE,
643 
644 	/**
645 	 * The binary data is the literal contents of the file.
646 	 */
647 	GIT_DIFF_BINARY_LITERAL,
648 
649 	/**
650 	 * The binary data is the delta from one side to the other.
651 	 */
652 	GIT_DIFF_BINARY_DELTA,
653 }
654 
655 /**
656  * The contents of one of the files in a binary diff.
657  */
658 struct git_diff_binary_file
659 {
660 	/**
661 	 * The type of binary data for this file.
662 	 */
663 	.git_diff_binary_t type;
664 
665 	/**
666 	 * The binary data, deflated.
667 	 */
668 	const (char)* data;
669 
670 	/**
671 	 * The length of the binary data.
672 	 */
673 	size_t datalen;
674 
675 	/**
676 	 * The length of the binary data after inflation.
677 	 */
678 	size_t inflatedlen;
679 }
680 
681 /**
682  * Structure describing the binary contents of a diff.
683  */
684 struct git_diff_binary
685 {
686 	/**
687 	 * Whether there is data in this binary structure or not.  If this
688 	 * is `1`, then this was produced and included binary content.  If
689 	 * this is `0` then this was generated knowing only that a binary
690 	 * file changed but without providing the data, probably from a patch
691 	 * that said `Binary files a/file.txt and b/file.txt differ`.
692 	 */
693 	uint contains_data;
694 
695 	/**
696 	 * The contents of the old file.
697 	 */
698 	.git_diff_binary_file old_file;
699 
700 	/**
701 	 * The contents of the new file.
702 	 */
703 	.git_diff_binary_file new_file;
704 }
705 
706 /**
707  * When iterating over a diff, callback that will be made for
708  * binary content within the diff.
709  */
710 alias git_diff_binary_cb = int function(const (.git_diff_delta)* delta, const (.git_diff_binary)* binary, void* payload);
711 
712 /**
713  * Structure describing a hunk of a diff.
714  *
715  * A `hunk` is a span of modified lines in a delta along with some stable
716  * surrounding context. You can configure the amount of context and other
717  * properties of how hunks are generated. Each hunk also comes with a
718  * header that described where it starts and ends in both the old and new
719  * versions in the delta.
720  */
721 struct git_diff_hunk
722 {
723 	/**
724 	 * Starting line number in old_file
725 	 */
726 	int old_start;
727 
728 	/**
729 	 * Number of lines in old_file
730 	 */
731 	int old_lines;
732 
733 	/**
734 	 * Starting line number in new_file
735 	 */
736 	int new_start;
737 
738 	/**
739 	 * Number of lines in new_file
740 	 */
741 	int new_lines;
742 
743 	/**
744 	 * Number of bytes in header text
745 	 */
746 	size_t header_len;
747 
748 	/**
749 	 * Header text, NUL-byte terminated
750 	 */
751 	char[.GIT_DIFF_HUNK_HEADER_SIZE] header = '\0'; 
752 }
753 
754 /**
755  * When iterating over a diff, callback that will be made per hunk.
756  */
757 alias git_diff_hunk_cb = int function(const (.git_diff_delta)* delta, const (.git_diff_hunk)* hunk, void* payload);
758 
759 /**
760  * Line origin constants.
761  *
762  * These values describe where a line came from and will be passed to
763  * the git_diff_line_cb when iterating over a diff.  There are some
764  * special origin constants at the end that are used for the text
765  * output callbacks to demarcate lines that are actually part of
766  * the file or hunk headers.
767  */
768 enum git_diff_line_t
769 {
770 	/* These values will be sent to `git_diff_line_cb` along with the line */
771 	GIT_DIFF_LINE_CONTEXT = ' ',
772 	GIT_DIFF_LINE_ADDITION = '+',
773 	GIT_DIFF_LINE_DELETION = '-',
774 
775 	/**
776 	 * Both files have no LF at end
777 	 */
778 	GIT_DIFF_LINE_CONTEXT_EOFNL = '=',
779 
780 	/**
781 	 * Old has no LF at end, new does
782 	 */
783 	GIT_DIFF_LINE_ADD_EOFNL = '>',
784 
785 	/**
786 	 * Old has LF at end, new does not
787 	 */
788 	GIT_DIFF_LINE_DEL_EOFNL = '<',
789 
790 	/*
791 	 * The following values will only be sent to a `git_diff_line_cb` when
792 	 * the content of a diff is being formatted through `git_diff_print`.
793 	 */
794 	GIT_DIFF_LINE_FILE_HDR = 'F',
795 	GIT_DIFF_LINE_HUNK_HDR = 'H',
796 
797 	/**
798 	 * For "Binary files x and y differ"
799 	 */
800 	GIT_DIFF_LINE_BINARY = 'B',
801 }
802 
803 /**
804  * Structure describing a line (or data span) of a diff.
805  *
806  * A `line` is a range of characters inside a hunk.  It could be a context
807  * line (i.e. in both old and new versions), an added line (i.e. only in
808  * the new version), or a removed line (i.e. only in the old version).
809  * Unfortunately, we don't know anything about the encoding of data in the
810  * file being diffed, so we cannot tell you much about the line content.
811  * Line data will not be NUL-byte terminated, however, because it will be
812  * just a span of bytes inside the larger file.
813  */
814 struct git_diff_line
815 {
816 	/**
817 	 * A git_diff_line_t value
818 	 */
819 	char origin = '\0';
820 
821 	/**
822 	 * Line number in old file or -1 for added line
823 	 */
824 	int old_lineno;
825 
826 	/**
827 	 * Line number in new file or -1 for deleted line
828 	 */
829 	int new_lineno;
830 
831 	/**
832 	 * Number of newline characters in content
833 	 */
834 	int num_lines;
835 
836 	/**
837 	 * Number of bytes of data
838 	 */
839 	size_t content_len;
840 
841 	/**
842 	 * Offset in the original file to the content
843 	 */
844 	libgit2_d.types.git_off_t content_offset;
845 
846 	/**
847 	 * Pointer to diff text, not NUL-byte terminated
848 	 */
849 	const (char)* content;
850 }
851 
852 /**
853  * When iterating over a diff, callback that will be made per text diff
854  * line. In this context, the provided range will be null.
855  *
856  * When printing a diff, callback that will be made to output each line
857  * of text.  This uses some extra GIT_DIFF_LINE_... constants for output
858  * of lines of file and hunk headers.
859  */
860 alias git_diff_line_cb = int function(
861     const (.git_diff_delta)* delta, /**< delta that contains this data */
862     const (.git_diff_hunk)* hunk,   /**< hunk containing this data */
863     const (.git_diff_line)* line,   /**< line data */
864     void* payload);              /**< user reference data */
865 
866 /**
867  * Flags to control the behavior of diff rename/copy detection.
868  */
869 enum git_diff_find_t
870 {
871 	/**
872 	 * Obey `diff.renames`. Overridden by any other GIT_DIFF_FIND_... flag.
873 	 */
874 	GIT_DIFF_FIND_BY_CONFIG = 0,
875 
876 	/**
877 	 * Look for renames? (`--find-renames`)
878 	 */
879 	GIT_DIFF_FIND_RENAMES = 1u << 0,
880 
881 	/**
882 	 * Consider old side of MODIFIED for renames? (`--break-rewrites=N`)
883 	 */
884 	GIT_DIFF_FIND_RENAMES_FROM_REWRITES = 1u << 1,
885 
886 	/**
887 	 * Look for copies? (a la `--find-copies`).
888 	 */
889 	GIT_DIFF_FIND_COPIES = 1u << 2,
890 
891 	/**
892 	 * Consider UNMODIFIED as copy sources? (`--find-copies-harder`).
893 	 *
894 	 * For this to work correctly, use git_diff_option_t.GIT_DIFF_INCLUDE_UNMODIFIED when
895 	 * the initial `git_diff` is being generated.
896 	 */
897 	GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED = 1u << 3,
898 
899 	/**
900 	 * Mark significant rewrites for split (`--break-rewrites=/M`)
901 	 */
902 	GIT_DIFF_FIND_REWRITES = 1u << 4,
903 
904 	/**
905 	 * Actually split large rewrites into delete/add pairs
906 	 */
907 	GIT_DIFF_BREAK_REWRITES = 1u << 5,
908 
909 	/**
910 	 * Mark rewrites for split and break into delete/add pairs
911 	 */
912 	GIT_DIFF_FIND_AND_BREAK_REWRITES = GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES,
913 
914 	/**
915 	 * Find renames/copies for UNTRACKED items in working directory.
916 	 *
917 	 * For this to work correctly, use git_diff_option_t.GIT_DIFF_INCLUDE_UNTRACKED when the
918 	 * initial `git_diff` is being generated (and obviously the diff must
919 	 * be against the working directory for this to make sense).
920 	 */
921 	GIT_DIFF_FIND_FOR_UNTRACKED = 1u << 6,
922 
923 	/**
924 	 * Turn on all finding features.
925 	 */
926 	GIT_DIFF_FIND_ALL = 0x00FF,
927 
928 	/**
929 	 * Measure similarity ignoring leading whitespace (default)
930 	 */
931 	GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE = 0,
932 
933 	/**
934 	 * Measure similarity ignoring all whitespace
935 	 */
936 	GIT_DIFF_FIND_IGNORE_WHITESPACE = 1u << 12,
937 
938 	/**
939 	 * Measure similarity including all data
940 	 */
941 	GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = 1u << 13,
942 
943 	/**
944 	 * Measure similarity only by comparing SHAs (fast and cheap)
945 	 */
946 	GIT_DIFF_FIND_EXACT_MATCH_ONLY = 1u << 14,
947 
948 	/**
949 	 * Do not break rewrites unless they contribute to a rename.
950 	 *
951 	 * Normally, GIT_DIFF_FIND_AND_BREAK_REWRITES will measure the self-
952 	 * similarity of modified files and split the ones that have changed a
953 	 * lot into a DELETE / ADD pair.  Then the sides of that pair will be
954 	 * considered candidates for rename and copy detection.
955 	 *
956 	 * If you add this flag in and the split pair is *not* used for an
957 	 * actual rename or copy, then the modified record will be restored to
958 	 * a regular MODIFIED record instead of being split.
959 	 */
960 	GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = 1u << 15,
961 
962 	/**
963 	 * Remove any UNMODIFIED deltas after find_similar is done.
964 	 *
965 	 * Using GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED to emulate the
966 	 * --find-copies-harder behavior requires building a diff with the
967 	 * GIT_DIFF_INCLUDE_UNMODIFIED flag.  If you do not want UNMODIFIED
968 	 * records in the final result, pass this flag to have them removed.
969 	 */
970 	GIT_DIFF_FIND_REMOVE_UNMODIFIED = 1u << 16,
971 }
972 
973 /**
974  * Pluggable similarity metric
975  */
976 struct git_diff_similarity_metric
977 {
978 	int function(void** out_, const (.git_diff_file)* file, const (char)* fullpath, void* payload) file_signature;
979 	int function(void** out_, const (.git_diff_file)* file, const (char)* buf, size_t buflen, void* payload) buffer_signature;
980 	void function(void* sig, void* payload) free_signature;
981 	int function(int* score, void* siga, void* sigb, void* payload) similarity;
982 	void* payload;
983 }
984 
985 /**
986  * Control behavior of rename and copy detection
987  *
988  * These options mostly mimic parameters that can be passed to git-diff.
989  */
990 struct git_diff_find_options
991 {
992 	uint version_;
993 
994 	/**
995 	 * Combination of git_diff_find_t values (default git_diff_find_t.GIT_DIFF_FIND_BY_CONFIG).
996 	 * NOTE: if you don't explicitly set this, `diff.renames` could be set
997 	 * to false, resulting in `git_diff_find_similar` doing nothing.
998 	 */
999 	uint flags;
1000 
1001 	/**
1002 	 * Threshold above which similar files will be considered renames.
1003 	 * This is equivalent to the -M option. Defaults to 50.
1004 	 */
1005 	ushort rename_threshold;
1006 
1007 	/**
1008 	 * Threshold below which similar files will be eligible to be a rename source.
1009 	 * This is equivalent to the first part of the -B option. Defaults to 50.
1010 	 */
1011 	ushort rename_from_rewrite_threshold;
1012 
1013 	/**
1014 	 * Threshold above which similar files will be considered copies.
1015 	 * This is equivalent to the -C option. Defaults to 50.
1016 	 */
1017 	ushort copy_threshold;
1018 
1019 	/**
1020 	 * Treshold below which similar files will be split into a delete/add pair.
1021 	 * This is equivalent to the last part of the -B option. Defaults to 60.
1022 	 */
1023 	ushort break_rewrite_threshold;
1024 
1025 	/**
1026 	 * Maximum number of matches to consider for a particular file.
1027 	 *
1028 	 * This is a little different from the `-l` option from Git because we
1029 	 * will still process up to this many matches before abandoning the search.
1030 	 * Defaults to 200.
1031 	 */
1032 	size_t rename_limit;
1033 
1034 	/**
1035 	 * The `metric` option allows you to plug in a custom similarity metric.
1036 	 *
1037 	 * Set it to NULL to use the default internal metric.
1038 	 *
1039 	 * The default metric is based on sampling hashes of ranges of data in
1040 	 * the file, which is a pretty good similarity approximation that should
1041 	 * work fairly well for both text and binary data while still being
1042 	 * pretty fast with a fixed memory overhead.
1043 	 */
1044 	.git_diff_similarity_metric* metric;
1045 }
1046 
1047 enum GIT_DIFF_FIND_OPTIONS_VERSION = 1;
1048 
1049 pragma(inline, true)
1050 pure nothrow @safe @nogc
1051 .git_diff_find_options GIT_DIFF_FIND_OPTIONS_INIT()
1052 
1053 	do
1054 	{
1055 		.git_diff_find_options OUTPUT =
1056 		{
1057 			version_: .GIT_DIFF_FIND_OPTIONS_VERSION,
1058 		};
1059 
1060 		return OUTPUT;
1061 	}
1062 
1063 /**
1064  * Initialize git_diff_find_options structure
1065  *
1066  * Initializes a `git_diff_find_options` with default values. Equivalent to creating
1067  * an instance with GIT_DIFF_FIND_OPTIONS_INIT.
1068  *
1069  * @param opts The `git_diff_find_options` struct to initialize.
1070  * @param version The struct version; pass `GIT_DIFF_FIND_OPTIONS_VERSION`.
1071  * @return Zero on success; -1 on failure.
1072  */
1073 //GIT_EXTERN
1074 int git_diff_find_options_init(.git_diff_find_options* opts, uint version_);
1075 
1076 /**
1077  * @name Diff Generator Functions
1078  *
1079  * These are the functions you would use to create (or destroy) a
1080  * git_diff from various objects in a repository.
1081  */
1082 /**@{*/
1083 
1084 /**
1085  * Deallocate a diff.
1086  *
1087  * @param diff The previously created diff; cannot be used after free.
1088  */
1089 //GIT_EXTERN
1090 void git_diff_free(.git_diff* diff);
1091 
1092 /**
1093  * Create a diff with the difference between two tree objects.
1094  *
1095  * This is equivalent to `git diff <old-tree> <new-tree>`
1096  *
1097  * The first tree will be used for the "old_file" side of the delta and the
1098  * second tree will be used for the "new_file" side of the delta.  You can
1099  * pass null to indicate an empty tree, although it is an error to pass
1100  * null for both the `old_tree` and `new_tree`.
1101  *
1102  * @param diff Output pointer to a git_diff pointer to be allocated.
1103  * @param repo The repository containing the trees.
1104  * @param old_tree A git_tree object to diff from, or null for empty tree.
1105  * @param new_tree A git_tree object to diff to, or null for empty tree.
1106  * @param opts Structure with options to influence diff or null for defaults.
1107  */
1108 //GIT_EXTERN
1109 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);
1110 
1111 /**
1112  * Create a diff between a tree and repository index.
1113  *
1114  * This is equivalent to `git diff --cached <treeish>` or if you pass
1115  * the HEAD tree, then like `git diff --cached`.
1116  *
1117  * The tree you pass will be used for the "old_file" side of the delta, and
1118  * the index will be used for the "new_file" side of the delta.
1119  *
1120  * If you pass null for the index, then the existing index of the `repo`
1121  * will be used.  In this case, the index will be refreshed from disk
1122  * (if it has changed) before the diff is generated.
1123  *
1124  * @param diff Output pointer to a git_diff pointer to be allocated.
1125  * @param repo The repository containing the tree and index.
1126  * @param old_tree A git_tree object to diff from, or null for empty tree.
1127  * @param index The index to diff with; repo index used if null.
1128  * @param opts Structure with options to influence diff or null for defaults.
1129  */
1130 //GIT_EXTERN
1131 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);
1132 
1133 /**
1134  * Create a diff between the repository index and the workdir directory.
1135  *
1136  * This matches the `git diff` command.  See the note below on
1137  * `git_diff_tree_to_workdir` for a discussion of the difference between
1138  * `git diff` and `git diff HEAD` and how to emulate a `git diff <treeish>`
1139  * using libgit2.
1140  *
1141  * The index will be used for the "old_file" side of the delta, and the
1142  * working directory will be used for the "new_file" side of the delta.
1143  *
1144  * If you pass null for the index, then the existing index of the `repo`
1145  * will be used.  In this case, the index will be refreshed from disk
1146  * (if it has changed) before the diff is generated.
1147  *
1148  * @param diff Output pointer to a git_diff pointer to be allocated.
1149  * @param repo The repository.
1150  * @param index The index to diff from; repo index used if null.
1151  * @param opts Structure with options to influence diff or null for defaults.
1152  */
1153 //GIT_EXTERN
1154 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);
1155 
1156 /**
1157  * Create a diff between a tree and the working directory.
1158  *
1159  * The tree you provide will be used for the "old_file" side of the delta,
1160  * and the working directory will be used for the "new_file" side.
1161  *
1162  * This is not the same as `git diff <treeish>` or `git diff-index
1163  * <treeish>`.  Those commands use information from the index, whereas this
1164  * function strictly returns the differences between the tree and the files
1165  * in the working directory, regardless of the state of the index.  Use
1166  * `git_diff_tree_to_workdir_with_index` to emulate those commands.
1167  *
1168  * To see difference between this and `git_diff_tree_to_workdir_with_index`,
1169  * consider the example of a staged file deletion where the file has then
1170  * been put back into the working dir and further modified.  The
1171  * tree-to-workdir diff for that file is 'modified', but `git diff` would
1172  * show status 'deleted' since there is a staged delete.
1173  *
1174  * @param diff A pointer to a git_diff pointer that will be allocated.
1175  * @param repo The repository containing the tree.
1176  * @param old_tree A git_tree object to diff from, or null for empty tree.
1177  * @param opts Structure with options to influence diff or null for defaults.
1178  */
1179 //GIT_EXTERN
1180 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);
1181 
1182 /**
1183  * Create a diff between a tree and the working directory using index data
1184  * to account for staged deletes, tracked files, etc.
1185  *
1186  * This emulates `git diff <tree>` by diffing the tree to the index and
1187  * the index to the working directory and blending the results into a
1188  * single diff that includes staged deleted, etc.
1189  *
1190  * @param diff A pointer to a git_diff pointer that will be allocated.
1191  * @param repo The repository containing the tree.
1192  * @param old_tree A git_tree object to diff from, or null for empty tree.
1193  * @param opts Structure with options to influence diff or null for defaults.
1194  */
1195 //GIT_EXTERN
1196 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);
1197 
1198 /**
1199  * Create a diff with the difference between two index objects.
1200  *
1201  * The first index will be used for the "old_file" side of the delta and the
1202  * second index will be used for the "new_file" side of the delta.
1203  *
1204  * @param diff Output pointer to a git_diff pointer to be allocated.
1205  * @param repo The repository containing the indexes.
1206  * @param old_index A git_index object to diff from.
1207  * @param new_index A git_index object to diff to.
1208  * @param opts Structure with options to influence diff or null for defaults.
1209  */
1210 //GIT_EXTERN
1211 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);
1212 
1213 /**
1214  * Merge one diff into another.
1215  *
1216  * This merges items from the "from" list into the "onto" list.  The
1217  * resulting diff will have all items that appear in either list.
1218  * If an item appears in both lists, then it will be "merged" to appear
1219  * as if the old version was from the "onto" list and the new version
1220  * is from the "from" list (with the exception that if the item has a
1221  * pending DELETE in the middle, then it will show as deleted).
1222  *
1223  * @param onto Diff to merge into.
1224  * @param from Diff to merge.
1225  */
1226 //GIT_EXTERN
1227 int git_diff_merge(.git_diff* onto, const (.git_diff)* from);
1228 
1229 /**
1230  * Transform a diff marking file renames, copies, etc.
1231  *
1232  * This modifies a diff in place, replacing old entries that look
1233  * like renames or copies with new entries reflecting those changes.
1234  * This also will, if requested, break modified files into add/remove
1235  * pairs if the amount of change is above a threshold.
1236  *
1237  * @param diff diff to run detection algorithms on
1238  * @param options Control how detection should be run, null for defaults
1239  * @return 0 on success, -1 on failure
1240  */
1241 //GIT_EXTERN
1242 int git_diff_find_similar(.git_diff* diff, const (.git_diff_find_options)* options);
1243 
1244 /**@}*/
1245 
1246 /**
1247  * @name Diff Processor Functions
1248  *
1249  * These are the functions you apply to a diff to process it
1250  * or read it in some way.
1251  */
1252 /**@{*/
1253 
1254 /**
1255  * Query how many diff records are there in a diff.
1256  *
1257  * @param diff A git_diff generated by one of the above functions
1258  * @return Count of number of deltas in the list
1259  */
1260 //GIT_EXTERN
1261 size_t git_diff_num_deltas(const (.git_diff)* diff);
1262 
1263 /**
1264  * Query how many diff deltas are there in a diff filtered by type.
1265  *
1266  * This works just like `git_diff_entrycount()` with an extra parameter
1267  * that is a `git_delta_t` and returns just the count of how many deltas
1268  * match that particular type.
1269  *
1270  * @param diff A git_diff generated by one of the above functions
1271  * @param type A git_delta_t value to filter the count
1272  * @return Count of number of deltas matching delta_t type
1273  */
1274 //GIT_EXTERN
1275 size_t git_diff_num_deltas_of_type(const (.git_diff)* diff, .git_delta_t type);
1276 
1277 /**
1278  * Return the diff delta for an entry in the diff list.
1279  *
1280  * The `git_diff_delta` pointer points to internal data and you do not
1281  * have to release it when you are done with it.  It will go away when
1282  * the * `git_diff` (or any associated `git_patch`) goes away.
1283  *
1284  * Note that the flags on the delta related to whether it has binary
1285  * content or not may not be set if there are no attributes set for the
1286  * file and there has been no reason to load the file data at this point.
1287  * For now, if you need those flags to be up to date, your only option is
1288  * to either use `git_diff_foreach` or create a `git_patch`.
1289  *
1290  * @param diff Diff list object
1291  * @param idx Index into diff list
1292  * @return Pointer to git_diff_delta (or null if `idx` out of range)
1293  */
1294 //GIT_EXTERN
1295 const (.git_diff_delta)* git_diff_get_delta(const (.git_diff)* diff, size_t idx);
1296 
1297 /**
1298  * Check if deltas are sorted case sensitively or insensitively.
1299  *
1300  * @param diff diff to check
1301  * @return 0 if case sensitive, 1 if case is ignored
1302  */
1303 //GIT_EXTERN
1304 int git_diff_is_sorted_icase(const (.git_diff)* diff);
1305 
1306 /**
1307  * Loop over all deltas in a diff issuing callbacks.
1308  *
1309  * This will iterate through all of the files described in a diff.  You
1310  * should provide a file callback to learn about each file.
1311  *
1312  * The "hunk" and "line" callbacks are optional, and the text diff of the
1313  * files will only be calculated if they are not null.  Of course, these
1314  * callbacks will not be invoked for binary files on the diff or for
1315  * files whose only changed is a file mode change.
1316  *
1317  * Returning a non-zero value from any of the callbacks will terminate
1318  * the iteration and return the value to the user.
1319  *
1320  * @param diff A git_diff generated by one of the above functions.
1321  * @param file_cb Callback function to make per file in the diff.
1322  * @param binary_cb Optional callback to make for binary files.
1323  * @param hunk_cb Optional callback to make per hunk of text diff.  This
1324  *                callback is called to describe a range of lines in the
1325  *                diff.  It will not be issued for binary files.
1326  * @param line_cb Optional callback to make per line of diff text.  This
1327  *                same callback will be made for context lines, added, and
1328  *                removed lines, and even for a deleted trailing newline.
1329  * @param payload Reference pointer that will be passed to your callbacks.
1330  * @return 0 on success, non-zero callback return value, or error code
1331  */
1332 //GIT_EXTERN
1333 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);
1334 
1335 /**
1336  * Look up the single character abbreviation for a delta status code.
1337  *
1338  * When you run `git diff --name-status` it uses single letter codes in
1339  * the output such as 'A' for added, 'D' for deleted, 'M' for modified,
1340  * etc.  This function converts a git_delta_t value into these letters for
1341  * your own purposes.  git_delta_t.GIT_DELTA_UNTRACKED will return a space (i.e. ' ').
1342  *
1343  * @param status The git_delta_t value to look up
1344  * @return The single character label for that code
1345  */
1346 //GIT_EXTERN
1347 char git_diff_status_char(.git_delta_t status);
1348 
1349 /**
1350  * Possible output formats for diff data
1351  */
1352 enum git_diff_format_t
1353 {
1354 	/**
1355 	 * full git diff
1356 	 */
1357 	GIT_DIFF_FORMAT_PATCH = 1u,
1358 
1359 	/**
1360 	 * just the file headers of patch
1361 	 */
1362 	GIT_DIFF_FORMAT_PATCH_HEADER = 2u,
1363 
1364 	/**
1365 	 * like git diff --raw
1366 	 */
1367 	GIT_DIFF_FORMAT_RAW = 3u,
1368 
1369 	/**
1370 	 * like git diff --name-only
1371 	 */
1372 	GIT_DIFF_FORMAT_NAME_ONLY = 4u,
1373 
1374 	/**
1375 	 * like git diff --name-status
1376 	 */
1377 	GIT_DIFF_FORMAT_NAME_STATUS = 5u,
1378 
1379 	/**
1380 	 * git diff as used by git patch-id
1381 	 */
1382 	GIT_DIFF_FORMAT_PATCH_ID = 6u,
1383 }
1384 
1385 /**
1386  * Iterate over a diff generating formatted text output.
1387  *
1388  * Returning a non-zero value from the callbacks will terminate the
1389  * iteration and return the non-zero value to the caller.
1390  *
1391  * @param diff A git_diff generated by one of the above functions.
1392  * @param format A git_diff_format_t value to pick the text format.
1393  * @param print_cb Callback to make per line of diff text.
1394  * @param payload Reference pointer that will be passed to your callback.
1395  * @return 0 on success, non-zero callback return value, or error code
1396  */
1397 //GIT_EXTERN
1398 int git_diff_print(.git_diff* diff, .git_diff_format_t format, .git_diff_line_cb print_cb, void* payload);
1399 
1400 /**
1401  * Produce the complete formatted text output from a diff into a
1402  * buffer.
1403  *
1404  * @param out_ A pointer to a user-allocated git_buf that will
1405  *            contain the diff text
1406  * @param diff A git_diff generated by one of the above functions.
1407  * @param format A git_diff_format_t value to pick the text format.
1408  * @return 0 on success or error code
1409  */
1410 //GIT_EXTERN
1411 int git_diff_to_buf(libgit2_d.buffer.git_buf* out_, .git_diff* diff, .git_diff_format_t format);
1412 
1413 /**@}*/
1414 
1415 /*
1416  * Misc
1417  */
1418 
1419 /**
1420  * Directly run a diff on two blobs.
1421  *
1422  * Compared to a file, a blob lacks some contextual information. As such,
1423  * the `git_diff_file` given to the callback will have some fake data; i.e.
1424  * `mode` will be 0 and `path` will be null.
1425  *
1426  * null is allowed for either `old_blob` or `new_blob` and will be treated
1427  * as an empty blob, with the `oid` set to null in the `git_diff_file` data.
1428  * Passing null for both blobs is a noop; no callbacks will be made at all.
1429  *
1430  * We do run a binary content check on the blob content and if either blob
1431  * looks like binary data, the `git_diff_delta` binary attribute will be set
1432  * to 1 and no call to the hunk_cb nor line_cb will be made (unless you pass
1433  * `git_diff_option_t.GIT_DIFF_FORCE_TEXT` of course).
1434  *
1435  * @param old_blob Blob for old side of diff, or null for empty blob
1436  * @param old_as_path Treat old blob as if it had this filename; can be null
1437  * @param new_blob Blob for new side of diff, or null for empty blob
1438  * @param new_as_path Treat new blob as if it had this filename; can be null
1439  * @param options Options for diff, or null for default options
1440  * @param file_cb Callback for "file"; made once if there is a diff; can be null
1441  * @param binary_cb Callback for binary files; can be null
1442  * @param hunk_cb Callback for each hunk in diff; can be null
1443  * @param line_cb Callback for each line in diff; can be null
1444  * @param payload Payload passed to each callback function
1445  * @return 0 on success, non-zero callback return value, or error code
1446  */
1447 //GIT_EXTERN
1448 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);
1449 
1450 /**
1451  * Directly run a diff between a blob and a buffer.
1452  *
1453  * As with `git_diff_blobs`, comparing a blob and buffer lacks some context,
1454  * so the `git_diff_file` parameters to the callbacks will be faked a la the
1455  * rules for `git_diff_blobs()`.
1456  *
1457  * Passing null for `old_blob` will be treated as an empty blob (i.e. the
1458  * `file_cb` will be invoked with git_delta_t.GIT_DELTA_ADDED and the diff will be the
1459  * entire content of the buffer added).  Passing null to the buffer will do
1460  * the reverse, with GIT_DELTA_REMOVED and blob content removed.
1461  *
1462  * @param old_blob Blob for old side of diff, or null for empty blob
1463  * @param old_as_path Treat old blob as if it had this filename; can be null
1464  * @param buffer Raw data for new side of diff, or null for empty
1465  * @param buffer_len Length of raw data for new side of diff
1466  * @param buffer_as_path Treat buffer as if it had this filename; can be null
1467  * @param options Options for diff, or null for default options
1468  * @param file_cb Callback for "file"; made once if there is a diff; can be null
1469  * @param binary_cb Callback for binary files; can be null
1470  * @param hunk_cb Callback for each hunk in diff; can be null
1471  * @param line_cb Callback for each line in diff; can be null
1472  * @param payload Payload passed to each callback function
1473  * @return 0 on success, non-zero callback return value, or error code
1474  */
1475 //GIT_EXTERN
1476 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);
1477 
1478 /**
1479  * Directly run a diff between two buffers.
1480  *
1481  * Even more than with `git_diff_blobs`, comparing two buffer lacks
1482  * context, so the `git_diff_file` parameters to the callbacks will be
1483  * faked a la the rules for `git_diff_blobs()`.
1484  *
1485  * @param old_buffer Raw data for old side of diff, or null for empty
1486  * @param old_len Length of the raw data for old side of the diff
1487  * @param old_as_path Treat old buffer as if it had this filename; can be null
1488  * @param new_buffer Raw data for new side of diff, or null for empty
1489  * @param new_len Length of raw data for new side of diff
1490  * @param new_as_path Treat buffer as if it had this filename; can be null
1491  * @param options Options for diff, or null for default options
1492  * @param file_cb Callback for "file"; made once if there is a diff; can be null
1493  * @param binary_cb Callback for binary files; can be null
1494  * @param hunk_cb Callback for each hunk in diff; can be null
1495  * @param line_cb Callback for each line in diff; can be null
1496  * @param payload Payload passed to each callback function
1497  * @return 0 on success, non-zero callback return value, or error code
1498  */
1499 //GIT_EXTERN
1500 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);
1501 
1502 /**
1503  * Read the contents of a git patch file into a `git_diff` object.
1504  *
1505  * The diff object produced is similar to the one that would be
1506  * produced if you actually produced it computationally by comparing
1507  * two trees, however there may be subtle differences.  For example,
1508  * a patch file likely contains abbreviated object IDs, so the
1509  * object IDs in a `git_diff_delta` produced by this function will
1510  * also be abbreviated.
1511  *
1512  * This function will only read patch files created by a git
1513  * implementation, it will not read unified diffs produced by
1514  * the `diff` program, nor any other types of patch files.
1515  *
1516  * @param out_ A pointer to a git_diff pointer that will be allocated.
1517  * @param content The contents of a patch file
1518  * @param content_len The length of the patch file contents
1519  * @return 0 or an error code
1520  */
1521 //GIT_EXTERN
1522 int git_diff_from_buffer(.git_diff** out_, const (char)* content, size_t content_len);
1523 
1524 /**
1525  * This is an opaque structure which is allocated by `git_diff_get_stats`.
1526  * You are responsible for releasing the object memory when done, using the
1527  * `git_diff_stats_free()` function.
1528  */
1529 struct git_diff_stats;
1530 
1531 /**
1532  * Formatting options for diff stats
1533  */
1534 enum git_diff_stats_format_t
1535 {
1536 	/**
1537 	 * No stats
1538 	 */
1539 	GIT_DIFF_STATS_NONE = 0,
1540 
1541 	/**
1542 	 * Full statistics, equivalent of `--stat`
1543 	 */
1544 	GIT_DIFF_STATS_FULL = 1u << 0,
1545 
1546 	/**
1547 	 * Short statistics, equivalent of `--shortstat`
1548 	 */
1549 	GIT_DIFF_STATS_SHORT = 1u << 1,
1550 
1551 	/**
1552 	 * Number statistics, equivalent of `--numstat`
1553 	 */
1554 	GIT_DIFF_STATS_NUMBER = 1u << 2,
1555 
1556 	/**
1557 	 * Extended header information such as creations, renames and mode changes,
1558 	 * equivalent of `--summary`
1559 	 */
1560 	GIT_DIFF_STATS_INCLUDE_SUMMARY = 1u << 3,
1561 }
1562 
1563 /**
1564  * Accumulate diff statistics for all patches.
1565  *
1566  * @param out_ Structure containg the diff statistics.
1567  * @param diff A git_diff generated by one of the above functions.
1568  * @return 0 on success; non-zero on error
1569  */
1570 //GIT_EXTERN
1571 int git_diff_get_stats(.git_diff_stats** out_, .git_diff* diff);
1572 
1573 /**
1574  * Get the total number of files changed in a diff
1575  *
1576  * @param stats A `git_diff_stats` generated by one of the above functions.
1577  * @return total number of files changed in the diff
1578  */
1579 //GIT_EXTERN
1580 size_t git_diff_stats_files_changed(const (.git_diff_stats)* stats);
1581 
1582 /**
1583  * Get the total number of insertions in a diff
1584  *
1585  * @param stats A `git_diff_stats` generated by one of the above functions.
1586  * @return total number of insertions in the diff
1587  */
1588 //GIT_EXTERN
1589 size_t git_diff_stats_insertions(const (.git_diff_stats)* stats);
1590 
1591 /**
1592  * Get the total number of deletions in a diff
1593  *
1594  * @param stats A `git_diff_stats` generated by one of the above functions.
1595  * @return total number of deletions in the diff
1596  */
1597 //GIT_EXTERN
1598 size_t git_diff_stats_deletions(const (.git_diff_stats)* stats);
1599 
1600 /**
1601  * Print diff statistics to a `git_buf`.
1602  *
1603  * @param out_ buffer to store the formatted diff statistics in.
1604  * @param stats A `git_diff_stats` generated by one of the above functions.
1605  * @param format Formatting option.
1606  * @param width Target width for output (only affects git_diff_stats_format_t.GIT_DIFF_STATS_FULL)
1607  * @return 0 on success; non-zero on error
1608  */
1609 //GIT_EXTERN
1610 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);
1611 
1612 /**
1613  * Deallocate a `git_diff_stats`.
1614  *
1615  * @param stats The previously created statistics object;
1616  * cannot be used after free.
1617  */
1618 //GIT_EXTERN
1619 void git_diff_stats_free(.git_diff_stats* stats);
1620 
1621 /**
1622  * Formatting options for diff e-mail generation
1623  */
1624 enum git_diff_format_email_flags_t
1625 {
1626 	/**
1627 	 * Normal patch, the default
1628 	 */
1629 	GIT_DIFF_FORMAT_EMAIL_NONE = 0,
1630 
1631 	/**
1632 	 * Don't insert "[PATCH]" in the subject header
1633 	 */
1634 	GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = 1 << 0,
1635 }
1636 
1637 /**
1638  * Options for controlling the formatting of the generated e-mail.
1639  */
1640 struct git_diff_format_email_options
1641 {
1642 	uint version_;
1643 
1644 	/**
1645 	 * see `git_diff_format_email_flags_t` above
1646 	 */
1647 	uint flags;
1648 
1649 	/**
1650 	 * This patch number
1651 	 */
1652 	size_t patch_no;
1653 
1654 	/**
1655 	 * Total number of patches in this series
1656 	 */
1657 	size_t total_patches;
1658 
1659 	/**
1660 	 * id to use for the commit
1661 	 */
1662 	const (libgit2_d.oid.git_oid)* id;
1663 
1664 	/**
1665 	 * Summary of the change
1666 	 */
1667 	const (char)* summary;
1668 
1669 	/**
1670 	 * Commit message's body
1671 	 */
1672 	const (char)* body_;
1673 
1674 	/**
1675 	 * Author of the change
1676 	 */
1677 	const (libgit2_d.types.git_signature)* author;
1678 }
1679 
1680 enum GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION = 1;
1681 
1682 pragma(inline, true)
1683 pure nothrow @safe @nogc
1684 .git_diff_format_email_options GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT()
1685 
1686 	do
1687 	{
1688 		.git_diff_format_email_options OUTPUT =
1689 		{
1690 			version_: .GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION,
1691 			flags: .git_diff_format_email_flags_t.GIT_DIFF_FORMAT_EMAIL_NONE,
1692 			patch_no: 1,
1693 			total_patches: 1,
1694 			id: null,
1695 			summary: null,
1696 			body_: null,
1697 			author: null,
1698 		};
1699 
1700 		return OUTPUT;
1701 	}
1702 
1703 /**
1704  * Create an e-mail ready patch from a diff.
1705  *
1706  * @param out_ buffer to store the e-mail patch in
1707  * @param diff containing the commit
1708  * @param opts structure with options to influence content and formatting.
1709  * @return 0 or an error code
1710  */
1711 //GIT_EXTERN
1712 int git_diff_format_email(libgit2_d.buffer.git_buf* out_, .git_diff* diff, const (.git_diff_format_email_options)* opts);
1713 
1714 /**
1715  * Create an e-mail ready patch for a commit.
1716  *
1717  * Does not support creating patches for merge commits (yet).
1718  *
1719  * @param out_ buffer to store the e-mail patch in
1720  * @param repo containing the commit
1721  * @param commit pointer to up commit
1722  * @param patch_no patch number of the commit
1723  * @param total_patches total number of patches in the patch set
1724  * @param flags determines the formatting of the e-mail
1725  * @param diff_opts structure with options to influence diff or null for
1726  * defaults.
1727  * @return 0 or an error code
1728  */
1729 //GIT_EXTERN
1730 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);
1731 
1732 /**
1733  * Initialize git_diff_format_email_options structure
1734  *
1735  * Initializes a `git_diff_format_email_options` with default values. Equivalent
1736  * to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
1737  *
1738  * @param opts The `git_blame_options` struct to initialize.
1739  * @param version The struct version; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`.
1740  * @return Zero on success; -1 on failure.
1741  */
1742 //GIT_EXTERN
1743 int git_diff_format_email_options_init(.git_diff_format_email_options* opts, uint version_);
1744 
1745 /**
1746  * Patch ID options structure
1747  *
1748  * Initialize with `GIT_PATCHID_OPTIONS_INIT`. Alternatively, you can
1749  * use `git_diff_patchid_options_init`.
1750  */
1751 struct git_diff_patchid_options
1752 {
1753 	uint version_;
1754 }
1755 
1756 enum GIT_DIFF_PATCHID_OPTIONS_VERSION = 1;
1757 
1758 pragma(inline, true)
1759 pure nothrow @safe @nogc
1760 .git_diff_patchid_options GIT_DIFF_PATCHID_OPTIONS_INIT()
1761 
1762 	do
1763 	{
1764 		.git_diff_patchid_options OUTPUT =
1765 		{
1766 			version_: .GIT_DIFF_PATCHID_OPTIONS_VERSION,
1767 		};
1768 
1769 		return OUTPUT;
1770 	}
1771 
1772 /**
1773  * Initialize git_diff_patchid_options structure
1774  *
1775  * Initializes a `git_diff_patchid_options` with default values. Equivalent to
1776  * creating an instance with `GIT_DIFF_PATCHID_OPTIONS_INIT`.
1777  *
1778  * @param opts The `git_diff_patchid_options` struct to initialize.
1779  * @param version The struct version; pass `GIT_DIFF_PATCHID_OPTIONS_VERSION`.
1780  * @return Zero on success; -1 on failure.
1781  */
1782 //GIT_EXTERN
1783 int git_diff_patchid_options_init(.git_diff_patchid_options* opts, uint version_);
1784 
1785 /**
1786  * Calculate the patch ID for the given patch.
1787  *
1788  * Calculate a stable patch ID for the given patch by summing the
1789  * hash of the file diffs, ignoring whitespace and line numbers.
1790  * This can be used to derive whether two diffs are the same with
1791  * a high probability.
1792  *
1793  * Currently, this function only calculates stable patch IDs, as
1794  * defined in git-patch-id(1), and should in fact generate the
1795  * same IDs as the upstream git project does.
1796  *
1797  * @param out_ Pointer where the calculated patch ID should be stored
1798  * @param diff The diff to calculate the ID for
1799  * @param opts Options for how to calculate the patch ID. This is
1800  *  intended for future changes, as currently no options are
1801  *  available.
1802  * @return 0 on success, an error code otherwise.
1803  */
1804 //GIT_EXTERN
1805 int git_diff_patchid(libgit2_d.oid.git_oid* out_, .git_diff* diff, .git_diff_patchid_options* opts);
1806 
1807 /** @} */