1package mergeconflicts
2
3// mergeConflict : A git conflict with a start, ancestor (if exists), target, and end corresponding to line
4// numbers in the file where the conflict markers appear.
5// If no ancestor is present (i.e. we're not using the diff3 algorithm), then
6// the `ancestor` field's value will be -1
7type mergeConflict struct {
8	start    int
9	ancestor int
10	target   int
11	end      int
12}
13
14func (c *mergeConflict) hasAncestor() bool {
15	return c.ancestor >= 0
16}
17
18func (c *mergeConflict) isMarkerLine(i int) bool {
19	return i == c.start ||
20		i == c.ancestor ||
21		i == c.target ||
22		i == c.end
23}
24
25type Selection int
26
27const (
28	TOP Selection = iota
29	MIDDLE
30	BOTTOM
31	ALL
32)
33
34func (s Selection) isIndexToKeep(conflict *mergeConflict, i int) bool {
35	// we're only handling one conflict at a time so any lines outside this
36	// conflict we'll keep
37	if i < conflict.start || conflict.end < i {
38		return true
39	}
40
41	if conflict.isMarkerLine(i) {
42		return false
43	}
44
45	return s.selected(conflict, i)
46}
47
48func (s Selection) bounds(c *mergeConflict) (int, int) {
49	switch s {
50	case TOP:
51		if c.hasAncestor() {
52			return c.start, c.ancestor
53		} else {
54			return c.start, c.target
55		}
56	case MIDDLE:
57		return c.ancestor, c.target
58	case BOTTOM:
59		return c.target, c.end
60	case ALL:
61		return c.start, c.end
62	}
63
64	panic("unexpected selection for merge conflict")
65}
66
67func (s Selection) selected(c *mergeConflict, idx int) bool {
68	start, end := s.bounds(c)
69	return start < idx && idx < end
70}
71
72func availableSelections(c *mergeConflict) []Selection {
73	if c.hasAncestor() {
74		return []Selection{TOP, MIDDLE, BOTTOM}
75	} else {
76		return []Selection{TOP, BOTTOM}
77	}
78}
79