Beispiel #1
0
// wrapper for diff.Granular() -- should only concatanate changes for similar text nodes
func granular(gran int, dd diffData, changes []diff.Change) []diff.Change {
	ret := make([]diff.Change, 0, len(changes))
	startSame := 0
	changeCount := 0
	lastAleaf, lastBleaf := (*dd.a)[0].leaf, (*dd.b)[0].leaf
	for c, cc := range changes {
		if cc.A < len(*dd.a) && cc.B < len(*dd.b) &&
			lastAleaf.Type == html.TextNode && lastBleaf.Type == html.TextNode &&
			(*dd.a)[cc.A].leaf == lastAleaf && (*dd.b)[cc.B].leaf == lastBleaf &&
			nodeEqualExText(lastAleaf, lastBleaf) { // TODO is this last constraint required?
			// do nothing yet, queue it up until there is a difference
			changeCount++
		} else { // no match
			if changeCount > 0 { // flush
				ret = append(ret, diff.Granular(gran, changes[startSame:startSame+changeCount])...)
			}
			ret = append(ret, cc)
			startSame = c + 1 // the one after this
			changeCount = 0
			if cc.A < len(*dd.a) && cc.B < len(*dd.b) {
				lastAleaf, lastBleaf = (*dd.a)[cc.A].leaf, (*dd.b)[cc.B].leaf
			}
		}
	}
	if changeCount > 0 { // flush
		ret = append(ret, diff.Granular(gran, changes[startSame:])...)
	}
	return ret
}
Beispiel #2
0
// Diff computes the difference between old and new. A granularity of 1 or more
// combines changes with no greater than that many bytes between them.
func Diff(old, new []byte, granularity int) (patch []byte) {
	changes := diff.Bytes(old, new)
	if granularity > 0 {
		changes = diff.Granular(granularity, changes)
	}

	for i, c := range changes {
		a, b := c.A, c.B
		for _, prev := range changes[:i] {
			if prev.A < c.A {
				a -= prev.Del
				a += prev.Ins
			}
			if prev.B < c.B {
				b -= prev.Ins
				b += prev.Del
			}
		}
		patch = writeUvarint(patch, a)
		patch = writeUvarint(patch, b)
		patch = writeUvarint(patch, c.Del)
		patch = append(patch, old[c.A:c.A+c.Del]...)
		patch = writeUvarint(patch, c.Ins)
		patch = append(patch, new[c.B:c.B+c.Ins]...)
	}

	return
}
Beispiel #3
0
func ExampleGranular() {
	a := "hElLo!"
	b := "hello!"
	changes := diff.Granular(5, diff.ByteStrings(a, b)) // ignore small gaps in differences
	for l := len(changes) - 1; l >= 0; l-- {
		change := changes[l]
		b = b[:change.B] + "|" + b[change.B:change.B+change.Ins] + "|" + b[change.B+change.Ins:]
	}
	fmt.Println(b)
	// Output:
	// h|ell|o!
}
Beispiel #4
0
Datei: dt.go Projekt: adg/dt
func byteDiff(a, b []byte) []byte {
	var buf bytes.Buffer
	n := 0
	for _, c := range diff.Granular(1, diff.Bytes(a, b)) {
		buf.Write(b[n:c.B])
		if c.Ins > 0 {
			buf.Write(colorize(b[c.B : c.B+c.Ins]))
		}
		n = c.B + c.Ins
	}
	buf.Write(b[n:])
	return buf.Bytes()
}
Beispiel #5
0
func TestGranularStrings(t *testing.T) {
	a := "abcdefghijklmnopqrstuvwxyza"
	b := "AbCdeFghiJklmnOpqrstUvwxyzab"
	// each iteration of i increases granularity and will absorb one more lower-letter-followed-by-upper-letters sequence
	changesI := [][]diff.Change{
		{{0, 0, 1, 1}, {2, 2, 1, 1}, {5, 5, 1, 1}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}},
		{{0, 0, 3, 3}, {5, 5, 1, 1}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}},
		{{0, 0, 6, 6}, {9, 9, 1, 1}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}},
		{{0, 0, 10, 10}, {14, 14, 1, 1}, {20, 20, 1, 1}, {27, 27, 0, 1}},
		{{0, 0, 15, 15}, {20, 20, 1, 1}, {27, 27, 0, 1}},
		{{0, 0, 21, 21}, {27, 27, 0, 1}},
		{{0, 0, 27, 28}},
	}
	for i := 0; i < len(changesI); i++ {
		diffs := diff.Granular(i, diff.ByteStrings(a, b))
		if !diffsEqual(diffs, changesI[i]) {
			t.Errorf("expected %v, got %v", diffs, changesI[i])
		}
	}
}