this repo has no description
0
fork

Configure Feed

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

Add basic fragment parsing function

This should work, but does no validation on the fragment after parsing.

+85 -7
+23
gitdiff/gitdiff.go
··· 35 35 36 36 NewPosition int64 37 37 NewLines int64 38 + 39 + LinesAdded int64 40 + LinesDeleted int64 41 + 42 + Lines []FragmentLine 38 43 } 44 + 45 + // FragmentLine is a line in a fragment. 46 + type FragmentLine struct { 47 + Op LineOp 48 + Line string 49 + } 50 + 51 + // LineOp describes the type of a fragment line: context, added, or removed. 52 + type LineOp int 53 + 54 + const ( 55 + // OpContext indicates a context line 56 + OpContext LineOp = iota 57 + // OpDelete indicates a deleted line 58 + OpDelete 59 + // OpAdd indicates an added line 60 + OpAdd 61 + ) 39 62 40 63 // Header returns the cannonical header of this fragment. 41 64 func (f *Fragment) Header() string {
+62 -7
gitdiff/parser.go
··· 45 45 // by allowing users to set or override defaults 46 46 47 47 // parser invariants: 48 - // - methods that parse objects start on the first line of the first object 49 - // - methods that parse objects return on the first line after the last object 50 - // - if a parse method returns a nil object, the parser was not advanced 48 + // - methods that parse objects: 49 + // - start with the parser on the first line of the first object 50 + // - if returning nil, do not advance 51 + // - if returning an error, do not advance past the object 52 + // - if returning an object, advance to the first line after the object 51 53 // - any exported parsing methods must initialize the parser by calling Next() 52 54 53 55 type parser struct { ··· 170 172 171 173 parts := strings.SplitAfterN(p.Line(0), endMark, 2) 172 174 if len(parts) < 2 { 173 - return nil, fmt.Errorf("invalid fragment header") 175 + return nil, p.Errorf(0, "invalid fragment header") 174 176 } 175 177 176 178 f := &Fragment{} ··· 179 181 header := parts[0][len(startMark) : len(parts[0])-len(endMark)] 180 182 ranges := strings.Split(header, " +") 181 183 if len(ranges) != 2 { 182 - return nil, fmt.Errorf("invalid fragment header") 184 + return nil, p.Errorf(0, "invalid fragment header") 183 185 } 184 186 185 187 var err error 186 188 if f.OldPosition, f.OldLines, err = parseRange(ranges[0]); err != nil { 187 - return nil, fmt.Errorf("invalid fragment header: %v", err) 189 + return nil, p.Errorf(0, "invalid fragment header: %v", err) 188 190 } 189 191 if f.NewPosition, f.NewLines, err = parseRange(ranges[1]); err != nil { 190 - return nil, fmt.Errorf("invalid fragment header: %v", err) 192 + return nil, p.Errorf(0, "invalid fragment header: %v", err) 191 193 } 192 194 193 195 if err := p.Next(); err != nil && err != io.EOF { 194 196 return nil, err 195 197 } 196 198 return f, nil 199 + } 200 + 201 + func (p *parser) ParseFragment() (*Fragment, error) { 202 + frag, err := p.ParseFragmentHeader() 203 + if err != nil { 204 + return nil, err 205 + } 206 + if frag == nil { 207 + return nil, nil 208 + } 209 + if p.Line(0) == "" { 210 + return nil, p.Errorf(0, "no content following fragment header") 211 + } 212 + 213 + oldLines, newLines := frag.OldLines, frag.NewLines 214 + for oldLines > 0 && newLines > 0 { 215 + line := p.Line(0) 216 + switch line[0] { 217 + case '\n': 218 + fallthrough // newer GNU diff versions create empty context lines 219 + case ' ': 220 + oldLines-- 221 + newLines-- 222 + frag.Lines = append(frag.Lines, FragmentLine{OpContext, line[1:]}) 223 + case '-': 224 + frag.LinesDeleted++ 225 + oldLines-- 226 + frag.Lines = append(frag.Lines, FragmentLine{OpDelete, line[1:]}) 227 + case '+': 228 + frag.LinesAdded++ 229 + newLines-- 230 + frag.Lines = append(frag.Lines, FragmentLine{OpAdd, line[1:]}) 231 + default: 232 + // this could be "\ No newline at end of file", which we allow 233 + // only check the prefix because the text changes by locale 234 + // git also asserts that any translation is at least 12 characters 235 + if len(line) >= 12 && strings.HasPrefix("\\ ", line) { 236 + break 237 + } 238 + return nil, p.Errorf(0, "invalid fragment line") 239 + } 240 + 241 + if err := p.Next(); err != nil { 242 + if err == io.EOF { 243 + break 244 + } 245 + return nil, err 246 + } 247 + } 248 + 249 + // TODO(bkeyes): verify stuff about the fragment 250 + 251 + return frag, nil 197 252 } 198 253 199 254 func parseRange(s string) (start int64, end int64, err error) {