Skip to content

Commit d915db2

Browse files
committed
Handle no-newline-at-end-of-file for orig
1 parent 1d9fcb0 commit d915db2

11 files changed

+87
-14
lines changed

diff/diff.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ func (d *FileDiff) Stat() Stat {
3636
// A Hunk represents a series of changes (additions or deletions) in a
3737
// file's unified diff.
3838
type Hunk struct {
39-
OrigStartLine int // starting line number in original file
40-
OrigLines int // number of lines the hunk applies to in the original file
39+
OrigStartLine int // starting line number in original file
40+
OrigLines int // number of lines the hunk applies to in the original file
41+
OrigNoNewlineAt int // if > 0, then the original file had a 'No newline at end of file' mark at this offset
4142

4243
NewStartLine int // starting line number in new file
4344
NewLines int // number of lines the hunk applies to in the new file

diff/diff_test.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ func TestParseHunksAndPrintHunks(t *testing.T) {
5454
{
5555
filename: "sample_hunks_no_newline.diff",
5656
},
57+
{filename: "no_newline_both.diff"},
58+
{filename: "no_newline_both2.diff"},
59+
{filename: "no_newline_orig.diff"},
60+
{filename: "no_newline_new.diff"},
61+
{filename: "empty_orig.diff"},
62+
{filename: "empty_new.diff"},
63+
{filename: "oneline_hunk.diff"},
5764
{filename: "empty.diff"},
5865
}
5966
for _, test := range tests {
@@ -162,14 +169,14 @@ func TestParseMultiFileDiffAndPrintMultiFileDiff(t *testing.T) {
162169

163170
func TestNoNewlineAtEnd(t *testing.T) {
164171
orig := `@@ -1,1 +1,1 @@
165-
-b
172+
-a
166173
+b
167174
\ No newline at end of file
168175
`
169176

170177
hunks, err := ParseHunks([]byte(orig))
171178
if err != nil {
172-
t.Fatal("ParseHunks: %s", err)
179+
t.Fatalf("ParseHunks: %s", err)
173180
}
174181

175182
for _, hunk := range hunks {
@@ -182,7 +189,7 @@ func TestNoNewlineAtEnd(t *testing.T) {
182189

183190
printed, err := PrintHunks(hunks)
184191
if err != nil {
185-
t.Fatal("PrintHunks: %s", err)
192+
t.Fatalf("PrintHunks: %s", err)
186193
}
187194
if printed := string(printed); printed != orig {
188195
t.Errorf("printed diff hunks != original diff hunks\n\n# PrintHunks output:\n%q\n\n# Original:\n%q", printed, orig)

diff/parse.go

+17-3
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ type HunksReader struct {
324324
// returns error io.EOF.
325325
func (r *HunksReader) ReadHunk() (*Hunk, error) {
326326
r.hunk = nil
327+
lastLineFromOrig := true
327328
var line []byte
328329
for {
329330
if r.nextHunkHeaderLine != nil {
@@ -392,13 +393,26 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
392393
return r.hunk, &ParseError{r.line, r.offset, &ErrBadHunkLine{Line: line}}
393394
}
394395
if bytes.Equal(line, []byte(noNewlineMessage)) {
395-
// Remove previous line's newline.
396-
if len(r.hunk.Body) != 0 {
397-
r.hunk.Body = r.hunk.Body[:len(r.hunk.Body)-1]
396+
if lastLineFromOrig {
397+
// Retain the newline in the body (otherwise the
398+
// diff line would be like "-a+b", where "+b" is
399+
// the the next line of the new file, which is not
400+
// validly formatted) but record that the orig had
401+
// no newline.
402+
r.hunk.OrigNoNewlineAt = len(r.hunk.Body)
403+
} else {
404+
// Remove previous line's newline.
405+
if len(r.hunk.Body) != 0 {
406+
r.hunk.Body = r.hunk.Body[:len(r.hunk.Body)-1]
407+
}
398408
}
399409
continue
400410
}
401411

412+
if len(line) > 0 {
413+
lastLineFromOrig = line[0] == '-'
414+
}
415+
402416
r.hunk.Body = append(r.hunk.Body, line...)
403417
r.hunk.Body = append(r.hunk.Body, '\n')
404418
}

diff/print.go

+27-6
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,41 @@ func PrintHunks(hunks []*Hunk) ([]byte, error) {
8686
if _, err := fmt.Fprintln(&buf); err != nil {
8787
return nil, err
8888
}
89-
if _, err := buf.Write(hunk.Body); err != nil {
90-
return nil, err
91-
}
92-
if !bytes.HasSuffix(hunk.Body, []byte{'\n'}) {
93-
if _, err := fmt.Fprintln(&buf); err != nil {
89+
90+
if hunk.OrigNoNewlineAt == 0 {
91+
if _, err := buf.Write(hunk.Body); err != nil {
9492
return nil, err
9593
}
96-
if _, err := buf.Write([]byte(noNewlineMessage)); err != nil {
94+
} else {
95+
if _, err := buf.Write(hunk.Body[:hunk.OrigNoNewlineAt]); err != nil {
9796
return nil, err
9897
}
98+
if err := printNoNewlineMessage(&buf); err != nil {
99+
return nil, err
100+
}
101+
if _, err := buf.Write(hunk.Body[hunk.OrigNoNewlineAt:]); err != nil {
102+
return nil, err
103+
}
104+
}
105+
106+
if !bytes.HasSuffix(hunk.Body, []byte{'\n'}) {
99107
if _, err := fmt.Fprintln(&buf); err != nil {
100108
return nil, err
101109
}
110+
if err := printNoNewlineMessage(&buf); err != nil {
111+
return nil, err
112+
}
102113
}
103114
}
104115
return buf.Bytes(), nil
105116
}
117+
118+
func printNoNewlineMessage(w io.Writer) error {
119+
if _, err := w.Write([]byte(noNewlineMessage)); err != nil {
120+
return err
121+
}
122+
if _, err := fmt.Fprintln(w); err != nil {
123+
return err
124+
}
125+
return nil
126+
}

diff/testdata/empty_new.diff

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@@ -1,1 +0,0 @@
2+
-b

diff/testdata/empty_orig.diff

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@@ -0,0 +1,1 @@
2+
+b

diff/testdata/no_newline_both.diff

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@@ -1,1 +1,1 @@
2+
-a
3+
\ No newline at end of file
4+
+b
5+
\ No newline at end of file

diff/testdata/no_newline_both2.diff

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@@ -1,3 +1,3 @@
2+
0
3+
-a
4+
-a
5+
\ No newline at end of file
6+
+b
7+
+b
8+
\ No newline at end of file

diff/testdata/no_newline_new.diff

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@@ -1,3 +1,2 @@
2+
a
3+
-a
4+
-a
5+
+a
6+
\ No newline at end of file

diff/testdata/no_newline_orig.diff

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@@ -1,1 +1,1 @@
2+
-a
3+
\ No newline at end of file
4+
+b

diff/testdata/oneline_hunk.diff

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@@ -1,1 +1,1 @@
2+
-a
3+
+b

0 commit comments

Comments
 (0)