@@ -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,29 +300,69 @@ 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
p [sep ] = '\0' ;
288
- if (index < 0 )
289
- index = find_unique (p , items );
336
+ if (from < 0 ) {
337
+ from = find_unique (p , items );
338
+ if (from >= 0 )
339
+ to = from + 1 ;
340
+ }
290
341
291
- if (index < 0 || index >= items -> items .nr )
342
+ if (from < 0 || from >= items -> items .nr ||
343
+ (singleton && from + 1 != to )) {
292
344
color_fprintf_ln (stdout , s -> error_color ,
293
345
_ ("Huh (%s)?" ), p );
294
- else {
295
- res = index ;
346
+ break ;
347
+ } else if (singleton ) {
348
+ res = from ;
296
349
break ;
297
350
}
298
351
352
+ if (to > items -> items .nr )
353
+ to = items -> items .nr ;
354
+
355
+ for (; from < to ; from ++ )
356
+ if (items -> selected [from ] != choose ) {
357
+ items -> selected [from ] = choose ;
358
+ res += choose ? +1 : -1 ;
359
+ }
360
+
299
361
p += sep + 1 ;
300
362
}
301
363
302
- if (res != LIST_AND_CHOOSE_ERROR )
364
+ if ((immediate && res != LIST_AND_CHOOSE_ERROR ) ||
365
+ !strcmp (input .buf , "*" ))
303
366
break ;
304
367
}
305
368
@@ -496,7 +559,7 @@ struct print_file_item_data {
496
559
struct strbuf buf , index , worktree ;
497
560
};
498
561
499
- static void print_file_item (int i , struct string_list_item * item ,
562
+ static void print_file_item (int i , int selected , struct string_list_item * item ,
500
563
void * print_file_item_data )
501
564
{
502
565
struct file_item * c = item -> util ;
@@ -511,7 +574,7 @@ static void print_file_item(int i, struct string_list_item *item,
511
574
strbuf_addf (& d -> buf , d -> modified_fmt ,
512
575
d -> index .buf , d -> worktree .buf , item -> string );
513
576
514
- printf (" % 2d: %s" , i + 1 , d -> buf .buf );
577
+ printf ("%c% 2d: %s" , selected ? '*' : ' ' , i + 1 , d -> buf .buf );
515
578
}
516
579
517
580
static int run_status (struct add_i_state * s , const struct pathspec * ps ,
@@ -520,7 +583,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps,
520
583
if (get_modified_files (s -> r , NO_FILTER , files , ps ) < 0 )
521
584
return -1 ;
522
585
523
- list (s , files , opts );
586
+ list (s , files , NULL , opts );
524
587
putchar ('\n' );
525
588
526
589
return 0 ;
@@ -559,7 +622,8 @@ struct print_command_item_data {
559
622
const char * color , * reset ;
560
623
};
561
624
562
- static void print_command_item (int i , struct string_list_item * item ,
625
+ static void print_command_item (int i , int selected ,
626
+ struct string_list_item * item ,
563
627
void * print_command_item_data )
564
628
{
565
629
struct print_command_item_data * d = print_command_item_data ;
@@ -592,7 +656,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
592
656
struct print_command_item_data data = { "[" , "]" };
593
657
struct list_and_choose_options main_loop_opts = {
594
658
{ 4 , N_ ("*** Commands ***" ), print_command_item , & data },
595
- N_ ("What now" ), command_prompt_help
659
+ N_ ("What now" ), SINGLETON | IMMEDIATE , command_prompt_help
596
660
};
597
661
struct {
598
662
const char * string ;
0 commit comments