Exemple #1
0
func DiffLines(orgLines, newLines []string, format string) {
	if len(orgLines)+len(newLines) == 0 {
		return
	} // if

	_, matA, matB := ed.EditDistanceFFull(len(orgLines), len(newLines), func(iA, iB int) int {
		sa, sb := strings.TrimSpace(orgLines[iA]), strings.TrimSpace(newLines[iB])
		// When sa and sb has 1/3 in common, convertion const is equal to del+ins const
		return tm.CalcDiffOfSourceLine(sa, sb, (len(sa)+len(sb))*120)
	}, func(iA int) int {
		return max(1, len(strings.TrimSpace(orgLines[iA]))*100)
	}, func(iB int) int {
		return max(1, len(strings.TrimSpace(newLines[iB]))*100)
	})
	var lo lineOutput

	for i, j := 0, 0; i < len(orgLines) || j < len(newLines); {
		switch {
		case j >= len(newLines) || i < len(orgLines) && matA[i] < 0:
			lo.outputDel(fmt.Sprintf(format, orgLines[i]))
			i++
		case i >= len(orgLines) || j < len(newLines) && matB[j] < 0:
			lo.outputIns(fmt.Sprintf(format, newLines[j]))
			j++
		default:
			if strings.TrimSpace(orgLines[i]) != strings.TrimSpace(newLines[j]) {
				lo.outputChange(fmt.Sprintf(format, orgLines[i]), fmt.Sprintf(format, newLines[j]))
			} else {
				lo.outputSame(fmt.Sprintf(format, newLines[j]))
			} // else
			i++
			j++
		}
	} // for i, j
	lo.end()
}
Exemple #2
0
func diffLinesTo(orgLines, newLines []string, format string, lo lineOutputer) int {
	if len(orgLines)+len(newLines) == 0 {
		return 0
	}

	start, orgEnd, newEnd := 0, len(orgLines), len(newLines)

	if len(orgLines)*len(newLines) > 1024*1024 {
		// Use trivial comparison to offset same head and tail lines.
		start, orgEnd, newEnd = offsetHeadTails(orgLines, newLines)
	}

	fastMode := false
	if len(orgLines)*len(newLines) > 1024*1024 {
		fastMode = true
	}

	_, matA, matB := ed.EditDistanceFFull(orgEnd-start, newEnd-start, func(iA, iB int) int {
		sa, sb := orgLines[iA+start], newLines[iB+start]
		rawEqual := sa == sb
		sa, sb = strings.TrimSpace(sa), strings.TrimSpace(sb)

		posCost := 0
		if isBlockStart(sa) {
			posCost += (newEnd - start - 1 - iB) * 10 / (newEnd - start)
		}

		if rawEqual {
			return posCost
		}
		if sa == sb {
			return posCost + 1
		}

		mx := (len(sa) + len(sb)) * 150

		var dist int

		if fastMode && len(sa) > 10*len(sb) {
			dist = 100 * (len(sa) - len(sb))
		} else if fastMode && len(sb) > 10*len(sa) {
			dist = 100 * (len(sb) - len(sa))
		} else {
			// When sa and sb has 1/3 in common, convertion const is equal to del+ins const
			dist = tm.CalcDiffOfSourceLine(sa, sb, mx)
		}
		// Even a small change, both lines will be shown, so add a 20% penalty on that.
		return (dist*4+mx)/5 + 1 + posCost
	}, func(iA int) int {
		return mathp.MaxI(1, len(strings.TrimSpace(orgLines[iA+start]))*100)
	}, func(iB int) int {
		return mathp.MaxI(1, len(strings.TrimSpace(newLines[iB+start]))*100)
	})

	cnt := 0

	for i, j := 0, 0; i < len(orgLines) || j < len(newLines); {
		switch {
		case i < start || i >= orgEnd && j >= newEnd:
			// cut by offsetHeadTails
			lo.outputSame(fmt.Sprintf(format, newLines[j]))
			i++
			j++
		case j >= newEnd || i < orgEnd && matA[i-start] < 0:
			lo.outputDel(fmt.Sprintf(format, orgLines[i]))
			cnt++
			i++
		case i >= orgEnd || j < newEnd && matB[j-start] < 0:
			lo.outputIns(fmt.Sprintf(format, newLines[j]))
			cnt++
			j++
		default:
			if strings.TrimSpace(orgLines[i]) != strings.TrimSpace(newLines[j]) {
				lo.outputChange(fmt.Sprintf(format, orgLines[i]), fmt.Sprintf(format, newLines[j]))
				cnt += 2
			} else {
				lo.outputSame(fmt.Sprintf(format, newLines[j]))
			} // else
			i++
			j++
		}
	}
	lo.end()
	return cnt
}