{"thread":{"id":"50105","subject":"[PATCH] completion: escape metacharacters when completing paths","startedAt":"2018-12-26T16:09:00Z","lastAt":"2019-01-01T14:06:03Z","messageCount":6,"participants":["Chayoung You","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"365810","messageId":"20181226160835.66342-1-yousbe@gmail.com","threadId":"50105","inReplyTo":null,"subject":"[PATCH] completion: escape metacharacters when completing paths","fromName":"Chayoung You","fromEmail":"yousbe@gmail.com","sentAt":"2018-12-26T16:08:35Z","receivedAt":"2018-12-26T16:09:00Z","isPatch":true,"sender":{"key":"yousbe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/853977?v=4"},"body":"The following is the description of -Q flag of zsh compadd [1]:\n\n  This flag instructs the completion code not to quote any\n  metacharacters in the words when inserting them into the command line.\n\nLet's say there is a file named 'foo bar.txt' in repository, but it's\nnot yet added to the repository. Then the following command triggers a\ncompletion:\n\n  git add fo<Tab>\n  git add 'fo<Tab>\n  git add \"fo<Tab>\n\nThe completion results in bash:\n\n  git add foo\\ bar.txt\n  git add 'foo bar.txt'\n  git add \"foo bar.txt\"\n\nWhile them in zsh:\n\n  git add foo bar.txt\n  git add 'foo bar.txt'\n  git add \"foo bar.txt\"\n\nThe main cause of this behavior is __gitcomp_file_direct(). The both\nimplementions of bash and zsh are called with an argument 'foo bar.txt',\nbut only bash adds a backslash before a space on command line.\n\n[1]: http://zsh.sourceforge.net/Doc/Release/Completion-Widgets.html\n\nSigned-off-by: Chayoung You <yousbe@gmail.com>\n---\n contrib/completion/git-completion.bash | 4 ++--\n contrib/completion/git-completion.zsh  | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 9e8ec95c3..816ee3280 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2993,7 +2993,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -f -- ${=1} && _ret=0\n+\t\tcompadd -f -- ${=1} && _ret=0\n \t}\n \n \t__gitcomp_file ()\n@@ -3002,7 +3002,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\t\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n \t}\n \n \t_git ()\ndiff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh\nindex 049d6b80f..886bf95d1 100644\n--- a/contrib/completion/git-completion.zsh\n+++ b/contrib/completion/git-completion.zsh\n@@ -99,7 +99,7 @@ __gitcomp_file_direct ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -f -- ${=1} && _ret=0\n+\tcompadd -f -- ${=1} && _ret=0\n }\n \n __gitcomp_file ()\n@@ -108,7 +108,7 @@ __gitcomp_file ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n }\n \n __git_zsh_bash_func ()\n-- \n2.20.1\n\n"},{"id":"365935","messageId":"xmqqefa1kzcp.fsf@gitster-ct.c.googlers.com","threadId":"50105","inReplyTo":"20181226160835.66342-1-yousbe@gmail.com","subject":"Re: [PATCH] completion: escape metacharacters when completing paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-28T23:25:58Z","receivedAt":"2018-12-28T23:26:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chayoung You <yousbe@gmail.com> writes:\n\n> Subject: Re: [PATCH] completion: escape metacharacters when completing paths\n\nI am not a zsh user, but from the patch text I am getting the\nimpression that this patch is only about zsh.  If so, please help\nreaders of \"git shortlog\" by saying so in the title.\n\n\tSubject: zsh: complete unquoted paths with spaces correctly\n\nor something like that, perhaps?\n\n> Let's say there is a file named 'foo bar.txt' in repository, but it's\n> not yet added to the repository. Then the following command triggers a\n> completion:\n>\n>   git add fo<Tab>\n>   git add 'fo<Tab>\n>   git add \"fo<Tab>\n>\n> The completion results in bash:\n>\n>   git add foo\\ bar.txt\n>   git add 'foo bar.txt'\n>   git add \"foo bar.txt\"\n>\n> While them in zsh:\n>\n>   git add foo bar.txt\n>   git add 'foo bar.txt'\n>   git add \"foo bar.txt\"\n\nYou leave it unsaid what you think is wrong, and what you think\nshould be the right output, before saying \"cause of this is...\".\n\nI do not think it is given that \"git add fo<TAB>\" should be\ncompleted to \"git add foo\\ bar.txt\".  It would also be OK if the\ncompletion produced \"git add 'foo bar.txt'\", for example.  So what\nyour ideal output is is rather important, and by doing that you end\nup with saying what problem you have with the current output is.\n\nSo, say something here, perhaps like...\n\n\tThe first one, where the pathname is not enclosed in quotes,\n\tshould escape the SP with a backslash, just like bash\n\tcompletion does.\n\n"},{"id":"365983","messageId":"20181230053125.55896-1-yousbe@gmail.com","threadId":"50105","inReplyTo":"xmqqefa1kzcp.fsf@gitster-ct.c.googlers.com","subject":"[PATCH v2] zsh: complete unquoted paths with spaces correctly","fromName":"Chayoung You","fromEmail":"yousbe@gmail.com","sentAt":"2018-12-30T05:31:26Z","receivedAt":"2018-12-30T05:45:21Z","isPatch":true,"sender":{"key":"yousbe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/853977?v=4"},"body":"The following is the description of -Q flag of zsh compadd [1]:\n\n    This flag instructs the completion code not to quote any\n    metacharacters in the words when inserting them into the command\n    line.\n\nLet's say there is a file named 'foo bar.txt' in repository, but it's\nnot yet added to the repository. Then the following command triggers a\ncompletion:\n\n    git add fo<Tab>\n    git add 'fo<Tab>\n    git add \"fo<Tab>\n\nThe completion results in bash:\n\n    git add foo\\ bar.txt\n    git add 'foo bar.txt'\n    git add \"foo bar.txt\"\n\nWhile them in zsh:\n\n    git add foo bar.txt\n    git add 'foo bar.txt'\n    git add \"foo bar.txt\"\n\nThe first one, where the pathname is not enclosed in quotes, should\nescape the space with a backslash, just like bash completion does.\nOtherwise, this leads git to think there are two files; foo, and\nbar.txt.\n\nThe main cause of this behavior is __gitcomp_file_direct(). The both\nimplementions of bash and zsh are called with an argument 'foo bar.txt',\nbut only bash adds a backslash before a space on command line.\n\n[1]: http://zsh.sourceforge.net/Doc/Release/Completion-Widgets.html\n\nSigned-off-by: Chayoung You <yousbe@gmail.com>\nReviewed-by: Junio C Hamano <gitster@pobox.com>\n---\n contrib/completion/git-completion.bash | 4 ++--\n contrib/completion/git-completion.zsh  | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 9e8ec95c3..816ee3280 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2993,7 +2993,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -f -- ${=1} && _ret=0\n+\t\tcompadd -f -- ${=1} && _ret=0\n \t}\n \n \t__gitcomp_file ()\n@@ -3002,7 +3002,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\t\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n \t}\n \n \t_git ()\ndiff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh\nindex 049d6b80f..886bf95d1 100644\n--- a/contrib/completion/git-completion.zsh\n+++ b/contrib/completion/git-completion.zsh\n@@ -99,7 +99,7 @@ __gitcomp_file_direct ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -f -- ${=1} && _ret=0\n+\tcompadd -f -- ${=1} && _ret=0\n }\n \n __gitcomp_file ()\n@@ -108,7 +108,7 @@ __gitcomp_file ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n }\n \n __git_zsh_bash_func ()\n-- \n2.20.1\n\n"},{"id":"366018","messageId":"20190101140509.1857-1-yousbe@gmail.com","threadId":"50105","inReplyTo":"20181230053125.55896-1-yousbe@gmail.com","subject":"[PATCH v3 0/2] completion: handle paths with spaces correctly","fromName":"Chayoung You","fromEmail":"yousbe@gmail.com","sentAt":"2019-01-01T14:05:07Z","receivedAt":"2019-01-01T14:05:54Z","isPatch":true,"sender":{"key":"yousbe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/853977?v=4"},"body":"I found more issues with completion for git show ref:path, so here I add one\nmore patch.\n\nChayoung You (2):\n  zsh: complete unquoted paths with spaces correctly\n  completion: treat results of git ls-tree as file paths\n\n contrib/completion/git-completion.bash | 35 +++++++++++---------------\n contrib/completion/git-completion.zsh  |  4 +--\n t/t9902-completion.sh                  | 10 ++++----\n 3 files changed, 21 insertions(+), 28 deletions(-)\n\n-- \n2.17.1\n\n"},{"id":"366019","messageId":"20190101140509.1857-2-yousbe@gmail.com","threadId":"50105","inReplyTo":"20190101140509.1857-1-yousbe@gmail.com","subject":"[PATCH v3 1/2] zsh: complete unquoted paths with spaces correctly","fromName":"Chayoung You","fromEmail":"yousbe@gmail.com","sentAt":"2019-01-01T14:05:08Z","receivedAt":"2019-01-01T14:06:01Z","isPatch":true,"sender":{"key":"yousbe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/853977?v=4"},"body":"The following is the description of -Q flag of zsh compadd [1]:\n\n    This flag instructs the completion code not to quote any\n    metacharacters in the words when inserting them into the command\n    line.\n\nLet's say there is a file named 'foo bar.txt' in repository, but it's\nnot yet added to the repository. Then the following command triggers a\ncompletion:\n\n    git add fo<Tab>\n    git add 'fo<Tab>\n    git add \"fo<Tab>\n\nThe completion results in bash:\n\n    git add foo\\ bar.txt\n    git add 'foo bar.txt'\n    git add \"foo bar.txt\"\n\nWhile them in zsh:\n\n    git add foo bar.txt\n    git add 'foo bar.txt'\n    git add \"foo bar.txt\"\n\nThe first one, where the pathname is not enclosed in quotes, should\nescape the space with a backslash, just like bash completion does.\nOtherwise, this leads git to think there are two files; foo, and\nbar.txt.\n\nThe main cause of this behavior is __gitcomp_file_direct(). The both\nimplementions of bash and zsh are called with an argument 'foo bar.txt',\nbut only bash adds a backslash before a space on command line.\n\n[1]: http://zsh.sourceforge.net/Doc/Release/Completion-Widgets.html\n\nSigned-off-by: Chayoung You <yousbe@gmail.com>\nReviewed-by: Junio C Hamano <gitster@pobox.com>\n---\n contrib/completion/git-completion.bash | 4 ++--\n contrib/completion/git-completion.zsh  | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 9e8ec95c3..816ee3280 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2993,7 +2993,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -f -- ${=1} && _ret=0\n+\t\tcompadd -f -- ${=1} && _ret=0\n \t}\n \n \t__gitcomp_file ()\n@@ -3002,7 +3002,7 @@ if [[ -n ${ZSH_VERSION-} ]] &&\n \n \t\tlocal IFS=$'\\n'\n \t\tcompset -P '*[=:]'\n-\t\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\t\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n \t}\n \n \t_git ()\ndiff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh\nindex 049d6b80f..886bf95d1 100644\n--- a/contrib/completion/git-completion.zsh\n+++ b/contrib/completion/git-completion.zsh\n@@ -99,7 +99,7 @@ __gitcomp_file_direct ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -f -- ${=1} && _ret=0\n+\tcompadd -f -- ${=1} && _ret=0\n }\n \n __gitcomp_file ()\n@@ -108,7 +108,7 @@ __gitcomp_file ()\n \n \tlocal IFS=$'\\n'\n \tcompset -P '*[=:]'\n-\tcompadd -Q -p \"${2-}\" -f -- ${=1} && _ret=0\n+\tcompadd -p \"${2-}\" -f -- ${=1} && _ret=0\n }\n \n __git_zsh_bash_func ()\n-- \n2.17.1\n\n"},{"id":"366020","messageId":"20190101140509.1857-3-yousbe@gmail.com","threadId":"50105","inReplyTo":"20190101140509.1857-1-yousbe@gmail.com","subject":"[PATCH v3 2/2] completion: treat results of git ls-tree as file paths","fromName":"Chayoung You","fromEmail":"yousbe@gmail.com","sentAt":"2019-01-01T14:05:09Z","receivedAt":"2019-01-01T14:06:03Z","isPatch":true,"sender":{"key":"yousbe@gmail.com","avatar":"https://avatars.githubusercontent.com/u/853977?v=4"},"body":"Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in\nrepository. When following commands trigger a completion:\n\n    git show HEAD:fo<Tab>\n    git show HEAD:ab<Tab>\n\nThe completion results in bash/zsh:\n\n    git show HEAD:foo bar.txt\n    git show HEAD:abc def/\n\nWhere the both of them have an unescaped space in paths, so they'll be\nmisread by git. All entries of git ls-tree either a filename or a\ndirectory, so __gitcomp_file() is proper rather than __gitcomp_nl().\n\nNote the commit f12785a3, which handles quoted paths properly. Like this\ncase, we should dequote $cur_ for ?*:* case. For example, let's say\nthere is untracked directory 'abc deg', then trigger a completion:\n\n    git show HEAD:abc\\ de<Tab>\n    git show HEAD:'abc de<Tab>\n    git show HEAD:\"abc de<Tab>\n\nshould uniquely complete 'abc def', but bash completes 'abc def' and\n'abc deg' instead. In zsh, triggering a completion:\n\n    git show HEAD:abc\\ def/<Tab>\n\nshould complete 'test.txt', but nothing comes. The both problems will be\nresolved by dequoting paths.\n\n__git_complete_revlist_file() passes arguments to __gitcomp_nl() where\nthe first one is a list something like:\n\n    abc def/Z\n    foo bar.txt Z\n\nwhere Z is the mark of the EOL.\n\n- The trailing space of blob in __git ls-tree | sed.\n  It makes the completion results become:\n\n      git show HEAD:foo\\ bar.txt\\ <CURSOR>\n\n  So git will try to find a file named 'foo bar.txt ' instead.\n\n- The trailing slash of tree in __git ls-tree | sed.\n  It makes the completion results on zsh become:\n\n      git show HEAD:abc\\ def/ <CURSOR>\n\n  So that the last space on command like should be removed on zsh to\n  complete filenames under 'abc def/'.\n\nSigned-off-by: Chayoung You <yousbe@gmail.com>\n---\n contrib/completion/git-completion.bash | 31 ++++++++++----------------\n t/t9902-completion.sh                  | 10 ++++-----\n 2 files changed, 17 insertions(+), 24 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 816ee3280..26ea310fd 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -855,7 +855,7 @@ __git_compute_merge_strategies ()\n \n __git_complete_revlist_file ()\n {\n-\tlocal pfx ls ref cur_=\"$cur\"\n+\tlocal dequoted_word pfx ls ref cur_=\"$cur\"\n \tcase \"$cur_\" in\n \t*..?*:*)\n \t\treturn\n@@ -863,14 +863,18 @@ __git_complete_revlist_file ()\n \t?*:*)\n \t\tref=\"${cur_%%:*}\"\n \t\tcur_=\"${cur_#*:}\"\n-\t\tcase \"$cur_\" in\n+\n+\t\t__git_dequote \"$cur_\"\n+\n+\t\tcase \"$dequoted_word\" in\n \t\t?*/*)\n-\t\t\tpfx=\"${cur_%/*}\"\n-\t\t\tcur_=\"${cur_##*/}\"\n+\t\t\tpfx=\"${dequoted_word%/*}\"\n+\t\t\tcur_=\"${dequoted_word##*/}\"\n \t\t\tls=\"$ref:$pfx\"\n \t\t\tpfx=\"$pfx/\"\n \t\t\t;;\n \t\t*)\n+\t\t\tcur_=\"$dequoted_word\"\n \t\t\tls=\"$ref\"\n \t\t\t;;\n \t\tesac\n@@ -880,21 +884,10 @@ __git_complete_revlist_file ()\n \t\t*)   pfx=\"$ref:$pfx\" ;;\n \t\tesac\n \n-\t\t__gitcomp_nl \"$(__git ls-tree \"$ls\" \\\n-\t\t\t\t| sed '/^100... blob /{\n-\t\t\t\t           s,^.*\t,,\n-\t\t\t\t           s,$, ,\n-\t\t\t\t       }\n-\t\t\t\t       /^120000 blob /{\n-\t\t\t\t           s,^.*\t,,\n-\t\t\t\t           s,$, ,\n-\t\t\t\t       }\n-\t\t\t\t       /^040000 tree /{\n-\t\t\t\t           s,^.*\t,,\n-\t\t\t\t           s,$,/,\n-\t\t\t\t       }\n-\t\t\t\t       s/^.*\t//')\" \\\n-\t\t\t\"$pfx\" \"$cur_\" \"\"\n+\t\t__gitcomp_file \"$(__git ls-tree \"$ls\" \\\n+\t\t\t\t| sed 's/^.*\t//\n+\t\t\t\t       s/$//')\" \\\n+\t\t\t\"$pfx\" \"$cur_\"\n \t\t;;\n \t*...*)\n \t\tpfx=\"${cur_%...*}...\"\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 137fdc9bd..94157e587 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1515,8 +1515,8 @@ test_expect_success 'show completes all refs' '\n \n test_expect_success '<ref>: completes paths' '\n \ttest_completion \"git show mytag:f\" <<-\\EOF\n-\tfile1 Z\n-\tfile2 Z\n+\tfile1Z\n+\tfile2Z\n \tEOF\n '\n \n@@ -1525,7 +1525,7 @@ test_expect_success 'complete tree filename with spaces' '\n \tgit add \"name with spaces\" &&\n \tgit commit -m spaces &&\n \ttest_completion \"git show HEAD:nam\" <<-\\EOF\n-\tname with spaces Z\n+\tname with spacesZ\n \tEOF\n '\n \n@@ -1534,8 +1534,8 @@ test_expect_success 'complete tree filename with metacharacters' '\n \tgit add \"name with \\${meta}\" &&\n \tgit commit -m meta &&\n \ttest_completion \"git show HEAD:nam\" <<-\\EOF\n-\tname with ${meta} Z\n-\tname with spaces Z\n+\tname with ${meta}Z\n+\tname with spacesZ\n \tEOF\n '\n \n-- \n2.17.1\n\n"}]}