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