diff: initial implementation
This commit is contained in:
parent
98f99ce31f
commit
fc51fe732b
96
diff/diff.go
Normal file
96
diff/diff.go
Normal file
@ -0,0 +1,96 @@
|
||||
package diff
|
||||
|
||||
import (
|
||||
"html"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Paul's Simple Diff Algorithm v 0.1
|
||||
(C) Paul Butler 2007 <http://www.paulbutler.org/>
|
||||
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 `<ins>` + strings.Join(this.Content, Separator) + `</ins>`
|
||||
case OP_REMOVED:
|
||||
return `<del>` + strings.Join(this.Content, Separator) + `</del>`
|
||||
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()))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user