From fc51fe732bd438f480a582e45f8fb5cc57c29b31 Mon Sep 17 00:00:00 2001 From: mappu Date: Tue, 11 Jul 2017 17:14:00 +1200 Subject: [PATCH] diff: initial implementation --- diff/diff.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 diff/diff.go diff --git a/diff/diff.go b/diff/diff.go new file mode 100644 index 0000000..e6c3213 --- /dev/null +++ b/diff/diff.go @@ -0,0 +1,96 @@ +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())) + } +}