hunks.go

v0.4.0
Doc Versions Source
1
package sync
2
3
import "strings"
4
5
// hunk is one maximal run of consecutive non-equal edits in the local→remote
6
// diff. opStart/opEnd index that run in the ops slice; preview renders it as a
7
// `-local` / `+remote` block for the prompt.
8
type hunk struct {
9
	opStart, opEnd int
10
	preview        string
11
}
12
13
// splitHunks computes the local→remote edit script and groups its consecutive
14
// non-equal ops into hunks. Reuses diff.go's LCS engine — there is one diff
15
// implementation in this package (GPC8). Applying every hunk yields remote;
16
// applying none yields local.
17
func splitHunks(local, remote []string) ([]diffOp, []hunk) {
18
	t, _ := lcs(local, remote)
19
	ops := diffOps(local, remote, t, 0)
20
21
	var hunks []hunk
22
	ia, ib := 0, 0
23
	for i := 0; i < len(ops); {
24
		if ops[i].kind == opEqual {
25
			ia++
26
			ib++
27
			i++
28
			continue
29
		}
30
		start := i
31
		var b strings.Builder
32
		for i < len(ops) && ops[i].kind != opEqual {
33
			switch ops[i].kind {
34
			case opDel:
35
				b.WriteString("-" + local[ia])
36
				ia++
37
			case opAdd:
38
				b.WriteString("+" + remote[ib])
39
				ib++
40
			}
41
			i++
42
		}
43
		hunks = append(hunks, hunk{opStart: start, opEnd: i, preview: b.String()})
44
	}
45
	return ops, hunks
46
}
47
48
// applyHunks rebuilds the local file with only the selected hunks applied: an
49
// unselected del keeps the local line, an unselected add is dropped, equal lines
50
// are always kept. selected is indexed by hunk position.
51
func applyHunks(local, remote []string, ops []diffOp, hunks []hunk, selected []bool) []string {
52
	hunkOf := make([]int, len(ops))
53
	for i := range hunkOf {
54
		hunkOf[i] = -1
55
	}
56
	for hi, h := range hunks {
57
		for i := h.opStart; i < h.opEnd; i++ {
58
			hunkOf[i] = hi
59
		}
60
	}
61
62
	var out []string
63
	ia, ib := 0, 0
64
	for i, op := range ops {
65
		sel := hunkOf[i] >= 0 && selected[hunkOf[i]]
66
		switch op.kind {
67
		case opEqual:
68
			out = append(out, local[ia])
69
			ia++
70
			ib++
71
		case opDel:
72
			if !sel {
73
				out = append(out, local[ia]) // keep the local line when not applying
74
			}
75
			ia++
76
		case opAdd:
77
			if sel {
78
				out = append(out, remote[ib])
79
			}
80
			ib++
81
		}
82
	}
83
	return out
84
}
85

Source Files