@@ -79,14 +79,8 @@ func (p *parser) ParseTextChunk(frag *TextFragment) error {
79
79
return p .Errorf (0 , "no content following fragment header" )
80
80
}
81
81
82
- isNoNewlineLine := func (s string ) bool {
83
- // test for "\ No newline at end of file" by prefix because the text
84
- // changes by locale (git claims all versions are at least 12 chars)
85
- return len (s ) >= 12 && s [:2 ] == "\\ "
86
- }
87
-
88
82
oldLines , newLines := frag .OldLines , frag .NewLines
89
- for {
83
+ for oldLines > 0 || newLines > 0 {
90
84
line := p .Line (0 )
91
85
op , data := line [0 ], line [1 :]
92
86
@@ -113,13 +107,14 @@ func (p *parser) ParseTextChunk(frag *TextFragment) error {
113
107
frag .LinesAdded ++
114
108
frag .TrailingContext = 0
115
109
frag .Lines = append (frag .Lines , Line {OpAdd , data })
116
- default :
110
+ case '\\' :
117
111
// this may appear in middle of fragment if it's for a deleted line
118
- if isNoNewlineLine (line ) {
119
- last := & frag .Lines [len (frag .Lines )- 1 ]
120
- last .Line = strings .TrimSuffix (last .Line , "\n " )
112
+ if isNoNewlineMarker (line ) {
113
+ removeLastNewline (frag )
121
114
break
122
115
}
116
+ fallthrough
117
+ default :
123
118
// TODO(bkeyes): if this is because we hit the next header, it
124
119
// would be helpful to return the miscounts line error. We could
125
120
// either test for the common headers ("@@ -", "diff --git") or
@@ -128,11 +123,6 @@ func (p *parser) ParseTextChunk(frag *TextFragment) error {
128
123
return p .Errorf (0 , "invalid line operation: %q" , op )
129
124
}
130
125
131
- next := p .Line (1 )
132
- if oldLines <= 0 && newLines <= 0 && ! isNoNewlineLine (next ) {
133
- break
134
- }
135
-
136
126
if err := p .Next (); err != nil {
137
127
if err == io .EOF {
138
128
break
@@ -145,13 +135,35 @@ func (p *parser) ParseTextChunk(frag *TextFragment) error {
145
135
hdr := max (frag .OldLines - oldLines , frag .NewLines - newLines ) + 1
146
136
return p .Errorf (- hdr , "fragment header miscounts lines: %+d old, %+d new" , - oldLines , - newLines )
147
137
}
138
+ if frag .LinesAdded == 0 && frag .LinesDeleted == 0 {
139
+ return p .Errorf (0 , "fragment contains no changes" )
140
+ }
148
141
149
- if err := p .Next (); err != nil && err != io .EOF {
150
- return err
142
+ // check for a final "no newline" marker since it is not included in the
143
+ // counters used to stop the loop above
144
+ if isNoNewlineMarker (p .Line (0 )) {
145
+ removeLastNewline (frag )
146
+ if err := p .Next (); err != nil && err != io .EOF {
147
+ return err
148
+ }
151
149
}
150
+
152
151
return nil
153
152
}
154
153
154
+ func isNoNewlineMarker (s string ) bool {
155
+ // test for "\ No newline at end of file" by prefix because the text
156
+ // changes by locale (git claims all versions are at least 12 chars)
157
+ return len (s ) >= 12 && s [:2 ] == "\\ "
158
+ }
159
+
160
+ func removeLastNewline (frag * TextFragment ) {
161
+ if len (frag .Lines ) > 0 {
162
+ last := & frag .Lines [len (frag .Lines )- 1 ]
163
+ last .Line = strings .TrimSuffix (last .Line , "\n " )
164
+ }
165
+ }
166
+
155
167
func parseRange (s string ) (start int64 , end int64 , err error ) {
156
168
parts := strings .SplitN (s , "," , 2 )
157
169
0 commit comments