{"thread":{"id":"54610","subject":"[PATCH v3 0/2] completion: bash: support for recursive aliases","startedAt":"2020-11-10T02:03:47Z","lastAt":"2020-11-12T17:21:01Z","messageCount":5,"participants":["Felipe Contreras","SZEDER Gábor","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":2},"messages":[{"id":"409456","messageId":"20201110020343.548848-1-felipe.contreras@gmail.com","threadId":"54610","inReplyTo":null,"subject":"[PATCH v3 0/2] completion: bash: support for recursive aliases","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-11-10T02:03:41Z","receivedAt":"2020-11-10T02:03:47Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Hello,\n\nAs Philippe reported, aliases of aliases are not completed correctly in the\nBash completion. This patch series attempts to fix that problem.\n\nSince v2:\n\n * Reshuffle the commits to have a simplified history\n\n\nFelipe Contreras (2):\n  completion: bash: support recursive aliases\n  completion: bash: check for alias loop\n\n contrib/completion/git-completion.bash | 53 +++++++++++++++++---------\n t/t9902-completion.sh                  | 19 +++++++++\n 2 files changed, 54 insertions(+), 18 deletions(-)\n\n-- \n2.29.2\n\n"},{"id":"409457","messageId":"20201110020343.548848-2-felipe.contreras@gmail.com","threadId":"54610","inReplyTo":"20201110020343.548848-1-felipe.contreras@gmail.com","subject":"[PATCH v3 1/2] completion: bash: support recursive aliases","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-11-10T02:03:42Z","receivedAt":"2020-11-10T02:03:50Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"It is possible to have recursive aliases like:\n\n  l = log --oneline\n  lg = l --graph\n\nSo the completion should detect such aliases as well.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/completion/git-completion.bash | 50 ++++++++++++++++----------\n t/t9902-completion.sh                  | 19 ++++++++++\n 2 files changed, 50 insertions(+), 19 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 36f5a91c7a..eb00d9ba22 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1121,26 +1121,38 @@ __git_pretty_aliases ()\n # __git_aliased_command requires 1 argument\n __git_aliased_command ()\n {\n-\tlocal word cmdline=$(__git config --get \"alias.$1\")\n-\tfor word in $cmdline; do\n-\t\tcase \"$word\" in\n-\t\t\\!gitk|gitk)\n-\t\t\techo \"gitk\"\n-\t\t\treturn\n-\t\t\t;;\n-\t\t\\!*)\t: shell command alias ;;\n-\t\t-*)\t: option ;;\n-\t\t*=*)\t: setting env ;;\n-\t\tgit)\t: git itself ;;\n-\t\t\\(\\))   : skip parens of shell function definition ;;\n-\t\t{)\t: skip start of shell helper function ;;\n-\t\t:)\t: skip null command ;;\n-\t\t\\'*)\t: skip opening quote after sh -c ;;\n-\t\t*)\n-\t\t\techo \"$word\"\n-\t\t\treturn\n-\t\tesac\n+\tlocal cur=$1 last word cmdline\n+\n+\twhile [[ -n \"$cur\" ]]; do\n+\t\tcmdline=$(__git config --get \"alias.$cur\")\n+\t\tlast=$cur\n+\t\tcur=\n+\n+\t\tfor word in $cmdline; do\n+\t\t\tcase \"$word\" in\n+\t\t\t\\!gitk|gitk)\n+\t\t\t\tcur=\"gitk\"\n+\t\t\t\tbreak\n+\t\t\t\t;;\n+\t\t\t\\!*)\t: shell command alias ;;\n+\t\t\t-*)\t: option ;;\n+\t\t\t*=*)\t: setting env ;;\n+\t\t\tgit)\t: git itself ;;\n+\t\t\t\\(\\))   : skip parens of shell function definition ;;\n+\t\t\t{)\t: skip start of shell helper function ;;\n+\t\t\t:)\t: skip null command ;;\n+\t\t\t\\'*)\t: skip opening quote after sh -c ;;\n+\t\t\t*)\n+\t\t\t\tcur=\"$word\"\n+\t\t\t\tbreak\n+\t\t\tesac\n+\t\tdone\n \tdone\n+\n+\tcur=$last\n+\tif [[ \"$cur\" != \"$1\" ]]; then\n+\t\techo \"$cur\"\n+\tfi\n }\n \n # Check whether one of the given words is present on the command line,\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 4e943393cf..0e2db6e7fa 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -2195,6 +2195,25 @@ test_expect_success 'complete files' '\n \ttest_completion \"git add mom\" \"momified\"\n '\n \n+test_expect_success \"simple alias\" '\n+\ttest_config alias.co checkout &&\n+\ttest_completion \"git co m\" <<-\\EOF\n+\tmaster Z\n+\tmybranch Z\n+\tmytag Z\n+\tEOF\n+'\n+\n+test_expect_success \"recursive alias\" '\n+\ttest_config alias.co checkout &&\n+\ttest_config alias.cod \"co --detached\" &&\n+\ttest_completion \"git cod m\" <<-\\EOF\n+\tmaster Z\n+\tmybranch Z\n+\tmytag Z\n+\tEOF\n+'\n+\n test_expect_success \"completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'\" '\n \ttest_config alias.co \"!sh -c '\"'\"'git checkout ...'\"'\"'\" &&\n \ttest_completion \"git co m\" <<-\\EOF\n-- \n2.29.2\n\n"},{"id":"409458","messageId":"20201110020343.548848-3-felipe.contreras@gmail.com","threadId":"54610","inReplyTo":"20201110020343.548848-1-felipe.contreras@gmail.com","subject":"[PATCH v3 2/2] completion: bash: check for alias loop","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2020-11-10T02:03:43Z","receivedAt":"2020-11-10T02:03:52Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"We don't want to be stuck in an endless cycle.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/completion/git-completion.bash | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex eb00d9ba22..ce0dc1e0f8 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1121,11 +1121,16 @@ __git_pretty_aliases ()\n # __git_aliased_command requires 1 argument\n __git_aliased_command ()\n {\n-\tlocal cur=$1 last word cmdline\n+\tlocal cur=$1 list word cmdline\n \n \twhile [[ -n \"$cur\" ]]; do\n+\t\tif [[ \"$list\" == *\"$cur \"* ]]; then\n+\t\t\t# loop detected\n+\t\t\treturn\n+\t\tfi\n+\n \t\tcmdline=$(__git config --get \"alias.$cur\")\n-\t\tlast=$cur\n+\t\tlist=\"$cur $list\"\n \t\tcur=\n \n \t\tfor word in $cmdline; do\n@@ -1149,7 +1154,7 @@ __git_aliased_command ()\n \t\tdone\n \tdone\n \n-\tcur=$last\n+\tcur=\"${list%% *}\"\n \tif [[ \"$cur\" != \"$1\" ]]; then\n \t\techo \"$cur\"\n \tfi\n-- \n2.29.2\n\n"},{"id":"409750","messageId":"20201112100204.GC4270@szeder.dev","threadId":"54610","inReplyTo":"20201110020343.548848-3-felipe.contreras@gmail.com","subject":"Re: [PATCH v3 2/2] completion: bash: check for alias loop","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-11-12T10:02:04Z","receivedAt":"2020-11-12T10:02:12Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Mon, Nov 09, 2020 at 08:03:43PM -0600, Felipe Contreras wrote:\n> We don't want to be stuck in an endless cycle.\n> \n> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n> ---\n>  contrib/completion/git-completion.bash | 11 ++++++++---\n>  1 file changed, 8 insertions(+), 3 deletions(-)\n> \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index eb00d9ba22..ce0dc1e0f8 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -1121,11 +1121,16 @@ __git_pretty_aliases ()\n>  # __git_aliased_command requires 1 argument\n>  __git_aliased_command ()\n>  {\n> -\tlocal cur=$1 last word cmdline\n> +\tlocal cur=$1 list word cmdline\n>  \n>  \twhile [[ -n \"$cur\" ]]; do\n> +\t\tif [[ \"$list\" == *\"$cur \"* ]]; then\n\nI suspect the right hand side should be *\" $cur \"* ...\n\n> +\t\t\t# loop detected\n> +\t\t\treturn\n> +\t\tfi\n> +\n>  \t\tcmdline=$(__git config --get \"alias.$cur\")\n> -\t\tlast=$cur\n> +\t\tlist=\"$cur $list\"\n\n... and this should be list=\" $cur $list\", because otherwise a partial\nmatch is possible and would be mistaken for a loop (though I didn't\nactually test whether that's indeed the case).\n\n>  \t\tcur=\n>  \n>  \t\tfor word in $cmdline; do\n> @@ -1149,7 +1154,7 @@ __git_aliased_command ()\n>  \t\tdone\n>  \tdone\n>  \n> -\tcur=$last\n> +\tcur=\"${list%% *}\"\n>  \tif [[ \"$cur\" != \"$1\" ]]; then\n>  \t\techo \"$cur\"\n>  \tfi\n> -- \n> 2.29.2\n> \n"},{"id":"409773","messageId":"xmqqsg9ejxu0.fsf@gitster.c.googlers.com","threadId":"54610","inReplyTo":"20201112100204.GC4270@szeder.dev","subject":"Re: [PATCH v3 2/2] completion: bash: check for alias loop","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-11-12T17:20:55Z","receivedAt":"2020-11-12T17:21:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n>>  \twhile [[ -n \"$cur\" ]]; do\n>> +\t\tif [[ \"$list\" == *\"$cur \"* ]]; then\n>\n> I suspect the right hand side should be *\" $cur \"* ...\n>\n>> +\t\t\t# loop detected\n>> +\t\t\treturn\n>> +\t\tfi\n>> +\n>>  \t\tcmdline=$(__git config --get \"alias.$cur\")\n>> -\t\tlast=$cur\n>> +\t\tlist=\"$cur $list\"\n>\n> ... and this should be list=\" $cur $list\", because otherwise a partial\n> match is possible and would be mistaken for a loop (though I didn't\n> actually test whether that's indeed the case).\n\nTraditionist may use\n\n\tlist=\n\twhile :\n\tdo\n\t\tcur=$(obtain cur somehow)\n                case \" $list \" in\n                *\" $cur \"*) : cur appears in list ;;\n                esac\n                list=\"$cur${list+ }$list\"\n\tdone\n\nto make the invariant \"$list is a SP-separated tokens, no extra SP on\neither ends\" and I think the same idea would work with [[ $a == $b ]],\nbut \"one SP on both ends, two SPs in between\" like yours do is OK, too.\n\nNot keeping excess SPs out of the list (unlike the above \"no extra\nSP on ends\") means how \"finally, take the first token in the list,\nthat's the answer\" is coded, though.  You'd need to split off the\nleading SP from it (below).\n\n>>  \t\tcur=\n>>  \n>>  \t\tfor word in $cmdline; do\n>> @@ -1149,7 +1154,7 @@ __git_aliased_command ()\n>>  \t\tdone\n>>  \tdone\n>>  \n>> -\tcur=$last\n>> +\tcur=\"${list%% *}\"\n>>  \tif [[ \"$cur\" != \"$1\" ]]; then\n>>  \t\techo \"$cur\"\n>>  \tfi\n>> -- \n>> 2.29.2\n>> \n"}]}