{"thread":{"id":"48312","subject":"[PATCH/RFC] completion: complete all possible -no-<options>","startedAt":"2018-04-17T18:13:24Z","lastAt":"2018-06-06T09:42:15Z","messageCount":23,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Duy Nguyen","Eric Sunshine","Stefan Beller","Aaron Schrab","Andreas Heiduk"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"344917","messageId":"20180417181300.23683-1-pclouds@gmail.com","threadId":"48312","inReplyTo":null,"subject":"[PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-17T18:13:00Z","receivedAt":"2018-04-17T18:13:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is not a complete topic but I'd like to present the problem and\nmy approach to see if it's a good way to go.\n\nWe have started recently to rely on parse-options to help complete\noptions. One of the leftover items is allowing completing --no- form.\nThis patch enables that (some options should not have --no- form, but\nthat's easy not included here).\n\nThe problem with completing --no- form is that the number of\ncompletable options now usually doubles, taking precious screen space\nand also making it hard to find the option you want.\n\nSo the other half of this patch, the part in git-completion.bash, is\nto uncomplete --no- options. When you do \"git checkout --<tab>\",\ninstead of displaying all --no- options, this patch simply displays\none item: the --no- prefix. If you do \"git checkout --no-<tab>\" then\nall negative options are displayed. This helps reduce completable\noptions quite efficiently.\n\nOf course life is not that simple, we do have --no- options by default\nsometimes (taking priority over the positive form), e.g. \"git clone\n--no-checkout\". Collapsing all --no-options into --no- would be a\nregression.\n\nTo avoid it, the order of options --git-completion-helper returns does\nmatter. The first 4 negative options are not collapsed. Only options\nafter the 4th are. Extra --no- options are always printed at the end,\nafter all the --no- defined in struct option, this kinda works. Not\npretty but works.\n\nAfter all this \"git checkout --<tab>\" now looks like this\n\n    > ~/w/git $ git co --\n    --conflict=                   --orphan=\n    --detach                      --ours \n    --ignore-other-worktrees      --patch \n    --ignore-skip-worktree-bits   --progress \n    --merge                       --quiet \n    --no-                         --recurse-submodules \n    --no-detach                   --theirs \n    --no-quiet                    --track \n    --no-track                    \n\nand all the no options\n\n    > ~/w/git $ git co --no-\n    --no-conflict                    --no-patch \n    --no-detach                      --no-progress \n    --no-ignore-other-worktrees      --no-quiet \n    --no-ignore-skip-worktree-bits   --no-recurse-submodules \n    --no-merge                       --no-track \n    --no-orphan                      \n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 25 +++++++++++++++-\n parse-options.c                        | 40 +++++++++++++++++++++++---\n 2 files changed, 60 insertions(+), 5 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..85b9f24465 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -266,7 +266,7 @@ __gitcomp ()\n \tcase \"$cur_\" in\n \t--*=)\n \t\t;;\n-\t*)\n+\t--no-*)\n \t\tlocal c i=0 IFS=$' \\t\\n'\n \t\tfor c in $1; do\n \t\t\tc=\"$c${4-}\"\n@@ -279,6 +279,29 @@ __gitcomp ()\n \t\t\tfi\n \t\tdone\n \t\t;;\n+\t*)\n+\t\tlocal c i=0 IFS=$' \\t\\n' n=0\n+\t\tfor c in $1; do\n+\t\t\tc=\"$c${4-}\"\n+\t\t\tif [[ $c == \"$cur_\"* ]]; then\n+\t\t\t\tcase $c in\n+\t\t\t\t--*=*|*.) ;;\n+\t\t\t\t--no-*)\n+\t\t\t\t\tn=$(($n+1))\n+\t\t\t\t\tif [ \"$n\" -eq 4 ]; then\n+\t\t\t\t\t\tc=\"--no-${4-} \"\n+\t\t\t\t\telif [ \"$n\" -gt 4 ]; then\n+\t\t\t\t\t\tcontinue\n+\t\t\t\t\telse\n+\t\t\t\t\t\tc=\"$c \"\n+\t\t\t\t\tfi\n+\t\t\t\t\t;;\n+\t\t\t\t*) c=\"$c \" ;;\n+\t\t\t\tesac\n+\t\t\t\tCOMPREPLY[i++]=\"${2-}$c\"\n+\t\t\tfi\n+\t\tdone\n+\t\t;;\n \tesac\n }\n \ndiff --git a/parse-options.c b/parse-options.c\nindex 0f7059a8ab..f6cd7ca8d2 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,13 +427,11 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \tparse_options_check(options);\n }\n \n-/*\n- * TODO: we are not completing the --no-XXX form yet because there are\n- * many options that do not suppress it properly.\n- */\n static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tconst struct option *opts)\n {\n+\tconst struct option *original_opts = opts;\n+\n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tconst char *suffix = \"\";\n \n@@ -465,6 +463,40 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tsuffix = \"=\";\n \t\tprintf(\" --%s%s\", opts->long_name, suffix);\n \t}\n+\tfor (opts = original_opts; opts->type != OPTION_END; opts++) {\n+\t\tint has_unset_form = 0;\n+\n+\t\tif (!opts->long_name)\n+\t\t\tcontinue;\n+\t\tif (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))\n+\t\t\tcontinue;\n+\t\tif (opts->flags & PARSE_OPT_NONEG)\n+\t\t\tcontinue;\n+\n+\t\tswitch (opts->type) {\n+\t\tcase OPTION_STRING:\n+\t\tcase OPTION_FILENAME:\n+\t\tcase OPTION_INTEGER:\n+\t\tcase OPTION_MAGNITUDE:\n+\t\tcase OPTION_CALLBACK:\n+\t\tcase OPTION_BIT:\n+\t\tcase OPTION_NEGBIT:\n+\t\tcase OPTION_COUNTUP:\n+\t\tcase OPTION_SET_INT:\n+\t\t\thas_unset_form = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (has_unset_form) {\n+\t\t\tconst char *name;\n+\n+\t\t\tif (skip_prefix(opts->long_name, \"no-\", &name))\n+\t\t\t\tprintf(\" --%s\", name);\n+\t\t\telse\n+\t\t\t\tprintf(\" --no-%s\", opts->long_name);\n+\t\t}\n+\t}\n \tfputc('\\n', stdout);\n \texit(0);\n }\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344966","messageId":"xmqq604pji2f.fsf@gitster-ct.c.googlers.com","threadId":"48312","inReplyTo":"20180417181300.23683-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-18T03:43:04Z","receivedAt":"2018-04-18T03:43:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> So the other half of this patch, the part in git-completion.bash, is\n> to uncomplete --no- options. When you do \"git checkout --<tab>\",\n> instead of displaying all --no- options, this patch simply displays\n> one item: the --no- prefix. If you do \"git checkout --no-<tab>\" then\n> all negative options are displayed. This helps reduce completable\n> options quite efficiently.\n\nClever.\n\n> Of course life is not that simple, we do have --no- options by default\n> sometimes (taking priority over the positive form), e.g. \"git clone\n> --no-checkout\". Collapsing all --no-options into --no- would be a\n> regression.\n>\n> To avoid it, the order of options --git-completion-helper returns does\n> matter. The first 4 negative options are not collapsed. Only options\n> after the 4th are. Extra --no- options are always printed at the end,\n> after all the --no- defined in struct option, this kinda works. Not\n> pretty but works.\n\nSo, the earlier mention of \"clone --no-checkout\" sounded about not\nlosing this historical practice, but (desirabilty of magic number 4\naside) this \"show first handful of --no-foo\" feature is not about\nhistorical practice but is forward looking, in the sense that you do\nnot mark \"important\" negated options in the source, which would be a\nway to handle the histrical \"clone --no-checkout\", but let the\nmachinery mechanically choose among --no-foo (with the stupid choice\ncriterion \"first four are shown\").  That allows other commands to\nhave many --no-foo form without overwhelming the choices, but I am\nnot sure if it is much better than a possible alternative of only\nshowing --no-foo for more \"important\" foo's when show_gitcomp() is\nasked to list all of things.  It would certainly be a more involved\nsolution, that might require an update to the way how the choices\nare precomputed (you'd end up having to keep a separate \"use this\nlist when completing '--no-'\" in addition to the normal list).\n\nIn any case, count this as a vote to support an update in this\ndirection.  A quite promising work ;-)\n\nThanks.\n"},{"id":"344989","messageId":"CACsJy8CU255jmXFRXVEQUBCvUiDhRHLyTOhMorzyCDYZ4aF9xg@mail.gmail.com","threadId":"48312","inReplyTo":"xmqq604pji2f.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-18T15:08:50Z","receivedAt":"2018-04-18T15:09:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Apr 18, 2018 at 5:43 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> So, the earlier mention of \"clone --no-checkout\" sounded about not\n> losing this historical practice, but (desirabilty of magic number 4\n> aside) this \"show first handful of --no-foo\" feature is not about\n> historical practice but is forward looking, in the sense that you do\n> not mark \"important\" negated options in the source, which would be a\n> way to handle the histrical \"clone --no-checkout\", but let the\n> machinery mechanically choose among --no-foo (with the stupid choice\n> criterion \"first four are shown\").\n\nWell you kinda mark important in the source too. --no-checkout for\nexampled is declared as OPT_BOOL(0, \"no-checkout\"... and parse-options\ncode has to add the double-negative form --checkout back [1].\n\nThe \"first four\" is chosen after carefully examining all commands and\nobserving that none of them have more than 4 \"important\" --no-. But\nyes it is questionable and I should be able to do better to separate\nthe favorable --no- from the other extra and most-of-the-time-useless\n--no- options.\n\n> That allows other commands to\n> have many --no-foo form without overwhelming the choices, but I am\n> not sure if it is much better than a possible alternative of only\n> showing --no-foo for more \"important\" foo's when show_gitcomp() is\n> asked to list all of things. It would certainly be a more involved\n> solution, that might require an update to the way how the choices\n> are precomputed (you'd end up having to keep a separate \"use this\n> list when completing '--no-'\" in addition to the normal list).\n\nI did think about this alternative and was still undecided. Suppose\nthat you have less than 4 \"important\" --no- options, showing some\nextra ones to me does not really hurt anything and if we could show\nmore options (within the same screen space) we should. But on the\nother hand maintaining this magic number could be a maintenance\nnightmare... Yeah I think I'm shifting towards no magic number now.\n\n[1] These double negative options will _always_ show up,  there is no\neasy way to hide them because they don't start with --no-. But we\ndon't have a lot of options starting with \"no-\" so it's probably fine.\n-- \nDuy\n"},{"id":"345445","messageId":"CAPig+cRkUrdtbyGEsY=DQCDoEWTrC-9n4=vKXHEap2gokB2uQg@mail.gmail.com","threadId":"48312","inReplyTo":"20180417181300.23683-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-23T05:36:17Z","receivedAt":"2018-04-23T05:36:24Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Apr 17, 2018 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> The problem with completing --no- form is that the number of\n> completable options now usually doubles, taking precious screen space\n> and also making it hard to find the option you want.\n>\n> So the other half of this patch, the part in git-completion.bash, is\n> to uncomplete --no- options. When you do \"git checkout --<tab>\",\n> instead of displaying all --no- options, this patch simply displays\n> one item: the --no- prefix. If you do \"git checkout --no-<tab>\" then\n> all negative options are displayed. This helps reduce completable\n> options quite efficiently.\n>\n> After all this \"git checkout --<tab>\" now looks like this\n>\n>     > ~/w/git $ git co --\n>     --conflict=                   --orphan=\n>     --detach                      --ours\n>     --ignore-other-worktrees      --patch\n>     --ignore-skip-worktree-bits   --progress\n>     --merge                       --quiet\n>     --no-                         --recurse-submodules\n>     --no-detach                   --theirs\n>     --no-quiet                    --track\n>     --no-track\n\nI haven't looked at the implementation, so this may be an entirely\nstupid suggestion, but would it be possible to instead render the\ncompletions as?\n\n    % git checkout --<tab>\n    --[no-]conflict=                   --[no-]patch\n    --[no-]detach                      --[no-]progress\n    --[no-]ignore-other-worktrees      --[no-]quiet\n    --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules\n    --[no-]merge                       --theirs\n    --[no-]orphan=                     --[no-]track\n    --ours\n\nThis would address the problem of the --no-* options taking double the\nscreen space.\n\nIt's also more intuitive than that lone and somewhat weird-looking\n\"--no-\" suggestion.\n"},{"id":"346990","messageId":"CACsJy8BGs7EOYFKayL-bgvEbKOJiROF52o3SneLyG9Nm6nUngA@mail.gmail.com","threadId":"48312","inReplyTo":"CAPig+cRkUrdtbyGEsY=DQCDoEWTrC-9n4=vKXHEap2gokB2uQg@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-08T15:24:02Z","receivedAt":"2018-05-08T15:24:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 23, 2018 at 7:36 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> I haven't looked at the implementation, so this may be an entirely\n> stupid suggestion, but would it be possible to instead render the\n> completions as?\n>\n>     % git checkout --<tab>\n>     --[no-]conflict=                   --[no-]patch\n>     --[no-]detach                      --[no-]progress\n>     --[no-]ignore-other-worktrees      --[no-]quiet\n>     --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules\n>     --[no-]merge                       --theirs\n>     --[no-]orphan=                     --[no-]track\n>     --ours\n>\n> This would address the problem of the --no-* options taking double the\n> screen space.\n\nIt took me so long to reply partly because I remember seeing some guy\ndoing clever trick with tab completion that also shows a short help\ntext in addition to the complete words. I could not find that again\nand from my reading (also internet searching) it's probably not\npossible to do this without trickery.\n\n> It's also more intuitive than that lone and somewhat weird-looking\n> \"--no-\" suggestion.\n\nIt's not that weird if you think about file path completion, where you\ncomplete one path component at a time not full path, bash just does\nnot show you full paths to everything.\n\nI'm arguing about this because I want to see your reaction, because\nI'm thinking of doing the very same thing for config completion. Right\nnow \"git config <tab>\" gives you two pages of all available config\nvariables. I'm thinking that we \"git config <tab>\" just shows the\ngroups, e.g.\n\n> ~/w/git $ git config\nadd.              interactive.\nadvice.           log.\nalias.            mailmap.\nam.               man.\n\nOnly when you do \"git config log.<tab>\" that it shows you log.*\n-- \nDuy\n"},{"id":"346993","messageId":"CAGZ79kb1VEkB4aw9ukx1LsOUX7=HzFcC=2=LwU4ipFEH60ALag@mail.gmail.com","threadId":"48312","inReplyTo":"CACsJy8BGs7EOYFKayL-bgvEbKOJiROF52o3SneLyG9Nm6nUngA@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-08T16:39:12Z","receivedAt":"2018-05-08T16:39:16Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, May 8, 2018 at 8:24 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n\n> I'm arguing about this because I want to see your reaction, because\n> I'm thinking of doing the very same thing for config completion. Right\n> now \"git config <tab>\" gives you two pages of all available config\n> variables. I'm thinking that we \"git config <tab>\" just shows the\n> groups, e.g.\n>\n>> ~/w/git $ git config\n> add.              interactive.\n> advice.           log.\n> alias.            mailmap.\n> am.               man.\n>\n> Only when you do \"git config log.<tab>\" that it shows you log.*\n\nHow cool is that? I'd love it.\n"},{"id":"347049","messageId":"20180509032050.GA23510@pug.qqx.org","threadId":"48312","inReplyTo":"CACsJy8BGs7EOYFKayL-bgvEbKOJiROF52o3SneLyG9Nm6nUngA@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Aaron Schrab","fromEmail":"aaron@schrab.com","sentAt":"2018-05-09T03:20:50Z","receivedAt":"2018-05-09T03:28:19Z","isPatch":true,"sender":{"key":"aaron@schrab.com","avatar":"https://avatars.githubusercontent.com/u/39620?v=4"},"body":"At 17:24 +0200 08 May 2018, Duy Nguyen <pclouds@gmail.com> wrote:\n>It took me so long to reply partly because I remember seeing some guy\n>doing clever trick with tab completion that also shows a short help\n>text in addition to the complete words. I could not find that again\n>and from my reading (also internet searching) it's probably not\n>possible to do this without trickery.\n\nWas that perhaps using zsh rather than bash? Below is some of the \ndisplay from its git completion (this is likely affected somewhat by my \nconfiguration).  The group descriptions (lines that begin with \n\"Completing\") appear in a different color, and are not available for \nselection.\n\n1113$ git c<tab>\nCompleting alias\nci               -- alias for 'commit -v'\ncia              -- alias for 'commit -v -a'\nco               -- alias for 'checkout'\nconf             -- alias for 'config'\nCompleting main porcelain command\ncheckout         -- checkout branch or paths to working tree\ncherry-pick      -- apply changes introduced by some existing commits\ncitool           -- graphical alternative to git commit\nclean            -- remove untracked files from working tree\nclone            -- clone repository into new directory\ncommit           -- record changes to repository\nCompleting ancillary manipulator command\nconfig           -- get and set repository or global options\nCompleting ancillary interrogator command\ncherry           -- find commits not merged upstream\ncount-objects    -- count unpacked objects and display their disk consumption\nCompleting plumbing manipulator command\ncheckout-index   -- copy files from index to working directory\ncommit-tree      -- create new commit object\nCompleting plumbing interrogator command\ncat-file         -- provide content or type information for repository objects\n\n1114$ git commit -<tab>\nCompleting option\n--all                  -a       -- stage all modified and deleted paths\n--allow-empty                   -- allow recording an empty commit\n--allow-empty-message           -- allow recording a commit with an empty message\n--amend                         -- amend the tip of the current branch\n--author                        -- override the author name used in the commit\n"},{"id":"347567","messageId":"CAPig+cRUD7FnJqSZ=hkz0GAgOROiY+gvHKRjKVfkKtqDZyt5mA@mail.gmail.com","threadId":"48312","inReplyTo":"CACsJy8BGs7EOYFKayL-bgvEbKOJiROF52o3SneLyG9Nm6nUngA@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-05-14T03:33:07Z","receivedAt":"2018-05-14T03:33:11Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, May 8, 2018 at 11:24 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Mon, Apr 23, 2018 at 7:36 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> I haven't looked at the implementation, so this may be an entirely\n>> stupid suggestion, but would it be possible to instead render the\n>> completions as?\n>>\n>>     % git checkout --<tab>\n>>     --[no-]conflict=                   --[no-]patch\n>>     --[no-]detach                      --[no-]progress\n>>\n>> This would address the problem of the --no-* options taking double the\n>> screen space.\n>\n> It took me so long to reply partly because I remember seeing some guy\n> doing clever trick with tab completion that also shows a short help\n> text in addition to the complete words. I could not find that again\n> and from my reading (also internet searching) it's probably not\n> possible to do this without trickery.\n\nOkay.\n\n>> It's also more intuitive than that lone and somewhat weird-looking\n>> \"--no-\" suggestion.\n>\n> It's not that weird if you think about file path completion, where you\n> complete one path component at a time not full path, bash just does\n> not show you full paths to everything.\n\nThe \"path completion\" analogy and the dotted configuration variable\nanalogy (below) don't really help me find \"--no-\" less weird. We're\nused to \"/\" as a separator in paths, and \".\" a separator in\nconfiguration variables, so they are easier to digest than \"-\" somehow\nbeing a separator for --no-<option>.\n\nIt _might_ feel as bit less weird if it was presented as --no-<option>\nor --no-{...} or --no-<...> or --no-... or something, but those seem\npretty weird too, so perhaps not. Anyhow, it's not a major issue; the\n--[no-]foo idea seems pretty intuitive, but if it can't be easily\nimplemented, then falling back to your --no- idea makes sense.\n\n> I'm arguing about this because I want to see your reaction, because\n> I'm thinking of doing the very same thing for config completion. Right\n> now \"git config <tab>\" gives you two pages of all available config\n> variables. I'm thinking that we \"git config <tab>\" just shows the\n> groups, e.g.\n>\n>> ~/w/git $ git config\n> add.              interactive.\n> advice.           log.\n> alias.            mailmap.\n> am.               man.\n>\n> Only when you do \"git config log.<tab>\" that it shows you log.*\n\nJust wondering out loud (again): add.<var> | add.{...} | add.<...> |\nadd...; those aren't very attractive either, so plain \"add.\" may\nindeed be best.\n"},{"id":"347607","messageId":"CACsJy8C+-f61H_kyUGspFh2z1q1fb0ug=p9e0tmCJC-ovC9ryA@mail.gmail.com","threadId":"48312","inReplyTo":"CAPig+cRUD7FnJqSZ=hkz0GAgOROiY+gvHKRjKVfkKtqDZyt5mA@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-14T16:39:44Z","receivedAt":"2018-05-14T16:40:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, May 14, 2018 at 5:33 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> It _might_ feel as bit less weird if it was presented as --no-<option>\n> or --no-{...} or --no-<...> or --no-... or something, but those seem\n> pretty weird too, so perhaps not. Anyhow, it's not a major issue; the\n> --[no-]foo idea seems pretty intuitive, but if it can't be easily\n> implemented, then falling back to your --no- idea makes sense.\n\nOh good I was thinking --no-... too or we could even do \"--no- (press\ntab for more)\" or something to make it more obvious. As long as we\nmake sure there's another --no-option somewhere, then we will only\ncomplete the --no- part and can replace the \"...\" (or \"press tab for\nmore\") with real candidates in the next tab/\n--\nDuy\n"},{"id":"347608","messageId":"ef3709f1-d9c2-860a-23d3-8d496294e1ac@gmail.com","threadId":"48312","inReplyTo":"CACsJy8BGs7EOYFKayL-bgvEbKOJiROF52o3SneLyG9Nm6nUngA@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Andreas Heiduk","fromEmail":"asheiduk@gmail.com","sentAt":"2018-05-14T17:03:01Z","receivedAt":"2018-05-14T17:03:12Z","isPatch":true,"sender":{"key":"asheiduk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9371344?v=4"},"body":"Am 08.05.2018 um 17:24 schrieb Duy Nguyen:\n> On Mon, Apr 23, 2018 at 7:36 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> I haven't looked at the implementation, so this may be an entirely\n>> stupid suggestion, but would it be possible to instead render the\n>> completions as?\n>>\n>>     % git checkout --<tab>\n>>     --[no-]conflict=                   --[no-]patch\n>>     --[no-]detach                      --[no-]progress\n>>     --[no-]ignore-other-worktrees      --[no-]quiet\n>>     --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules\n>>     --[no-]merge                       --theirs\n>>     --[no-]orphan=                     --[no-]track\n>>     --ours\n>>\n>> This would address the problem of the --no-* options taking double the\n>> screen space.\n> \n> It took me so long to reply partly because I remember seeing some guy\n> doing clever trick with tab completion that also shows a short help\n> text in addition to the complete words. I could not find that again\n> and from my reading (also internet searching) it's probably not\n> possible to do this without trickery.\n\nThe fish-shell does something like that.\n\n    > git status --<tab here>\n    --branch  (Show the branch and tracking info even in short-format)\n    --help                       (Display the manual of a git command)\n    --ignore-submodules                 (Ignore changes to submodules)\n    --porcelain    (Give the output in a stable, easy-to-parse format)\n    --short                      (Give the output in the short-format)\n    --untracked-files              (The untracked files handling mode)\n\nAnother tab will put a selection-cursor on the displayed list - you can\nnavigate that list with Cursor-Up/Cursor-Down, select an entry and that\nentry will be inserted into the commandline. That selection process\nwould be useless if the options are presented as \"--[no-]x\" because THAT\ncannot be inserted into the commandline without manual editing. And\nthat's the point of the fast option selection process.\n\n> \n>> It's also more intuitive than that lone and somewhat weird-looking\n>> \"--no-\" suggestion.\n> \n> It's not that weird if you think about file path completion, where you\n> complete one path component at a time not full path, bash just does\n> not show you full paths to everything.\n> \n> I'm arguing about this because I want to see your reaction, because\n> I'm thinking of doing the very same thing for config completion. Right\n> now \"git config <tab>\" gives you two pages of all available config\n> variables. I'm thinking that we \"git config <tab>\" just shows the\n> groups, e.g.\n> \n>> ~/w/git $ git config\n> add.              interactive.\n> advice.           log.\n> alias.            mailmap.\n> am.               man.\n> \n> Only when you do \"git config log.<tab>\" that it shows you log.*\n> \n\n"},{"id":"347609","messageId":"CACsJy8BPPbaoecp_xecG2_Sa0eFKwxs60JJooQZoo9Wpo59wHw@mail.gmail.com","threadId":"48312","inReplyTo":"20180509032050.GA23510@pug.qqx.org","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-14T17:14:04Z","receivedAt":"2018-05-14T17:14:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, May 9, 2018 at 5:20 AM, Aaron Schrab <aaron@schrab.com> wrote:\n> At 17:24 +0200 08 May 2018, Duy Nguyen <pclouds@gmail.com> wrote:\n>>\n>> It took me so long to reply partly because I remember seeing some guy\n>> doing clever trick with tab completion that also shows a short help\n>> text in addition to the complete words. I could not find that again\n>> and from my reading (also internet searching) it's probably not\n>> possible to do this without trickery.\n>\n>\n> Was that perhaps using zsh rather than bash? Below is some of the display\n> from its git completion (this is likely affected somewhat by my\n> configuration).  The group descriptions (lines that begin with \"Completing\")\n> appear in a different color, and are not available for selection.\n\nAh. That's probably it.\n\n>\n> 1113$ git c<tab>\n> Completing alias\n> ci               -- alias for 'commit -v'\n> cia              -- alias for 'commit -v -a'\n> co               -- alias for 'checkout'\n> conf             -- alias for 'config'\n> Completing main porcelain command\n> checkout         -- checkout branch or paths to working tree\n> cherry-pick      -- apply changes introduced by some existing commits\n> citool           -- graphical alternative to git commit\n> clean            -- remove untracked files from working tree\n> clone            -- clone repository into new directory\n> commit           -- record changes to repository\n> Completing ancillary manipulator command\n> config           -- get and set repository or global options\n> Completing ancillary interrogator command\n> cherry           -- find commits not merged upstream\n> count-objects    -- count unpacked objects and display their disk\n> consumption\n> Completing plumbing manipulator command\n> checkout-index   -- copy files from index to working directory\n> commit-tree      -- create new commit object\n> Completing plumbing interrogator command\n> cat-file         -- provide content or type information for repository\n> objects\n\nIt's interesting that zsh could do this. I looked at the script and\nthese texts are hard coded in there. I don't use zsh myself and won't\nbe doing this, but this information should be now available from git\nbinary so you can lower maintenance cost for the zsh completion\nscript.\n\n>\n> 1114$ git commit -<tab>\n> Completing option\n> --all                  -a       -- stage all modified and deleted paths\n> --allow-empty                   -- allow recording an empty commit\n> --allow-empty-message           -- allow recording a commit with an empty\n> message\n> --amend                         -- amend the tip of the current branch\n> --author                        -- override the author name used in the\n> commit\n\nHm.. no idea where this is from. Maybe zsh can extract \"git <command>\n-h\"? Anyway it does not matter.\n-- \nDuy\n"},{"id":"347610","messageId":"CACsJy8CwwseqL9M=-ML6hwgHG_GSK6pfeQU+MGWsx6=WCCZtmQ@mail.gmail.com","threadId":"48312","inReplyTo":"ef3709f1-d9c2-860a-23d3-8d496294e1ac@gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-14T17:26:39Z","receivedAt":"2018-05-14T17:27:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, May 14, 2018 at 7:03 PM, Andreas Heiduk <asheiduk@gmail.com> wrote:\n> Am 08.05.2018 um 17:24 schrieb Duy Nguyen:\n>> On Mon, Apr 23, 2018 at 7:36 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>> I haven't looked at the implementation, so this may be an entirely\n>>> stupid suggestion, but would it be possible to instead render the\n>>> completions as?\n>>>\n>>>     % git checkout --<tab>\n>>>     --[no-]conflict=                   --[no-]patch\n>>>     --[no-]detach                      --[no-]progress\n>>>     --[no-]ignore-other-worktrees      --[no-]quiet\n>>>     --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules\n>>>     --[no-]merge                       --theirs\n>>>     --[no-]orphan=                     --[no-]track\n>>>     --ours\n>>>\n>>> This would address the problem of the --no-* options taking double the\n>>> screen space.\n>>\n>> It took me so long to reply partly because I remember seeing some guy\n>> doing clever trick with tab completion that also shows a short help\n>> text in addition to the complete words. I could not find that again\n>> and from my reading (also internet searching) it's probably not\n>> possible to do this without trickery.\n>\n> The fish-shell does something like that.\n>\n>     > git status --<tab here>\n>     --branch  (Show the branch and tracking info even in short-format)\n>     --help                       (Display the manual of a git command)\n>     --ignore-submodules                 (Ignore changes to submodules)\n>     --porcelain    (Give the output in a stable, easy-to-parse format)\n>     --short                      (Give the output in the short-format)\n>     --untracked-files              (The untracked files handling mode)\n>\n> Another tab will put a selection-cursor on the displayed list - you can\n> navigate that list with Cursor-Up/Cursor-Down, select an entry and that\n> entry will be inserted into the commandline. That selection process\n> would be useless if the options are presented as \"--[no-]x\" because THAT\n> cannot be inserted into the commandline without manual editing. And\n> that's the point of the fast option selection process.\n\nGood to know.\n\nBTW I looked at the git.fish completion script [1] and see that recent\neffort to help automate more in git-completion.bash might help there\ntoo. I notice a lot of options and help text hard coded there, if\nsomeone can explain to me how git.fish uses those, maybe I can change\ngit to export something suitable for git.fish to use too [2].\n\nFor example with latest git (in 'master') doing this\n\n    ./git add --git-completion-helper\n\ngives you the list of all options of \"git add\". Giving the help text\nfor each option is definitely possible (I just didn't see any use for\nit until I looked at zsh/fish completion scripts) and maybe more in\nthe future.\n\n[1] https://github.com/fish-shell/fish-shell/blob/master/share/completions/git.fish\n[2] But then if your script has to work with old git versions too then\nthis is a moot point.\n-- \nDuy\n"},{"id":"347623","messageId":"bda62b25-a569-9199-5973-2ea7b223ed5d@gmail.com","threadId":"48312","inReplyTo":"CACsJy8CwwseqL9M=-ML6hwgHG_GSK6pfeQU+MGWsx6=WCCZtmQ@mail.gmail.com","subject":"Re: [PATCH/RFC] completion: complete all possible -no-<options>","fromName":"Andreas Heiduk","fromEmail":"asheiduk@gmail.com","sentAt":"2018-05-14T19:58:21Z","receivedAt":"2018-05-14T19:58:28Z","isPatch":true,"sender":{"key":"asheiduk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9371344?v=4"},"body":"Am 14.05.2018 um 19:26 schrieb Duy Nguyen:\n> On Mon, May 14, 2018 at 7:03 PM, Andreas Heiduk <asheiduk@gmail.com> wrote:\n>> Am 08.05.2018 um 17:24 schrieb Duy Nguyen:\n>>> On Mon, Apr 23, 2018 at 7:36 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>>>> I haven't looked at the implementation, so this may be an entirely\n>>>> stupid suggestion, but would it be possible to instead render the\n>>>> completions as?\n>>>>\n>>>>     % git checkout --<tab>\n>>>>     --[no-]conflict=                   --[no-]patch\n>>>>     --[no-]detach                      --[no-]progress\n>>>>     --[no-]ignore-other-worktrees      --[no-]quiet\n>>>>     --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules\n>>>>     --[no-]merge                       --theirs\n>>>>     --[no-]orphan=                     --[no-]track\n>>>>     --ours\n>>>>\n>>>> This would address the problem of the --no-* options taking double the\n>>>> screen space.\n>>>\n>>> It took me so long to reply partly because I remember seeing some guy\n>>> doing clever trick with tab completion that also shows a short help\n>>> text in addition to the complete words. I could not find that again\n>>> and from my reading (also internet searching) it's probably not\n>>> possible to do this without trickery.\n>>\n>> The fish-shell does something like that.\n>>\n>>     > git status --<tab here>\n>>     --branch  (Show the branch and tracking info even in short-format)\n>>     --help                       (Display the manual of a git command)\n>>     --ignore-submodules                 (Ignore changes to submodules)\n>>     --porcelain    (Give the output in a stable, easy-to-parse format)\n>>     --short                      (Give the output in the short-format)\n>>     --untracked-files              (The untracked files handling mode)\n>>\n>> Another tab will put a selection-cursor on the displayed list - you can\n>> navigate that list with Cursor-Up/Cursor-Down, select an entry and that\n>> entry will be inserted into the commandline. That selection process\n>> would be useless if the options are presented as \"--[no-]x\" because THAT\n>> cannot be inserted into the commandline without manual editing. And\n>> that's the point of the fast option selection process.\n> \n> Good to know.\n> \n> BTW I looked at the git.fish completion script [1] and see that recent\n> effort to help automate more in git-completion.bash might help there\n> too. I notice a lot of options and help text hard coded there, if\n> someone can explain to me how git.fish uses those, maybe I can change\n> git to export something suitable for git.fish to use too [2].\n\nI'm no expert, but some additional things required by fish (and I\nsuppose zsh too) but not by bash:\n\n- grouping of long and short options\n- help text\n- argument types for options\n\nHelp text and long/short option grouping look like this:\n\n    > git rebase -<tab>\n    --force-rebase  -f                                (Force the rebase)\n    --merge  -m                       (Use merging strategies to rebase)\n\nAll these infos seem to be available in `struct option` (for C stuff\nat least). So I guess It would be easiest for Fish & Co if git just\nexports the complete info in some stable format.\n\n> \n> For example with latest git (in 'master') doing this\n> \n>     ./git add --git-completion-helper\n> \n> gives you the list of all options of \"git add\". Giving the help text\n> for each option is definitely possible (I just didn't see any use for\n> it until I looked at zsh/fish completion scripts) and maybe more in\n> the future.\n> \n> [1] https://github.com/fish-shell/fish-shell/blob/master/share/completions/git.fish\n> [2] But then if your script has to work with old git versions too then\n> this is a moot point.\n\nWell, sooner or later those old git versions might not be supported by\nthose shells exactly due to the involved maintenance overhead. So\nproviding some helper is a step in the right direction. Not providing\nonly fossilizes the current state.\n"},{"id":"348621","messageId":"20180527083828.6919-1-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180417181300.23683-1-pclouds@gmail.com","subject":"[PATCH v2 0/3] completion: complete all possible -no-<options>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-27T08:38:25Z","receivedAt":"2018-05-27T08:38:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The RFC was here [1]. We have started recently to rely on\nparse-options to help complete options. One of the leftover items is\nallowing completing --no- form. This series enables that.\n\nChanges since the RFC version:\n\n- There's no magic numbers (previously we keep 3 --no- options)\n- When there are some --no- options hidden, then we show --no-...\n  instead of just --no-\n\n[1] https://public-inbox.org/git/20180417181300.23683-1-pclouds@gmail.com/\n\nNguyễn Thái Ngọc Duy (3):\n  parse-options: option to let --git-completion-helper show negative form\n  completion: suppress some -no- options\n  completion: collapse extra --no-.. options\n\n builtin/checkout.c                     | 10 +++--\n contrib/completion/git-completion.bash | 58 +++++++++++++++-----------\n parse-options.c                        | 58 ++++++++++++++++++++++++--\n t/t9902-completion.sh                  |  5 ++-\n 4 files changed, 97 insertions(+), 34 deletions(-)\n\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348622","messageId":"20180527083828.6919-2-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180527083828.6919-1-pclouds@gmail.com","subject":"[PATCH v2 1/3] parse-options: option to let --git-completion-helper show negative form","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-27T08:38:26Z","receivedAt":"2018-05-27T08:38:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"When 7fb6aefd2a (Merge branch 'nd/parseopt-completion' - 2018-03-14)\nis merged, the completion for negative form is left out because the\nseries is alread long and it could be done in a follow up series. This\nis it.\n\n--git-completion-helper now provides --no-xxx so that git-completion.bash\ncan drop the extra custom --no-xxx in the script. It adds a lot more\n--no-xxx than what's current provided by the git-completion.bash\nscript. We'll trim that down later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 38 ++++++++++----------------\n parse-options.c                        | 22 ++++++++++++---\n t/t9902-completion.sh                  | 16 +++++++++--\n 3 files changed, 46 insertions(+), 30 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 961a0ed76f..952e660f06 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1126,7 +1126,7 @@ _git_am ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin am \"--no-utf8\" \\\n+\t\t__gitcomp_builtin am \"\" \\\n \t\t\t\"$__git_am_inprogress_options\"\n \t\treturn\n \tesac\n@@ -1226,9 +1226,7 @@ _git_branch ()\n \t\t__git_complete_refs --cur=\"${cur##--set-upstream-to=}\"\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin branch \"--no-color --no-abbrev\n-\t\t\t--no-track --no-column\n-\t\t\t\"\n+\t\t__gitcomp_builtin branch\n \t\t;;\n \t*)\n \t\tif [ $only_local_ref = \"y\" -a $has_r = \"n\" ]; then\n@@ -1269,7 +1267,7 @@ _git_checkout ()\n \t\t__gitcomp \"diff3 merge\" \"\" \"${cur##--conflict=}\"\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin checkout \"--no-track --no-recurse-submodules\"\n+\t\t__gitcomp_builtin checkout\n \t\t;;\n \t*)\n \t\t# check if --track, --no-track, or --no-guess was specified\n@@ -1332,7 +1330,7 @@ _git_clone ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin clone \"--no-single-branch\"\n+\t\t__gitcomp_builtin clone\n \t\treturn\n \t\t;;\n \tesac\n@@ -1365,7 +1363,7 @@ _git_commit ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin commit \"--no-edit --verify\"\n+\t\t__gitcomp_builtin commit\n \t\treturn\n \tesac\n \n@@ -1468,7 +1466,7 @@ _git_fetch ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin fetch \"--no-tags\"\n+\t\t__gitcomp_builtin fetch\n \t\treturn\n \t\t;;\n \tesac\n@@ -1505,7 +1503,7 @@ _git_fsck ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin fsck \"--no-reflogs\"\n+\t\t__gitcomp_builtin fsck\n \t\treturn\n \t\t;;\n \tesac\n@@ -1612,7 +1610,7 @@ _git_ls_files ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin ls-files \"--no-empty-directory\"\n+\t\t__gitcomp_builtin ls-files\n \t\treturn\n \t\t;;\n \tesac\n@@ -1763,12 +1761,7 @@ _git_merge ()\n \n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin merge \"--no-rerere-autoupdate\n-\t\t\t\t--no-commit --no-edit --no-ff\n-\t\t\t\t--no-log --no-progress\n-\t\t\t\t--no-squash --no-stat\n-\t\t\t\t--no-verify-signatures\n-\t\t\t\t\"\n+\t\t__gitcomp_builtin merge\n \t\treturn\n \tesac\n \t__git_complete_refs\n@@ -1867,10 +1860,7 @@ _git_pull ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin pull \"--no-autostash --no-commit --no-edit\n-\t\t\t\t\t--no-ff --no-log --no-progress --no-rebase\n-\t\t\t\t\t--no-squash --no-stat --no-tags\n-\t\t\t\t\t--no-verify-signatures\"\n+\t\t__gitcomp_builtin pull\n \n \t\treturn\n \t\t;;\n@@ -2061,7 +2051,7 @@ _git_status ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin status \"--no-column\"\n+\t\t__gitcomp_builtin status\n \t\treturn\n \t\t;;\n \tesac\n@@ -2615,7 +2605,7 @@ _git_remote ()\n \n \tcase \"$subcommand,$cur\" in\n \tadd,--*)\n-\t\t__gitcomp_builtin remote_add \"--no-tags\"\n+\t\t__gitcomp_builtin remote_add\n \t\t;;\n \tadd,*)\n \t\t;;\n@@ -2695,7 +2685,7 @@ _git_revert ()\n \tfi\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin revert \"--no-edit\" \\\n+\t\t__gitcomp_builtin revert \"\" \\\n \t\t\t\"$__git_revert_inprogress_options\"\n \t\treturn\n \t\t;;\n@@ -2765,7 +2755,7 @@ _git_show_branch ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin show-branch \"--no-color\"\n+\t\t__gitcomp_builtin show-branch\n \t\treturn\n \t\t;;\n \tesac\ndiff --git a/parse-options.c b/parse-options.c\nindex 0f7059a8ab..b86612148f 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,15 +427,12 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \tparse_options_check(options);\n }\n \n-/*\n- * TODO: we are not completing the --no-XXX form yet because there are\n- * many options that do not suppress it properly.\n- */\n static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tconst struct option *opts)\n {\n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tconst char *suffix = \"\";\n+\t\tint has_unset_form = 0;\n \n \t\tif (!opts->long_name)\n \t\t\tcontinue;\n@@ -450,6 +447,8 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\tcase OPTION_INTEGER:\n \t\tcase OPTION_MAGNITUDE:\n \t\tcase OPTION_CALLBACK:\n+\t\t\thas_unset_form = 1;\n+\n \t\t\tif (opts->flags & PARSE_OPT_NOARG)\n \t\t\t\tbreak;\n \t\t\tif (opts->flags & PARSE_OPT_OPTARG)\n@@ -458,12 +457,27 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\t\tbreak;\n \t\t\tsuffix = \"=\";\n \t\t\tbreak;\n+\t\tcase OPTION_BIT:\n+\t\tcase OPTION_NEGBIT:\n+\t\tcase OPTION_COUNTUP:\n+\t\tcase OPTION_SET_INT:\n+\t\t\thas_unset_form = 1;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n \t\tif (opts->flags & PARSE_OPT_COMP_ARG)\n \t\t\tsuffix = \"=\";\n \t\tprintf(\" --%s%s\", opts->long_name, suffix);\n+\n+\t\tif (has_unset_form && !(opts->flags & PARSE_OPT_NONEG)) {\n+\t\t\tconst char *name;\n+\n+\t\t\tif (skip_prefix(opts->long_name, \"no-\", &name))\n+\t\t\t\tprintf(\" --%s\", name);\n+\t\t\telse\n+\t\t\t\tprintf(\" --no-%s\", opts->long_name);\n+\t\t}\n \t}\n \tfputc('\\n', stdout);\n \texit(0);\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..07c3e3b760 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1237,20 +1237,31 @@ test_expect_success 'double dash \"git\" itself' '\n test_expect_success 'double dash \"git checkout\"' '\n \ttest_completion \"git checkout --\" <<-\\EOF\n \t--quiet Z\n+\t--no-quiet Z\n \t--detach Z\n+\t--no-detach Z\n \t--track Z\n+\t--no-track Z\n \t--orphan=Z\n+\t--no-orphan Z\n \t--ours Z\n+\t--no-ours Z\n \t--theirs Z\n+\t--no-theirs Z\n \t--merge Z\n+\t--no-merge Z\n \t--conflict=Z\n+\t--no-conflict Z\n \t--patch Z\n+\t--no-patch Z\n \t--ignore-skip-worktree-bits Z\n+\t--no-ignore-skip-worktree-bits Z\n \t--ignore-other-worktrees Z\n+\t--no-ignore-other-worktrees Z\n \t--recurse-submodules Z\n-\t--progress Z\n-\t--no-track Z\n \t--no-recurse-submodules Z\n+\t--progress Z\n+\t--no-progress Z\n \tEOF\n '\n \n@@ -1457,6 +1468,7 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c\n test_expect_success 'completion without explicit _git_xxx function' '\n \ttest_completion \"git version --\" <<-\\EOF\n \t--build-options Z\n+\t--no-build-options Z\n \tEOF\n '\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348623","messageId":"20180527083828.6919-4-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180527083828.6919-1-pclouds@gmail.com","subject":"[PATCH v2 3/3] completion: collapse extra --no-.. options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-27T08:38:28Z","receivedAt":"2018-05-27T08:38:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The commands that make use of --git-completion-helper feature could\nnow produce a lot of --no-xxx options that a command can take. This in\nmany case could nearly double the amount of completable options, using\nmore screen estate and also harder to search for the wanted option.\n\nThis patch attempts to mitigate that by collapsing extra --no-\noptions, the ones that are added by --git-completion-helper and not in\noriginal struct option arrays. The \"--no-...\" option will be displayed\nin this case to hint about more options, e.g.\n\n    > ~/w/git $ git clone --\n    --bare                 --origin=\n    --branch=              --progress\n    --checkout             --quiet\n    --config=              --recurse-submodules\n    --depth=               --reference=\n    --dissociate           --reference-if-able=\n    --filter=              --separate-git-dir=\n    --hardlinks            --shallow-exclude=\n    --ipv4                 --shallow-since=\n    --ipv6                 --shallow-submodules\n    --jobs=                --shared\n    --local                --single-branch\n    --mirror               --tags\n    --no-...               --template=\n    --no-checkout          --upload-pack=\n    --no-hardlinks         --verbose\n    --no-tags\n\nand when you complete it with --no-<tab>, all negative options will be\npresented:\n\n    > ~/w/git $ git clone --no-\n    --no-bare                 --no-quiet\n    --no-branch               --no-recurse-submodules\n    --no-checkout             --no-reference\n    --no-config               --no-reference-if-able\n    --no-depth                --no-separate-git-dir\n    --no-dissociate           --no-shallow-exclude\n    --no-filter               --no-shallow-since\n    --no-hardlinks            --no-shallow-submodules\n    --no-ipv4                 --no-shared\n    --no-ipv6                 --no-single-branch\n    --no-jobs                 --no-tags\n    --no-local                --no-template\n    --no-mirror               --no-upload-pack\n    --no-origin               --no-verbose\n    --no-progress\n\nCorner case: to make sure that people will never accidentally complete\nthe fake option \"--no-...\" there must be one real --no- in the first\ncomplete listing even if it's not from the original struct option.\n\nPS. This could could be made simpler with \";&\" to fall through from\n\"--no-*\" block and share the code but \";&\" is not available on bash-3\n(i.e. Mac)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 20 +++++++\n parse-options.c                        | 72 +++++++++++++++++++-------\n t/t9902-completion.sh                  | 13 +----\n 3 files changed, 76 insertions(+), 29 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 952e660f06..4eef353ee2 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -266,9 +266,29 @@ __gitcomp ()\n \tcase \"$cur_\" in\n \t--*=)\n \t\t;;\n+\t--no-*)\n+\t\tlocal c i=0 IFS=$' \\t\\n'\n+\t\tfor c in $1; do\n+\t\t\tif [[ $c == \"--\" ]]; then\n+\t\t\t\tcontinue\n+\t\t\tfi\n+\t\t\tc=\"$c${4-}\"\n+\t\t\tif [[ $c == \"$cur_\"* ]]; then\n+\t\t\t\tcase $c in\n+\t\t\t\t--*=*|*.) ;;\n+\t\t\t\t*) c=\"$c \" ;;\n+\t\t\t\tesac\n+\t\t\t\tCOMPREPLY[i++]=\"${2-}$c\"\n+\t\t\tfi\n+\t\tdone\n+\t\t;;\n \t*)\n \t\tlocal c i=0 IFS=$' \\t\\n'\n \t\tfor c in $1; do\n+\t\t\tif [[ $c == \"--\" ]]; then\n+\t\t\t\tCOMPREPLY[i++]=\"${2-}--no-...${4-} \"\n+\t\t\t\tbreak\n+\t\t\tfi\n \t\t\tc=\"$c${4-}\"\n \t\t\tif [[ $c == \"$cur_\"* ]]; then\n \t\t\t\tcase $c in\ndiff --git a/parse-options.c b/parse-options.c\nindex b86612148f..7db84227ab 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,12 +427,61 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \tparse_options_check(options);\n }\n \n+static void show_negated_gitcomp(const struct option *opts, int nr_noopts)\n+{\n+\tint printed_dashdash = 0;\n+\n+\tfor (; opts->type != OPTION_END; opts++) {\n+\t\tint has_unset_form = 0;\n+\t\tconst char *name;\n+\n+\t\tif (!opts->long_name)\n+\t\t\tcontinue;\n+\t\tif (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))\n+\t\t\tcontinue;\n+\t\tif (opts->flags & PARSE_OPT_NONEG)\n+\t\t\tcontinue;\n+\n+\t\tswitch (opts->type) {\n+\t\tcase OPTION_STRING:\n+\t\tcase OPTION_FILENAME:\n+\t\tcase OPTION_INTEGER:\n+\t\tcase OPTION_MAGNITUDE:\n+\t\tcase OPTION_CALLBACK:\n+\t\tcase OPTION_BIT:\n+\t\tcase OPTION_NEGBIT:\n+\t\tcase OPTION_COUNTUP:\n+\t\tcase OPTION_SET_INT:\n+\t\t\thas_unset_form = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!has_unset_form)\n+\t\t\tcontinue;\n+\n+\t\tif (skip_prefix(opts->long_name, \"no-\", &name)) {\n+\t\t\tif (nr_noopts < 0)\n+\t\t\t\tprintf(\" --%s\", name);\n+\t\t} else if (nr_noopts >= 0) {\n+\t\t\tif (nr_noopts && !printed_dashdash) {\n+\t\t\t\tprintf(\" --\");\n+\t\t\t\tprinted_dashdash = 1;\n+\t\t\t}\n+\t\t\tprintf(\" --no-%s\", opts->long_name);\n+\t\t\tnr_noopts++;\n+\t\t}\n+\t}\n+}\n+\n static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tconst struct option *opts)\n {\n+\tconst struct option *original_opts = opts;\n+\tint nr_noopts = 0;\n+\n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tconst char *suffix = \"\";\n-\t\tint has_unset_form = 0;\n \n \t\tif (!opts->long_name)\n \t\t\tcontinue;\n@@ -447,8 +496,6 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\tcase OPTION_INTEGER:\n \t\tcase OPTION_MAGNITUDE:\n \t\tcase OPTION_CALLBACK:\n-\t\t\thas_unset_form = 1;\n-\n \t\t\tif (opts->flags & PARSE_OPT_NOARG)\n \t\t\t\tbreak;\n \t\t\tif (opts->flags & PARSE_OPT_OPTARG)\n@@ -457,28 +504,17 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\t\tbreak;\n \t\t\tsuffix = \"=\";\n \t\t\tbreak;\n-\t\tcase OPTION_BIT:\n-\t\tcase OPTION_NEGBIT:\n-\t\tcase OPTION_COUNTUP:\n-\t\tcase OPTION_SET_INT:\n-\t\t\thas_unset_form = 1;\n-\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n \t\tif (opts->flags & PARSE_OPT_COMP_ARG)\n \t\t\tsuffix = \"=\";\n+\t\tif (starts_with(opts->long_name, \"no-\"))\n+\t\t\tnr_noopts++;\n \t\tprintf(\" --%s%s\", opts->long_name, suffix);\n-\n-\t\tif (has_unset_form && !(opts->flags & PARSE_OPT_NONEG)) {\n-\t\t\tconst char *name;\n-\n-\t\t\tif (skip_prefix(opts->long_name, \"no-\", &name))\n-\t\t\t\tprintf(\" --%s\", name);\n-\t\t\telse\n-\t\t\t\tprintf(\" --no-%s\", opts->long_name);\n-\t\t}\n \t}\n+\tshow_negated_gitcomp(original_opts, -1);\n+\tshow_negated_gitcomp(original_opts, nr_noopts);\n \tfputc('\\n', stdout);\n \texit(0);\n }\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 7e5e3ad5b1..eb4a43584a 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1237,29 +1237,20 @@ test_expect_success 'double dash \"git\" itself' '\n test_expect_success 'double dash \"git checkout\"' '\n \ttest_completion \"git checkout --\" <<-\\EOF\n \t--quiet Z\n-\t--no-quiet Z\n \t--detach Z\n-\t--no-detach Z\n \t--track Z\n-\t--no-track Z\n \t--orphan=Z\n-\t--no-orphan Z\n \t--ours Z\n \t--theirs Z\n \t--merge Z\n-\t--no-merge Z\n \t--conflict=Z\n-\t--no-conflict Z\n \t--patch Z\n-\t--no-patch Z\n \t--ignore-skip-worktree-bits Z\n-\t--no-ignore-skip-worktree-bits Z\n \t--ignore-other-worktrees Z\n-\t--no-ignore-other-worktrees Z\n \t--recurse-submodules Z\n-\t--no-recurse-submodules Z\n \t--progress Z\n-\t--no-progress Z\n+\t--no-quiet Z\n+\t--no-... Z\n \tEOF\n '\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348624","messageId":"20180527083828.6919-3-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180527083828.6919-1-pclouds@gmail.com","subject":"[PATCH v2 2/3] completion: suppress some -no- options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-27T08:38:27Z","receivedAt":"2018-05-27T08:38:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Most --no- options do have some use, even if rarely to negate some\noption that's specified in an alias.\n\nThese options --no-ours and --no-theirs however have no clear\nsemantics. If I specify \"--ours --no-theirs\", the second will reset\nwriteout stage and is equivalent of \"--no-ours --no-theirs\" which is\nnot that easy to see. Drop them. You can either switch from --ours to\n--theirs and back but you can never negate them.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c    | 10 ++++++----\n t/t9902-completion.sh |  2 --\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2b3b768eff..c7670dbbfe 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1119,10 +1119,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('t', \"track\",  &opts.track, N_(\"set upstream info for new branch\"),\n \t\t\tBRANCH_TRACK_EXPLICIT),\n \t\tOPT_STRING(0, \"orphan\", &opts.new_orphan_branch, N_(\"new-branch\"), N_(\"new unparented branch\")),\n-\t\tOPT_SET_INT('2', \"ours\", &opts.writeout_stage, N_(\"checkout our version for unmerged files\"),\n-\t\t\t    2),\n-\t\tOPT_SET_INT('3', \"theirs\", &opts.writeout_stage, N_(\"checkout their version for unmerged files\"),\n-\t\t\t    3),\n+\t\tOPT_SET_INT_F('2', \"ours\", &opts.writeout_stage,\n+\t\t\t      N_(\"checkout our version for unmerged files\"),\n+\t\t\t      2, PARSE_OPT_NONEG),\n+\t\tOPT_SET_INT_F('3', \"theirs\", &opts.writeout_stage,\n+\t\t\t      N_(\"checkout their version for unmerged files\"),\n+\t\t\t      3, PARSE_OPT_NONEG),\n \t\tOPT__FORCE(&opts.force, N_(\"force checkout (throw away local modifications)\"),\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_BOOL('m', \"merge\", &opts.merge, N_(\"perform a 3-way merge with the new branch\")),\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 07c3e3b760..7e5e3ad5b1 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1245,9 +1245,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--orphan=Z\n \t--no-orphan Z\n \t--ours Z\n-\t--no-ours Z\n \t--theirs Z\n-\t--no-theirs Z\n \t--merge Z\n \t--no-merge Z\n \t--conflict=Z\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"348714","messageId":"CAGZ79kZ+kDRHKJj917rZ-=mmusuTcB4_Su-BNupqdQqT6rWRaQ@mail.gmail.com","threadId":"48312","inReplyTo":"20180527083828.6919-4-pclouds@gmail.com","subject":"Re: [PATCH v2 3/3] completion: collapse extra --no-.. options","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-29T18:48:51Z","receivedAt":"2018-05-29T18:48:55Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Sun, May 27, 2018 at 1:38 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> The commands that make use of --git-completion-helper feature could\n> now produce a lot of --no-xxx options that a command can take. This in\n> many case could nearly double the amount of completable options, using\n> more screen estate and also harder to search for the wanted option.\n>\n> This patch attempts to mitigate that by collapsing extra --no-\n> options, the ones that are added by --git-completion-helper and not in\n> original struct option arrays. The \"--no-...\" option will be displayed\n> in this case to hint about more options, e.g.\n>\n>     > ~/w/git $ git clone --\n>     --bare                 --origin=\n>     --branch=              --progress\n>     --checkout             --quiet\n>     --config=              --recurse-submodules\n>     --depth=               --reference=\n>     --dissociate           --reference-if-able=\n>     --filter=              --separate-git-dir=\n>     --hardlinks            --shallow-exclude=\n>     --ipv4                 --shallow-since=\n>     --ipv6                 --shallow-submodules\n>     --jobs=                --shared\n>     --local                --single-branch\n>     --mirror               --tags\n>     --no-...               --template=\n>     --no-checkout          --upload-pack=\n>     --no-hardlinks         --verbose\n>     --no-tags\n\nhttps://public-inbox.org/git/20180527083828.6919-1-pclouds@gmail.com/\n\" There's no magic numbers (previously we keep 3 --no- options)\"\n\nHere I see 3 no- options, is the number how many no's to show configurable now?\n"},{"id":"348715","messageId":"CACsJy8Cq8LaFf=fvU02e4aepOUXC8CUTFeiUVHVvzYk50AqmVA@mail.gmail.com","threadId":"48312","inReplyTo":"CAGZ79kZ+kDRHKJj917rZ-=mmusuTcB4_Su-BNupqdQqT6rWRaQ@mail.gmail.com","subject":"Re: [PATCH v2 3/3] completion: collapse extra --no-.. options","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-29T19:04:31Z","receivedAt":"2018-05-29T19:05:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, May 29, 2018 at 8:48 PM, Stefan Beller <sbeller@google.com> wrote:\n> On Sun, May 27, 2018 at 1:38 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> The commands that make use of --git-completion-helper feature could\n>> now produce a lot of --no-xxx options that a command can take. This in\n>> many case could nearly double the amount of completable options, using\n>> more screen estate and also harder to search for the wanted option.\n>>\n>> This patch attempts to mitigate that by collapsing extra --no-\n>> options, the ones that are added by --git-completion-helper and not in\n>> original struct option arrays. The \"--no-...\" option will be displayed\n>> in this case to hint about more options, e.g.\n>>\n>>     > ~/w/git $ git clone --\n>>     --bare                 --origin=\n>>     --branch=              --progress\n>>     --checkout             --quiet\n>>     --config=              --recurse-submodules\n>>     --depth=               --reference=\n>>     --dissociate           --reference-if-able=\n>>     --filter=              --separate-git-dir=\n>>     --hardlinks            --shallow-exclude=\n>>     --ipv4                 --shallow-since=\n>>     --ipv6                 --shallow-submodules\n>>     --jobs=                --shared\n>>     --local                --single-branch\n>>     --mirror               --tags\n>>     --no-...               --template=\n>>     --no-checkout          --upload-pack=\n>>     --no-hardlinks         --verbose\n>>     --no-tags\n>\n> https://public-inbox.org/git/20180527083828.6919-1-pclouds@gmail.com/\n> \" There's no magic numbers (previously we keep 3 --no- options)\"\n>\n> Here I see 3 no- options, is the number how many no's to show configurable now?\n\nIn a sense, yes. If you write OPT_BOOL(0, \"no-foo\",...) then that\n--no-foo _always_ shows. \"git clone\" just happens to have three of\nthem.\n-- \nDuy\n"},{"id":"349463","messageId":"20180606094139.30906-1-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180527083828.6919-1-pclouds@gmail.com","subject":"[PATCH v3 0/3] ompletion: complete all possible -no-<options>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T09:41:36Z","receivedAt":"2018-06-06T09:42:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v3 fixes an annoying bug in 3/3. If you do \"git commit --fi<tab>\"\nthen the \"fi\" part is eaten up by bash and you got back to\n\"git commit --\" on the command line.\n\nThis is because we give COMPREPLY with two options \"--fixup\" and\n\"--no-...\". The second one forces the common prefix \"--\" for both\nof them, instead of \"--fi\". Bash does the rest according to the book.\n\nSome tests are added to verify new behavior in __gitcomp and make sure\nthis does not happen again.\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 4eef353ee2..425d06256f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -286,7 +286,10 @@ __gitcomp ()\n \t\tlocal c i=0 IFS=$' \\t\\n'\n \t\tfor c in $1; do\n \t\t\tif [[ $c == \"--\" ]]; then\n-\t\t\t\tCOMPREPLY[i++]=\"${2-}--no-...${4-} \"\n+\t\t\t\tc=\"--no-...${4-}\"\n+\t\t\t\tif [[ $c == \"$cur_\"* ]]; then\n+\t\t\t\t\tCOMPREPLY[i++]=\"${2-}$c \"\n+\t\t\t\tfi\n \t\t\t\tbreak\n \t\t\tfi\n \t\t\tc=\"$c${4-}\"\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex eb4a43584a..157ee7085d 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -459,6 +459,42 @@ test_expect_success '__gitcomp - suffix' '\n \tEOF\n '\n \n+test_expect_success '__gitcomp - ignore optional negative options' '\n+\ttest_gitcomp \"--\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--abc Z\n+\t--def Z\n+\t--no-one Z\n+\t--no-... Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - ignore/narrow optional negative options' '\n+\ttest_gitcomp \"--a\" \"--abc --abcdef --no-one -- --no-two\" <<-\\EOF\n+\t--abc Z\n+\t--abcdef Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - ignore/narrow optional negative options' '\n+\ttest_gitcomp \"--n\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\t--no-... Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - expand all negative options' '\n+\ttest_gitcomp \"--no-\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\t--no-two Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - expand/narrow all negative options' '\n+\ttest_gitcomp \"--no-o\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\tEOF\n+'\n+\n test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '\n \t__gitcomp \"$invalid_variable_name\"\n '\n\n\nNguyễn Thái Ngọc Duy (3):\n  parse-options: option to let --git-completion-helper show negative\n    form\n  completion: suppress some -no- options\n  completion: collapse extra --no-.. options\n\n builtin/checkout.c                     | 10 +++--\n contrib/completion/git-completion.bash | 61 ++++++++++++++++----------\n parse-options.c                        | 58 ++++++++++++++++++++++--\n t/t9902-completion.sh                  | 41 ++++++++++++++++-\n 4 files changed, 136 insertions(+), 34 deletions(-)\n\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349464","messageId":"20180606094139.30906-3-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180606094139.30906-1-pclouds@gmail.com","subject":"[PATCH v3 2/3] completion: suppress some -no- options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T09:41:38Z","receivedAt":"2018-06-06T09:42:10Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Most --no- options do have some use, even if rarely to negate some\noption that's specified in an alias.\n\nThese options --no-ours and --no-theirs however have no clear\nsemantics. If I specify \"--ours --no-theirs\", the second will reset\nwriteout stage and is equivalent of \"--no-ours --no-theirs\" which is\nnot that easy to see. Drop them. You can either switch from --ours to\n--theirs and back but you can never negate them.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c    | 10 ++++++----\n t/t9902-completion.sh |  2 --\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2b3b768eff..c7670dbbfe 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1119,10 +1119,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('t', \"track\",  &opts.track, N_(\"set upstream info for new branch\"),\n \t\t\tBRANCH_TRACK_EXPLICIT),\n \t\tOPT_STRING(0, \"orphan\", &opts.new_orphan_branch, N_(\"new-branch\"), N_(\"new unparented branch\")),\n-\t\tOPT_SET_INT('2', \"ours\", &opts.writeout_stage, N_(\"checkout our version for unmerged files\"),\n-\t\t\t    2),\n-\t\tOPT_SET_INT('3', \"theirs\", &opts.writeout_stage, N_(\"checkout their version for unmerged files\"),\n-\t\t\t    3),\n+\t\tOPT_SET_INT_F('2', \"ours\", &opts.writeout_stage,\n+\t\t\t      N_(\"checkout our version for unmerged files\"),\n+\t\t\t      2, PARSE_OPT_NONEG),\n+\t\tOPT_SET_INT_F('3', \"theirs\", &opts.writeout_stage,\n+\t\t\t      N_(\"checkout their version for unmerged files\"),\n+\t\t\t      3, PARSE_OPT_NONEG),\n \t\tOPT__FORCE(&opts.force, N_(\"force checkout (throw away local modifications)\"),\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_BOOL('m', \"merge\", &opts.merge, N_(\"perform a 3-way merge with the new branch\")),\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 07c3e3b760..7e5e3ad5b1 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1245,9 +1245,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--orphan=Z\n \t--no-orphan Z\n \t--ours Z\n-\t--no-ours Z\n \t--theirs Z\n-\t--no-theirs Z\n \t--merge Z\n \t--no-merge Z\n \t--conflict=Z\n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349465","messageId":"20180606094139.30906-2-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180606094139.30906-1-pclouds@gmail.com","subject":"[PATCH v3 1/3] parse-options: option to let --git-completion-helper show negative form","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T09:41:37Z","receivedAt":"2018-06-06T09:42:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"When 7fb6aefd2a (Merge branch 'nd/parseopt-completion' - 2018-03-14)\nis merged, the completion for negative form is left out because the\nseries is alread long and it could be done in a follow up series. This\nis it.\n\n--git-completion-helper now provides --no-xxx so that git-completion.bash\ncan drop the extra custom --no-xxx in the script. It adds a lot more\n--no-xxx than what's current provided by the git-completion.bash\nscript. We'll trim that down later.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n contrib/completion/git-completion.bash | 38 ++++++++++----------------\n parse-options.c                        | 22 ++++++++++++---\n t/t9902-completion.sh                  | 16 +++++++++--\n 3 files changed, 46 insertions(+), 30 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 961a0ed76f..952e660f06 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1126,7 +1126,7 @@ _git_am ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin am \"--no-utf8\" \\\n+\t\t__gitcomp_builtin am \"\" \\\n \t\t\t\"$__git_am_inprogress_options\"\n \t\treturn\n \tesac\n@@ -1226,9 +1226,7 @@ _git_branch ()\n \t\t__git_complete_refs --cur=\"${cur##--set-upstream-to=}\"\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin branch \"--no-color --no-abbrev\n-\t\t\t--no-track --no-column\n-\t\t\t\"\n+\t\t__gitcomp_builtin branch\n \t\t;;\n \t*)\n \t\tif [ $only_local_ref = \"y\" -a $has_r = \"n\" ]; then\n@@ -1269,7 +1267,7 @@ _git_checkout ()\n \t\t__gitcomp \"diff3 merge\" \"\" \"${cur##--conflict=}\"\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin checkout \"--no-track --no-recurse-submodules\"\n+\t\t__gitcomp_builtin checkout\n \t\t;;\n \t*)\n \t\t# check if --track, --no-track, or --no-guess was specified\n@@ -1332,7 +1330,7 @@ _git_clone ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin clone \"--no-single-branch\"\n+\t\t__gitcomp_builtin clone\n \t\treturn\n \t\t;;\n \tesac\n@@ -1365,7 +1363,7 @@ _git_commit ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin commit \"--no-edit --verify\"\n+\t\t__gitcomp_builtin commit\n \t\treturn\n \tesac\n \n@@ -1468,7 +1466,7 @@ _git_fetch ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin fetch \"--no-tags\"\n+\t\t__gitcomp_builtin fetch\n \t\treturn\n \t\t;;\n \tesac\n@@ -1505,7 +1503,7 @@ _git_fsck ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin fsck \"--no-reflogs\"\n+\t\t__gitcomp_builtin fsck\n \t\treturn\n \t\t;;\n \tesac\n@@ -1612,7 +1610,7 @@ _git_ls_files ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin ls-files \"--no-empty-directory\"\n+\t\t__gitcomp_builtin ls-files\n \t\treturn\n \t\t;;\n \tesac\n@@ -1763,12 +1761,7 @@ _git_merge ()\n \n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin merge \"--no-rerere-autoupdate\n-\t\t\t\t--no-commit --no-edit --no-ff\n-\t\t\t\t--no-log --no-progress\n-\t\t\t\t--no-squash --no-stat\n-\t\t\t\t--no-verify-signatures\n-\t\t\t\t\"\n+\t\t__gitcomp_builtin merge\n \t\treturn\n \tesac\n \t__git_complete_refs\n@@ -1867,10 +1860,7 @@ _git_pull ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin pull \"--no-autostash --no-commit --no-edit\n-\t\t\t\t\t--no-ff --no-log --no-progress --no-rebase\n-\t\t\t\t\t--no-squash --no-stat --no-tags\n-\t\t\t\t\t--no-verify-signatures\"\n+\t\t__gitcomp_builtin pull\n \n \t\treturn\n \t\t;;\n@@ -2061,7 +2051,7 @@ _git_status ()\n \t\treturn\n \t\t;;\n \t--*)\n-\t\t__gitcomp_builtin status \"--no-column\"\n+\t\t__gitcomp_builtin status\n \t\treturn\n \t\t;;\n \tesac\n@@ -2615,7 +2605,7 @@ _git_remote ()\n \n \tcase \"$subcommand,$cur\" in\n \tadd,--*)\n-\t\t__gitcomp_builtin remote_add \"--no-tags\"\n+\t\t__gitcomp_builtin remote_add\n \t\t;;\n \tadd,*)\n \t\t;;\n@@ -2695,7 +2685,7 @@ _git_revert ()\n \tfi\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin revert \"--no-edit\" \\\n+\t\t__gitcomp_builtin revert \"\" \\\n \t\t\t\"$__git_revert_inprogress_options\"\n \t\treturn\n \t\t;;\n@@ -2765,7 +2755,7 @@ _git_show_branch ()\n {\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp_builtin show-branch \"--no-color\"\n+\t\t__gitcomp_builtin show-branch\n \t\treturn\n \t\t;;\n \tesac\ndiff --git a/parse-options.c b/parse-options.c\nindex 0f7059a8ab..b86612148f 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,15 +427,12 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \tparse_options_check(options);\n }\n \n-/*\n- * TODO: we are not completing the --no-XXX form yet because there are\n- * many options that do not suppress it properly.\n- */\n static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tconst struct option *opts)\n {\n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tconst char *suffix = \"\";\n+\t\tint has_unset_form = 0;\n \n \t\tif (!opts->long_name)\n \t\t\tcontinue;\n@@ -450,6 +447,8 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\tcase OPTION_INTEGER:\n \t\tcase OPTION_MAGNITUDE:\n \t\tcase OPTION_CALLBACK:\n+\t\t\thas_unset_form = 1;\n+\n \t\t\tif (opts->flags & PARSE_OPT_NOARG)\n \t\t\t\tbreak;\n \t\t\tif (opts->flags & PARSE_OPT_OPTARG)\n@@ -458,12 +457,27 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\t\tbreak;\n \t\t\tsuffix = \"=\";\n \t\t\tbreak;\n+\t\tcase OPTION_BIT:\n+\t\tcase OPTION_NEGBIT:\n+\t\tcase OPTION_COUNTUP:\n+\t\tcase OPTION_SET_INT:\n+\t\t\thas_unset_form = 1;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n \t\tif (opts->flags & PARSE_OPT_COMP_ARG)\n \t\t\tsuffix = \"=\";\n \t\tprintf(\" --%s%s\", opts->long_name, suffix);\n+\n+\t\tif (has_unset_form && !(opts->flags & PARSE_OPT_NONEG)) {\n+\t\t\tconst char *name;\n+\n+\t\t\tif (skip_prefix(opts->long_name, \"no-\", &name))\n+\t\t\t\tprintf(\" --%s\", name);\n+\t\t\telse\n+\t\t\t\tprintf(\" --no-%s\", opts->long_name);\n+\t\t}\n \t}\n \tfputc('\\n', stdout);\n \texit(0);\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..07c3e3b760 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1237,20 +1237,31 @@ test_expect_success 'double dash \"git\" itself' '\n test_expect_success 'double dash \"git checkout\"' '\n \ttest_completion \"git checkout --\" <<-\\EOF\n \t--quiet Z\n+\t--no-quiet Z\n \t--detach Z\n+\t--no-detach Z\n \t--track Z\n+\t--no-track Z\n \t--orphan=Z\n+\t--no-orphan Z\n \t--ours Z\n+\t--no-ours Z\n \t--theirs Z\n+\t--no-theirs Z\n \t--merge Z\n+\t--no-merge Z\n \t--conflict=Z\n+\t--no-conflict Z\n \t--patch Z\n+\t--no-patch Z\n \t--ignore-skip-worktree-bits Z\n+\t--no-ignore-skip-worktree-bits Z\n \t--ignore-other-worktrees Z\n+\t--no-ignore-other-worktrees Z\n \t--recurse-submodules Z\n-\t--progress Z\n-\t--no-track Z\n \t--no-recurse-submodules Z\n+\t--progress Z\n+\t--no-progress Z\n \tEOF\n '\n \n@@ -1457,6 +1468,7 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c\n test_expect_success 'completion without explicit _git_xxx function' '\n \ttest_completion \"git version --\" <<-\\EOF\n \t--build-options Z\n+\t--no-build-options Z\n \tEOF\n '\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"},{"id":"349466","messageId":"20180606094139.30906-4-pclouds@gmail.com","threadId":"48312","inReplyTo":"20180606094139.30906-1-pclouds@gmail.com","subject":"[PATCH v3 3/3] completion: collapse extra --no-.. options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-06-06T09:41:39Z","receivedAt":"2018-06-06T09:42:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The commands that make use of --git-completion-helper feature could\nnow produce a lot of --no-xxx options that a command can take. This in\nmany case could nearly double the amount of completable options, using\nmore screen estate and also harder to search for the wanted option.\n\nThis patch attempts to mitigate that by collapsing extra --no-\noptions, the ones that are added by --git-completion-helper and not in\noriginal struct option arrays. The \"--no-...\" option will be displayed\nin this case to hint about more options, e.g.\n\n    > ~/w/git $ git clone --\n    --bare                 --origin=\n    --branch=              --progress\n    --checkout             --quiet\n    --config=              --recurse-submodules\n    --depth=               --reference=\n    --dissociate           --reference-if-able=\n    --filter=              --separate-git-dir=\n    --hardlinks            --shallow-exclude=\n    --ipv4                 --shallow-since=\n    --ipv6                 --shallow-submodules\n    --jobs=                --shared\n    --local                --single-branch\n    --mirror               --tags\n    --no-...               --template=\n    --no-checkout          --upload-pack=\n    --no-hardlinks         --verbose\n    --no-tags\n\nand when you complete it with --no-<tab>, all negative options will be\npresented:\n\n    > ~/w/git $ git clone --no-\n    --no-bare                 --no-quiet\n    --no-branch               --no-recurse-submodules\n    --no-checkout             --no-reference\n    --no-config               --no-reference-if-able\n    --no-depth                --no-separate-git-dir\n    --no-dissociate           --no-shallow-exclude\n    --no-filter               --no-shallow-since\n    --no-hardlinks            --no-shallow-submodules\n    --no-ipv4                 --no-shared\n    --no-ipv6                 --no-single-branch\n    --no-jobs                 --no-tags\n    --no-local                --no-template\n    --no-mirror               --no-upload-pack\n    --no-origin               --no-verbose\n    --no-progress\n\nCorner case: to make sure that people will never accidentally complete\nthe fake option \"--no-...\" there must be one real --no- in the first\ncomplete listing even if it's not from the original struct option.\n\nPS. This could could be made simpler with \";&\" to fall through from\n\"--no-*\" block and share the code but \";&\" is not available on bash-3\n(i.e. Mac)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n contrib/completion/git-completion.bash | 23 ++++++++\n parse-options.c                        | 72 +++++++++++++++++++-------\n t/t9902-completion.sh                  | 49 ++++++++++++++----\n 3 files changed, 115 insertions(+), 29 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 952e660f06..425d06256f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -266,9 +266,32 @@ __gitcomp ()\n \tcase \"$cur_\" in\n \t--*=)\n \t\t;;\n+\t--no-*)\n+\t\tlocal c i=0 IFS=$' \\t\\n'\n+\t\tfor c in $1; do\n+\t\t\tif [[ $c == \"--\" ]]; then\n+\t\t\t\tcontinue\n+\t\t\tfi\n+\t\t\tc=\"$c${4-}\"\n+\t\t\tif [[ $c == \"$cur_\"* ]]; then\n+\t\t\t\tcase $c in\n+\t\t\t\t--*=*|*.) ;;\n+\t\t\t\t*) c=\"$c \" ;;\n+\t\t\t\tesac\n+\t\t\t\tCOMPREPLY[i++]=\"${2-}$c\"\n+\t\t\tfi\n+\t\tdone\n+\t\t;;\n \t*)\n \t\tlocal c i=0 IFS=$' \\t\\n'\n \t\tfor c in $1; do\n+\t\t\tif [[ $c == \"--\" ]]; then\n+\t\t\t\tc=\"--no-...${4-}\"\n+\t\t\t\tif [[ $c == \"$cur_\"* ]]; then\n+\t\t\t\t\tCOMPREPLY[i++]=\"${2-}$c \"\n+\t\t\t\tfi\n+\t\t\t\tbreak\n+\t\t\tfi\n \t\t\tc=\"$c${4-}\"\n \t\t\tif [[ $c == \"$cur_\"* ]]; then\n \t\t\t\tcase $c in\ndiff --git a/parse-options.c b/parse-options.c\nindex b86612148f..7db84227ab 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -427,12 +427,61 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \tparse_options_check(options);\n }\n \n+static void show_negated_gitcomp(const struct option *opts, int nr_noopts)\n+{\n+\tint printed_dashdash = 0;\n+\n+\tfor (; opts->type != OPTION_END; opts++) {\n+\t\tint has_unset_form = 0;\n+\t\tconst char *name;\n+\n+\t\tif (!opts->long_name)\n+\t\t\tcontinue;\n+\t\tif (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))\n+\t\t\tcontinue;\n+\t\tif (opts->flags & PARSE_OPT_NONEG)\n+\t\t\tcontinue;\n+\n+\t\tswitch (opts->type) {\n+\t\tcase OPTION_STRING:\n+\t\tcase OPTION_FILENAME:\n+\t\tcase OPTION_INTEGER:\n+\t\tcase OPTION_MAGNITUDE:\n+\t\tcase OPTION_CALLBACK:\n+\t\tcase OPTION_BIT:\n+\t\tcase OPTION_NEGBIT:\n+\t\tcase OPTION_COUNTUP:\n+\t\tcase OPTION_SET_INT:\n+\t\t\thas_unset_form = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!has_unset_form)\n+\t\t\tcontinue;\n+\n+\t\tif (skip_prefix(opts->long_name, \"no-\", &name)) {\n+\t\t\tif (nr_noopts < 0)\n+\t\t\t\tprintf(\" --%s\", name);\n+\t\t} else if (nr_noopts >= 0) {\n+\t\t\tif (nr_noopts && !printed_dashdash) {\n+\t\t\t\tprintf(\" --\");\n+\t\t\t\tprinted_dashdash = 1;\n+\t\t\t}\n+\t\t\tprintf(\" --no-%s\", opts->long_name);\n+\t\t\tnr_noopts++;\n+\t\t}\n+\t}\n+}\n+\n static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\tconst struct option *opts)\n {\n+\tconst struct option *original_opts = opts;\n+\tint nr_noopts = 0;\n+\n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tconst char *suffix = \"\";\n-\t\tint has_unset_form = 0;\n \n \t\tif (!opts->long_name)\n \t\t\tcontinue;\n@@ -447,8 +496,6 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\tcase OPTION_INTEGER:\n \t\tcase OPTION_MAGNITUDE:\n \t\tcase OPTION_CALLBACK:\n-\t\t\thas_unset_form = 1;\n-\n \t\t\tif (opts->flags & PARSE_OPT_NOARG)\n \t\t\t\tbreak;\n \t\t\tif (opts->flags & PARSE_OPT_OPTARG)\n@@ -457,28 +504,17 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,\n \t\t\t\tbreak;\n \t\t\tsuffix = \"=\";\n \t\t\tbreak;\n-\t\tcase OPTION_BIT:\n-\t\tcase OPTION_NEGBIT:\n-\t\tcase OPTION_COUNTUP:\n-\t\tcase OPTION_SET_INT:\n-\t\t\thas_unset_form = 1;\n-\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n \t\tif (opts->flags & PARSE_OPT_COMP_ARG)\n \t\t\tsuffix = \"=\";\n+\t\tif (starts_with(opts->long_name, \"no-\"))\n+\t\t\tnr_noopts++;\n \t\tprintf(\" --%s%s\", opts->long_name, suffix);\n-\n-\t\tif (has_unset_form && !(opts->flags & PARSE_OPT_NONEG)) {\n-\t\t\tconst char *name;\n-\n-\t\t\tif (skip_prefix(opts->long_name, \"no-\", &name))\n-\t\t\t\tprintf(\" --%s\", name);\n-\t\t\telse\n-\t\t\t\tprintf(\" --no-%s\", opts->long_name);\n-\t\t}\n \t}\n+\tshow_negated_gitcomp(original_opts, -1);\n+\tshow_negated_gitcomp(original_opts, nr_noopts);\n \tfputc('\\n', stdout);\n \texit(0);\n }\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 7e5e3ad5b1..157ee7085d 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -459,6 +459,42 @@ test_expect_success '__gitcomp - suffix' '\n \tEOF\n '\n \n+test_expect_success '__gitcomp - ignore optional negative options' '\n+\ttest_gitcomp \"--\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--abc Z\n+\t--def Z\n+\t--no-one Z\n+\t--no-... Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - ignore/narrow optional negative options' '\n+\ttest_gitcomp \"--a\" \"--abc --abcdef --no-one -- --no-two\" <<-\\EOF\n+\t--abc Z\n+\t--abcdef Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - ignore/narrow optional negative options' '\n+\ttest_gitcomp \"--n\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\t--no-... Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - expand all negative options' '\n+\ttest_gitcomp \"--no-\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\t--no-two Z\n+\tEOF\n+'\n+\n+test_expect_success '__gitcomp - expand/narrow all negative options' '\n+\ttest_gitcomp \"--no-o\" \"--abc --def --no-one -- --no-two\" <<-\\EOF\n+\t--no-one Z\n+\tEOF\n+'\n+\n test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '\n \t__gitcomp \"$invalid_variable_name\"\n '\n@@ -1237,29 +1273,20 @@ test_expect_success 'double dash \"git\" itself' '\n test_expect_success 'double dash \"git checkout\"' '\n \ttest_completion \"git checkout --\" <<-\\EOF\n \t--quiet Z\n-\t--no-quiet Z\n \t--detach Z\n-\t--no-detach Z\n \t--track Z\n-\t--no-track Z\n \t--orphan=Z\n-\t--no-orphan Z\n \t--ours Z\n \t--theirs Z\n \t--merge Z\n-\t--no-merge Z\n \t--conflict=Z\n-\t--no-conflict Z\n \t--patch Z\n-\t--no-patch Z\n \t--ignore-skip-worktree-bits Z\n-\t--no-ignore-skip-worktree-bits Z\n \t--ignore-other-worktrees Z\n-\t--no-ignore-other-worktrees Z\n \t--recurse-submodules Z\n-\t--no-recurse-submodules Z\n \t--progress Z\n-\t--no-progress Z\n+\t--no-quiet Z\n+\t--no-... Z\n \tEOF\n '\n \n-- \n2.18.0.rc0.333.g22e6ee6cdf\n\n"}]}