diff --git a/lib/diff.rb b/lib/diff.rb index 59510bed..14fa0511 100644 --- a/lib/diff.rb +++ b/lib/diff.rb @@ -1,3 +1,4 @@ +require_relative "./diff/combined" require_relative "./diff/hunk" require_relative "./diff/myers" @@ -29,4 +30,9 @@ def self.diff(a, b) def self.diff_hunks(a, b) Hunk.filter(diff(a, b)) end + + def self.combined(as, b) + diffs = as.map { |a| diff(a, b) } + Combined.new(diffs).to_a + end end diff --git a/lib/diff/combined.rb b/lib/diff/combined.rb new file mode 100644 index 00000000..d6f6b7ae --- /dev/null +++ b/lib/diff/combined.rb @@ -0,0 +1,59 @@ +module Diff + class Combined + + include Enumerable + + Row = Struct.new(:edits) do + def to_s + symbols = edits.map { |edit| SYMBOLS.fetch(edit&.type, " ") } + + del = edits.find { |edit| edit&.type == :del } + line = del ? del.a_line : edits.first.b_line + + symbols.join("") + line.text + end + end + + def initialize(diffs) + @diffs = diffs + end + + def each + @offsets = @diffs.map { 0 } + + loop do + @diffs.each_with_index do |diff, i| + consume_deletions(diff, i) { |row| yield row } + end + + return if complete? + + edits = offset_diffs.map { |offset, diff| diff[offset] } + @offsets.map! { |offset| offset + 1 } + + yield Row.new(edits) + end + end + + private + + def complete? + offset_diffs.all? { |offset, diff| offset == diff.size } + end + + def offset_diffs + @offsets.zip(@diffs) + end + + def consume_deletions(diff, i) + while @offsets[i] < diff.size and diff[@offsets[i]].type == :del + edits = Array.new(@diffs.size) + edits[i] = diff[@offsets[i]] + @offsets[i] += 1 + + yield Row.new(edits) + end + end + + end +end