2222#include "utf8.h"
2323#include "userdiff.h"
2424#include "line-range.h"
25+ #include "line-log.h"
2526
2627static char blame_usage [] = N_ ("git blame [options] [rev-opts] [rev] [--] file" );
2728
@@ -1937,18 +1938,6 @@ static const char *add_prefix(const char *prefix, const char *path)
19371938 return prefix_path (prefix , prefix ? strlen (prefix ) : 0 , path );
19381939}
19391940
1940- /*
1941- * Parsing of -L option
1942- */
1943- static void prepare_blame_range (struct scoreboard * sb ,
1944- const char * bottomtop ,
1945- long lno ,
1946- long * bottom , long * top )
1947- {
1948- if (parse_range_arg (bottomtop , nth_line_cb , sb , lno , bottom , top , sb -> path ))
1949- usage (blame_usage );
1950- }
1951-
19521941static int git_blame_config (const char * var , const char * value , void * cb )
19531942{
19541943 if (!strcmp (var , "blame.showroot" )) {
@@ -2245,29 +2234,18 @@ static int blame_move_callback(const struct option *option, const char *arg, int
22452234 return 0 ;
22462235}
22472236
2248- static int blame_bottomtop_callback (const struct option * option , const char * arg , int unset )
2249- {
2250- const char * * bottomtop = option -> value ;
2251- if (!arg )
2252- return -1 ;
2253- if (* bottomtop )
2254- die ("More than one '-L n,m' option given" );
2255- * bottomtop = arg ;
2256- return 0 ;
2257- }
2258-
22592237int cmd_blame (int argc , const char * * argv , const char * prefix )
22602238{
22612239 struct rev_info revs ;
22622240 const char * path ;
22632241 struct scoreboard sb ;
22642242 struct origin * o ;
2265- struct blame_entry * ent ;
2266- long dashdash_pos , bottom , top , lno ;
2243+ struct blame_entry * ent = NULL ;
2244+ long dashdash_pos , lno ;
22672245 const char * final_commit_name = NULL ;
22682246 enum object_type type ;
22692247
2270- static const char * bottomtop = NULL ;
2248+ static struct string_list range_list ;
22712249 static int output_option = 0 , opt = 0 ;
22722250 static int show_stats = 0 ;
22732251 static const char * revs_file = NULL ;
@@ -2293,13 +2271,16 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
22932271 OPT_STRING (0 , "contents" , & contents_from , N_ ("file" ), N_ ("Use <file>'s contents as the final image" )),
22942272 { OPTION_CALLBACK , 'C' , NULL , & opt , N_ ("score" ), N_ ("Find line copies within and across files" ), PARSE_OPT_OPTARG , blame_copy_callback },
22952273 { OPTION_CALLBACK , 'M' , NULL , & opt , N_ ("score" ), N_ ("Find line movements within and across files" ), PARSE_OPT_OPTARG , blame_move_callback },
2296- OPT_CALLBACK ('L' , NULL , & bottomtop , N_ ("n,m" ), N_ ("Process only line range n,m, counting from 1" ), blame_bottomtop_callback ),
2274+ OPT_STRING_LIST ('L' , NULL , & range_list , N_ ("n,m" ), N_ ("Process only line range n,m, counting from 1" )),
22972275 OPT__ABBREV (& abbrev ),
22982276 OPT_END ()
22992277 };
23002278
23012279 struct parse_opt_ctx_t ctx ;
23022280 int cmd_is_annotate = !strcmp (argv [0 ], "annotate" );
2281+ struct range_set ranges ;
2282+ unsigned int range_i ;
2283+ long anchor ;
23032284
23042285 git_config (git_blame_config , NULL );
23052286 init_revisions (& revs , NULL );
@@ -2492,22 +2473,48 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
24922473 num_read_blob ++ ;
24932474 lno = prepare_lines (& sb );
24942475
2495- bottom = top = 0 ;
2496- if (bottomtop )
2497- prepare_blame_range (& sb , bottomtop , lno , & bottom , & top );
2498- if (lno < top || ((lno || bottom ) && lno < bottom ))
2499- die ("file %s has only %lu lines" , path , lno );
2500- if (bottom < 1 )
2501- bottom = 1 ;
2502- if (top < 1 )
2503- top = lno ;
2504- bottom -- ;
2505-
2506- ent = xcalloc (1 , sizeof (* ent ));
2507- ent -> lno = bottom ;
2508- ent -> num_lines = top - bottom ;
2509- ent -> suspect = o ;
2510- ent -> s_lno = bottom ;
2476+ if (lno && !range_list .nr )
2477+ string_list_append (& range_list , xstrdup ("1" ));
2478+
2479+ anchor = 1 ;
2480+ range_set_init (& ranges , range_list .nr );
2481+ for (range_i = 0 ; range_i < range_list .nr ; ++ range_i ) {
2482+ long bottom , top ;
2483+ if (parse_range_arg (range_list .items [range_i ].string ,
2484+ nth_line_cb , & sb , lno , anchor ,
2485+ & bottom , & top , sb .path ))
2486+ usage (blame_usage );
2487+ if (lno < top || ((lno || bottom ) && lno < bottom ))
2488+ die ("file %s has only %lu lines" , path , lno );
2489+ if (bottom < 1 )
2490+ bottom = 1 ;
2491+ if (top < 1 )
2492+ top = lno ;
2493+ bottom -- ;
2494+ range_set_append_unsafe (& ranges , bottom , top );
2495+ anchor = top + 1 ;
2496+ }
2497+ sort_and_merge_range_set (& ranges );
2498+
2499+ for (range_i = ranges .nr ; range_i > 0 ; -- range_i ) {
2500+ const struct range * r = & ranges .ranges [range_i - 1 ];
2501+ long bottom = r -> start ;
2502+ long top = r -> end ;
2503+ struct blame_entry * next = ent ;
2504+ ent = xcalloc (1 , sizeof (* ent ));
2505+ ent -> lno = bottom ;
2506+ ent -> num_lines = top - bottom ;
2507+ ent -> suspect = o ;
2508+ ent -> s_lno = bottom ;
2509+ ent -> next = next ;
2510+ if (next )
2511+ next -> prev = ent ;
2512+ origin_incref (o );
2513+ }
2514+ origin_decref (o );
2515+
2516+ range_set_release (& ranges );
2517+ string_list_clear (& range_list , 0 );
25112518
25122519 sb .ent = ent ;
25132520 sb .path = path ;
0 commit comments