From 7d2f5240d94fd96760fdf884ec08aee14184cb8e Mon Sep 17 00:00:00 2001 From: Nacho Caballero Date: Fri, 11 Oct 2019 09:50:37 +0200 Subject: [PATCH] FIX: Show a correct diff when editing consecutive paragraphs (#8177) --- lib/discourse_diff.rb | 2 +- lib/onpdiff.rb | 71 ++++++++++++++++++++++++++ spec/components/discourse_diff_spec.rb | 7 +++ spec/components/onpdiff_spec.rb | 34 ++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/lib/discourse_diff.rb b/lib/discourse_diff.rb index 6445ac88cd1..c2b31716237 100644 --- a/lib/discourse_diff.rb +++ b/lib/discourse_diff.rb @@ -12,7 +12,7 @@ class DiscourseDiff before_markdown = tokenize_line(CGI::escapeHTML(@before)) after_markdown = tokenize_line(CGI::escapeHTML(@after)) - @block_by_block_diff = ONPDiff.new(before_html, after_html).diff + @block_by_block_diff = ONPDiff.new(before_html, after_html).paragraph_diff @line_by_line_diff = ONPDiff.new(before_markdown, after_markdown).short_diff end diff --git a/lib/onpdiff.rb b/lib/onpdiff.rb index ef4799f2a4a..6c86a79327e 100644 --- a/lib/onpdiff.rb +++ b/lib/onpdiff.rb @@ -25,6 +25,10 @@ class ONPDiff @short_diff ||= build_short_edit_script(compose) end + def paragraph_diff + @paragraph_diff ||= build_paragraph_edit_script(diff) + end + private def compose @@ -156,4 +160,71 @@ class ONPDiff ses end + def build_paragraph_edit_script(ses) + paragraph_ses = [] + i = 0 + while i < ses.size + if ses[i][1] == :common + paragraph_ses << ses[i] + else + if ses[i][1] == :add + op_code = :add + opposite_op_code = :delete + else + op_code = :delete + opposite_op_code = :add + end + j = i + 1 + + while j < ses.size && ses[j][1] == op_code + j += 1 + end + + if j >= ses.size + paragraph_ses = paragraph_ses.concat(ses[i..j]) + i = j + else + k = j + j -= 1 + + while k < ses.size && ses[k][1] == opposite_op_code + k += 1 + end + k -= 1 + + num_before = j - i + 1 + num_after = k - j + if num_after > 1 + if num_before > num_after + i2 = i + num_before - num_after + paragraph_ses = paragraph_ses.concat(ses[i..i2 - 1]) + i = i2 + elsif num_after > num_before + k -= num_after - num_before + end + paragraph_ses = paragraph_ses.concat(pair_paragraphs(ses, i, j)) + else + paragraph_ses = paragraph_ses.concat(ses[i..k]) + end + i = k + end + end + i += 1 + end + + paragraph_ses + end + + def pair_paragraphs(ses, i, j) + pairs = [] + num_pairs = j - i + 1 + num_pairs.times do + pairs << ses[i] + pairs << ses[i + num_pairs] + i += 1 + end + + pairs + end + end diff --git a/spec/components/discourse_diff_spec.rb b/spec/components/discourse_diff_spec.rb index a7aefc53fa0..d1158aef206 100644 --- a/spec/components/discourse_diff_spec.rb +++ b/spec/components/discourse_diff_spec.rb @@ -76,6 +76,13 @@ describe DiscourseDiff do expect(DiscourseDiff.new(before, after).side_by_side_html).to eq("

this is a paragraph

this is a great paragraph

") end + it "adds and tags on consecutive paragraphs", :focus do + before = "

this is one paragraph

here is yet another

" + after = "

this is one great paragraph

here is another

" + got = DiscourseDiff.new(before, after).side_by_side_html + expect(got).to eq("

this is one paragraph

here is yet another

this is one great paragraph

here is another

") + end + it "adds tags around removed text on the left div" do before = "

this is a great paragraph

" after = "

this is a paragraph

" diff --git a/spec/components/onpdiff_spec.rb b/spec/components/onpdiff_spec.rb index 67c5b0beab3..60b40397203 100644 --- a/spec/components/onpdiff_spec.rb +++ b/spec/components/onpdiff_spec.rb @@ -39,4 +39,38 @@ describe ONPDiff do end + describe "paragraph_diff" do + + it "returns an empty array when there is no content to diff" do + expect(ONPDiff.new("", "").paragraph_diff).to eq([]) + end + + it "returns an array with the operation code for each element" do + expect(ONPDiff.new("abc", "acd").paragraph_diff).to eq([["a", :common], ["b", :delete], ["c", :common], ["d", :add]]) + end + + it "pairs as many elements as possible", :focus do + expect(ONPDiff.new("abcd", "abef").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["e", :add], ["c", :delete], + ["f", :add], ["d", :delete] + ]) + + expect(ONPDiff.new("abcde", "abfg").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["c", :delete], + ["d", :delete], ["f", :add], + ["e", :delete], ["g", :add] + ]) + + expect(ONPDiff.new("abcd", "abefg").paragraph_diff).to eq([ + ["a", :common], ["b", :common], + ["e", :add], + ["f", :add], ["c", :delete], + ["g", :add], ["d", :delete] + ]) + end + + end + end