{"thread":{"id":"52058","subject":"[PATCH 0/6] completion: improve completion for 'git worktree'","startedAt":"2019-10-17T17:35:13Z","lastAt":"2019-12-19T15:09:46Z","messageCount":22,"participants":["SZEDER Gábor","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"384272","messageId":"20191017173501.3198-1-szeder.dev@gmail.com","threadId":"52058","inReplyTo":null,"subject":"[PATCH 0/6] completion: improve completion for 'git worktree'","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:34:55Z","receivedAt":"2019-10-17T17:35:13Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete paths of working trees and refs for 'git worktree's various\nsubcommands.\n\nThe last two patches do the actual improvements, the first four are\npreparatory steps.\n\nAn early version of the last patch was already sent to the list as a\nPoC over four years ago [1], but I didn't like the part completing\noptions for 'git worktree add', and thus never seriously submitted it.\nI still don't really like that part :), but it is really useful when\nworking with working trees, and at least other parts of the completion\nfunction got simpler (thanks to automagically completing --options\nvia parse-options, and after the preparatory steps in this series).\n\n\n[1] https://public-inbox.org/git/1440190256-21794-1-git-send-email-szeder@ira.uka.de/\n\n\nSZEDER Gábor (6):\n  t9902-completion: add tests for the __git_find_on_cmdline() helper\n  completion: clean up the __git_find_on_cmdline() helper function\n  completion: return the index of found word from\n    __git_find_on_cmdline()\n  completion: simplify completing 'git worktree' subcommands and options\n  completion: list existing working trees for 'git worktree' subcommands\n  completion: list paths and refs for 'git worktree add'\n\n contrib/completion/git-completion.bash | 117 +++++++++++++++++++------\n t/t9902-completion.sh                  |  57 ++++++++++++\n 2 files changed, 148 insertions(+), 26 deletions(-)\n\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384273","messageId":"20191017173501.3198-2-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 1/6] t9902-completion: add tests for the __git_find_on_cmdline() helper","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:34:56Z","receivedAt":"2019-10-17T17:35:15Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The following two patches will refactor and extend the\n__git_find_on_cmdline() helper function, so let's add a few tests\nfirst to make sure that its basic behavior doesn't change.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n t/t9902-completion.sh | 28 ++++++++++++++++++++++++++++\n 1 file changed, 28 insertions(+)\n\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 54f8ce18cb..847ce601d2 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1363,6 +1363,34 @@ test_expect_success 'teardown after path completion tests' '\n \t       BS\\\\dir '$'separators\\034in\\035dir''\n '\n \n+test_expect_success '__git_find_on_cmdline - single match' '\n+\techo list >expect &&\n+\t(\n+\t\twords=(git command --opt list) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - multiple matches' '\n+\techo remove >expect &&\n+\t(\n+\t\twords=(git command -o --opt remove list add) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - no match' '\n+\t(\n+\t\twords=(git command --opt branch) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_must_be_empty actual\n+'\n \n test_expect_success '__git_get_config_variables' '\n \tcat >expect <<-EOF &&\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384274","messageId":"20191017173501.3198-3-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 2/6] completion: clean up the __git_find_on_cmdline() helper function","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:34:57Z","receivedAt":"2019-10-17T17:35:16Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The __git_find_on_cmdline() helper function started its life as\n__git_find_subcommand() [1], but it served a more general purpose than\nlooking for subcommands, so later it was renamed accordingly [2].\nHowever, that rename didn't touch the body of the function, and left\nthe $subcommand local variable behind, still reminiscent of the\nfunction's original purpose.\n\nLet's clean up the names of __git_find_on_cmdline()'s local variables\nand get rid of that $subcommand variable name.\n\nWhile at it, add a short comment describing the function's purpose.\n\n[1] 3ff1320d4b (bash: refactor searching for subcommands on the\n    command line, 2008-03-10),\n[2] 918c03c2a7 (bash: rename __git_find_subcommand() to\n    __git_find_on_cmdline(), 2009-09-15)\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 13 ++++++++-----\n 1 file changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 00fbe6c03d..2384f91e78 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1070,14 +1070,17 @@ __git_aliased_command ()\n }\n \n # __git_find_on_cmdline requires 1 argument\n+# Check whether one of the given words is present on the command line,\n+# and print the first word found.\n __git_find_on_cmdline ()\n {\n-\tlocal word subcommand c=1\n+\tlocal word c=1\n+\tlocal wordlist=\"$1\"\n+\n \twhile [ $c -lt $cword ]; do\n-\t\tword=\"${words[c]}\"\n-\t\tfor subcommand in $1; do\n-\t\t\tif [ \"$subcommand\" = \"$word\" ]; then\n-\t\t\t\techo \"$subcommand\"\n+\t\tfor word in $wordlist; do\n+\t\t\tif [ \"$word\" = \"${words[c]}\" ]; then\n+\t\t\t\techo \"$word\"\n \t\t\t\treturn\n \t\t\tfi\n \t\tdone\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384275","messageId":"20191017173501.3198-4-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:34:58Z","receivedAt":"2019-10-17T17:35:18Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When using the __git_find_on_cmdline() helper function so far we've\nonly been interested in which one of a set of words appear on the\ncommand line.  To complete options for some of 'git worktree's\nsubcommands in the following patches we'll need not only that, but the\nindex of that word on the command line as well.\n\nExtend __git_find_on_cmdline() to optionally show the index of the\nfound word on the command line (IOW in the $words array) when the\n'--show-idx' option is given.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 20 +++++++++++++++---\n t/t9902-completion.sh                  | 29 ++++++++++++++++++++++++++\n 2 files changed, 46 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2384f91e78..55a2d3e174 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1069,18 +1069,32 @@ __git_aliased_command ()\n \tdone\n }\n \n-# __git_find_on_cmdline requires 1 argument\n # Check whether one of the given words is present on the command line,\n # and print the first word found.\n+#\n+# Usage: __git_find_on_cmdline [<option>]... \"<wordlist>\"\n+# --show-idx: Optionally show the index of the found word in the $words array.\n __git_find_on_cmdline ()\n {\n-\tlocal word c=1\n+\tlocal word c=1 show_idx\n+\n+\twhile test $# -gt 1; do\n+\t\tcase \"$1\" in\n+\t\t--show-idx)\tshow_idx=y ;;\n+\t\t*)\t\treturn 1 ;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \tlocal wordlist=\"$1\"\n \n \twhile [ $c -lt $cword ]; do\n \t\tfor word in $wordlist; do\n \t\t\tif [ \"$word\" = \"${words[c]}\" ]; then\n-\t\t\t\techo \"$word\"\n+\t\t\t\tif [ -n \"$show_idx\" ]; then\n+\t\t\t\t\techo \"$c $word\"\n+\t\t\t\telse\n+\t\t\t\t\techo \"$word\"\n+\t\t\t\tfi\n \t\t\t\treturn\n \t\t\tfi\n \t\tdone\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 847ce601d2..3e3299819a 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1392,6 +1392,35 @@ test_expect_success '__git_find_on_cmdline - no match' '\n \ttest_must_be_empty actual\n '\n \n+test_expect_success '__git_find_on_cmdline - single match with index' '\n+\techo \"3 list\" >expect &&\n+\t(\n+\t\twords=(git command --opt list) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - multiple matches with index' '\n+\techo \"4 remove\" >expect &&\n+\t(\n+\t\twords=(git command -o --opt remove list add) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - no match with index' '\n+\t(\n+\t\twords=(git command --opt branch) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_must_be_empty actual\n+'\n+\n test_expect_success '__git_get_config_variables' '\n \tcat >expect <<-EOF &&\n \tname-1\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384276","messageId":"20191017173501.3198-7-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 6/6] completion: list paths and refs for 'git worktree add'","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:35:01Z","receivedAt":"2019-10-17T17:35:20Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete paths after 'git worktree add <TAB>' and refs after 'git\nworktree add -b <TAB>' and 'git worktree add some/dir <TAB>'.\n\nUncharacteristically for a Git command, 'git worktree add' takes a\nmandatory path parameter before a commit-ish as its optional last\nparameter.  In addition, it has both standalone --options and options\nwith a mandatory unstuck parameter ('-b <new-branch>').  Consequently,\ntrying to complete refs for that last optional commit-ish parameter\nresulted in a more convoluted than usual completion function, but\nhopefully all the included comments will make it not too hard to\ndigest.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 36 ++++++++++++++++++++++++++\n 1 file changed, 36 insertions(+)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 4eb13b06d6..4e5cad4966 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3004,6 +3004,42 @@ _git_worktree ()\n \t*,--*)\n \t\t__gitcomp_builtin worktree_$subcommand\n \t\t;;\n+\tadd,*)\t# usage: git worktree add [<options>] <path> [<commit-ish>]\n+\t\t# Here we are not completing an --option, it's either the\n+\t\t# path or a ref.\n+\t\tcase \"$prev\" in\n+\t\t-b|-B)\t# Complete refs for branch to be created/reseted.\n+\t\t\t__git_complete_refs\n+\t\t\t;;\n+\t\t-*)\t# The previous word is an -o|--option without an\n+\t\t\t# unstuck argument: have to complete the path for\n+\t\t\t# the new worktree, so don't list anything, but let\n+\t\t\t# Bash fall back to filename completion.\n+\t\t\t;;\n+\t\t*)\t# The previous word is not an --option, so it must\n+\t\t\t# be either the 'add' subcommand, the unstuck\n+\t\t\t# argument of an option (e.g. branch for -b|-B), or\n+\t\t\t# the path for the new worktree.\n+\t\t\tif [ $cword -eq $((subcommand_idx+1)) ]; then\n+\t\t\t\t# Right after the 'add' subcommand: have to\n+\t\t\t\t# complete the path, so fall back to Bash\n+\t\t\t\t# filename completion.\n+\t\t\t\t:\n+\t\t\telse\n+\t\t\t\tcase \"${words[cword-2]}\" in\n+\t\t\t\t-b|-B)\t# After '-b <branch>': have to\n+\t\t\t\t\t# complete the path, so fall back\n+\t\t\t\t\t# to Bash filename completion.\n+\t\t\t\t\t;;\n+\t\t\t\t*)\t# After the path: have to complete\n+\t\t\t\t\t# the ref to be checked out.\n+\t\t\t\t\t__git_complete_refs\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tfi\n+\t\t\t;;\n+\t\tesac\n+\t\t;;\n \tlock,*|remove,*|unlock,*)\n \t\t__git_complete_worktree_paths\n \t\t;;\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384277","messageId":"20191017173501.3198-6-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 5/6] completion: list existing working trees for 'git worktree' subcommands","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:35:00Z","receivedAt":"2019-10-17T17:35:20Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete the paths of existing working trees for 'git worktree's\n'move', 'remove', 'lock', and 'unlock' subcommands.\n\nNote that 'git worktree list --porcelain' shows absolute paths, so for\nsimplicity's sake we'll complete full absolute paths as well (as\nopposed to turning them into relative paths by finding common leading\ndirectories between $PWD and the working tree's path and removing\nthem, risking trouble with symbolic links or Windows drive letters; or\ncompleting them one path component at a time).\n\nNever list the path of the main working tree, as it cannot be moved,\nremoved, locked, or unlocked.\n\nArguably 'git worktree unlock <TAB>' should only complete locked\nworking trees, but 'git worktree list --porcelain' doesn't indicate\nwhich working trees are locked.  So for now it will complete the paths\nof all existing working trees, including non-locked ones as well.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 28 +++++++++++++++++++++++++-\n 1 file changed, 27 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 643272eb2f..4eb13b06d6 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2981,10 +2981,21 @@ _git_whatchanged ()\n \t_git_log\n }\n \n+__git_complete_worktree_paths ()\n+{\n+\tlocal IFS=$'\\n'\n+\t__gitcomp_nl \"$(git worktree list --porcelain |\n+\t\tsed -n -e '2,$ s/^worktree //p')\"\n+}\n+\n _git_worktree ()\n {\n \tlocal subcommands=\"add list lock move prune remove unlock\"\n-\tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n+\tlocal subcommand subcommand_idx\n+\n+\tsubcommand=\"$(__git_find_on_cmdline --show-idx \"$subcommands\")\"\n+\tsubcommand_idx=\"${subcommand% *}\"\n+\tsubcommand=\"${subcommand#* }\"\n \n \tcase \"$subcommand,$cur\" in\n \t,*)\n@@ -2993,6 +3004,21 @@ _git_worktree ()\n \t*,--*)\n \t\t__gitcomp_builtin worktree_$subcommand\n \t\t;;\n+\tlock,*|remove,*|unlock,*)\n+\t\t__git_complete_worktree_paths\n+\t\t;;\n+\tmove,*)\n+\t\tif [ $cword -eq $((subcommand_idx+1)) ]; then\n+\t\t\t# The first parameter must be an existing working\n+\t\t\t# tree to be moved.\n+\t\t\t__git_complete_worktree_paths\n+\t\telse\n+\t\t\t# The second parameter is the destination: it could\n+\t\t\t# be any path, so don't list anything, but let Bash\n+\t\t\t# fall back to filename completion.\n+\t\t\t:\n+\t\tfi\n+\t\t;;\n \tesac\n }\n \n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384278","messageId":"20191017173501.3198-5-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH 4/6] completion: simplify completing 'git worktree' subcommands and options","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-17T17:34:59Z","receivedAt":"2019-10-17T17:35:21Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The completion function for 'git worktree' uses separate but very\nsimilar case arms to complete --options for each subcommand.\n\nCombine these into a single case arm to avoid repetition.\n\nNote that after this change we won't complete 'git worktree remove's\n'--force' option, but that is consistent with our general stance on\nnot offering '--force', as it should be used with care.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 30 +++++++-------------------\n 1 file changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 55a2d3e174..643272eb2f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2985,29 +2985,15 @@ _git_worktree ()\n {\n \tlocal subcommands=\"add list lock move prune remove unlock\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n-\tif [ -z \"$subcommand\" ]; then\n+\n+\tcase \"$subcommand,$cur\" in\n+\t,*)\n \t\t__gitcomp \"$subcommands\"\n-\telse\n-\t\tcase \"$subcommand,$cur\" in\n-\t\tadd,--*)\n-\t\t\t__gitcomp_builtin worktree_add\n-\t\t\t;;\n-\t\tlist,--*)\n-\t\t\t__gitcomp_builtin worktree_list\n-\t\t\t;;\n-\t\tlock,--*)\n-\t\t\t__gitcomp_builtin worktree_lock\n-\t\t\t;;\n-\t\tprune,--*)\n-\t\t\t__gitcomp_builtin worktree_prune\n-\t\t\t;;\n-\t\tremove,--*)\n-\t\t\t__gitcomp \"--force\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\t;;\n-\t\tesac\n-\tfi\n+\t\t;;\n+\t*,--*)\n+\t\t__gitcomp_builtin worktree_$subcommand\n+\t\t;;\n+\tesac\n }\n \n __git_complete_common () {\n-- \n2.23.0.1084.gae250eaa40\n\n"},{"id":"384281","messageId":"CAPig+cTLCTPtUWHKVBQEaP9GkrmrnHPwfef8KnktOSqYQY-jPA@mail.gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-4-szeder.dev@gmail.com","subject":"Re: [PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-10-17T17:52:27Z","receivedAt":"2019-10-17T17:52:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Oct 17, 2019 at 1:35 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> When using the __git_find_on_cmdline() helper function so far we've\n> only been interested in which one of a set of words appear on the\n> command line.  To complete options for some of 'git worktree's\n> subcommands in the following patches we'll need not only that, but the\n> index of that word on the command line as well.\n>\n> Extend __git_find_on_cmdline() to optionally show the index of the\n> found word on the command line (IOW in the $words array) when the\n> '--show-idx' option is given.\n>\n> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n> ---\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> @@ -1069,18 +1069,32 @@ __git_aliased_command ()\n>  # Check whether one of the given words is present on the command line,\n>  # and print the first word found.\n> +#\n> +# Usage: __git_find_on_cmdline [<option>]... \"<wordlist>\"\n> +# --show-idx: Optionally show the index of the found word in the $words array.\n>  __git_find_on_cmdline ()\n>  {\n> -       local word c=1\n> +       local word c=1 show_idx\n> +\n> +       while test $# -gt 1; do\n> +               case \"$1\" in\n> +               --show-idx)     show_idx=y ;;\n> +               *)              return 1 ;;\n\nShould this emit an error message to aid a person debugging a test\nwhich fails on a call to __git_find_on_cmdline()? For instance:\n\n    echo \"unrecognized option/argument: $1\" >&2\n    return 1\n    ;;\n\nor something...\n\n> +               esac\n> +               shift\n> +       done\n>         local wordlist=\"$1\"\n>\n>         while [ $c -lt $cword ]; do\n>                 for word in $wordlist; do\n>                         if [ \"$word\" = \"${words[c]}\" ]; then\n> -                               echo \"$word\"\n> +                               if [ -n \"$show_idx\" ]; then\n> +                                       echo \"$c $word\"\n> +                               else\n> +                                       echo \"$word\"\n> +                               fi\n>                                 return\n>                         fi\n>                 done\n"},{"id":"384283","messageId":"CAPig+cSGXqJuaZPhUhOVX5X=LMrjVfv8ye_6ncMUbyKox1i7QA@mail.gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-6-szeder.dev@gmail.com","subject":"Re: [PATCH 5/6] completion: list existing working trees for 'git worktree' subcommands","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-10-17T18:08:12Z","receivedAt":"2019-10-17T18:08:26Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Oct 17, 2019 at 1:35 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> Complete the paths of existing working trees for 'git worktree's\n> 'move', 'remove', 'lock', and 'unlock' subcommands.\n> [...]\n> Arguably 'git worktree unlock <TAB>' should only complete locked\n> working trees, but 'git worktree list --porcelain' doesn't indicate\n> which working trees are locked.  So for now it will complete the paths\n> of all existing working trees, including non-locked ones as well.\n\nIt is a long-standing To-Do[1] for \"git worktree list [--porcelain]\"\nto indicate whether a worktree is locked, prunable, etc. Looking at\nthe implementation of builtin/worktree.c:show_worktree_porcelain(), it\nshould be easy enough to add. (Adding it for the non-porcelain case\nwould perhaps require more thinking and design since we might want a\n--verbose option to trigger the extra information.)\n\n[1]: https://public-inbox.org/git/CAPig+cTTrv2C7JLu1dr4+N8xo+7YQ+deiwLDA835wBGD6fhS1g@mail.gmail.com/\n\n> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n> ---\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> @@ -2981,10 +2981,21 @@ _git_whatchanged ()\n> +__git_complete_worktree_paths ()\n> +{\n> +       local IFS=$'\\n'\n> +       __gitcomp_nl \"$(git worktree list --porcelain |\n> +               sed -n -e '2,$ s/^worktree //p')\"\n> +}\n\nI know that the commit message talks about it, but it might deserve an\nin-code comment here (or a function-level comment) explaining why the\nfirst line of \"git worktree list --porcelain\" output is thrown away\nsince it's not necessarily obvious to the casual reader.\n"},{"id":"384382","messageId":"20191018143728.GC29845@szeder.dev","threadId":"52058","inReplyTo":"CAPig+cTLCTPtUWHKVBQEaP9GkrmrnHPwfef8KnktOSqYQY-jPA@mail.gmail.com","subject":"Re: [PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-18T14:37:28Z","receivedAt":"2019-10-18T14:37:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, Oct 17, 2019 at 01:52:27PM -0400, Eric Sunshine wrote:\n> >  __git_find_on_cmdline ()\n> >  {\n> > -       local word c=1\n> > +       local word c=1 show_idx\n> > +\n> > +       while test $# -gt 1; do\n> > +               case \"$1\" in\n> > +               --show-idx)     show_idx=y ;;\n> > +               *)              return 1 ;;\n> \n> Should this emit an error message to aid a person debugging a test\n> which fails on a call to __git_find_on_cmdline()? For instance:\n> \n>     echo \"unrecognized option/argument: $1\" >&2\n>     return 1\n>     ;;\n> \n> or something...\n\nWhen debugging the completion script I frequently resort to 'echo >&2\n\"<msg>\"', for lack of better options.  However, I intentionally did\nnot add an error message like that here, or in any similar option\nparsing loops before, because due to a bug it might spew such a\nmessage to standard error during regular completion (i.e. not during\ndebugging).\n\nAnd printing anything to standard error during completion is\ninherently bad: it disrupts the command line, can't be deleted (you\nhit backspace, and in the terminal it looks as if the error message\nwas deleted, but in reality it's the command you've already entered\nthat gets deleted), and the user is eventually fored to Ctrl-C and\nstart over most of the time.  Well, at least I always end up hitting\nCtrl-C and start over.  Remaining silent about the unrecognized option\nis in my opinion better, because then the completion script usually\ndoes nothing, and Bash falls back to filename completion.  Yeah,\nthat's not ideal, but at least the user can easily correct it and\nfinish entering the command.\n\n"},{"id":"384384","messageId":"20191018150006.GD29845@szeder.dev","threadId":"52058","inReplyTo":"CAPig+cSGXqJuaZPhUhOVX5X=LMrjVfv8ye_6ncMUbyKox1i7QA@mail.gmail.com","subject":"Re: [PATCH 5/6] completion: list existing working trees for 'git worktree' subcommands","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-10-18T15:00:06Z","receivedAt":"2019-10-18T15:00:12Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, Oct 17, 2019 at 02:08:12PM -0400, Eric Sunshine wrote:\n> On Thu, Oct 17, 2019 at 1:35 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> > Complete the paths of existing working trees for 'git worktree's\n> > 'move', 'remove', 'lock', and 'unlock' subcommands.\n> > [...]\n> > Arguably 'git worktree unlock <TAB>' should only complete locked\n> > working trees, but 'git worktree list --porcelain' doesn't indicate\n> > which working trees are locked.  So for now it will complete the paths\n> > of all existing working trees, including non-locked ones as well.\n> \n> It is a long-standing To-Do[1] for \"git worktree list [--porcelain]\"\n> to indicate whether a worktree is locked, prunable, etc. Looking at\n> the implementation of builtin/worktree.c:show_worktree_porcelain(), it\n> should be easy enough to add.\n\nI didn't look at the implementation, but only at the docs, which says:\n\n  --porcelain\n      With list, output in an easy-to-parse format for scripts. This\n      format will remain stable across Git versions and regardless of\n      user configuration. See below for details.\n\nI'm not sure whether introducing a new boolean attribute (i.e. a line\ncontaining only \"locked\") would still be considered acceptable, or\nwould count as changing the format.  I can imagine that a too strict\nparser would barf upon encountering the unrecognized \"locked\"\nattribute; but yeah, no sensible parser should be that strict IMO.\n\nFurthermore, I'm not sure what to do with the reason for locking.  In\ngeneral I would think that it makes sense to display the reason in an\neasy-to-parse format as well.  However, doing so will inherently make\nthe format less easy to parse, because the reason could span multiple\nlines, so without some sort of encoding/escaping it would violate the\n\"a line per attribute\" format.\n\nI would say that this is beyong the scope of this patch series :)\n\n> > diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> > @@ -2981,10 +2981,21 @@ _git_whatchanged ()\n> > +__git_complete_worktree_paths ()\n> > +{\n> > +       local IFS=$'\\n'\n> > +       __gitcomp_nl \"$(git worktree list --porcelain |\n> > +               sed -n -e '2,$ s/^worktree //p')\"\n> > +}\n> \n> I know that the commit message talks about it, but it might deserve an\n> in-code comment\n\nOK.\n"},{"id":"384411","messageId":"CAPig+cTitWCs5vB=0iXuUyEY22c0gvjXvY1ZtTT90s74ydhE=A@mail.gmail.com","threadId":"52058","inReplyTo":"20191018150006.GD29845@szeder.dev","subject":"Re: [PATCH 5/6] completion: list existing working trees for 'git worktree' subcommands","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-10-18T20:45:38Z","receivedAt":"2019-10-18T20:45:55Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Oct 18, 2019 at 11:00 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Thu, Oct 17, 2019 at 02:08:12PM -0400, Eric Sunshine wrote:\n> > It is a long-standing To-Do[1] for \"git worktree list [--porcelain]\"\n> > to indicate whether a worktree is locked, prunable, etc. Looking at\n> > the implementation of builtin/worktree.c:show_worktree_porcelain(), it\n> > should be easy enough to add.\n>\n> I didn't look at the implementation, but only at the docs, which says:\n>\n>   --porcelain\n>       With list, output in an easy-to-parse format for scripts. This\n>       format will remain stable across Git versions and regardless of\n>       user configuration. See below for details.\n>\n> I'm not sure whether introducing a new boolean attribute (i.e. a line\n> containing only \"locked\") would still be considered acceptable, or\n> would count as changing the format.  I can imagine that a too strict\n> parser would barf upon encountering the unrecognized \"locked\"\n> attribute; but yeah, no sensible parser should be that strict IMO.\n\nThe stanza-based format of the porcelain output was chosen with the\nspecific intention of being easy to parse _and_ to allow extension\nsuch as the introduction of new attributes. It is unfortunate that the\ndocumentation you quoted, as well as the description of the porcelain\nformat itself, does a poor job of (or utterly fails at) conveying that\nintention. (Had I been around to review the later iteration(s) of the\nseries which introduced the porcelain format, I likely would have\npointed out these shortcomings, however, Real Life had other ideas,\nand I didn't manage to review it until weeks after the series had made\nit into an actual release.)\n\nI'm not convinced, though, that we're locked into exactly the few\nattributes shown only in an example in the porcelain section of the\ndocumentation. That documentation is so woefully underspecified --\nindeed, it doesn't even talk about what attributes are available, but\nonly gives a single example showing some of the (possible) attributes\n-- that it effectively makes no promises about what will or will not\nappear in a stanza. (The only thing is says strongly is that stanzas\nwill be separated by a blank line -- despite the intention all along\nbeing that each new stanza would start with a \"worktree\" attributes,\nand that blank lines, if output, were to be ignored.)\n\nSo, I am of the opinion that we are not prevented from adding new\nattributes, such as \"locked\" and \"prunable\".\n\n> Furthermore, I'm not sure what to do with the reason for locking.  In\n> general I would think that it makes sense to display the reason in an\n> easy-to-parse format as well.  However, doing so will inherently make\n> the format less easy to parse, because the reason could span multiple\n> lines, so without some sort of encoding/escaping it would violate the\n> \"a line per attribute\" format.\n\nYep, I believe my thinking at the time was that the lock reason and\nthe prunable reason would be escaped if needed. So, for instance:\n\n    worktree /blah\n    branch refs/heads/blah\n    locked Sneaker-net removable storage\\nNot always mounted\n\n> I would say that this is beyong the scope of this patch series :)\n\nOh, I wasn't suggesting that this series do anything of the sort.\nInstead, I was merely responding to the point in the commit message\nthat the porcelain format was lacking information about the lock, and\nto say that it could (eventually) be solved by extending the output.\n"},{"id":"384414","messageId":"CAPig+cRSGfaRggDhauSvJyrO1Zu7ZFSG+gfF134z8UV1ovSuEw@mail.gmail.com","threadId":"52058","inReplyTo":"20191018143728.GC29845@szeder.dev","subject":"Re: [PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-10-18T21:01:42Z","receivedAt":"2019-10-18T21:01:58Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Oct 18, 2019 at 10:37 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Thu, Oct 17, 2019 at 01:52:27PM -0400, Eric Sunshine wrote:\n> > > +               case \"$1\" in\n> > > +               --show-idx)     show_idx=y ;;\n> > > +               *)              return 1 ;;\n> >\n> > Should this emit an error message to aid a person debugging a test\n> > which fails on a call to __git_find_on_cmdline()? [...]\n>\n> And printing anything to standard error during completion is\n> inherently bad: it disrupts the command line, can't be deleted [...]\n> Remaining silent about the unrecognized option\n> is in my opinion better, because then the completion script usually\n> does nothing, and Bash falls back to filename completion.  Yeah,\n> that's not ideal, but at least the user can easily correct it and\n> finish entering the command.\n\nI had tunnel-vision and was thinking about this only in the context of\nthe tests. However, while I agree that spewing errors during\ncompletion is not ideal, aren't there two different classes of errors\nto consider? Some errors can crop up via normal usage of Git commands\nin Real World situations; those errors should be suppressed since they\nare expected and can be tolerated. However, the second class of error\n(such as passing a bogus option to this internal function) is an\noutright programming mistake by a maintainer of the completion script\nitself, and it would be helpful to let the programmer know as early as\npossible about the mistake.\n\nOr, are there backward-compatibility or other concerns which would\nmake emitting error messages undesirable even for outright programmer\nmistakes?\n"},{"id":"388514","messageId":"20191219143927.GD8609@szeder.dev","threadId":"52058","inReplyTo":"CAPig+cRSGfaRggDhauSvJyrO1Zu7ZFSG+gfF134z8UV1ovSuEw@mail.gmail.com","subject":"Re: [PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T14:39:27Z","receivedAt":"2019-12-19T14:39:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Oct 18, 2019 at 05:01:42PM -0400, Eric Sunshine wrote:\n> On Fri, Oct 18, 2019 at 10:37 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> > On Thu, Oct 17, 2019 at 01:52:27PM -0400, Eric Sunshine wrote:\n> > > > +               case \"$1\" in\n> > > > +               --show-idx)     show_idx=y ;;\n> > > > +               *)              return 1 ;;\n> > >\n> > > Should this emit an error message to aid a person debugging a test\n> > > which fails on a call to __git_find_on_cmdline()? [...]\n> >\n> > And printing anything to standard error during completion is\n> > inherently bad: it disrupts the command line, can't be deleted [...]\n> > Remaining silent about the unrecognized option\n> > is in my opinion better, because then the completion script usually\n> > does nothing, and Bash falls back to filename completion.  Yeah,\n> > that's not ideal, but at least the user can easily correct it and\n> > finish entering the command.\n> \n> I had tunnel-vision and was thinking about this only in the context of\n> the tests. However, while I agree that spewing errors during\n> completion is not ideal, aren't there two different classes of errors\n> to consider? Some errors can crop up via normal usage of Git commands\n> in Real World situations; those errors should be suppressed since they\n> are expected and can be tolerated. However, the second class of error\n> (such as passing a bogus option to this internal function) is an\n> outright programming mistake by a maintainer of the completion script\n> itself, and it would be helpful to let the programmer know as early as\n> possible about the mistake.\n> \n> Or, are there backward-compatibility or other concerns which would\n> make emitting error messages undesirable even for outright programmer\n> mistakes?\n\nIt's not necessarily an outright programming mistake, and that error\ncould be triggered by ordinary users as well.\n\nLet's suppose that a user has a custom 'git-foo' command in $PATH with\na custom '_git_foo' completion function in '~/.my-git-completions',\nwhich the helper function '__git_bar --option' from our completion\nscript.  Let's also suppose that the user sources this completion\nfunction from '~/.bashrc', but otherwise uses the system-wide git\ncompletion script, and that $HOME is shared across multiple computers.\n\nIn this (arguably somewhat convoluted) scenario it might happen that\non a not quote up-to-date computer the system-wide git completion\nscript already has the '__git_bar' helper function, but it doesn't yet\nsupport '--option'.  If '__git_bar' then prints an error to stderr,\nthen the command line will get badly messed up, and the user will have\nto ctrl-C and start over.\n\nHowever, if '__git_bar' silently ignores the unknown option, then the\nworst that can happen is that completion doesn't work, and e.g. it\nfalls back to Bash's filename completion or offers something\nnonsensical.  In either case, after a brief \"Huh?!\" moment the user\ncan correct it by hitting backspace a couple of times and then enter\nthe rest of the command by hand.\n\n"},{"id":"388515","messageId":"20191219144419.GE8609@szeder.dev","threadId":"52058","inReplyTo":"20191018143728.GC29845@szeder.dev","subject":"Re: [PATCH 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T14:44:19Z","receivedAt":"2019-12-19T14:44:27Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Oct 18, 2019 at 04:37:28PM +0200, SZEDER Gábor wrote:\n> On Thu, Oct 17, 2019 at 01:52:27PM -0400, Eric Sunshine wrote:\n> > >  __git_find_on_cmdline ()\n> > >  {\n> > > -       local word c=1\n> > > +       local word c=1 show_idx\n> > > +\n> > > +       while test $# -gt 1; do\n> > > +               case \"$1\" in\n> > > +               --show-idx)     show_idx=y ;;\n> > > +               *)              return 1 ;;\n> > \n> > Should this emit an error message to aid a person debugging a test\n> > which fails on a call to __git_find_on_cmdline()? For instance:\n> > \n> >     echo \"unrecognized option/argument: $1\" >&2\n> >     return 1\n> >     ;;\n> > \n> > or something...\n> \n> When debugging the completion script I frequently resort to 'echo >&2\n> \"<msg>\"', for lack of better options.\n\nWell, there is a better option for debugging: adding 'echo >>~/LOG\n\"<msg>\"' to the completion script and running 'tail -f ~/LOG' in a\nseparate terminal window is so much more convenient than screwing up\nthe command line with those messages to stderr every time.\n\nI just wonder why it took me about a dozen years to figure this one\nout... ;)\n\n"},{"id":"388517","messageId":"20191219150921.5889-1-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191017173501.3198-1-szeder.dev@gmail.com","subject":"[PATCH v2 0/6] completion: improve completion for 'git worktree'","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:15Z","receivedAt":"2019-12-19T15:09:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete paths of working trees and refs for 'git worktree's various\nsubcommands.\n\nThe last two patches do the actual improvements, the first four are\npreparatory steps.\n\nChanges since v1:\n\n  - Added an in-code comment and clarified the commit message of patch\n    5/6.\n\nv1: https://public-inbox.org/git/20191017173501.3198-1-szeder.dev@gmail.com/T/#u\n\nSZEDER Gábor (6):\n  t9902-completion: add tests for the __git_find_on_cmdline() helper\n  completion: clean up the __git_find_on_cmdline() helper function\n  completion: return the index of found word from\n    __git_find_on_cmdline()\n  completion: simplify completing 'git worktree' subcommands and options\n  completion: list existing working trees for 'git worktree' subcommands\n  completion: list paths and refs for 'git worktree add'\n\n contrib/completion/git-completion.bash | 119 +++++++++++++++++++------\n t/t9902-completion.sh                  |  57 ++++++++++++\n 2 files changed, 150 insertions(+), 26 deletions(-)\n\nRange-diff against v1:\n1:  bd68b0b64b = 1:  b370a97edc t9902-completion: add tests for the __git_find_on_cmdline() helper\n2:  b5c0312db6 = 2:  fb8f1e4840 completion: clean up the __git_find_on_cmdline() helper function\n3:  6999b0b8e2 = 3:  47aecb9ac0 completion: return the index of found word from __git_find_on_cmdline()\n4:  dd38374f2f = 4:  00c5a0f7df completion: simplify completing 'git worktree' subcommands and options\n5:  619ff7021c ! 5:  2e4b1b3931 completion: list existing working trees for 'git worktree' subcommands\n    @@ Commit message\n         Never list the path of the main working tree, as it cannot be moved,\n         removed, locked, or unlocked.\n     \n    -    Arguably 'git worktree unlock <TAB>' should only complete locked\n    -    working trees, but 'git worktree list --porcelain' doesn't indicate\n    -    which working trees are locked.  So for now it will complete the paths\n    -    of all existing working trees, including non-locked ones as well.\n    +    Ideally we would only list unlocked working trees for the 'move',\n    +    'remove', and 'lock' subcommands, and only locked ones for 'unlock'.\n    +    Alas, 'git worktree list --porcelain' doesn't indicate which working\n    +    trees are locked, so for now we'll complete the paths of all existing\n    +    working trees.\n     \n         Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n     \n    @@ contrib/completion/git-completion.bash: _git_whatchanged ()\n     +{\n     +\tlocal IFS=$'\\n'\n     +\t__gitcomp_nl \"$(git worktree list --porcelain |\n    ++\t\t# Skip the first entry: it's the path of the main worktree,\n    ++\t\t# which can't be moved, removed, locked, etc.\n     +\t\tsed -n -e '2,$ s/^worktree //p')\"\n     +}\n     +\n6:  29a32e5d36 = 6:  16a9b5f4b2 completion: list paths and refs for 'git worktree add'\n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388518","messageId":"20191219150921.5889-2-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 1/6] t9902-completion: add tests for the __git_find_on_cmdline() helper","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:16Z","receivedAt":"2019-12-19T15:09:39Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The following two patches will refactor and extend the\n__git_find_on_cmdline() helper function, so let's add a few tests\nfirst to make sure that its basic behavior doesn't change.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n t/t9902-completion.sh | 28 ++++++++++++++++++++++++++++\n 1 file changed, 28 insertions(+)\n\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 54f8ce18cb..847ce601d2 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1363,6 +1363,34 @@ test_expect_success 'teardown after path completion tests' '\n \t       BS\\\\dir '$'separators\\034in\\035dir''\n '\n \n+test_expect_success '__git_find_on_cmdline - single match' '\n+\techo list >expect &&\n+\t(\n+\t\twords=(git command --opt list) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - multiple matches' '\n+\techo remove >expect &&\n+\t(\n+\t\twords=(git command -o --opt remove list add) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - no match' '\n+\t(\n+\t\twords=(git command --opt branch) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline \"add list remove\" >actual\n+\t) &&\n+\ttest_must_be_empty actual\n+'\n \n test_expect_success '__git_get_config_variables' '\n \tcat >expect <<-EOF &&\n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388519","messageId":"20191219150921.5889-3-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 2/6] completion: clean up the __git_find_on_cmdline() helper function","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:17Z","receivedAt":"2019-12-19T15:09:40Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The __git_find_on_cmdline() helper function started its life as\n__git_find_subcommand() [1], but it served a more general purpose than\nlooking for subcommands, so later it was renamed accordingly [2].\nHowever, that rename didn't touch the body of the function, and left\nthe $subcommand local variable behind, still reminiscent of the\nfunction's original purpose.\n\nLet's clean up the names of __git_find_on_cmdline()'s local variables\nand get rid of that $subcommand variable name.\n\nWhile at it, add a short comment describing the function's purpose.\n\n[1] 3ff1320d4b (bash: refactor searching for subcommands on the\n    command line, 2008-03-10),\n[2] 918c03c2a7 (bash: rename __git_find_subcommand() to\n    __git_find_on_cmdline(), 2009-09-15)\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 13 ++++++++-----\n 1 file changed, 8 insertions(+), 5 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 00fbe6c03d..2384f91e78 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1070,14 +1070,17 @@ __git_aliased_command ()\n }\n \n # __git_find_on_cmdline requires 1 argument\n+# Check whether one of the given words is present on the command line,\n+# and print the first word found.\n __git_find_on_cmdline ()\n {\n-\tlocal word subcommand c=1\n+\tlocal word c=1\n+\tlocal wordlist=\"$1\"\n+\n \twhile [ $c -lt $cword ]; do\n-\t\tword=\"${words[c]}\"\n-\t\tfor subcommand in $1; do\n-\t\t\tif [ \"$subcommand\" = \"$word\" ]; then\n-\t\t\t\techo \"$subcommand\"\n+\t\tfor word in $wordlist; do\n+\t\t\tif [ \"$word\" = \"${words[c]}\" ]; then\n+\t\t\t\techo \"$word\"\n \t\t\t\treturn\n \t\t\tfi\n \t\tdone\n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388520","messageId":"20191219150921.5889-4-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 3/6] completion: return the index of found word from __git_find_on_cmdline()","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:18Z","receivedAt":"2019-12-19T15:09:42Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When using the __git_find_on_cmdline() helper function so far we've\nonly been interested in which one of a set of words appear on the\ncommand line.  To complete options for some of 'git worktree's\nsubcommands in the following patches we'll need not only that, but the\nindex of that word on the command line as well.\n\nExtend __git_find_on_cmdline() to optionally show the index of the\nfound word on the command line (IOW in the $words array) when the\n'--show-idx' option is given.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 20 +++++++++++++++---\n t/t9902-completion.sh                  | 29 ++++++++++++++++++++++++++\n 2 files changed, 46 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2384f91e78..55a2d3e174 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1069,18 +1069,32 @@ __git_aliased_command ()\n \tdone\n }\n \n-# __git_find_on_cmdline requires 1 argument\n # Check whether one of the given words is present on the command line,\n # and print the first word found.\n+#\n+# Usage: __git_find_on_cmdline [<option>]... \"<wordlist>\"\n+# --show-idx: Optionally show the index of the found word in the $words array.\n __git_find_on_cmdline ()\n {\n-\tlocal word c=1\n+\tlocal word c=1 show_idx\n+\n+\twhile test $# -gt 1; do\n+\t\tcase \"$1\" in\n+\t\t--show-idx)\tshow_idx=y ;;\n+\t\t*)\t\treturn 1 ;;\n+\t\tesac\n+\t\tshift\n+\tdone\n \tlocal wordlist=\"$1\"\n \n \twhile [ $c -lt $cword ]; do\n \t\tfor word in $wordlist; do\n \t\t\tif [ \"$word\" = \"${words[c]}\" ]; then\n-\t\t\t\techo \"$word\"\n+\t\t\t\tif [ -n \"$show_idx\" ]; then\n+\t\t\t\t\techo \"$c $word\"\n+\t\t\t\telse\n+\t\t\t\t\techo \"$word\"\n+\t\t\t\tfi\n \t\t\t\treturn\n \t\t\tfi\n \t\tdone\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 847ce601d2..3e3299819a 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1392,6 +1392,35 @@ test_expect_success '__git_find_on_cmdline - no match' '\n \ttest_must_be_empty actual\n '\n \n+test_expect_success '__git_find_on_cmdline - single match with index' '\n+\techo \"3 list\" >expect &&\n+\t(\n+\t\twords=(git command --opt list) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - multiple matches with index' '\n+\techo \"4 remove\" >expect &&\n+\t(\n+\t\twords=(git command -o --opt remove list add) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '__git_find_on_cmdline - no match with index' '\n+\t(\n+\t\twords=(git command --opt branch) &&\n+\t\tcword=${#words[@]} &&\n+\t\t__git_find_on_cmdline --show-idx \"add list remove\" >actual\n+\t) &&\n+\ttest_must_be_empty actual\n+'\n+\n test_expect_success '__git_get_config_variables' '\n \tcat >expect <<-EOF &&\n \tname-1\n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388521","messageId":"20191219150921.5889-5-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 4/6] completion: simplify completing 'git worktree' subcommands and options","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:19Z","receivedAt":"2019-12-19T15:09:44Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The completion function for 'git worktree' uses separate but very\nsimilar case arms to complete --options for each subcommand.\n\nCombine these into a single case arm to avoid repetition.\n\nNote that after this change we won't complete 'git worktree remove's\n'--force' option, but that is consistent with our general stance on\nnot offering '--force', as it should be used with care.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 30 +++++++-------------------\n 1 file changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 55a2d3e174..643272eb2f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2985,29 +2985,15 @@ _git_worktree ()\n {\n \tlocal subcommands=\"add list lock move prune remove unlock\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n-\tif [ -z \"$subcommand\" ]; then\n+\n+\tcase \"$subcommand,$cur\" in\n+\t,*)\n \t\t__gitcomp \"$subcommands\"\n-\telse\n-\t\tcase \"$subcommand,$cur\" in\n-\t\tadd,--*)\n-\t\t\t__gitcomp_builtin worktree_add\n-\t\t\t;;\n-\t\tlist,--*)\n-\t\t\t__gitcomp_builtin worktree_list\n-\t\t\t;;\n-\t\tlock,--*)\n-\t\t\t__gitcomp_builtin worktree_lock\n-\t\t\t;;\n-\t\tprune,--*)\n-\t\t\t__gitcomp_builtin worktree_prune\n-\t\t\t;;\n-\t\tremove,--*)\n-\t\t\t__gitcomp \"--force\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\t;;\n-\t\tesac\n-\tfi\n+\t\t;;\n+\t*,--*)\n+\t\t__gitcomp_builtin worktree_$subcommand\n+\t\t;;\n+\tesac\n }\n \n __git_complete_common () {\n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388522","messageId":"20191219150921.5889-6-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 5/6] completion: list existing working trees for 'git worktree' subcommands","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:20Z","receivedAt":"2019-12-19T15:09:45Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete the paths of existing working trees for 'git worktree's\n'move', 'remove', 'lock', and 'unlock' subcommands.\n\nNote that 'git worktree list --porcelain' shows absolute paths, so for\nsimplicity's sake we'll complete full absolute paths as well (as\nopposed to turning them into relative paths by finding common leading\ndirectories between $PWD and the working tree's path and removing\nthem, risking trouble with symbolic links or Windows drive letters; or\ncompleting them one path component at a time).\n\nNever list the path of the main working tree, as it cannot be moved,\nremoved, locked, or unlocked.\n\nIdeally we would only list unlocked working trees for the 'move',\n'remove', and 'lock' subcommands, and only locked ones for 'unlock'.\nAlas, 'git worktree list --porcelain' doesn't indicate which working\ntrees are locked, so for now we'll complete the paths of all existing\nworking trees.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 30 +++++++++++++++++++++++++-\n 1 file changed, 29 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 643272eb2f..5eae0bfd18 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2981,10 +2981,23 @@ _git_whatchanged ()\n \t_git_log\n }\n \n+__git_complete_worktree_paths ()\n+{\n+\tlocal IFS=$'\\n'\n+\t__gitcomp_nl \"$(git worktree list --porcelain |\n+\t\t# Skip the first entry: it's the path of the main worktree,\n+\t\t# which can't be moved, removed, locked, etc.\n+\t\tsed -n -e '2,$ s/^worktree //p')\"\n+}\n+\n _git_worktree ()\n {\n \tlocal subcommands=\"add list lock move prune remove unlock\"\n-\tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n+\tlocal subcommand subcommand_idx\n+\n+\tsubcommand=\"$(__git_find_on_cmdline --show-idx \"$subcommands\")\"\n+\tsubcommand_idx=\"${subcommand% *}\"\n+\tsubcommand=\"${subcommand#* }\"\n \n \tcase \"$subcommand,$cur\" in\n \t,*)\n@@ -2993,6 +3006,21 @@ _git_worktree ()\n \t*,--*)\n \t\t__gitcomp_builtin worktree_$subcommand\n \t\t;;\n+\tlock,*|remove,*|unlock,*)\n+\t\t__git_complete_worktree_paths\n+\t\t;;\n+\tmove,*)\n+\t\tif [ $cword -eq $((subcommand_idx+1)) ]; then\n+\t\t\t# The first parameter must be an existing working\n+\t\t\t# tree to be moved.\n+\t\t\t__git_complete_worktree_paths\n+\t\telse\n+\t\t\t# The second parameter is the destination: it could\n+\t\t\t# be any path, so don't list anything, but let Bash\n+\t\t\t# fall back to filename completion.\n+\t\t\t:\n+\t\tfi\n+\t\t;;\n \tesac\n }\n \n-- \n2.24.1.982.ga4d4aba446\n\n"},{"id":"388523","messageId":"20191219150921.5889-7-szeder.dev@gmail.com","threadId":"52058","inReplyTo":"20191219150921.5889-1-szeder.dev@gmail.com","subject":"[PATCH v2 6/6] completion: list paths and refs for 'git worktree add'","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-12-19T15:09:21Z","receivedAt":"2019-12-19T15:09:46Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Complete paths after 'git worktree add <TAB>' and refs after 'git\nworktree add -b <TAB>' and 'git worktree add some/dir <TAB>'.\n\nUncharacteristically for a Git command, 'git worktree add' takes a\nmandatory path parameter before a commit-ish as its optional last\nparameter.  In addition, it has both standalone --options and options\nwith a mandatory unstuck parameter ('-b <new-branch>').  Consequently,\ntrying to complete refs for that last optional commit-ish parameter\nresulted in a more convoluted than usual completion function, but\nhopefully all the included comments will make it not too hard to\ndigest.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n contrib/completion/git-completion.bash | 36 ++++++++++++++++++++++++++\n 1 file changed, 36 insertions(+)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 5eae0bfd18..0b163e2c59 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3006,6 +3006,42 @@ _git_worktree ()\n \t*,--*)\n \t\t__gitcomp_builtin worktree_$subcommand\n \t\t;;\n+\tadd,*)\t# usage: git worktree add [<options>] <path> [<commit-ish>]\n+\t\t# Here we are not completing an --option, it's either the\n+\t\t# path or a ref.\n+\t\tcase \"$prev\" in\n+\t\t-b|-B)\t# Complete refs for branch to be created/reseted.\n+\t\t\t__git_complete_refs\n+\t\t\t;;\n+\t\t-*)\t# The previous word is an -o|--option without an\n+\t\t\t# unstuck argument: have to complete the path for\n+\t\t\t# the new worktree, so don't list anything, but let\n+\t\t\t# Bash fall back to filename completion.\n+\t\t\t;;\n+\t\t*)\t# The previous word is not an --option, so it must\n+\t\t\t# be either the 'add' subcommand, the unstuck\n+\t\t\t# argument of an option (e.g. branch for -b|-B), or\n+\t\t\t# the path for the new worktree.\n+\t\t\tif [ $cword -eq $((subcommand_idx+1)) ]; then\n+\t\t\t\t# Right after the 'add' subcommand: have to\n+\t\t\t\t# complete the path, so fall back to Bash\n+\t\t\t\t# filename completion.\n+\t\t\t\t:\n+\t\t\telse\n+\t\t\t\tcase \"${words[cword-2]}\" in\n+\t\t\t\t-b|-B)\t# After '-b <branch>': have to\n+\t\t\t\t\t# complete the path, so fall back\n+\t\t\t\t\t# to Bash filename completion.\n+\t\t\t\t\t;;\n+\t\t\t\t*)\t# After the path: have to complete\n+\t\t\t\t\t# the ref to be checked out.\n+\t\t\t\t\t__git_complete_refs\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tfi\n+\t\t\t;;\n+\t\tesac\n+\t\t;;\n \tlock,*|remove,*|unlock,*)\n \t\t__git_complete_worktree_paths\n \t\t;;\n-- \n2.24.1.982.ga4d4aba446\n\n"}]}