@@ -72,15 +72,17 @@ static void init_add_i_state(struct add_i_state *s, struct repository *r)
72
72
struct prefix_item_list {
73
73
struct string_list items ;
74
74
struct string_list sorted ;
75
+ int * selected ; /* for multi-selections */
75
76
size_t min_length , max_length ;
76
77
};
77
78
#define PREFIX_ITEM_LIST_INIT \
78
- { STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, 1, 4 }
79
+ { STRING_LIST_INIT_DUP, STRING_LIST_INIT_NODUP, NULL, 1, 4 }
79
80
80
81
static void prefix_item_list_clear (struct prefix_item_list * list )
81
82
{
82
83
string_list_clear (& list -> items , 1 );
83
84
string_list_clear (& list -> sorted , 0 );
85
+ FREE_AND_NULL (list -> selected );
84
86
}
85
87
86
88
static void extend_prefix_length (struct string_list_item * p ,
@@ -182,11 +184,12 @@ static ssize_t find_unique(const char *string, struct prefix_item_list *list)
182
184
struct list_options {
183
185
int columns ;
184
186
const char * header ;
185
- void (* print_item )(int i , struct string_list_item * item , void * print_item_data );
187
+ void (* print_item )(int i , int selected , struct string_list_item * item ,
188
+ void * print_item_data );
186
189
void * print_item_data ;
187
190
};
188
191
189
- static void list (struct add_i_state * s , struct string_list * list ,
192
+ static void list (struct add_i_state * s , struct string_list * list , int * selected ,
190
193
struct list_options * opts )
191
194
{
192
195
int i , last_lf = 0 ;
@@ -199,7 +202,8 @@ static void list(struct add_i_state *s, struct string_list *list,
199
202
"%s" , opts -> header );
200
203
201
204
for (i = 0 ; i < list -> nr ; i ++ ) {
202
- opts -> print_item (i , list -> items + i , opts -> print_item_data );
205
+ opts -> print_item (i , selected ? selected [i ] : 0 , list -> items + i ,
206
+ opts -> print_item_data );
203
207
204
208
if ((opts -> columns ) && ((i + 1 ) % (opts -> columns ))) {
205
209
putchar ('\t' );
@@ -218,14 +222,19 @@ struct list_and_choose_options {
218
222
struct list_options list_opts ;
219
223
220
224
const char * prompt ;
225
+ enum {
226
+ SINGLETON = (1 <<0 ),
227
+ IMMEDIATE = (1 <<1 ),
228
+ } flags ;
221
229
void (* print_help )(struct add_i_state * s );
222
230
};
223
231
224
232
#define LIST_AND_CHOOSE_ERROR (-1)
225
233
#define LIST_AND_CHOOSE_QUIT (-2)
226
234
227
235
/*
228
- * Returns the selected index.
236
+ * Returns the selected index in singleton mode, the number of selected items
237
+ * otherwise.
229
238
*
230
239
* If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
231
240
* `LIST_AND_CHOOSE_QUIT` is returned.
@@ -234,8 +243,19 @@ static ssize_t list_and_choose(struct add_i_state *s,
234
243
struct prefix_item_list * items ,
235
244
struct list_and_choose_options * opts )
236
245
{
246
+ int singleton = opts -> flags & SINGLETON ;
247
+ int immediate = opts -> flags & IMMEDIATE ;
248
+
237
249
struct strbuf input = STRBUF_INIT ;
238
- ssize_t res = LIST_AND_CHOOSE_ERROR ;
250
+ ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0 ;
251
+
252
+ if (!singleton ) {
253
+ free (items -> selected );
254
+ CALLOC_ARRAY (items -> selected , items -> items .nr );
255
+ }
256
+
257
+ if (singleton && !immediate )
258
+ BUG ("singleton requires immediate" );
239
259
240
260
find_unique_prefixes (items );
241
261
@@ -244,15 +264,16 @@ static ssize_t list_and_choose(struct add_i_state *s,
244
264
245
265
strbuf_reset (& input );
246
266
247
- list (s , & items -> items , & opts -> list_opts );
267
+ list (s , & items -> items , items -> selected , & opts -> list_opts );
248
268
249
269
color_fprintf (stdout , s -> prompt_color , "%s" , opts -> prompt );
250
- fputs (" > " , stdout );
270
+ fputs (singleton ? "> " : "> > " , stdout );
251
271
fflush (stdout );
252
272
253
273
if (strbuf_getline (& input , stdin ) == EOF ) {
254
274
putchar ('\n' );
255
- res = LIST_AND_CHOOSE_QUIT ;
275
+ if (immediate )
276
+ res = LIST_AND_CHOOSE_QUIT ;
256
277
break ;
257
278
}
258
279
strbuf_trim (& input );
@@ -268,7 +289,9 @@ static ssize_t list_and_choose(struct add_i_state *s,
268
289
p = input .buf ;
269
290
for (;;) {
270
291
size_t sep = strcspn (p , " \t\r\n," );
271
- ssize_t index = -1 ;
292
+ int choose = 1 ;
293
+ /* `from` is inclusive, `to` is exclusive */
294
+ ssize_t from = -1 , to = -1 ;
272
295
273
296
if (!sep ) {
274
297
if (!* p )
@@ -277,30 +300,70 @@ static ssize_t list_and_choose(struct add_i_state *s,
277
300
continue ;
278
301
}
279
302
280
- if (isdigit (* p )) {
303
+ /* Input that begins with '-'; de-select */
304
+ if (* p == '-' ) {
305
+ choose = 0 ;
306
+ p ++ ;
307
+ sep -- ;
308
+ }
309
+
310
+ if (sep == 1 && * p == '*' ) {
311
+ from = 0 ;
312
+ to = items -> items .nr ;
313
+ } else if (isdigit (* p )) {
281
314
char * endp ;
282
- index = strtoul (p , & endp , 10 ) - 1 ;
283
- if (endp != p + sep )
284
- index = -1 ;
315
+ /*
316
+ * A range can be specified like 5-7 or 5-.
317
+ *
318
+ * Note: `from` is 0-based while the user input
319
+ * is 1-based, hence we have to decrement by
320
+ * one. We do not have to decrement `to` even
321
+ * if it is 0-based because it is an exclusive
322
+ * boundary.
323
+ */
324
+ from = strtoul (p , & endp , 10 ) - 1 ;
325
+ if (endp == p + sep )
326
+ to = from + 1 ;
327
+ else if (* endp == '-' ) {
328
+ to = strtoul (++ endp , & endp , 10 );
329
+ /* extra characters after the range? */
330
+ if (endp != p + sep )
331
+ from = -1 ;
332
+ }
285
333
}
286
334
287
335
if (p [sep ])
288
336
p [sep ++ ] = '\0' ;
289
- if (index < 0 )
290
- index = find_unique (p , items );
337
+ if (from < 0 ) {
338
+ from = find_unique (p , items );
339
+ if (from >= 0 )
340
+ to = from + 1 ;
341
+ }
291
342
292
- if (index < 0 || index >= items -> items .nr )
343
+ if (from < 0 || from >= items -> items .nr ||
344
+ (singleton && from + 1 != to )) {
293
345
color_fprintf_ln (stdout , s -> error_color ,
294
346
_ ("Huh (%s)?" ), p );
295
- else {
296
- res = index ;
347
+ break ;
348
+ } else if (singleton ) {
349
+ res = from ;
297
350
break ;
298
351
}
299
352
353
+ if (to > items -> items .nr )
354
+ to = items -> items .nr ;
355
+
356
+ for (; from < to ; from ++ )
357
+ if (items -> selected [from ] != choose ) {
358
+ items -> selected [from ] = choose ;
359
+ res += choose ? +1 : -1 ;
360
+ }
361
+
300
362
p += sep ;
301
363
}
302
364
303
- if (res != LIST_AND_CHOOSE_ERROR )
365
+ if ((immediate && res != LIST_AND_CHOOSE_ERROR ) ||
366
+ !strcmp (input .buf , "*" ))
304
367
break ;
305
368
}
306
369
@@ -500,7 +563,7 @@ struct print_file_item_data {
500
563
struct strbuf buf , index , worktree ;
501
564
};
502
565
503
- static void print_file_item (int i , struct string_list_item * item ,
566
+ static void print_file_item (int i , int selected , struct string_list_item * item ,
504
567
void * print_file_item_data )
505
568
{
506
569
struct file_item * c = item -> util ;
@@ -515,7 +578,7 @@ static void print_file_item(int i, struct string_list_item *item,
515
578
strbuf_addf (& d -> buf , d -> modified_fmt ,
516
579
d -> index .buf , d -> worktree .buf , item -> string );
517
580
518
- printf (" % 2d: %s" , i + 1 , d -> buf .buf );
581
+ printf ("%c% 2d: %s" , selected ? '*' : ' ' , i + 1 , d -> buf .buf );
519
582
}
520
583
521
584
static int run_status (struct add_i_state * s , const struct pathspec * ps ,
@@ -524,7 +587,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps,
524
587
if (get_modified_files (s -> r , NO_FILTER , files , ps ) < 0 )
525
588
return -1 ;
526
589
527
- list (s , files , opts );
590
+ list (s , files , NULL , opts );
528
591
putchar ('\n' );
529
592
530
593
return 0 ;
@@ -563,7 +626,8 @@ struct print_command_item_data {
563
626
const char * color , * reset ;
564
627
};
565
628
566
- static void print_command_item (int i , struct string_list_item * item ,
629
+ static void print_command_item (int i , int selected ,
630
+ struct string_list_item * item ,
567
631
void * print_command_item_data )
568
632
{
569
633
struct print_command_item_data * d = print_command_item_data ;
@@ -596,7 +660,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
596
660
struct print_command_item_data data = { "[" , "]" };
597
661
struct list_and_choose_options main_loop_opts = {
598
662
{ 4 , N_ ("*** Commands ***" ), print_command_item , & data },
599
- N_ ("What now" ), command_prompt_help
663
+ N_ ("What now" ), SINGLETON | IMMEDIATE , command_prompt_help
600
664
};
601
665
struct {
602
666
const char * string ;
0 commit comments