at master 130 lines 3.4 kB view raw
1package types 2 3import ( 4 "github.com/bluekeyes/go-gitdiff/gitdiff" 5) 6 7type SplitLine struct { 8 LineNumber int `json:"line_number,omitempty"` 9 Content string `json:"content"` 10 Op gitdiff.LineOp `json:"op"` 11 IsEmpty bool `json:"is_empty"` 12} 13 14type SplitFragment struct { 15 Header string `json:"header"` 16 LeftLines []SplitLine `json:"left_lines"` 17 RightLines []SplitLine `json:"right_lines"` 18} 19 20type SplitDiff struct { 21 Name string `json:"name"` 22 TextFragments []SplitFragment `json:"fragments"` 23} 24 25func (d SplitDiff) Id() string { 26 return d.Name 27} 28 29// separate lines into left and right, this includes additional logic to 30// group consecutive runs of additions and deletions in order to align them 31// properly in the final output 32// 33// TODO: move all diff stuff to a single package, we are spread across patchutil and types right now 34func SeparateLines(fragment *gitdiff.TextFragment) ([]SplitLine, []SplitLine) { 35 lines := fragment.Lines 36 var leftLines, rightLines []SplitLine 37 oldLineNum := fragment.OldPosition 38 newLineNum := fragment.NewPosition 39 40 // process deletions and additions in groups for better alignment 41 i := 0 42 for i < len(lines) { 43 line := lines[i] 44 45 switch line.Op { 46 case gitdiff.OpContext: 47 leftLines = append(leftLines, SplitLine{ 48 LineNumber: int(oldLineNum), 49 Content: line.Line, 50 Op: gitdiff.OpContext, 51 IsEmpty: false, 52 }) 53 rightLines = append(rightLines, SplitLine{ 54 LineNumber: int(newLineNum), 55 Content: line.Line, 56 Op: gitdiff.OpContext, 57 IsEmpty: false, 58 }) 59 oldLineNum++ 60 newLineNum++ 61 i++ 62 63 case gitdiff.OpDelete: 64 deletionCount := 0 65 for j := i; j < len(lines) && lines[j].Op == gitdiff.OpDelete; j++ { 66 leftLines = append(leftLines, SplitLine{ 67 LineNumber: int(oldLineNum), 68 Content: lines[j].Line, 69 Op: gitdiff.OpDelete, 70 IsEmpty: false, 71 }) 72 oldLineNum++ 73 deletionCount++ 74 } 75 i += deletionCount 76 77 additionCount := 0 78 for j := i; j < len(lines) && lines[j].Op == gitdiff.OpAdd; j++ { 79 rightLines = append(rightLines, SplitLine{ 80 LineNumber: int(newLineNum), 81 Content: lines[j].Line, 82 Op: gitdiff.OpAdd, 83 IsEmpty: false, 84 }) 85 newLineNum++ 86 additionCount++ 87 } 88 i += additionCount 89 90 // add empty lines to balance the sides 91 if deletionCount > additionCount { 92 // more deletions than additions - pad right side 93 for k := 0; k < deletionCount-additionCount; k++ { 94 rightLines = append(rightLines, SplitLine{ 95 Content: "", 96 Op: gitdiff.OpContext, 97 IsEmpty: true, 98 }) 99 } 100 } else if additionCount > deletionCount { 101 // more additions than deletions - pad left side 102 for k := 0; k < additionCount-deletionCount; k++ { 103 leftLines = append(leftLines, SplitLine{ 104 Content: "", 105 Op: gitdiff.OpContext, 106 IsEmpty: true, 107 }) 108 } 109 } 110 111 case gitdiff.OpAdd: 112 // standalone addition (not preceded by deletion) 113 leftLines = append(leftLines, SplitLine{ 114 Content: "", 115 Op: gitdiff.OpContext, 116 IsEmpty: true, 117 }) 118 rightLines = append(rightLines, SplitLine{ 119 LineNumber: int(newLineNum), 120 Content: line.Line, 121 Op: gitdiff.OpAdd, 122 IsEmpty: false, 123 }) 124 newLineNum++ 125 i++ 126 } 127 } 128 129 return leftLines, rightLines 130}