package diff import ( "html" "io" "strings" ) /* Paul's Simple Diff Algorithm v 0.1 (C) Paul Butler 2007 May be used and distributed under the zlib/libpng license. https://github.com/paulgb/simplediff/ */ var Separator string = "\n" type Operation int8 const ( OP_INSERTED Operation = 1 OP_UNCHANGED = 2 OP_REMOVED = 3 ) type Instruction struct { Op Operation Content []string } func (this *Instruction) RenderHTML() string { switch this.Op { case OP_INSERTED: return `` + strings.Join(this.Content, Separator) + `` case OP_REMOVED: return `` + strings.Join(this.Content, Separator) + `` default: //OP_UNCHANGED: return strings.Join(this.Content, Separator) } } func Diff(o, n []string) []Instruction { maxl := 0 omax := 0 nmax := 0 matrix := make(map[int]map[int]int, len(o)+1) for oindex, ovalue := range o { // Find keys in new, where value matchines ovalue nkeys := make([]int, 0) for nindex, nvalue := range n { if nvalue == ovalue { nkeys = append(nkeys, nindex) } } // Build diff matrix for nindex, _ := range n { if _, ok := matrix[oindex]; !ok { matrix[oindex] = make(map[int]int, len(n)+1) } matrix[oindex][nindex] = matrix[oindex-1][nindex-1] + 1 if matrix[oindex][nindex] > maxl { maxl = matrix[oindex][nindex] omax = oindex + 1 - maxl nmax = nindex + 1 - maxl } } } if maxl == 0 { return []Instruction{ Instruction{OP_REMOVED, o}, Instruction{OP_INSERTED, n}, } } ret := Diff(o[0:omax], n[0:nmax]) if maxl != nmax { ret = append(ret, Instruction{OP_UNCHANGED, n[nmax:maxl]}) } ret = append(ret, Diff(o[0:omax+maxl], n[0:nmax+maxl])...) return ret } // HtmlDiff splits o and n by newlines, and writes an HTML-safe version to the dest writer. func HtmlDiff(o, n string, dest io.Writer) { ops := Diff(strings.Split(html.EscapeString(o), Separator), strings.Split(html.EscapeString(n), Separator)) for _, op := range ops { dest.Write([]byte(op.RenderHTML())) } }