4
4
"errors"
5
5
"fmt"
6
6
"os"
7
+ "strings"
7
8
)
8
9
9
10
// File describes changes to a single file. It can be either a text file or a
@@ -38,6 +39,119 @@ type File struct {
38
39
ReverseBinaryFragment * BinaryFragment
39
40
}
40
41
42
+ // String returns a git diff representation of this file. The value can be
43
+ // parsed by this library to obtain the same File, but may not be the same as
44
+ // the original input or the same as what Git would produces
45
+ func (f * File ) String () string {
46
+ var diff strings.Builder
47
+
48
+ diff .WriteString ("diff --git " )
49
+
50
+ var aName , bName string
51
+ switch {
52
+ case f .OldName == "" :
53
+ aName = f .NewName
54
+ bName = f .NewName
55
+
56
+ case f .NewName == "" :
57
+ aName = f .OldName
58
+ bName = f .OldName
59
+
60
+ default :
61
+ aName = f .OldName
62
+ bName = f .NewName
63
+ }
64
+
65
+ writeQuotedName (& diff , "a/" + aName )
66
+ diff .WriteByte (' ' )
67
+ writeQuotedName (& diff , "b/" + bName )
68
+ diff .WriteByte ('\n' )
69
+
70
+ diff .WriteString ("--- " )
71
+ if f .OldName == "" {
72
+ diff .WriteString ("/dev/null" )
73
+ } else {
74
+ writeQuotedName (& diff , f .OldName )
75
+ }
76
+ diff .WriteByte ('\n' )
77
+
78
+ diff .WriteString ("+++ " )
79
+ if f .NewName == "" {
80
+ diff .WriteString ("/dev/null" )
81
+ } else {
82
+ writeQuotedName (& diff , f .NewName )
83
+ }
84
+ diff .WriteByte ('\n' )
85
+
86
+ if f .OldMode != 0 {
87
+ if f .IsDelete {
88
+ fmt .Fprintf (& diff , "deleted file mode %o\n " , f .OldMode )
89
+ } else {
90
+ fmt .Fprintf (& diff , "old mode %o\n " , f .OldMode )
91
+ }
92
+ }
93
+
94
+ if f .NewMode != 0 {
95
+ if f .IsNew {
96
+ fmt .Fprintf (& diff , "new file mode %o\n " , f .NewMode )
97
+ } else {
98
+ fmt .Fprintf (& diff , "new mode %o\n " , f .NewMode )
99
+ }
100
+ }
101
+
102
+ if f .Score > 0 {
103
+ if f .IsCopy || f .IsRename {
104
+ fmt .Fprintf (& diff , "similarity index %d%%\n " , f .Score )
105
+ } else {
106
+ fmt .Fprintf (& diff , "dissimilarity index %d%%\n " , f .Score )
107
+ }
108
+ }
109
+
110
+ if f .IsCopy {
111
+ if f .OldName != "" {
112
+ diff .WriteString ("copy from " )
113
+ writeQuotedName (& diff , f .OldName )
114
+ diff .WriteByte ('\n' )
115
+ }
116
+ if f .NewName != "" {
117
+ diff .WriteString ("copy to " )
118
+ writeQuotedName (& diff , f .NewName )
119
+ diff .WriteByte ('\n' )
120
+ }
121
+ }
122
+
123
+ if f .IsRename {
124
+ if f .OldName != "" {
125
+ diff .WriteString ("rename from " )
126
+ writeQuotedName (& diff , f .OldName )
127
+ diff .WriteByte ('\n' )
128
+ }
129
+ if f .NewName != "" {
130
+ diff .WriteString ("rename to " )
131
+ writeQuotedName (& diff , f .NewName )
132
+ diff .WriteByte ('\n' )
133
+ }
134
+ }
135
+
136
+ if f .OldOIDPrefix != "" && f .NewOIDPrefix != "" {
137
+ fmt .Fprintf (& diff , "index %s..%s" , f .OldOIDPrefix , f .NewOIDPrefix )
138
+ if f .OldMode != 0 {
139
+ fmt .Fprintf (& diff , " %o" , f .OldMode )
140
+ }
141
+ diff .WriteByte ('\n' )
142
+ }
143
+
144
+ if f .IsBinary {
145
+ // TODO(bkeyes): add string method for BinaryFragments
146
+ } else {
147
+ for _ , frag := range f .TextFragments {
148
+ diff .WriteString (frag .String ())
149
+ }
150
+ }
151
+
152
+ return diff .String ()
153
+ }
154
+
41
155
// TextFragment describes changed lines starting at a specific line in a text file.
42
156
type TextFragment struct {
43
157
Comment string
@@ -57,7 +171,26 @@ type TextFragment struct {
57
171
Lines []Line
58
172
}
59
173
60
- // Header returns the canonical header of this fragment.
174
+ // String returns a git diff format of this fragment. See [File.String] for
175
+ // more details on this format.
176
+ func (f * TextFragment ) String () string {
177
+ var diff strings.Builder
178
+
179
+ diff .WriteString (f .Header ())
180
+ diff .WriteString ("\n " )
181
+
182
+ for _ , line := range f .Lines {
183
+ diff .WriteString (line .String ())
184
+ if line .NoEOL () {
185
+ diff .WriteString ("\n \\ No newline at end of file\n " )
186
+ }
187
+ }
188
+
189
+ return diff .String ()
190
+ }
191
+
192
+ // Header returns a git diff header of this fragment. See [File.String] for
193
+ // more details on this format.
61
194
func (f * TextFragment ) Header () string {
62
195
return fmt .Sprintf ("@@ -%d,%d +%d,%d @@ %s" , f .OldPosition , f .OldLines , f .NewPosition , f .NewLines , f .Comment )
63
196
}
0 commit comments