git-clean: implement partial matching for selection
Document for interactive git-clean says: "You also could say `c` or `clean` above as long as the choice is unique". But it's not true, because only hotkey `c` and full match (`clean`) could work. Implement partial matching via find_unique function to make the document right. Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jiang Xin committed
Jul 24, 2013 at 10:22 UTC
60838613054f43d63086b0f4a7596baaee9e20c5
2 files changed
+90
-30
builtin/clean.c
+52
-28
@@ -365,6 +365,56 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
365
string_list_clear(&menu_list, 0);
366
}
367
368
+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
369
+{
370
+ struct menu_item *menu_item;
371
+ struct string_list_item *string_list_item;
372
+ int i, len, found = 0;
373
+
374
+ len = strlen(choice);
375
+ switch (menu_stuff->type) {
376
+ default:
377
+ die("Bad type of menu_stuff when parse choice");
378
+ case MENU_STUFF_TYPE_MENU_ITEM:
379
+
380
+ menu_item = (struct menu_item *)menu_stuff->stuff;
381
+ for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
382
+ if (len == 1 && *choice == menu_item->hotkey) {
383
+ found = i + 1;
384
+ break;
385
+ }
386
+ if (!strncasecmp(choice, menu_item->title, len)) {
387
+ if (found) {
388
+ if (len == 1) {
389
+ /* continue for hotkey matching */
390
+ found = -1;
391
+ } else {
392
+ found = 0;
393
+ break;
394
+ }
395
+ } else {
396
+ found = i + 1;
397
+ }
398
+ }
399
+ }
400
+ break;
401
+ case MENU_STUFF_TYPE_STRING_LIST:
402
+ string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
403
+ for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
404
+ if (!strncasecmp(choice, string_list_item->string, len)) {
405
+ if (found) {
406
+ found = 0;
407
+ break;
408
+ }
409
+ found = i + 1;
410
+ }
411
+ }
412
+ break;
413
+ }
414
+ return found;
415
+}
416
+
417
+
418
/*
419
* Parse user input, and return choice(s) for menu (menu_stuff).
420
*
@@ -392,8 +442,6 @@ static int parse_choice(struct menu_stuff *menu_stuff,
442
int **chosen)
443
{
444
struct strbuf **choice_list, **ptr;
395
- struct menu_item *menu_item;
396
- struct string_list_item *string_list_item;
445
int nr = 0;
446
int i;
447
@@ -457,32 +505,8 @@ static int parse_choice(struct menu_stuff *menu_stuff,
505
bottom = 1;
506
top = menu_stuff->nr;
507
} else {
460
- switch (menu_stuff->type) {
461
- default:
462
- die("Bad type of menu_stuff when parse choice");
463
- case MENU_STUFF_TYPE_MENU_ITEM:
464
- menu_item = (struct menu_item *)menu_stuff->stuff;
465
- for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
466
- if (((*ptr)->len == 1 &&
467
- *(*ptr)->buf == menu_item->hotkey) ||
468
- !strcasecmp((*ptr)->buf, menu_item->title)) {
469
- bottom = i + 1;
470
- top = bottom;
471
- break;
472
- }
473
- }
474
- break;
475
- case MENU_STUFF_TYPE_STRING_LIST:
476
- string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
477
- for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
478
- if (!strcasecmp((*ptr)->buf, string_list_item->string)) {
479
- bottom = i + 1;
480
- top = bottom;
481
- break;
482
- }
483
- }
484
- break;
485
- }
508
+ bottom = find_unique((*ptr)->buf, menu_stuff);
509
+ top = bottom;
510
}
511
512
if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
t/t7301-clean-interactive.sh
+38
-2
@@ -17,7 +17,7 @@ test_expect_success 'setup' '
17
18
'
19
20
-test_expect_success 'git clean -i (clean)' '
20
+test_expect_success 'git clean -i (c: clean hotkey)' '
21
22
mkdir -p build docs &&
23
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
@@ -38,12 +38,33 @@ test_expect_success 'git clean -i (clean)' '
38
39
'
40
41
+test_expect_success 'git clean -i (cl: clean prefix)' '
42
+
43
+ mkdir -p build docs &&
44
+ touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
45
+ docs/manual.txt obj.o build/lib.so &&
46
+ echo cl | git clean -i &&
47
+ test -f Makefile &&
48
+ test -f README &&
49
+ test -f src/part1.c &&
50
+ test -f src/part2.c &&
51
+ test ! -f a.out &&
52
+ test -f docs/manual.txt &&
53
+ test ! -f src/part3.c &&
54
+ test ! -f src/part3.h &&
55
+ test ! -f src/part4.c &&
56
+ test ! -f src/part4.h &&
57
+ test -f obj.o &&
58
+ test -f build/lib.so
59
+
60
+'
61
+
62
test_expect_success 'git clean -i (quit)' '
63
64
mkdir -p build docs &&
65
touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
66
docs/manual.txt obj.o build/lib.so &&
46
- echo q | git clean -i &&
67
+ echo quit | git clean -i &&
68
test -f Makefile &&
69
test -f README &&
70
test -f src/part1.c &&
@@ -256,6 +277,21 @@ test_expect_success 'git clean -id (select - number 3)' '
277
278
'
279
280
+test_expect_success 'git clean -id (select - filenames)' '
281
+
282
+ mkdir -p build docs &&
283
+ touch a.out foo.txt bar.txt baz.txt &&
284
+ (echo s; echo a.out fo ba bar; echo; echo c) | \
285
+ git clean -id &&
286
+ test -f Makefile &&
287
+ test ! -f a.out &&
288
+ test ! -f foo.txt &&
289
+ test ! -f bar.txt &&
290
+ test -f baz.txt &&
291
+ rm baz.txt
292
+
293
+'
294
+
295
test_expect_success 'git clean -id (select - range)' '
296
297
mkdir -p build docs &&