14
14
15
15
#![ deny( warnings) ]
16
16
17
- use git2:: { Diff , DiffOptions , Error , Object , ObjectType , Repository } ;
18
- use git2:: { DiffFindOptions , DiffFormat } ;
17
+ use git2:: { Blob , Diff , DiffOptions , Error , Object , ObjectType , Oid , Repository } ;
18
+ use git2:: { DiffDelta , DiffFindOptions , DiffFormat , DiffHunk , DiffLine } ;
19
19
use std:: str;
20
20
use structopt:: StructOpt ;
21
21
@@ -26,6 +26,9 @@ struct Args {
26
26
arg_from_oid : Option < String > ,
27
27
#[ structopt( name = "to_oid" ) ]
28
28
arg_to_oid : Option < String > ,
29
+ #[ structopt( name = "blobs" , long) ]
30
+ /// treat from_oid and to_oid as blob ids
31
+ flag_blobs : bool ,
29
32
#[ structopt( name = "patch" , short, long) ]
30
33
/// show output in patch format
31
34
flag_patch : bool ,
@@ -137,6 +140,33 @@ enum Cache {
137
140
None ,
138
141
}
139
142
143
+ fn line_color ( line : & DiffLine ) -> Option < & ' static str > {
144
+ match line. origin ( ) {
145
+ '+' => Some ( GREEN ) ,
146
+ '-' => Some ( RED ) ,
147
+ '>' => Some ( GREEN ) ,
148
+ '<' => Some ( RED ) ,
149
+ 'F' => Some ( BOLD ) ,
150
+ 'H' => Some ( CYAN ) ,
151
+ _ => None ,
152
+ }
153
+ }
154
+
155
+ fn print_diff_line ( _delta : DiffDelta , _hunk : Option < DiffHunk > , line : DiffLine , args : & Args ) -> bool {
156
+ if args. color ( ) {
157
+ print ! ( "{}" , RESET ) ;
158
+ if let Some ( color) = line_color ( & line) {
159
+ print ! ( "{}" , color) ;
160
+ }
161
+ }
162
+ match line. origin ( ) {
163
+ '+' | '-' | ' ' => print ! ( "{}" , line. origin( ) ) ,
164
+ _ => { }
165
+ }
166
+ print ! ( "{}" , str :: from_utf8( line. content( ) ) . unwrap( ) ) ;
167
+ true
168
+ }
169
+
140
170
fn run ( args : & Args ) -> Result < ( ) , Error > {
141
171
let path = args. flag_git_dir . as_ref ( ) . map ( |s| & s[ ..] ) . unwrap_or ( "." ) ;
142
172
let repo = Repository :: open ( path) ?;
@@ -171,6 +201,26 @@ fn run(args: &Args) -> Result<(), Error> {
171
201
opts. id_abbrev ( 40 ) ;
172
202
}
173
203
204
+ if args. flag_blobs {
205
+ let b1 = resolve_blob ( & repo, args. arg_from_oid . as_ref ( ) ) ?;
206
+ let b2 = resolve_blob ( & repo, args. arg_to_oid . as_ref ( ) ) ?;
207
+ repo. diff_blobs (
208
+ b1. as_ref ( ) ,
209
+ None ,
210
+ b2. as_ref ( ) ,
211
+ None ,
212
+ Some ( & mut opts) ,
213
+ None ,
214
+ None ,
215
+ None ,
216
+ Some ( & mut |d, h, l| print_diff_line ( d, h, l, args) ) ,
217
+ ) ?;
218
+ if args. color ( ) {
219
+ print ! ( "{}" , RESET ) ;
220
+ }
221
+ return Ok ( ( ) ) ;
222
+ }
223
+
174
224
// Prepare the diff to inspect
175
225
let t1 = tree_to_treeish ( & repo, args. arg_from_oid . as_ref ( ) ) ?;
176
226
let t2 = tree_to_treeish ( & repo, args. arg_to_oid . as_ref ( ) ) ?;
@@ -220,37 +270,7 @@ fn run(args: &Args) -> Result<(), Error> {
220
270
print_stats ( & diff, args) ?;
221
271
}
222
272
if args. flag_patch || !stats {
223
- if args. color ( ) {
224
- print ! ( "{}" , RESET ) ;
225
- }
226
- let mut last_color = None ;
227
- diff. print ( args. diff_format ( ) , |_delta, _hunk, line| {
228
- if args. color ( ) {
229
- let next = match line. origin ( ) {
230
- '+' => Some ( GREEN ) ,
231
- '-' => Some ( RED ) ,
232
- '>' => Some ( GREEN ) ,
233
- '<' => Some ( RED ) ,
234
- 'F' => Some ( BOLD ) ,
235
- 'H' => Some ( CYAN ) ,
236
- _ => None ,
237
- } ;
238
- if args. color ( ) && next != last_color {
239
- if last_color == Some ( BOLD ) || next == Some ( BOLD ) {
240
- print ! ( "{}" , RESET ) ;
241
- }
242
- print ! ( "{}" , next. unwrap_or( RESET ) ) ;
243
- last_color = next;
244
- }
245
- }
246
-
247
- match line. origin ( ) {
248
- '+' | '-' | ' ' => print ! ( "{}" , line. origin( ) ) ,
249
- _ => { }
250
- }
251
- print ! ( "{}" , str :: from_utf8( line. content( ) ) . unwrap( ) ) ;
252
- true
253
- } ) ?;
273
+ diff. print ( args. diff_format ( ) , |d, h, l| print_diff_line ( d, h, l, args) ) ?;
254
274
if args. color ( ) {
255
275
print ! ( "{}" , RESET ) ;
256
276
}
@@ -292,6 +312,14 @@ fn tree_to_treeish<'a>(
292
312
Ok ( Some ( tree) )
293
313
}
294
314
315
+ fn resolve_blob < ' a > ( repo : & ' a Repository , arg : Option < & String > ) -> Result < Option < Blob < ' a > > , Error > {
316
+ let arg = match arg {
317
+ Some ( s) => Oid :: from_str ( s) ?,
318
+ None => return Ok ( None ) ,
319
+ } ;
320
+ repo. find_blob ( arg) . map ( |b| Some ( b) )
321
+ }
322
+
295
323
impl Args {
296
324
fn cache ( & self ) -> Cache {
297
325
if self . flag_cached {
0 commit comments