diff --git a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs index dba762bfe..a5bb8c1ad 100644 --- a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs +++ b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs @@ -4,7 +4,6 @@ using System.Text; using LibGit2Sharp.Tests.TestHelpers; using Xunit; -using Xunit.Extensions; namespace LibGit2Sharp.Tests { @@ -1219,5 +1218,71 @@ public void UsingPatienceAlgorithmCompareOptionProducesPatienceDiff() Assert.Equal(diffPatience, changes); } } + + [Fact] + public void PatchWhitespaceModeIsObeyed() + { + string repoPath = InitNewRepository(); + + var compareOptions = Enum + .GetValues(typeof(PatchWhitespaceMode)) + .Cast() + .Select(whitespaceOption => new CompareOptions() { PatchWhitespaceMode = whitespaceOption }); + + using (var repo = new Repository(repoPath)) + { + const string fileName = "file.txt"; + var commits = new System.Collections.Generic.List(); + + Touch(repo.Info.WorkingDirectory, fileName, "White space is not wastedspace."); + Commands.Stage(repo, fileName); + commits.Add(repo.Commit("Initial", Constants.Signature, Constants.Signature)); + + Touch(repo.Info.WorkingDirectory, fileName, "White space is not wastedspace. \t"); + Commands.Stage(repo, fileName); + commits.Add(repo.Commit("Add trailing whitespace.", Constants.Signature, Constants.Signature)); + + Touch(repo.Info.WorkingDirectory, fileName, "White space\tis not wastedspace. "); + Commands.Stage(repo, fileName); + commits.Add(repo.Commit("Change whitespace.", Constants.Signature, Constants.Signature)); + + Touch(repo.Info.WorkingDirectory, fileName, " Whitespace is not wasted space."); + Commands.Stage(repo, fileName); + commits.Add(repo.Commit("Insert whitespace.", Constants.Signature, Constants.Signature)); + + Touch(repo.Info.WorkingDirectory, fileName, "Completely different content."); + Commands.Stage(repo, fileName); + commits.Add(repo.Commit("Completely different.", Constants.Signature, Constants.Signature)); + + var commitPairs = commits + .Select((oldCommit, index) => new { oldCommit, index }) + .Zip(commits.Skip(1), (old, newCommit) => new { old.oldCommit, newCommit, old.index }); + + foreach (var commitPair in commitPairs) + foreach (var compareOption in compareOptions) + using (var patch = repo.Diff.Compare(commitPair.oldCommit.Tree, commitPair.newCommit.Tree, compareOption)) + { + int expectedDiffLines; + switch (compareOption.PatchWhitespaceMode) + { + case PatchWhitespaceMode.DontIgnoreWhitespace: + expectedDiffLines = 1; + break; + case PatchWhitespaceMode.IgnoreAllWhitespace: + expectedDiffLines = commitPair.index > 2 ? 1 : 0; + break; + case PatchWhitespaceMode.IgnoreWhitespaceChange: + expectedDiffLines = commitPair.index > 1 ? 1 : 0; + break; + case PatchWhitespaceMode.IgnoreWhitespaceEol: + expectedDiffLines = commitPair.index > 0 ? 1 : 0; + break; + default: + throw new Exception("Unexpected " + nameof(PatchWhitespaceMode)); + } + Assert.Equal(expectedDiffLines, patch.LinesAdded); + } + } + } } } diff --git a/LibGit2Sharp/CompareOptions.cs b/LibGit2Sharp/CompareOptions.cs index fb4234439..0d7d93b26 100644 --- a/LibGit2Sharp/CompareOptions.cs +++ b/LibGit2Sharp/CompareOptions.cs @@ -2,6 +2,29 @@ namespace LibGit2Sharp { + /// + /// Represents a mode for handling whitespace while creating a patch. + /// + public enum PatchWhitespaceMode + { + /// + /// Do not ignore changes in whitespace when comparing lines. + /// + DontIgnoreWhitespace = 0, + /// + /// Ignore whitespace when comparing lines. This ignores differences even if one line has whitespace where the other line has none. + /// + IgnoreAllWhitespace = 1, + /// + /// Ignore changes in amount of whitespace. This ignores whitespace at line end, and considers all other sequences of one or more whitespace characters to be equivalent. + /// + IgnoreWhitespaceChange = 2, + /// + /// Ignore changes in whitespace at EOL. + /// + IgnoreWhitespaceEol = 3, + } + /// /// Options to define file comparison behavior. /// @@ -14,6 +37,7 @@ public CompareOptions() { ContextLines = 3; InterhunkLines = 0; + PatchWhitespaceMode = PatchWhitespaceMode.DontIgnoreWhitespace; Algorithm = DiffAlgorithm.Myers; } @@ -29,6 +53,11 @@ public CompareOptions() /// public int InterhunkLines { get; set; } + /// + /// The mode for handling whitespace when comparing lines + /// + public PatchWhitespaceMode PatchWhitespaceMode { get; set; } + /// /// Options for rename detection. If null, the `diff.renames` configuration setting is used. /// diff --git a/LibGit2Sharp/Diff.cs b/LibGit2Sharp/Diff.cs index 087ee8d6d..7420b360e 100644 --- a/LibGit2Sharp/Diff.cs +++ b/LibGit2Sharp/Diff.cs @@ -68,6 +68,21 @@ private static GitDiffOptions BuildOptions(DiffModifiers diffOptions, FilePath[] options.Flags |= GitDiffOptionFlags.GIT_DIFF_INDENT_HEURISTIC; } + switch (compareOptions.PatchWhitespaceMode) + { + case PatchWhitespaceMode.DontIgnoreWhitespace: + break; + case PatchWhitespaceMode.IgnoreAllWhitespace: + options.Flags |= GitDiffOptionFlags.GIT_DIFF_IGNORE_WHITESPACE; + break; + case PatchWhitespaceMode.IgnoreWhitespaceChange: + options.Flags |= GitDiffOptionFlags.GIT_DIFF_IGNORE_WHITESPACE_CHANGE; + break; + case PatchWhitespaceMode.IgnoreWhitespaceEol: + options.Flags |= GitDiffOptionFlags.GIT_DIFF_IGNORE_WHITESPACE_EOL; + break; + } + if (matchedPathsAggregator != null) { options.NotifyCallback = matchedPathsAggregator.OnGitDiffNotify;