using System; using System.Runtime.InteropServices; namespace LibGit2Sharp.Core { [Flags] internal enum GitDiffOptionFlags { /// /// Normal diff, the default /// GIT_DIFF_NORMAL = 0, /* * Options controlling which files will be in the diff */ /// /// Reverse the sides of the diff /// GIT_DIFF_REVERSE = (1 << 0), /// /// Include ignored files in the diff /// GIT_DIFF_INCLUDE_IGNORED = (1 << 1), /// /// Even with GIT_DIFF_INCLUDE_IGNORED, an entire ignored directory /// will be marked with only a single entry in the diff; this flag /// adds all files under the directory as IGNORED entries, too. /// GIT_DIFF_RECURSE_IGNORED_DIRS = (1 << 2), /// /// Include untracked files in the diff /// GIT_DIFF_INCLUDE_UNTRACKED = (1 << 3), /// /// Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked /// directory will be marked with only a single entry in the diff /// (a la what core Git does in `git status`); this flag adds *all* /// files under untracked directories as UNTRACKED entries, too. /// GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 4), /// /// Include unmodified files in the diff /// GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 5), /// /// Normally, a type change between files will be converted into a /// DELETED record for the old and an ADDED record for the new; this /// options enabled the generation of TYPECHANGE delta records. /// GIT_DIFF_INCLUDE_TYPECHANGE = (1 << 6), /// /// Even with GIT_DIFF_INCLUDE_TYPECHANGE, blob->tree changes still /// generally show as a DELETED blob. This flag tries to correctly /// label blob->tree transitions as TYPECHANGE records with new_file's /// mode set to tree. Note: the tree SHA will not be available. /// GIT_DIFF_INCLUDE_TYPECHANGE_TREES = (1 << 7), /// /// Ignore file mode changes /// GIT_DIFF_IGNORE_FILEMODE = (1 << 8), /// /// Treat all submodules as unmodified /// GIT_DIFF_IGNORE_SUBMODULES = (1 << 9), /// /// Use case insensitive filename comparisons /// GIT_DIFF_IGNORE_CASE = (1 << 10), /// /// May be combined with `GIT_DIFF_IGNORE_CASE` to specify that a file /// that has changed case will be returned as an add/delete pair. /// GIT_DIFF_INCLUDE_CASECHANGE = (1 << 11), /// /// If the pathspec is set in the diff options, this flags means to /// apply it as an exact match instead of as an fnmatch pattern. /// GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 12), /// /// Disable updating of the `binary` flag in delta records. This is /// useful when iterating over a diff if you don't need hunk and data /// callbacks and want to avoid having to load file completely. /// GIT_DIFF_SKIP_BINARY_CHECK = (1 << 13), /// /// When diff finds an untracked directory, to match the behavior of /// core Git, it scans the contents for IGNORED and UNTRACKED files. /// If *all* contents are IGNORED, then the directory is IGNORED; if /// any contents are not IGNORED, then the directory is UNTRACKED. /// This is extra work that may not matter in many cases. This flag /// turns off that scan and immediately labels an untracked directory /// as UNTRACKED (changing the behavior to not match core Git). /// GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS = (1 << 14), /// /// When diff finds a file in the working directory with stat /// information different from the index, but the OID ends up being the /// same, write the correct stat information into the index. Note: /// without this flag, diff will always leave the index untouched. /// GIT_DIFF_UPDATE_INDEX = (1 << 15), /// /// Include unreadable files in the diff /// GIT_DIFF_INCLUDE_UNREADABLE = (1 << 16), /// /// Include unreadable files in the diff /// GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED = (1 << 17), /* * Options controlling how output will be generated */ /// /// Use a heuristic that takes indentation and whitespace into account /// which generally can produce better diffs when dealing with ambiguous /// diff hunks. /// GIT_DIFF_INDENT_HEURISTIC = (1 << 18), /// /// Treat all files as text, disabling binary attributes and detection /// GIT_DIFF_FORCE_TEXT = (1 << 20), /// /// Treat all files as binary, disabling text diffs /// GIT_DIFF_FORCE_BINARY = (1 << 21), /// /// Ignore all whitespace /// GIT_DIFF_IGNORE_WHITESPACE = (1 << 22), /// /// Ignore changes in amount of whitespace /// GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 23), /// /// Ignore whitespace at end of line /// GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 24), /// /// When generating patch text, include the content of untracked /// files. This automatically turns on GIT_DIFF_INCLUDE_UNTRACKED but /// it does not turn on GIT_DIFF_RECURSE_UNTRACKED_DIRS. Add that /// flag if you want the content of every single UNTRACKED file. /// GIT_DIFF_SHOW_UNTRACKED_CONTENT = (1 << 25), /// /// When generating output, include the names of unmodified files if /// they are included in the git_diff. Normally these are skipped in /// the formats that list files (e.g. name-only, name-status, raw). /// Even with this, these will not be included in patch format. /// GIT_DIFF_SHOW_UNMODIFIED = (1 << 26), /// /// Use the "patience diff" algorithm /// GIT_DIFF_PATIENCE = (1 << 28), /// /// Take extra time to find minimal diff /// GIT_DIFF_MINIMAL = (1 << 29), /// /// Include the necessary deflate / delta information so that `git-apply` /// can apply given diff information to binary files. /// GIT_DIFF_SHOW_BINARY = (1 << 30), } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int diff_notify_cb( IntPtr diff_so_far, IntPtr delta_to_add, IntPtr matched_pathspec, IntPtr payload); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int diff_progress_cb( IntPtr diff_so_far, IntPtr old_path, IntPtr new_path, IntPtr payload); [StructLayout(LayoutKind.Sequential)] internal class GitDiffOptions : IDisposable { public uint Version = 1; public GitDiffOptionFlags Flags; /* options controlling which files are in the diff */ public SubmoduleIgnore IgnoreSubmodules; public GitStrArrayManaged PathSpec; public diff_notify_cb NotifyCallback; public diff_progress_cb ProgressCallback; public IntPtr Payload; /* options controlling how to diff text is generated */ public uint ContextLines; public uint InterhunkLines; public ushort IdAbbrev; public Int64 MaxSize; public IntPtr OldPrefixString; public IntPtr NewPrefixString; public void Dispose() { PathSpec.Dispose(); } } [Flags] internal enum GitDiffFlags { GIT_DIFF_FLAG_BINARY = (1 << 0), GIT_DIFF_FLAG_NOT_BINARY = (1 << 1), GIT_DIFF_FLAG_VALID_ID = (1 << 2), GIT_DIFF_FLAG_EXISTS = (1 << 3), } [StructLayout(LayoutKind.Sequential)] internal unsafe struct git_diff_file { public git_oid Id; public char* Path; public Int64 Size; public GitDiffFlags Flags; public UInt16 Mode; public UInt16 IdAbbrev; } [StructLayout(LayoutKind.Sequential)] internal unsafe struct git_diff_delta { public ChangeKind status; public GitDiffFlags flags; public UInt16 similarity; public UInt16 nfiles; public git_diff_file old_file; public git_diff_file new_file; } [StructLayout(LayoutKind.Sequential)] internal class GitDiffHunk { public int OldStart; public int OldLines; public int NewStart; public int NewLines; public UIntPtr HeaderLen; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] Header; } [StructLayout(LayoutKind.Sequential)] internal class GitDiffLine { public GitDiffLineOrigin lineOrigin; public int OldLineNo; public int NewLineNo; public int NumLines; public UIntPtr contentLen; public Int64 contentOffset; public IntPtr content; } enum GitDiffLineOrigin : byte { GIT_DIFF_LINE_CONTEXT = 0x20, //' ', GIT_DIFF_LINE_ADDITION = 0x2B, //'+', GIT_DIFF_LINE_DELETION = 0x2D, //'-', GIT_DIFF_LINE_ADD_EOFNL = 0x0A, //'\n', /**< LF was added at end of file */ GIT_DIFF_LINE_DEL_EOFNL = 0x0, //'\0', /**< LF was removed at end of file */ /* these values will only be sent to a `git_diff_output_fn` */ GIT_DIFF_LINE_FILE_HDR = 0x46, //'F', GIT_DIFF_LINE_HUNK_HDR = 0x48, //'H', GIT_DIFF_LINE_BINARY = 0x42, //'B', } enum GitDiffFormat { GIT_DIFF_FORMAT_PATCH = 1, // < full git diff GIT_DIFF_FORMAT_PATCH_HEADER = 2, // < just the file headers of patch GIT_DIFF_FORMAT_RAW = 3, // < like git diff --raw GIT_DIFF_FORMAT_NAME_ONLY = 4, // < like git diff --name-only GIT_DIFF_FORMAT_NAME_STATUS = 5, // < like git diff --name-status } [Flags] enum GitDiffFindFlags { // Obey `diff.renames`. Overridden by any other GIT_DIFF_FIND_... flag. GIT_DIFF_FIND_BY_CONFIG = 0, // Look for renames? (`--find-renames`) GIT_DIFF_FIND_RENAMES = (1 << 0), // consider old side of modified for renames? (`--break-rewrites=N`) GIT_DIFF_FIND_RENAMES_FROM_REWRITES = (1 << 1), // look for copies? (a la `--find-copies`) GIT_DIFF_FIND_COPIES = (1 << 2), // consider unmodified as copy sources? (`--find-copies-harder`) GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED = (1 << 3), // mark large rewrites for split (`--break-rewrites=/M`) GIT_DIFF_FIND_REWRITES = (1 << 4), // actually split large rewrites into delete/add pairs GIT_DIFF_BREAK_REWRITES = (1 << 5), // mark rewrites for split and break into delete/add pairs GIT_DIFF_FIND_AND_BREAK_REWRITES = (GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES), // find renames/copies for untracked items in working directory GIT_DIFF_FIND_FOR_UNTRACKED = (1 << 6), // turn on all finding features GIT_DIFF_FIND_ALL = (0x0ff), // measure similarity ignoring leading whitespace (default) GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE = 0, // measure similarity ignoring all whitespace GIT_DIFF_FIND_IGNORE_WHITESPACE = (1 << 12), // measure similarity including all data GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1 << 13), // measure similarity only by comparing SHAs (fast and cheap) GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1 << 14), // do not break rewrites unless they contribute to a rename GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = (1 << 15), // Remove any UNMODIFIED deltas after find_similar is done. GIT_DIFF_FIND_REMOVE_UNMODIFIED = (1 << 16), } [StructLayout(LayoutKind.Sequential)] internal class GitDiffFindOptions { public uint Version = 1; public GitDiffFindFlags Flags; public UInt16 RenameThreshold; public UInt16 RenameFromRewriteThreshold; public UInt16 CopyThreshold; public UInt16 BreakRewriteThreshold; public UIntPtr RenameLimit; // TODO public IntPtr SimilarityMetric; } [Flags] enum GitDiffBinaryType { // There is no binary delta. GIT_DIFF_BINARY_NONE = 0, // The binary data is the literal contents of the file. */ GIT_DIFF_BINARY_LITERAL, // The binary data is the delta from one side to the other. */ GIT_DIFF_BINARY_DELTA, } [StructLayout(LayoutKind.Sequential)] internal class GitDiffBinaryFile { public GitDiffBinaryType Type; public IntPtr Data; public UIntPtr DataLen; public UIntPtr InflatedLen; } [StructLayout(LayoutKind.Sequential)] internal class GitDiffBinary { public uint ContainsData; public GitDiffBinaryFile OldFile; public GitDiffBinaryFile NewFile; } }