Beispiel #1
0
        public IEnumerable<DiffMatchPatch.Patch> MakePatch(string contentOne, string contentTwo, CompareOptions options)
        {
            var diff = new my.utils.Diff();
            var changes = diff.DiffText(contentOne, contentTwo);
            var contentOneLines = contentOne.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            var contentTwoLines = contentTwo.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            var chunks = new HashSet<Chunk>();
            Chunk currentChunk = null;

            for (var i = 0; i < changes.Length; i++)
            {
                var change = changes[i];
                Diff.Item? nextChange = null;

                if (changes.Length > i + 1)
                    nextChange = changes.ElementAtOrDefault(i + 1);

                var continuation = currentChunk != null;

                if (!continuation)
                {
                    currentChunk = CreateChunk(change, options);
                    chunks.Add(currentChunk);
                }

                if (change.StartA != 0 && !continuation)
                {
                    // no start context needed
                    currentChunk.start1 = change.StartA - options.ContextSize;
                    currentChunk.start2 = change.StartB - options.ContextSize;

                    // stick some context in
                    var start = change.StartB - options.ContextSize;
                    for (var j = start; j < change.StartB; j++)
                    {
                        currentChunk.diffs.Add(new Line(Operation.EQUAL, contentTwoLines[j]));
                    }
                }

                if (change.deletedA > 0)
                {
                    for (var j = 0; j < change.deletedA; j++)
                    {
                        var line = contentOneLines[j + change.StartA];
                        currentChunk.diffs.Add(new Line(Operation.DELETE, line));
                    }
                }

                if (change.insertedB > 0)
                {
                    for (var j = 0; j < change.insertedB; j++)
                    {
                        var line = contentTwoLines[j + change.StartB];
                        currentChunk.diffs.Add(new Line(Operation.INSERT, line));
                    }
                }

                var start2 = change.StartB + change.insertedB;
                int end;

                if (nextChange.HasValue)
                    end = Min(start2 + options.ContextSize, contentTwoLines.Length, nextChange.Value.StartB);
                else
                    end = Min(start2 + options.ContextSize, contentTwoLines.Length);

                for (var j = start2; j < end; j++)
                {
                    currentChunk.diffs.Add(new Line(Operation.EQUAL, contentTwoLines[j]));
                }

                if (nextChange.HasValue && nextChange.Value.StartB - end > 0)
                {
                    // need to split the diff into multiple chunks
                    currentChunk = null;
                }
            }

            foreach (var chunk in chunks)
            {
                chunk.length1 = chunk.diffs.Count(x => x.operation == Operation.EQUAL || x.operation == Operation.DELETE);
                chunk.length2 = chunk.diffs.Count(x => x.operation == Operation.EQUAL || x.operation == Operation.INSERT);
            }

            return chunks;
        }
Beispiel #2
0
        public static Diff Compare(string fileOnePath, string fileOneContent, string fileTwoPath, string fileTwoContent, CompareOptions options)
        {
            if (fileOneContent == null && fileTwoContent == null)
                throw new InvalidOperationException("Both files were null");

            if (options.BomMode == BomMode.Ignore)
            {
                if (fileOneContent != null)
                    fileOneContent = RemoveBom(fileOneContent);
                if (fileTwoContent != null)
                    fileTwoContent = RemoveBom(fileTwoContent);
            }

            if (fileTwoContent == null)
                return DeletedFileDiff(fileOneContent, fileOnePath);
            if (fileOneContent == null)
                return NewFileDiff(fileTwoContent, fileTwoPath);
            if (IsBinary(fileOneContent))
                throw new BinaryFileException(fileOnePath);
            if (IsBinary(fileTwoContent))
                throw new BinaryFileException(fileTwoPath);

            var patchMaker = new PatchMaker();
            var patches = patchMaker.MakePatch(fileOneContent, fileTwoContent, options);
            var chunks = new List<Chunk>();

            foreach (var patch in patches)
            {
                var originalRange = new ChangeRange(patch.start1 + 1, patch.length1);
                var newRange = new ChangeRange(patch.start2 + 1, patch.length2);
                var range = new ChunkRange(originalRange, newRange);
                var snippets = new List<ISnippet>();

                var lines = new List<DiffMatchPatch.Diff>();
                Operation? previousOperation = null;
                var isModification = false;

                foreach (var diff in patch.diffs)
                {
                    if (previousOperation == null)
                        previousOperation = diff.operation;
                    if (previousOperation == Operation.DELETE && diff.operation == Operation.INSERT)
                        isModification = true;
                    else if (previousOperation != diff.operation)
                    {
                        // different operation
                        if (previousOperation == Operation.EQUAL)
                            snippets.Add(new ContextSnippet(lines.Select(x => new ContextLine(x.text)).Cast<ILine>()));
                        else if (isModification)
                            snippets.Add(new ModificationSnippet(
                                lines
                                    .Where(x => x.operation == Operation.DELETE)
                                    .Select(x => new SubtractionLine(x.text))
                                    .Cast<ILine>(),
                                lines
                                    .Where(x => x.operation == Operation.INSERT)
                                    .Select(x => new AdditionLine(x.text))
                                    .Cast<ILine>()
                            ));
                        else if (previousOperation == Operation.INSERT)
                            snippets.Add(new AdditionSnippet(lines.Select(x => new AdditionLine(x.text)).Cast<ILine>()));
                        else if (previousOperation == Operation.DELETE)
                            snippets.Add(new SubtractionSnippet(lines.Select(x => new SubtractionLine(x.text)).Cast<ILine>()));

                        lines.Clear();
                        isModification = false;
                    }

                    lines.Add(diff);
                    previousOperation = diff.operation;
                }

                if (lines.Count > 0)
                {
                    if (previousOperation == Operation.INSERT)
                        snippets.Add(new AdditionSnippet(lines.Select(x => new AdditionLine(x.text)).Cast<ILine>()));
                    else if (previousOperation == Operation.DELETE)
                        snippets.Add(new SubtractionSnippet(lines.Select(x => new SubtractionLine(x.text)).Cast<ILine>()));
                    else
                        snippets.Add(new ContextSnippet(lines.Select(x => new ContextLine(x.text)).Cast<ILine>()));
                }

                chunks.Add(new Chunk(range, snippets));
            }

            var header = new Header(new FormatType("generated"), new[]
            {
                new File('a', fileOnePath),
                new File('b', fileTwoPath)
            });

            return new Diff(header, chunks);
        }
Beispiel #3
0
 private Chunk CreateChunk(Diff.Item change, CompareOptions options)
 {
     var chunk = new Chunk();
     chunk.start1 = change.StartA;
     chunk.start2 = change.StartB;
     chunk.length1 = change.deletedA + options.ContextSize;
     chunk.length2 = change.insertedB + options.ContextSize;
     chunk.diffs = new List<Line>();
     return chunk;
 }