this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix no newline handling in fragment parser

Correctly process "\ No newline..." marker lines when parsing fragments,
triming the new line from the last read line and advancing the parser.

Also fix the text chunk parser to follow the invariant of not advancing
past the end of the object in the event of an error. The error in
question now has a correct line number as well.

+34 -9
+34 -9
gitdiff/parser.go
··· 236 236 return p.Errorf(0, "no content following fragment header") 237 237 } 238 238 239 + isNoNewlineLine := func(s string) bool { 240 + // test for "\ No newline at end of file" by prefix because the text 241 + // changes by locale (git claims all versions are at least 12 chars) 242 + return len(s) >= 12 && s[:2] == "\\ " 243 + } 244 + 239 245 oldLines, newLines := frag.OldLines, frag.NewLines 240 - for oldLines > 0 || newLines > 0 { 246 + for { 241 247 line := p.Line(0) 242 248 switch line[0] { 243 249 case '\n': ··· 252 258 } 253 259 frag.Lines = append(frag.Lines, FragmentLine{OpContext, line[1:]}) 254 260 case '-': 261 + oldLines-- 255 262 frag.LinesDeleted++ 256 - oldLines-- 263 + frag.TrailingContext = 0 257 264 frag.Lines = append(frag.Lines, FragmentLine{OpDelete, line[1:]}) 258 265 case '+': 266 + newLines-- 259 267 frag.LinesAdded++ 260 - newLines-- 268 + frag.TrailingContext = 0 261 269 frag.Lines = append(frag.Lines, FragmentLine{OpAdd, line[1:]}) 262 270 default: 263 - // this could be "\ No newline at end of file", which we allow 264 - // only check the prefix because the text changes by locale 265 - // git also asserts that any translation is at least 12 characters 266 - if len(line) >= 12 && strings.HasPrefix("\\ ", line) { 271 + // this may appear in middle of fragment if it's for a deleted line 272 + if isNoNewlineLine(line) { 273 + last := len(frag.Lines) - 1 274 + frag.Lines[last].Line = strings.TrimSuffix(frag.Lines[last].Line, "\n") 267 275 break 268 276 } 269 - return p.Errorf(0, "invalid fragment line") 277 + return p.Errorf(0, "invalid line operation: %q", line[0]) 278 + } 279 + 280 + next := p.Line(1) 281 + if oldLines <= 0 && newLines <= 0 && !isNoNewlineLine(next) { 282 + break 270 283 } 271 284 272 285 if err := p.Next(); err != nil { ··· 278 291 } 279 292 280 293 if oldLines != 0 || newLines != 0 { 281 - return p.Errorf(0, "invalid fragment: remaining lines: %d old, %d new", oldLines, newLines) 294 + hdr := max(frag.OldLines-oldLines, frag.NewLines-newLines) + 1 295 + return p.Errorf(-hdr, "fragment header miscounts lines: %+d old, %+d new", -oldLines, -newLines) 296 + } 297 + 298 + if err := p.Next(); err != nil && err != io.EOF { 299 + return err 282 300 } 283 301 return nil 284 302 } ··· 306 324 307 325 return 308 326 } 327 + 328 + func max(a, b int64) int64 { 329 + if a > b { 330 + return a 331 + } 332 + return b 333 + }