| 75 | } |
| 76 | |
| 77 | func (p *parser) ParseTextChunk(frag *TextFragment) error { |
| 78 | if p.Line(0) == "" { |
| 79 | return p.Errorf(0, "no content following fragment header") |
| 80 | } |
| 81 | |
| 82 | oldLines, newLines := frag.OldLines, frag.NewLines |
| 83 | for oldLines > 0 || newLines > 0 { |
| 84 | line := p.Line(0) |
| 85 | op, data := line[0], line[1:] |
| 86 | |
| 87 | switch op { |
| 88 | case '\n': |
| 89 | data = "\n" |
| 90 | fallthrough // newer GNU diff versions create empty context lines |
| 91 | case ' ': |
| 92 | oldLines-- |
| 93 | newLines-- |
| 94 | if frag.LinesAdded == 0 && frag.LinesDeleted == 0 { |
| 95 | frag.LeadingContext++ |
| 96 | } else { |
| 97 | frag.TrailingContext++ |
| 98 | } |
| 99 | frag.Lines = append(frag.Lines, Line{OpContext, data}) |
| 100 | case '-': |
| 101 | oldLines-- |
| 102 | frag.LinesDeleted++ |
| 103 | frag.TrailingContext = 0 |
| 104 | frag.Lines = append(frag.Lines, Line{OpDelete, data}) |
| 105 | case '+': |
| 106 | newLines-- |
| 107 | frag.LinesAdded++ |
| 108 | frag.TrailingContext = 0 |
| 109 | frag.Lines = append(frag.Lines, Line{OpAdd, data}) |
| 110 | case '\\': |
| 111 | // this may appear in middle of fragment if it's for a deleted line |
| 112 | if isNoNewlineMarker(line) { |
| 113 | removeLastNewline(frag) |
| 114 | break |
| 115 | } |
| 116 | fallthrough |
| 117 | default: |
| 118 | // TODO(bkeyes): if this is because we hit the next header, it |
| 119 | // would be helpful to return the miscounts line error. We could |
| 120 | // either test for the common headers ("@@ -", "diff --git") or |
| 121 | // assume any invalid op ends the fragment; git returns the same |
| 122 | // generic error in all cases so either is compatible |
| 123 | return p.Errorf(0, "invalid line operation: %q", op) |
| 124 | } |
| 125 | |
| 126 | if err := p.Next(); err != nil { |
| 127 | if err == io.EOF { |
| 128 | break |
| 129 | } |
| 130 | return err |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | if oldLines != 0 || newLines != 0 { |