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....@gmail.com>
---
 builtin/clean.c              | 80 ++++++++++++++++++++++++++++----------------
 t/t7301-clean-interactive.sh | 40 ++++++++++++++++++++--
 2 files changed, 90 insertions(+), 30 deletions(-)

diff --git a/builtin/clean.c b/builtin/clean.c
index dba8387..3c85e15 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -365,6 +365,56 @@ static void print_highlight_menu_stuff(struct menu_stuff 
*stuff, int **chosen)
        string_list_clear(&menu_list, 0);
 }
 
+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
+{
+       struct menu_item *menu_item;
+       struct string_list_item *string_list_item;
+       int i, len, found = 0;
+
+       len = strlen(choice);
+       switch (menu_stuff->type) {
+       default:
+               die("Bad type of menu_stuff when parse choice");
+       case MENU_STUFF_TYPE_MENU_ITEM:
+
+               menu_item = (struct menu_item *)menu_stuff->stuff;
+               for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
+                       if (len == 1 && *choice == menu_item->hotkey) {
+                               found = i + 1;
+                               break;
+                       }
+                       if (!strncasecmp(choice, menu_item->title, len)) {
+                               if (found) {
+                                       if (len == 1) {
+                                               /* continue for hotkey matching 
*/
+                                               found = -1;
+                                       } else {
+                                               found = 0;
+                                               break;
+                                       }
+                               } else {
+                                       found = i + 1;
+                               }
+                       }
+               }
+               break;
+       case MENU_STUFF_TYPE_STRING_LIST:
+               string_list_item = ((struct string_list 
*)menu_stuff->stuff)->items;
+               for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
+                       if (!strncasecmp(choice, string_list_item->string, 
len)) {
+                               if (found) {
+                                       found = 0;
+                                       break;
+                               }
+                               found = i + 1;
+                       }
+               }
+               break;
+       }
+       return found;
+}
+
+
 /*
  * Parse user input, and return choice(s) for menu (menu_stuff).
  *
@@ -392,8 +442,6 @@ static int parse_choice(struct menu_stuff *menu_stuff,
                        int **chosen)
 {
        struct strbuf **choice_list, **ptr;
-       struct menu_item *menu_item;
-       struct string_list_item *string_list_item;
        int nr = 0;
        int i;
 
@@ -457,32 +505,8 @@ static int parse_choice(struct menu_stuff *menu_stuff,
                        bottom = 1;
                        top = menu_stuff->nr;
                } else {
-                       switch (menu_stuff->type) {
-                       default:
-                               die("Bad type of menu_stuff when parse choice");
-                       case MENU_STUFF_TYPE_MENU_ITEM:
-                               menu_item = (struct menu_item 
*)menu_stuff->stuff;
-                               for (i = 0; i < menu_stuff->nr; i++, 
menu_item++) {
-                                       if (((*ptr)->len == 1 &&
-                                            *(*ptr)->buf == menu_item->hotkey) 
||
-                                           !strcasecmp((*ptr)->buf, 
menu_item->title)) {
-                                               bottom = i + 1;
-                                               top = bottom;
-                                               break;
-                                       }
-                               }
-                               break;
-                       case MENU_STUFF_TYPE_STRING_LIST:
-                               string_list_item = ((struct string_list 
*)menu_stuff->stuff)->items;
-                               for (i = 0; i < menu_stuff->nr; i++, 
string_list_item++) {
-                                       if (!strcasecmp((*ptr)->buf, 
string_list_item->string)) {
-                                               bottom = i + 1;
-                                               top = bottom;
-                                               break;
-                                       }
-                               }
-                               break;
-                       }
+                       bottom = find_unique((*ptr)->buf, menu_stuff);
+                       top = bottom;
                }
 
                if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > 
top ||
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
index 4e6055d..3ae394e 100755
--- a/t/t7301-clean-interactive.sh
+++ b/t/t7301-clean-interactive.sh
@@ -17,7 +17,7 @@ test_expect_success 'setup' '
 
 '
 
-test_expect_success 'git clean -i (clean)' '
+test_expect_success 'git clean -i (c: clean hotkey)' '
 
        mkdir -p build docs &&
        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)' '
 
 '
 
+test_expect_success 'git clean -i (cl: clean prefix)' '
+
+       mkdir -p build docs &&
+       touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
+       docs/manual.txt obj.o build/lib.so &&
+       echo cl | git clean -i &&
+       test -f Makefile &&
+       test -f README &&
+       test -f src/part1.c &&
+       test -f src/part2.c &&
+       test ! -f a.out &&
+       test -f docs/manual.txt &&
+       test ! -f src/part3.c &&
+       test ! -f src/part3.h &&
+       test ! -f src/part4.c &&
+       test ! -f src/part4.h &&
+       test -f obj.o &&
+       test -f build/lib.so
+
+'
+
 test_expect_success 'git clean -i (quit)' '
 
        mkdir -p build docs &&
        touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \
        docs/manual.txt obj.o build/lib.so &&
-       echo q | git clean -i &&
+       echo quit | git clean -i &&
        test -f Makefile &&
        test -f README &&
        test -f src/part1.c &&
@@ -256,6 +277,21 @@ test_expect_success 'git clean -id (select - number 3)' '
 
 '
 
+test_expect_success 'git clean -id (select - filenames)' '
+
+       mkdir -p build docs &&
+       touch a.out foo.txt bar.txt baz.txt &&
+       (echo s; echo a.out fo ba bar; echo; echo c) | \
+       git clean -id &&
+       test -f Makefile &&
+       test ! -f a.out &&
+       test ! -f foo.txt &&
+       test ! -f bar.txt &&
+       test -f baz.txt &&
+       rm baz.txt
+
+'
+
 test_expect_success 'git clean -id (select - range)' '
 
        mkdir -p build docs &&
-- 
1.8.3.4.842.g8e6673c

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to