at master 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 25// used by html elements as a unique ID for hrefs 26func (d *SplitDiff) Id() string { 27 return d.Name 28} 29 30// separate lines into left and right, this includes additional logic to 31// group consecutive runs of additions and deletions in order to align them 32// properly in the final output 33// 34// TODO: move all diff stuff to a single package, we are spread across patchutil and types right now 35func SeparateLines(fragment *gitdiff.TextFragment) ([]SplitLine, []SplitLine) { 36 lines := fragment.Lines 37 var leftLines, rightLines []SplitLine 38 oldLineNum := fragment.OldPosition 39 newLineNum := fragment.NewPosition 40 41 // process deletions and additions in groups for better alignment 42 i := 0 43 for i < len(lines) { 44 line := lines[i] 45 46 switch line.Op { 47 case gitdiff.OpContext: 48 leftLines = append(leftLines, SplitLine{ 49 LineNumber: int(oldLineNum), 50 Content: line.Line, 51 Op: gitdiff.OpContext, 52 IsEmpty: false, 53 }) 54 rightLines = append(rightLines, SplitLine{ 55 LineNumber: int(newLineNum), 56 Content: line.Line, 57 Op: gitdiff.OpContext, 58 IsEmpty: false, 59 }) 60 oldLineNum++ 61 newLineNum++ 62 i++ 63 64 case gitdiff.OpDelete: 65 deletionCount := 0 66 for j := i; j < len(lines) && lines[j].Op == gitdiff.OpDelete; j++ { 67 leftLines = append(leftLines, SplitLine{ 68 LineNumber: int(oldLineNum), 69 Content: lines[j].Line, 70 Op: gitdiff.OpDelete, 71 IsEmpty: false, 72 }) 73 oldLineNum++ 74 deletionCount++ 75 } 76 i += deletionCount 77 78 additionCount := 0 79 for j := i; j < len(lines) && lines[j].Op == gitdiff.OpAdd; j++ { 80 rightLines = append(rightLines, SplitLine{ 81 LineNumber: int(newLineNum), 82 Content: lines[j].Line, 83 Op: gitdiff.OpAdd, 84 IsEmpty: false, 85 }) 86 newLineNum++ 87 additionCount++ 88 } 89 i += additionCount 90 91 // add empty lines to balance the sides 92 if deletionCount > additionCount { 93 // more deletions than additions - pad right side 94 for k := 0; k < deletionCount-additionCount; k++ { 95 rightLines = append(rightLines, SplitLine{ 96 Content: "", 97 Op: gitdiff.OpContext, 98 IsEmpty: true, 99 }) 100 } 101 } else if additionCount > deletionCount { 102 // more additions than deletions - pad left side 103 for k := 0; k < additionCount-deletionCount; k++ { 104 leftLines = append(leftLines, SplitLine{ 105 Content: "", 106 Op: gitdiff.OpContext, 107 IsEmpty: true, 108 }) 109 } 110 } 111 112 case gitdiff.OpAdd: 113 // standalone addition (not preceded by deletion) 114 leftLines = append(leftLines, SplitLine{ 115 Content: "", 116 Op: gitdiff.OpContext, 117 IsEmpty: true, 118 }) 119 rightLines = append(rightLines, SplitLine{ 120 LineNumber: int(newLineNum), 121 Content: line.Line, 122 Op: gitdiff.OpAdd, 123 IsEmpty: false, 124 }) 125 newLineNum++ 126 i++ 127 } 128 } 129 130 return leftLines, rightLines 131}