diff --git a/diffmatchpatch/diff.go b/diffmatchpatch/diff.go index 2a9f2dc..06b7ba6 100644 --- a/diffmatchpatch/diff.go +++ b/diffmatchpatch/diff.go @@ -44,6 +44,16 @@ type Diff struct { Text string } +type PrettyInfo struct { + PrefixInsert string + SuffixInsert string + PrefixDelete string + SuffixDelete string + PrefixEqual string + SuffixEqual string + Escape bool +} + // splice removes amount elements from slice at index index, replacing them with elements. func splice(slice []Diff, index int, amount int, elements ...Diff) []Diff { if len(elements) == amount { @@ -1122,44 +1132,142 @@ func (dmp *DiffMatchPatch) DiffXIndex(diffs []Diff, loc int) int { // DiffPrettyHtml converts a []Diff into a pretty HTML report. // It is intended as an example from which to write one's own display functions. func (dmp *DiffMatchPatch) DiffPrettyHtml(diffs []Diff) string { + return dmp.DiffPretty(diffs, PrettyInfo{ + PrefixInsert: "", + SuffixInsert: "", + PrefixDelete: "", + SuffixDelete: "", + PrefixEqual: "", + SuffixEqual: "", + Escape: true, + }) +} + +// DiffPrettyText converts a []Diff into a colored text report. +func (dmp *DiffMatchPatch) DiffPrettyText(diffs []Diff) string { + return dmp.DiffPretty(diffs, PrettyInfo{ + PrefixInsert: "\x1b[32m", + SuffixInsert: "\x1b[0m", + PrefixDelete: "\x1b[31m", + SuffixDelete: "\x1b[0m", + PrefixEqual: "", + SuffixEqual: "", + }) +} + +// DiffPrettyMarkdown converts a []Diff into a colored makdown report. +func (dmp *DiffMatchPatch) DiffPrettyMarkdown(diffs []Diff) string { + return dmp.DiffPretty(diffs, PrettyInfo{ + PrefixInsert: "", + SuffixInsert: "", + PrefixDelete: "", + SuffixDelete: "", + PrefixEqual: "", + SuffixEqual: "", + }) +} + +func (dmp *DiffMatchPatch) DiffPrettyHtmlAll(diffs []Diff) (old, new string) { + prettyInfo := PrettyInfo{ + PrefixInsert: "", + SuffixInsert: "", + PrefixDelete: "", + SuffixDelete: "", + PrefixEqual: "", + SuffixEqual: "", + Escape: true, + } + return dmp.DiffPrettyOld(diffs, prettyInfo), dmp.DiffPrettyNew(diffs, prettyInfo) +} + +func (dmp *DiffMatchPatch) DiffPrettyTextAll(diffs []Diff) (old, new string) { + prettyInfo := PrettyInfo{ + PrefixInsert: "\x1b[32m", + SuffixInsert: "\x1b[0m", + PrefixDelete: "\x1b[31m", + SuffixDelete: "\x1b[0m", + PrefixEqual: "", + SuffixEqual: "", + } + return dmp.DiffPrettyOld(diffs, prettyInfo), dmp.DiffPrettyNew(diffs, prettyInfo) +} + +func (dmp *DiffMatchPatch) DiffPrettyMarkdownAll(diffs []Diff) (old, new string) { + prettyInfo := PrettyInfo{ + PrefixInsert: "", + SuffixInsert: "", + PrefixDelete: "", + SuffixDelete: "", + PrefixEqual: "", + SuffixEqual: "", + } + return dmp.DiffPrettyOld(diffs, prettyInfo), dmp.DiffPrettyNew(diffs, prettyInfo) +} + +func (dmp *DiffMatchPatch) DiffPretty(diffs []Diff, PrettyInfo PrettyInfo) string { var buff bytes.Buffer for _, diff := range diffs { - text := strings.Replace(html.EscapeString(diff.Text), "\n", "¶
", -1) + text := diff.Text + if PrettyInfo.Escape { + text = strings.Replace(html.EscapeString(diff.Text), "\n", "¶
", -1) + } switch diff.Type { case DiffInsert: - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.PrefixInsert) _, _ = buff.WriteString(text) - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.SuffixInsert) case DiffDelete: - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.PrefixDelete) _, _ = buff.WriteString(text) - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.SuffixDelete) case DiffEqual: - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.PrefixEqual) _, _ = buff.WriteString(text) - _, _ = buff.WriteString("") + _, _ = buff.WriteString(PrettyInfo.SuffixEqual) } } + return buff.String() } -// DiffPrettyText converts a []Diff into a colored text report. -func (dmp *DiffMatchPatch) DiffPrettyText(diffs []Diff) string { +func (dmp *DiffMatchPatch) DiffPrettyOld(diffs []Diff, PrettyInfo PrettyInfo) string { var buff bytes.Buffer for _, diff := range diffs { text := diff.Text + if PrettyInfo.Escape { + text = strings.Replace(html.EscapeString(diff.Text), "\n", "¶
", -1) + } + switch diff.Type { + case DiffDelete: + _, _ = buff.WriteString(PrettyInfo.PrefixDelete) + _, _ = buff.WriteString(text) + _, _ = buff.WriteString(PrettyInfo.SuffixDelete) + case DiffEqual: + _, _ = buff.WriteString(PrettyInfo.PrefixEqual) + _, _ = buff.WriteString(text) + _, _ = buff.WriteString(PrettyInfo.SuffixEqual) + } + } + return buff.String() +} + +func (dmp *DiffMatchPatch) DiffPrettyNew(diffs []Diff, PrettyInfo PrettyInfo) string { + var buff bytes.Buffer + for _, diff := range diffs { + text := diff.Text + if PrettyInfo.Escape { + text = strings.Replace(html.EscapeString(diff.Text), "\n", "¶
", -1) + } switch diff.Type { case DiffInsert: - _, _ = buff.WriteString("\x1b[32m") - _, _ = buff.WriteString(text) - _, _ = buff.WriteString("\x1b[0m") - case DiffDelete: - _, _ = buff.WriteString("\x1b[31m") + _, _ = buff.WriteString(PrettyInfo.PrefixInsert) _, _ = buff.WriteString(text) - _, _ = buff.WriteString("\x1b[0m") + _, _ = buff.WriteString(PrettyInfo.SuffixInsert) case DiffEqual: + _, _ = buff.WriteString(PrettyInfo.PrefixEqual) _, _ = buff.WriteString(text) + _, _ = buff.WriteString(PrettyInfo.SuffixEqual) } } diff --git a/diffmatchpatch/diff_test.go b/diffmatchpatch/diff_test.go index acb97e3..a31e1a9 100644 --- a/diffmatchpatch/diff_test.go +++ b/diffmatchpatch/diff_test.go @@ -1037,6 +1037,112 @@ func TestDiffPrettyText(t *testing.T) { } } +func TestDiffPrettyMarkdown(t *testing.T) { + type TestCase struct { + Diffs []Diff + + Expected string + } + + dmp := New() + + for i, tc := range []TestCase{ + { + Diffs: []Diff{ + {DiffEqual, "a\n"}, + {DiffDelete, "b"}, + {DiffInsert, "c&d"}, + }, + + Expected: "a\nbc&d", + }, + } { + actual := dmp.DiffPrettyMarkdown(tc.Diffs) + assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc)) + } +} + +func TestDiffPrettyHtmlAll(t *testing.T) { + type TestCase struct { + Diffs []Diff + + ExpectedOld string + ExpectedNew string + } + + dmp := New() + + for i, tc := range []TestCase{ + { + Diffs: []Diff{ + {DiffEqual, "a\n"}, + {DiffDelete, "b"}, + {DiffInsert, "c&d"}, + }, + ExpectedOld: "
<B>b</B>", + ExpectedNew: "
c&d", + }, + } { + actualOld, actualNew := dmp.DiffPrettyHtmlAll(tc.Diffs) + assert.Equal(t, tc.ExpectedOld, actualOld, fmt.Sprintf("Test case #%d, %#v", i, tc)) + assert.Equal(t, tc.ExpectedNew, actualNew, fmt.Sprintf("Test case #%d, %#v", i, tc)) + } +} + +func TestDiffPrettyTextAll(t *testing.T) { + type TestCase struct { + Diffs []Diff + + ExpectedOld string + ExpectedNew string + } + + dmp := New() + + for i, tc := range []TestCase{ + { + Diffs: []Diff{ + {DiffEqual, "a\n"}, + {DiffDelete, "b"}, + {DiffInsert, "c&d"}, + }, + ExpectedOld: "a\n\x1b[31mb\x1b[0m", + ExpectedNew: "a\n\x1b[32mc&d\x1b[0m", + }, + } { + actualOld, actualNew := dmp.DiffPrettyTextAll(tc.Diffs) + assert.Equal(t, tc.ExpectedOld, actualOld, fmt.Sprintf("Test case #%d, %#v", i, tc)) + assert.Equal(t, tc.ExpectedNew, actualNew, fmt.Sprintf("Test case #%d, %#v", i, tc)) + } +} + +func TestDiffPrettyMarkdownAll(t *testing.T) { + type TestCase struct { + Diffs []Diff + + ExpectedOld string + ExpectedNew string + } + + dmp := New() + + for i, tc := range []TestCase{ + { + Diffs: []Diff{ + {DiffEqual, "a\n"}, + {DiffDelete, "b"}, + {DiffInsert, "c&d"}, + }, + ExpectedOld: "a\nb", + ExpectedNew: "a\nc&d", + }, + } { + actualOld, actualNew := dmp.DiffPrettyMarkdownAll(tc.Diffs) + assert.Equal(t, tc.ExpectedOld, actualOld, fmt.Sprintf("Test case #%d, %#v", i, tc)) + assert.Equal(t, tc.ExpectedNew, actualNew, fmt.Sprintf("Test case #%d, %#v", i, tc)) + } +} + func TestDiffText(t *testing.T) { type TestCase struct { Diffs []Diff