{"thread":{"id":"34524","subject":"[PATCH] git-clean: implement partial matching for selection","startedAt":"2013-07-24T02:04:33Z","lastAt":"2013-07-24T02:22:04Z","messageCount":3,"participants":["Jiang Xin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"224017","messageId":"d099b22989d6e7c023e160a6a9b232bc58e6349c.1374631307.git.worldhello.net@gmail.com","threadId":"34524","inReplyTo":null,"subject":"[PATCH] git-clean: implement partial matching for selection","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-07-24T02:04:33Z","receivedAt":"2013-07-24T02:04:33Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Document for interactive git-clean says: \"You also could say `c` or\n`clean` above as long as the choice is unique\". But it's not true,\nbecause only hotkey `c` and full match (`clean`) could work.\n\nImplement partial matching via find_unique function to make the\ndocument right.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/clean.c              | 80 ++++++++++++++++++++++++++++----------------\n t/t7301-clean-interactive.sh | 41 +++++++++++++++++++++--\n 2 files changed, 91 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex dba8387..3c85e15 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -365,6 +365,56 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)\n \tstring_list_clear(&menu_list, 0);\n }\n \n+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)\n+{\n+\tstruct menu_item *menu_item;\n+\tstruct string_list_item *string_list_item;\n+\tint i, len, found = 0;\n+\n+\tlen = strlen(choice);\n+\tswitch (menu_stuff->type) {\n+\tdefault:\n+\t\tdie(\"Bad type of menu_stuff when parse choice\");\n+\tcase MENU_STUFF_TYPE_MENU_ITEM:\n+\n+\t\tmenu_item = (struct menu_item *)menu_stuff->stuff;\n+\t\tfor (i = 0; i < menu_stuff->nr; i++, menu_item++) {\n+\t\t\tif (len == 1 && *choice == menu_item->hotkey) {\n+\t\t\t\tfound = i + 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (!strncasecmp(choice, menu_item->title, len)) {\n+\t\t\t\tif (found) {\n+\t\t\t\t\tif (len == 1) {\n+\t\t\t\t\t\t/* continue for hotkey matching */\n+\t\t\t\t\t\tfound = -1;\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tfound = 0;\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t} else {\n+\t\t\t\t\tfound = i + 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\tcase MENU_STUFF_TYPE_STRING_LIST:\n+\t\tstring_list_item = ((struct string_list *)menu_stuff->stuff)->items;\n+\t\tfor (i = 0; i < menu_stuff->nr; i++, string_list_item++) {\n+\t\t\tif (!strncasecmp(choice, string_list_item->string, len)) {\n+\t\t\t\tif (found) {\n+\t\t\t\t\tfound = 0;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tfound = i + 1;\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\t}\n+\treturn found;\n+}\n+\n+\n /*\n  * Parse user input, and return choice(s) for menu (menu_stuff).\n  *\n@@ -392,8 +442,6 @@ static int parse_choice(struct menu_stuff *menu_stuff,\n \t\t\tint **chosen)\n {\n \tstruct strbuf **choice_list, **ptr;\n-\tstruct menu_item *menu_item;\n-\tstruct string_list_item *string_list_item;\n \tint nr = 0;\n \tint i;\n \n@@ -457,32 +505,8 @@ static int parse_choice(struct menu_stuff *menu_stuff,\n \t\t\tbottom = 1;\n \t\t\ttop = menu_stuff->nr;\n \t\t} else {\n-\t\t\tswitch (menu_stuff->type) {\n-\t\t\tdefault:\n-\t\t\t\tdie(\"Bad type of menu_stuff when parse choice\");\n-\t\t\tcase MENU_STUFF_TYPE_MENU_ITEM:\n-\t\t\t\tmenu_item = (struct menu_item *)menu_stuff->stuff;\n-\t\t\t\tfor (i = 0; i < menu_stuff->nr; i++, menu_item++) {\n-\t\t\t\t\tif (((*ptr)->len == 1 &&\n-\t\t\t\t\t     *(*ptr)->buf == menu_item->hotkey) ||\n-\t\t\t\t\t    !strcasecmp((*ptr)->buf, menu_item->title)) {\n-\t\t\t\t\t\tbottom = i + 1;\n-\t\t\t\t\t\ttop = bottom;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase MENU_STUFF_TYPE_STRING_LIST:\n-\t\t\t\tstring_list_item = ((struct string_list *)menu_stuff->stuff)->items;\n-\t\t\t\tfor (i = 0; i < menu_stuff->nr; i++, string_list_item++) {\n-\t\t\t\t\tif (!strcasecmp((*ptr)->buf, string_list_item->string)) {\n-\t\t\t\t\t\tbottom = i + 1;\n-\t\t\t\t\t\ttop = bottom;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\t}\n+\t\t\tbottom = find_unique((*ptr)->buf, menu_stuff);\n+\t\t\ttop = bottom;\n \t\t}\n \n \t\tif (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||\ndiff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh\nindex 4e6055d..71c5c6b 100755\n--- a/t/t7301-clean-interactive.sh\n+++ b/t/t7301-clean-interactive.sh\n@@ -17,7 +17,7 @@ test_expect_success 'setup' '\n \n '\n \n-test_expect_success 'git clean -i (clean)' '\n+test_expect_success 'git clean -i (c: clean hotkey)' '\n \n \tmkdir -p build docs &&\n \ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n@@ -38,12 +38,33 @@ test_expect_success 'git clean -i (clean)' '\n \n '\n \n+test_expect_success 'git clean -i (cl: clean prefix)' '\n+\n+\tmkdir -p build docs &&\n+\ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n+\tdocs/manual.txt obj.o build/lib.so &&\n+\techo cl | git clean -i &&\n+\ttest -f Makefile &&\n+\ttest -f README &&\n+\ttest -f src/part1.c &&\n+\ttest -f src/part2.c &&\n+\ttest ! -f a.out &&\n+\ttest -f docs/manual.txt &&\n+\ttest ! -f src/part3.c &&\n+\ttest ! -f src/part3.h &&\n+\ttest ! -f src/part4.c &&\n+\ttest ! -f src/part4.h &&\n+\ttest -f obj.o &&\n+\ttest -f build/lib.so\n+\n+'\n+\n test_expect_success 'git clean -i (quit)' '\n \n \tmkdir -p build docs &&\n \ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n \tdocs/manual.txt obj.o build/lib.so &&\n-\techo q | git clean -i &&\n+\techo quit | git clean -i &&\n \ttest -f Makefile &&\n \ttest -f README &&\n \ttest -f src/part1.c &&\n@@ -256,6 +277,22 @@ test_expect_success 'git clean -id (select - number 3)' '\n \n '\n \n+test_expect_success 'git clean -id (select - filenames)' '\n+\n+\tmkdir -p build docs &&\n+\ttouch a.out foo.txt bar.txt baz.txt &&\n+\t(echo s; echo a.out fo ba bar; echo; echo c) | \\\n+\tgit clean -id &&\n+\tfind . > /tmp/x &&\n+\ttest -f Makefile &&\n+\ttest ! -f a.out &&\n+\ttest ! -f foo.txt &&\n+\ttest ! -f bar.txt &&\n+\ttest -f baz.txt &&\n+\trm baz.txt\n+\n+'\n+\n test_expect_success 'git clean -id (select - range)' '\n \n \tmkdir -p build docs &&\n-- \n1.8.3.4.842.g8e6673c\n"},{"id":"224018","messageId":"cover.1374632255.git.worldhello.net@gmail.com","threadId":"34524","inReplyTo":"d099b22989d6e7c023e160a6a9b232bc58e6349c.1374631307.git.worldhello.net@gmail.com","subject":"[PATCH v2] git-clean: implement partial matching for selection","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-07-24T02:22:03Z","receivedAt":"2013-07-24T02:22:03Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"In the 1st version of this patch, I forgot to remove a shell command for\ndebug in t7301:\n\n    find . > /tmp/x &&\n\nRemove the above command in this version. Sorry about this.\n\nJiang Xin (1):\n  git-clean: implement partial matching for selection\n\n builtin/clean.c              | 80 ++++++++++++++++++++++++++++----------------\n t/t7301-clean-interactive.sh | 40 ++++++++++++++++++++--\n 2 files changed, 90 insertions(+), 30 deletions(-)\n\n-- \n1.8.3.4.842.g8e6673c\n"},{"id":"224019","messageId":"81f7abd21d03b90bcf46237c3655e8aa6f5a13cd.1374632255.git.worldhello.net@gmail.com","threadId":"34524","inReplyTo":"cover.1374632255.git.worldhello.net@gmail.com","subject":"[PATCH v2] git-clean: implement partial matching for selection","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-07-24T02:22:04Z","receivedAt":"2013-07-24T02:22:04Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Document for interactive git-clean says: \"You also could say `c` or\n`clean` above as long as the choice is unique\". But it's not true,\nbecause only hotkey `c` and full match (`clean`) could work.\n\nImplement partial matching via find_unique function to make the\ndocument right.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/clean.c              | 80 ++++++++++++++++++++++++++++----------------\n t/t7301-clean-interactive.sh | 40 ++++++++++++++++++++--\n 2 files changed, 90 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex dba8387..3c85e15 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -365,6 +365,56 @@ static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)\n \tstring_list_clear(&menu_list, 0);\n }\n \n+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)\n+{\n+\tstruct menu_item *menu_item;\n+\tstruct string_list_item *string_list_item;\n+\tint i, len, found = 0;\n+\n+\tlen = strlen(choice);\n+\tswitch (menu_stuff->type) {\n+\tdefault:\n+\t\tdie(\"Bad type of menu_stuff when parse choice\");\n+\tcase MENU_STUFF_TYPE_MENU_ITEM:\n+\n+\t\tmenu_item = (struct menu_item *)menu_stuff->stuff;\n+\t\tfor (i = 0; i < menu_stuff->nr; i++, menu_item++) {\n+\t\t\tif (len == 1 && *choice == menu_item->hotkey) {\n+\t\t\t\tfound = i + 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (!strncasecmp(choice, menu_item->title, len)) {\n+\t\t\t\tif (found) {\n+\t\t\t\t\tif (len == 1) {\n+\t\t\t\t\t\t/* continue for hotkey matching */\n+\t\t\t\t\t\tfound = -1;\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tfound = 0;\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t} else {\n+\t\t\t\t\tfound = i + 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\tcase MENU_STUFF_TYPE_STRING_LIST:\n+\t\tstring_list_item = ((struct string_list *)menu_stuff->stuff)->items;\n+\t\tfor (i = 0; i < menu_stuff->nr; i++, string_list_item++) {\n+\t\t\tif (!strncasecmp(choice, string_list_item->string, len)) {\n+\t\t\t\tif (found) {\n+\t\t\t\t\tfound = 0;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\tfound = i + 1;\n+\t\t\t}\n+\t\t}\n+\t\tbreak;\n+\t}\n+\treturn found;\n+}\n+\n+\n /*\n  * Parse user input, and return choice(s) for menu (menu_stuff).\n  *\n@@ -392,8 +442,6 @@ static int parse_choice(struct menu_stuff *menu_stuff,\n \t\t\tint **chosen)\n {\n \tstruct strbuf **choice_list, **ptr;\n-\tstruct menu_item *menu_item;\n-\tstruct string_list_item *string_list_item;\n \tint nr = 0;\n \tint i;\n \n@@ -457,32 +505,8 @@ static int parse_choice(struct menu_stuff *menu_stuff,\n \t\t\tbottom = 1;\n \t\t\ttop = menu_stuff->nr;\n \t\t} else {\n-\t\t\tswitch (menu_stuff->type) {\n-\t\t\tdefault:\n-\t\t\t\tdie(\"Bad type of menu_stuff when parse choice\");\n-\t\t\tcase MENU_STUFF_TYPE_MENU_ITEM:\n-\t\t\t\tmenu_item = (struct menu_item *)menu_stuff->stuff;\n-\t\t\t\tfor (i = 0; i < menu_stuff->nr; i++, menu_item++) {\n-\t\t\t\t\tif (((*ptr)->len == 1 &&\n-\t\t\t\t\t     *(*ptr)->buf == menu_item->hotkey) ||\n-\t\t\t\t\t    !strcasecmp((*ptr)->buf, menu_item->title)) {\n-\t\t\t\t\t\tbottom = i + 1;\n-\t\t\t\t\t\ttop = bottom;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\tcase MENU_STUFF_TYPE_STRING_LIST:\n-\t\t\t\tstring_list_item = ((struct string_list *)menu_stuff->stuff)->items;\n-\t\t\t\tfor (i = 0; i < menu_stuff->nr; i++, string_list_item++) {\n-\t\t\t\t\tif (!strcasecmp((*ptr)->buf, string_list_item->string)) {\n-\t\t\t\t\t\tbottom = i + 1;\n-\t\t\t\t\t\ttop = bottom;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\tbreak;\n-\t\t\t}\n+\t\t\tbottom = find_unique((*ptr)->buf, menu_stuff);\n+\t\t\ttop = bottom;\n \t\t}\n \n \t\tif (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||\ndiff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh\nindex 4e6055d..3ae394e 100755\n--- a/t/t7301-clean-interactive.sh\n+++ b/t/t7301-clean-interactive.sh\n@@ -17,7 +17,7 @@ test_expect_success 'setup' '\n \n '\n \n-test_expect_success 'git clean -i (clean)' '\n+test_expect_success 'git clean -i (c: clean hotkey)' '\n \n \tmkdir -p build docs &&\n \ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n@@ -38,12 +38,33 @@ test_expect_success 'git clean -i (clean)' '\n \n '\n \n+test_expect_success 'git clean -i (cl: clean prefix)' '\n+\n+\tmkdir -p build docs &&\n+\ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n+\tdocs/manual.txt obj.o build/lib.so &&\n+\techo cl | git clean -i &&\n+\ttest -f Makefile &&\n+\ttest -f README &&\n+\ttest -f src/part1.c &&\n+\ttest -f src/part2.c &&\n+\ttest ! -f a.out &&\n+\ttest -f docs/manual.txt &&\n+\ttest ! -f src/part3.c &&\n+\ttest ! -f src/part3.h &&\n+\ttest ! -f src/part4.c &&\n+\ttest ! -f src/part4.h &&\n+\ttest -f obj.o &&\n+\ttest -f build/lib.so\n+\n+'\n+\n test_expect_success 'git clean -i (quit)' '\n \n \tmkdir -p build docs &&\n \ttouch a.out src/part3.c src/part3.h src/part4.c src/part4.h \\\n \tdocs/manual.txt obj.o build/lib.so &&\n-\techo q | git clean -i &&\n+\techo quit | git clean -i &&\n \ttest -f Makefile &&\n \ttest -f README &&\n \ttest -f src/part1.c &&\n@@ -256,6 +277,21 @@ test_expect_success 'git clean -id (select - number 3)' '\n \n '\n \n+test_expect_success 'git clean -id (select - filenames)' '\n+\n+\tmkdir -p build docs &&\n+\ttouch a.out foo.txt bar.txt baz.txt &&\n+\t(echo s; echo a.out fo ba bar; echo; echo c) | \\\n+\tgit clean -id &&\n+\ttest -f Makefile &&\n+\ttest ! -f a.out &&\n+\ttest ! -f foo.txt &&\n+\ttest ! -f bar.txt &&\n+\ttest -f baz.txt &&\n+\trm baz.txt\n+\n+'\n+\n test_expect_success 'git clean -id (select - range)' '\n \n \tmkdir -p build docs &&\n-- \n1.8.3.4.842.g8e6673c\n"}]}