Esempio n. 1
1
File: dt.go Progetto: adg/dt
// lineDiff returns b with all lines added or changed from a highlighted.
// It discards spaces within lines when comparing lines, so subtle
// gofmt-induced alignment changes are not flagged as changes.
// It also handles single-line diffs specially, highlighting only the
// changes within those lines.
func lineDiff(a, b []byte) []byte {
	l := byteLines{bytes.Split(a, []byte("\n")), bytes.Split(b, []byte("\n"))}
	cs := diff.Diff(len(l.a), len(l.b), diff.Data(l))

	var buf bytes.Buffer
	n := 0
	for _, c := range cs {
		for _, b := range l.b[n:c.B] {
			buf.Write(b)
			buf.WriteByte('\n')
		}
		if c.Ins > 0 {
			if c.Ins == 1 && c.Del == 1 {
				buf.Write(byteDiff(l.a[c.A], l.b[c.B]))
				buf.WriteByte('\n')
			} else {
				for _, b := range l.b[c.B : c.B+c.Ins] {
					buf.Write(colorize(b))
					buf.WriteByte('\n')
				}
			}
		}
		n = c.B + c.Ins
	}
	for i, b := range l.b[n:] {
		if i > 0 {
			buf.WriteByte('\n')
		}
		buf.Write(b)
	}
	return buf.Bytes()
}
Esempio n. 2
0
func (this *tokenizedDiff) Update() {
	left := this.GetSources()[0].(*tokenizedGoContent)
	right := this.GetSources()[1].(*tokenizedGoContent)

	this.segments = nil

	dmp := tokenizedDiffHelper{left: left, right: right}
	diffs := diff.Diff(left.LenSegments(), right.LenSegments(), &dmp)

	// HACK: Fake first element.
	this.segments = append(this.segments, highlightSegment{offset: 0})

	for _, diff := range diffs {
		if !this.leftSide && diff.Ins > 0 {
			beginOffset := right.Segment(uint32(diff.B)).offset
			endOffset := right.Segment(uint32(diff.B + diff.Ins)).offset
			this.segments = append(this.segments, highlightSegment{offset: beginOffset, color: darkGreenColor})
			this.segments = append(this.segments, highlightSegment{offset: endOffset})
		} else if this.leftSide && diff.Del > 0 {
			beginOffset := left.Segment(uint32(diff.A)).offset
			endOffset := left.Segment(uint32(diff.A + diff.Del)).offset
			this.segments = append(this.segments, highlightSegment{offset: beginOffset, color: darkRedColor})
			this.segments = append(this.segments, highlightSegment{offset: endOffset})
		}
	}

	// HACK: Fake last element.
	this.segments = append(this.segments, highlightSegment{offset: uint32(500000000)}) // TODO, HACK
}
Esempio n. 3
0
func BenchmarkDiff(b *testing.B) {
	t := tests[len(tests)-1]
	d := &ints{t.a, t.b}
	n, m := len(d.a), len(d.b)
	for i := 0; i < b.N; i++ {
		diff.Diff(n, m, d)
	}
}
Esempio n. 4
0
func ExampleInterface() {
	m := &MixedInput{
		[]int{1, 2, 3, 1, 2, 2, 1},
		[]string{"three", "two", "one", "two", "one", "three"},
	}
	changes := diff.Diff(len(m.A), len(m.B), m)
	for _, c := range changes {
		fmt.Println("change at", c.A, c.B)
	}
}
Esempio n. 5
0
func ExampleDiff() {
	names = map[string]int{
		"one":   1,
		"two":   2,
		"three": 3,
	}

	m := &MixedInput{
		[]int{1, 2, 3, 1, 2, 2, 1},
		[]string{"three", "two", "one", "two", "one", "three"},
	}
	changes := diff.Diff(len(m.A), len(m.B), m)
	for _, c := range changes {
		fmt.Println("change at", c.A, c.B)
	}
	// Output:
	// change at 0 0
	// change at 2 2
	// change at 5 4
	// change at 7 5
}
Esempio n. 6
0
// HTMLdiff finds all the differences in the versions of HTML snippits,
// versions[0] is the original, all other versions are the edits to be compared.
// The resulting merged HTML snippits are as many as there are edits to compare.
func (c *Config) HTMLdiff(versions []string) ([]string, error) {
	if len(versions) < 2 {
		return nil, errors.New("there must be at least two versions to diff, the 0th element is the base")
	}
	parallelErrors := make(chan error, len(versions))
	sourceTrees := make([]*html.Node, len(versions))
	sourceTreeRunes := make([]*[]treeRune, len(versions))
	firstLeaves := make([]int, len(versions))
	for v, vv := range versions {
		go func(v int, vv string) {
			var err error
			sourceTrees[v], err = html.Parse(strings.NewReader(vv))
			if err == nil {
				tr := make([]treeRune, 0, c.clean(sourceTrees[v]))
				sourceTreeRunes[v] = &tr
				renderTreeRunes(sourceTrees[v], &tr)
				leaf1, ok := firstLeaf(findBody(sourceTrees[v]))
				if leaf1 == nil || !ok {
					firstLeaves[v] = 0 // could be wrong, but correct for simple examples
				} else {
					for x, y := range tr {
						if y.leaf == leaf1 {
							firstLeaves[v] = x
							break
						}
					}
				}
			}
			parallelErrors <- err
		}(v, vv)
	}
	for range versions {
		if err := <-parallelErrors; err != nil {
			return nil, err
		}
	}

	// now all the input trees are buit, we can do the merge
	mergedHTMLs := make([]string, len(versions)-1)

	for m := range mergedHTMLs {
		go func(m int) {
			treeRuneLimit := 250000 // from initial testing
			if len(*sourceTreeRunes[0]) > treeRuneLimit || len(*sourceTreeRunes[m+1]) > treeRuneLimit {
				parallelErrors <- errors.New("input data too large")
				return
			}
			dd := diffData{a: sourceTreeRunes[0], b: sourceTreeRunes[m+1]}
			var changes []diff.Change
			ch := make(chan []diff.Change)
			go func(ch chan []diff.Change) {
				ch <- diff.Diff(len(*sourceTreeRunes[0]), len(*sourceTreeRunes[m+1]), dd)
			}(ch)
			to := time.After(time.Second * 3)
			select {
			case <-to:
				parallelErrors <- errors.New("diff.Diff() took too long")
				go func(ch chan []diff.Change) {
					<-ch // make sure the timed-out diff cleans-up
				}(ch)
				return
			case changes = <-ch:
				// we have the diff
				go func(to <-chan time.Time) {
					<-to // make sure we don't leak the timer goroutine
				}(to)
			}
			changes = granular(c.Granularity, dd, changes)
			mergedTree, err := c.walkChanges(changes, sourceTreeRunes[0], sourceTreeRunes[m+1], firstLeaves[0], firstLeaves[m+1])
			if err != nil {
				parallelErrors <- err
				return
			}
			var mergedHTMLbuff bytes.Buffer
			err = html.Render(&mergedHTMLbuff, mergedTree)
			if err != nil {
				parallelErrors <- err
				return
			}
			mergedHTML := mergedHTMLbuff.Bytes()
			pfx := []byte("<html><head></head><body>")
			sfx := []byte("</body></html>")
			if bytes.HasPrefix(mergedHTML, pfx) && bytes.HasSuffix(mergedHTML, sfx) {
				mergedHTML = bytes.TrimSuffix(bytes.TrimPrefix(mergedHTML, pfx), sfx)
				mergedHTMLs[m] = string(mergedHTML)
				parallelErrors <- nil
				return
			}
			parallelErrors <- errors.New("correct render wrapper HTML not found: " + string(mergedHTML))
		}(m)
	}
	for range mergedHTMLs {
		if err := <-parallelErrors; err != nil {
			return nil, err
		}
	}
	return mergedHTMLs, nil
}
Esempio n. 7
0
func (d *lineDiffer) Diff() []mb0diff.Change {
	return mb0diff.Diff(len(d.a), len(d.b), d)
}
Esempio n. 8
0
func (this *lineDiff) Update() {
	left := this.GetSources()[0].(caret.MultilineContentI)
	right := this.GetSources()[1].(caret.MultilineContentI)

	dmp := lineDiffHelper{left: left, right: right}
	diffs := diff.Diff(left.LenLines(), right.LenLines(), &dmp)

	for side := range this.segments {
		this.segments[side] = nil

		// HACK: Fake first element.
		this.segments[side] = append(this.segments[side], highlightSegment{offset: 0})
	}
	this.lines[0] = make([]bool, left.LenLines())
	this.lines[1] = make([]bool, right.LenLines())

	for _, diff := range diffs {
		if diff.Del > 0 || diff.Ins > 0 {
			beginOffsetLeft := left.Line(diff.A).Start()
			endOffsetLeft := left.Line(diff.A + diff.Del).Start()
			beginOffsetRight := right.Line(diff.B).Start()
			endOffsetRight := right.Line(diff.B + diff.Ins).Start()

			for line := diff.A; line < diff.A+diff.Del; line++ {
				this.lines[0][line] = true
			}
			for line := diff.B; line < diff.B+diff.Ins; line++ {
				this.lines[1][line] = true
			}

			leftContent := left.Content()[beginOffsetLeft:endOffsetLeft]
			rightContent := right.Content()[beginOffsetRight:endOffsetRight]

			highlightedDiffFunc(leftContent, rightContent, &this.segments, [2]uint32{beginOffsetLeft, beginOffsetRight})

			this.segments[0] = append(this.segments[0], highlightSegment{offset: endOffsetLeft})
			this.segments[1] = append(this.segments[1], highlightSegment{offset: endOffsetRight})
		} /* else {
			for side := range this.segments {
				if side == 0 && diff.Del > 0 {
					beginOffset := left.Line(diff.A).Start()
					endOffset := left.Line(diff.A + diff.Del).Start()

					this.segments[side] = append(this.segments[side], highlightSegment{offset: beginOffset, color: darkRedColor})
					this.segments[side] = append(this.segments[side], highlightSegment{offset: endOffset})
				}
				if side == 1 && diff.Ins > 0 {
					beginOffset := right.Line(diff.B).Start()
					endOffset := right.Line(diff.B + diff.Ins).Start()

					this.segments[side] = append(this.segments[side], highlightSegment{offset: beginOffset, color: darkGreenColor})
					this.segments[side] = append(this.segments[side], highlightSegment{offset: endOffset})
				}
			}
		}*/
	}

	for side := range this.segments {
		// HACK: Fake last element.
		this.segments[side] = append(this.segments[side], highlightSegment{offset: uint32(500000000)}) // TODO, HACK
	}
}