{"thread":{"id":"53193","subject":"[PATCH] clean: explicitly `fflush` stdout","startedAt":"2020-04-08T19:33:08Z","lastAt":"2020-04-10T18:17:01Z","messageCount":16,"participants":["Johannes Schindelin via GitGitGadget","Jeff King","Junio C Hamano","마누엘 via GitGitGadget","Derrick Stolee","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"395091","messageId":"pull.755.git.git.1586374380709.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":null,"subject":"[PATCH] clean: explicitly `fflush` stdout","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-08T19:33:00Z","receivedAt":"2020-04-08T19:33:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n\nFor performance reasons `stdout` is buffered by default. That leads to\nproblems if after printing to `stdout` a read on `stdin` is performed.\n\nFor that reason interactive commands like `git clean -i` do not function\nproperly anymore if the `stdout` is not flushed by `fflush(stdout)` before\ntrying to read from `stdin`.\n\nSo let's precede all reads on `stdin` in `git clean -i` by flushing\n`stdout`.\n\nSigned-off-by: 마누엘 <nalla@hamal.uberspace.de>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n    Explicitly fflush stdout in git clean\n    \n    This is yet another patch that was funneled through a Git for Windows\n    PR. It has served us well for almost five years now, and it is beyond\n    time that it find its final home in core Git.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-755%2Fdscho%2Ffflush-in-git-clean-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-755/dscho/fflush-in-git-clean-v1\nPull-Request: https://github.com/git/git/pull/755\n\n builtin/clean.c | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 5abf087e7c4..2bd06d13395 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -580,6 +580,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t       clean_get_color(CLEAN_COLOR_RESET));\n \t\t}\n \n+\t\tfflush(stdout);\n \t\tif (strbuf_getline_lf(&choice, stdin) != EOF) {\n \t\t\tstrbuf_trim(&choice);\n \t\t} else {\n@@ -662,6 +663,7 @@ static int filter_by_patterns_cmd(void)\n \t\tclean_print_color(CLEAN_COLOR_PROMPT);\n \t\tprintf(_(\"Input ignore patterns>> \"));\n \t\tclean_print_color(CLEAN_COLOR_RESET);\n+\t\tfflush(stdout);\n \t\tif (strbuf_getline_lf(&confirm, stdin) != EOF)\n \t\t\tstrbuf_trim(&confirm);\n \t\telse\n@@ -760,6 +762,7 @@ static int ask_each_cmd(void)\n \t\t\tqname = quote_path_relative(item->string, NULL, &buf);\n \t\t\t/* TRANSLATORS: Make sure to keep [y/N] as is */\n \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n+\t\t\tfflush(stdout);\n \t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n \t\t\t\tstrbuf_trim(&confirm);\n \t\t\t} else {\n\nbase-commit: 9fadedd637b312089337d73c3ed8447e9f0aa775\n-- \ngitgitgadget\n"},{"id":"395097","messageId":"20200408201454.GB2270445@coredump.intra.peff.net","threadId":"53193","inReplyTo":"pull.755.git.git.1586374380709.gitgitgadget@gmail.com","subject":"Re: [PATCH] clean: explicitly `fflush` stdout","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-04-08T20:14:54Z","receivedAt":"2020-04-08T20:14:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 08, 2020 at 07:33:00PM +0000, Johannes Schindelin via GitGitGadget wrote:\n\n> From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n> \n> For performance reasons `stdout` is buffered by default. That leads to\n> problems if after printing to `stdout` a read on `stdin` is performed.\n\nThis first paragraph left me scratching my head. It's only a problem for\ninteractive uses, right? Would:\n\n  This can lead to problems for interactive commands which write a\n  prompt to `stdout` and then read user input on `stdin`. If the prompt\n  is left in the buffer, the user will not realize the program is\n  waiting for their input.\n\nmake sense?\n\n> For that reason interactive commands like `git clean -i` do not function\n> properly anymore if the `stdout` is not flushed by `fflush(stdout)` before\n> trying to read from `stdin`.\n\nI'm not sure I understand this \"anymore\". Did the buffering change at\nsome point, introducing a regression?\n\n> So let's precede all reads on `stdin` in `git clean -i` by flushing\n> `stdout`.\n\nThis (and the patch) make sense to me. It might be worth factoring out a\n\"read input from user\" function and putting the flush there, but with\nonly three affected call sites, I'm OK with it either way.\n\n>     This is yet another patch that was funneled through a Git for Windows\n>     PR. It has served us well for almost five years now, and it is beyond\n>     time that it find its final home in core Git.\n\nAgreed. I guess it didn't affect people on other platforms much because\nstdout to a terminal is generally line-buffered on POSIX systems. But\nit's better not to rely on that, plus it could create confusion if\nsomebody tried to manipulate the interactive operation through a pipe\n(e.g., driving it from a GUI or something).\n\n-Peff\n"},{"id":"395100","messageId":"xmqqr1wxoddc.fsf@gitster.c.googlers.com","threadId":"53193","inReplyTo":"20200408201454.GB2270445@coredump.intra.peff.net","subject":"Re: [PATCH] clean: explicitly `fflush` stdout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-08T21:51:11Z","receivedAt":"2020-04-08T21:51:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> This (and the patch) make sense to me. It might be worth factoring out a\n> \"read input from user\" function and putting the flush there, but with\n> only three affected call sites, I'm OK with it either way.\n>\n>>     This is yet another patch that was funneled through a Git for Windows\n>>     PR. It has served us well for almost five years now, and it is beyond\n>>     time that it find its final home in core Git.\n>\n> Agreed. I guess it didn't affect people on other platforms much because\n> stdout to a terminal is generally line-buffered on POSIX systems. But\n> it's better not to rely on that, plus it could create confusion if\n> somebody tried to manipulate the interactive operation through a pipe\n> (e.g., driving it from a GUI or something).\n\nHmph, I thought it was more common to do prompts etc. on the\nstandard error stream, which tends to make the buffering of the\noutput less of a problem, but apparently these prompts are given to\nthe standard output.  I am also OK to sprinkle fflush(stdout) but in\nthe longer term, it would probably be a good idea to introduce a\nhelper to \"prompt then grab input\" or \"read user input\" (if the\nformer, we'd be able to bring consistency into \"which between the\nstandard output or the standard error does a prompt come?\", and if\nthe latter we'd do fflush(NULL) before reading), especially if there\nare many git subcommands that go interactive.\n\nThanks.\n"},{"id":"395105","messageId":"20200408223821.GD3468797@coredump.intra.peff.net","threadId":"53193","inReplyTo":"xmqqr1wxoddc.fsf@gitster.c.googlers.com","subject":"Re: [PATCH] clean: explicitly `fflush` stdout","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-04-08T22:38:21Z","receivedAt":"2020-04-08T22:38:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 08, 2020 at 02:51:11PM -0700, Junio C Hamano wrote:\n\n> > Agreed. I guess it didn't affect people on other platforms much because\n> > stdout to a terminal is generally line-buffered on POSIX systems. But\n> > it's better not to rely on that, plus it could create confusion if\n> > somebody tried to manipulate the interactive operation through a pipe\n> > (e.g., driving it from a GUI or something).\n> \n> Hmph, I thought it was more common to do prompts etc. on the\n> standard error stream, which tends to make the buffering of the\n> output less of a problem, but apparently these prompts are given to\n> the standard output.\n\nThe prompts in git-add--interactive.perl go to stdout, as do the ones\nfor \"am --interactive\". I think that's reasonable, if you think of it as\nthe main output of the program.\n\nAt one point the \"am\" ones actually went to /dev/tty, but IMHO that's a\nmistake. In 99% of cases it behaves the same as looking at stdin/stdout\n(because they're connected to the terminal anyway), and in the other 1%\nit's just as likely to be the wrong thing as the right. Plus it makes\ntesting much harder.\n\n> I am also OK to sprinkle fflush(stdout) but in\n> the longer term, it would probably be a good idea to introduce a\n> helper to \"prompt then grab input\" or \"read user input\" (if the\n> former, we'd be able to bring consistency into \"which between the\n> standard output or the standard error does a prompt come?\", and if\n> the latter we'd do fflush(NULL) before reading), especially if there\n> are many git subcommands that go interactive.\n\nAgreed. There is git_prompt(), but that does the tty thing, which I\nthink we'd want to avoid in most cases. It's used by the credential\ncode, which really does want to use a terminal to do things like turn\noff character echoing. Plus it's not the main function of the program,\nbut rather a side effect (so we have to avoid disrupting the main\nstdin/stdout).\n\n-Peff\n"},{"id":"395176","messageId":"pull.755.v2.git.git.1586518072.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.git.git.1586374380709.gitgitgadget@gmail.com","subject":"[PATCH v2 0/2] Explicitly fflush stdout in git clean","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T11:27:49Z","receivedAt":"2020-04-10T11:27:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This is yet another patch that was funneled through a Git for Windows PR,\nread: it has been battle-tested.\n\nOf course, the current iteration of this patch series has not been\nbattle-tested, so please do review carefully, so that we can prevent bugs\nfrom slipping in during the review process.\n\nChanges since v1:\n\n * Added a preparatory patch that refactors all interactive input reading\n   via strbuf_getline(..., stdin).\n * Adjusted the patch and its commit message accordingly.\n\nJohannes Schindelin (1):\n  Refactor code asking the user for input interactively\n\n마누엘 (1):\n  Explicitly `fflush` stdout before expecting interactive input\n\n add-interactive.c |  4 ++--\n add-patch.c       |  4 ++--\n builtin/clean.c   | 14 ++++----------\n prompt.c          | 12 ++++++++++++\n prompt.h          |  2 ++\n shell.c           |  4 ++--\n 6 files changed, 24 insertions(+), 16 deletions(-)\n\n\nbase-commit: 9fadedd637b312089337d73c3ed8447e9f0aa775\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-755%2Fdscho%2Ffflush-in-git-clean-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-755/dscho/fflush-in-git-clean-v2\nPull-Request: https://github.com/git/git/pull/755\n\nRange-diff vs v1:\n\n 1:  21acd883b94 < -:  ----------- clean: explicitly `fflush` stdout\n -:  ----------- > 1:  9d2ee78a9e4 Refactor code asking the user for input interactively\n -:  ----------- > 2:  d3949e42004 Explicitly `fflush` stdout before expecting interactive input\n\n-- \ngitgitgadget\n"},{"id":"395177","messageId":"9d2ee78a9e414c0b6aacbc9c878ab08eb70703d5.1586518072.git.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.v2.git.git.1586518072.gitgitgadget@gmail.com","subject":"[PATCH v2 1/2] Refactor code asking the user for input interactively","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T11:27:50Z","receivedAt":"2020-04-10T11:27:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThere are quite a few code locations (e.g. `git clean --interactive`)\nwhere Git asks the user for an answer. In preparation for fixing a bug\nshared by all of them, and also to DRY up the code, let's refactor it.\n\nPlease note that most of these callers trimmed white-space both at the\nbeginning and at the end of the answer, instead of trimming only the\nend (as the caller in `add-patch.c` does).\n\nTHerefore, technically speaking, we change behavior in this patch. At\nthe same time, it can be argued that this is actually a bug fix.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n add-interactive.c |  4 ++--\n add-patch.c       |  4 ++--\n builtin/clean.c   | 14 ++++----------\n prompt.c          | 10 ++++++++++\n prompt.h          |  2 ++\n shell.c           |  4 ++--\n 6 files changed, 22 insertions(+), 16 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 4a9bf85cac0..29cd2fe0201 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -9,6 +9,7 @@\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"run-command.h\"\n+#include \"prompt.h\"\n \n static void init_color(struct repository *r, struct add_i_state *s,\n \t\t       const char *slot_name, char *dst,\n@@ -289,13 +290,12 @@ static ssize_t list_and_choose(struct add_i_state *s,\n \t\tfputs(singleton ? \"> \" : \">> \", stdout);\n \t\tfflush(stdout);\n \n-\t\tif (strbuf_getline(&input, stdin) == EOF) {\n+\t\tif (git_read_line_interactively(&input) == EOF) {\n \t\t\tputchar('\\n');\n \t\t\tif (immediate)\n \t\t\t\tres = LIST_AND_CHOOSE_QUIT;\n \t\t\tbreak;\n \t\t}\n-\t\tstrbuf_trim(&input);\n \n \t\tif (!input.len)\n \t\t\tbreak;\ndiff --git a/add-patch.c b/add-patch.c\nindex d8dafa8168d..d8bfe379be4 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -7,6 +7,7 @@\n #include \"color.h\"\n #include \"diff.h\"\n #include \"compat/terminal.h\"\n+#include \"prompt.h\"\n \n enum prompt_mode_type {\n \tPROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,\n@@ -1158,9 +1159,8 @@ static int read_single_character(struct add_p_state *s)\n \t\treturn res;\n \t}\n \n-\tif (strbuf_getline(&s->answer, stdin) == EOF)\n+\tif (git_read_line_interactively(&s->answer) == EOF)\n \t\treturn EOF;\n-\tstrbuf_trim_trailing_newline(&s->answer);\n \treturn 0;\n }\n \ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 5abf087e7c4..c8c011d2ddf 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -18,6 +18,7 @@\n #include \"color.h\"\n #include \"pathspec.h\"\n #include \"help.h\"\n+#include \"prompt.h\"\n \n static int force = -1; /* unset */\n static int interactive;\n@@ -420,7 +421,6 @@ static int find_unique(const char *choice, struct menu_stuff *menu_stuff)\n \treturn found;\n }\n \n-\n /*\n  * Parse user input, and return choice(s) for menu (menu_stuff).\n  *\n@@ -580,9 +580,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t       clean_get_color(CLEAN_COLOR_RESET));\n \t\t}\n \n-\t\tif (strbuf_getline_lf(&choice, stdin) != EOF) {\n-\t\t\tstrbuf_trim(&choice);\n-\t\t} else {\n+\t\tif (git_read_line_interactively(&choice) == EOF) {\n \t\t\teof = 1;\n \t\t\tbreak;\n \t\t}\n@@ -662,9 +660,7 @@ static int filter_by_patterns_cmd(void)\n \t\tclean_print_color(CLEAN_COLOR_PROMPT);\n \t\tprintf(_(\"Input ignore patterns>> \"));\n \t\tclean_print_color(CLEAN_COLOR_RESET);\n-\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF)\n-\t\t\tstrbuf_trim(&confirm);\n-\t\telse\n+\t\tif (git_read_line_interactively(&confirm) == EOF)\n \t\t\tputchar('\\n');\n \n \t\t/* quit filter_by_pattern mode if press ENTER or Ctrl-D */\n@@ -760,9 +756,7 @@ static int ask_each_cmd(void)\n \t\t\tqname = quote_path_relative(item->string, NULL, &buf);\n \t\t\t/* TRANSLATORS: Make sure to keep [y/N] as is */\n \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n-\t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n-\t\t\t\tstrbuf_trim(&confirm);\n-\t\t\t} else {\n+\t\t\tif (git_read_line_interactively(&confirm) == EOF) {\n \t\t\t\tputchar('\\n');\n \t\t\t\teof = 1;\n \t\t\t}\ndiff --git a/prompt.c b/prompt.c\nindex 6d5885d0096..098dcfb7cf9 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -74,3 +74,13 @@ char *git_prompt(const char *prompt, int flags)\n \t}\n \treturn r;\n }\n+\n+int git_read_line_interactively(struct strbuf *line)\n+{\n+\tint ret = strbuf_getline_lf(line, stdin);\n+\n+\tif (ret != EOF)\n+\t\tstrbuf_trim_trailing_newline(line);\n+\n+\treturn ret;\n+}\ndiff --git a/prompt.h b/prompt.h\nindex e04cced030c..e294e93541c 100644\n--- a/prompt.h\n+++ b/prompt.h\n@@ -6,4 +6,6 @@\n \n char *git_prompt(const char *prompt, int flags);\n \n+int git_read_line_interactively(struct strbuf *line);\n+\n #endif /* PROMPT_H */\ndiff --git a/shell.c b/shell.c\nindex 54cca7439de..cef7ffdc9e1 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"alias.h\"\n+#include \"prompt.h\"\n \n #define COMMAND_DIR \"git-shell-commands\"\n #define HELP_COMMAND COMMAND_DIR \"/help\"\n@@ -76,12 +77,11 @@ static void run_shell(void)\n \t\tint count;\n \n \t\tfprintf(stderr, \"git> \");\n-\t\tif (strbuf_getline_lf(&line, stdin) == EOF) {\n+\t\tif (git_read_line_interactively(&line) == EOF) {\n \t\t\tfprintf(stderr, \"\\n\");\n \t\t\tstrbuf_release(&line);\n \t\t\tbreak;\n \t\t}\n-\t\tstrbuf_trim(&line);\n \t\trawargs = strbuf_detach(&line, NULL);\n \t\tsplit_args = xstrdup(rawargs);\n \t\tcount = split_cmdline(split_args, &argv);\n-- \ngitgitgadget\n\n"},{"id":"395178","messageId":"d3949e42004f31e8741fad08352f782b4b8536eb.1586518072.git.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.v2.git.git.1586518072.gitgitgadget@gmail.com","subject":"[PATCH v2 2/2] Explicitly `fflush` stdout before expecting interactive input","fromName":"마누엘 via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T11:27:51Z","receivedAt":"2020-04-10T11:28:00Z","isPatch":true,"sender":{"key":"name:마누엘","avatar":null},"body":"From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n\nAt least one interactive command writes a prompt to `stdout` and then\nreads user input on `stdin`: `git clean --interactive`. If the prompt is\nleft in the buffer, the user will not realize the program is waiting for\ntheir input.\n\nSo let's just flush `stdout` before reading the user's input.\n\nSigned-off-by: 마누엘 <nalla@hamal.uberspace.de>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n prompt.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/prompt.c b/prompt.c\nindex 098dcfb7cf9..5ded21a017f 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -77,8 +77,10 @@ char *git_prompt(const char *prompt, int flags)\n \n int git_read_line_interactively(struct strbuf *line)\n {\n-\tint ret = strbuf_getline_lf(line, stdin);\n+\tint ret;\n \n+\tfflush(stdout);\n+\tret = strbuf_getline_lf(line, stdin);\n \tif (ret != EOF)\n \t\tstrbuf_trim_trailing_newline(line);\n \n-- \ngitgitgadget\n"},{"id":"395181","messageId":"cf6bdc4c-bacf-5de0-b0b3-255e66c7bc18@gmail.com","threadId":"53193","inReplyTo":"9d2ee78a9e414c0b6aacbc9c878ab08eb70703d5.1586518072.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/2] Refactor code asking the user for input interactively","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2020-04-10T12:27:36Z","receivedAt":"2020-04-10T12:27:40Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/10/2020 7:27 AM, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> There are quite a few code locations (e.g. `git clean --interactive`)\n> where Git asks the user for an answer. In preparation for fixing a bug\n> shared by all of them, and also to DRY up the code, let's refactor it.\n> \n> Please note that most of these callers trimmed white-space both at the\n> beginning and at the end of the answer, instead of trimming only the\n> end (as the caller in `add-patch.c` does).\n\nadd-patch also only trims the newline! This is still a good change.\n\n> THerefore, technically speaking, we change behavior in this patch. At\n\nStrange capitalization here.\n\n> the same time, it can be argued that this is actually a bug fix.\n> \n\n> @@ -1158,9 +1159,8 @@ static int read_single_character(struct add_p_state *s)\n>  \t\treturn res;\n>  \t}\n>  \n> -\tif (strbuf_getline(&s->answer, stdin) == EOF)\n> +\tif (git_read_line_interactively(&s->answer) == EOF)\n>  \t\treturn EOF;\n> -\tstrbuf_trim_trailing_newline(&s->answer);\n\n(Pointing out the trailing newline trim here.)\n\n> +\n> +int git_read_line_interactively(struct strbuf *line)\n> +{\n> +\tint ret = strbuf_getline_lf(line, stdin);\n> +\n> +\tif (ret != EOF)\n> +\t\tstrbuf_trim_trailing_newline(line);\n> +\n> +\treturn ret;\n> +}\n\nThis looks good. Do we need a trailing newline or something?\nThe way the diff ends abruptly after the \"}\" line made me\nthink so.\n\nThanks,\n-Stolee\n"},{"id":"395182","messageId":"5350e8fd-2ca6-7c07-497b-1bb35bb07c84@gmail.com","threadId":"53193","inReplyTo":"d3949e42004f31e8741fad08352f782b4b8536eb.1586518072.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/2] Explicitly `fflush` stdout before expecting interactive input","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2020-04-10T12:28:52Z","receivedAt":"2020-04-10T12:29:02Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/10/2020 7:27 AM, 마누엘 via GitGitGadget wrote:\n> From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n> \n> At least one interactive command writes a prompt to `stdout` and then\n> reads user input on `stdin`: `git clean --interactive`. If the prompt is\n> left in the buffer, the user will not realize the program is waiting for\n> their input.\n> \n> So let's just flush `stdout` before reading the user's input.\n> \n> Signed-off-by: 마누엘 <nalla@hamal.uberspace.de>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  prompt.c | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n> \n> diff --git a/prompt.c b/prompt.c\n> index 098dcfb7cf9..5ded21a017f 100644\n> --- a/prompt.c\n> +++ b/prompt.c\n> @@ -77,8 +77,10 @@ char *git_prompt(const char *prompt, int flags)\n>  \n>  int git_read_line_interactively(struct strbuf *line)\n>  {\n> -\tint ret = strbuf_getline_lf(line, stdin);\n> +\tint ret;\n>  \n> +\tfflush(stdout);\n> +\tret = strbuf_getline_lf(line, stdin);\n>  \tif (ret != EOF)\n>  \t\tstrbuf_trim_trailing_newline(line);\n\nNice and \"clean\" ;)\n\nLGTM\n-Stolee\n\n"},{"id":"395185","messageId":"nycvar.QRO.7.76.6.2004101559540.46@tvgsbejvaqbjf.bet","threadId":"53193","inReplyTo":"cf6bdc4c-bacf-5de0-b0b3-255e66c7bc18@gmail.com","subject":"Re: [PATCH v2 1/2] Refactor code asking the user for input interactively","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-04-10T14:01:23Z","receivedAt":"2020-04-10T14:01:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Dr Stolee,\n\nOn Fri, 10 Apr 2020, Derrick Stolee wrote:\n\n> On 4/10/2020 7:27 AM, Johannes Schindelin via GitGitGadget wrote:\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > There are quite a few code locations (e.g. `git clean --interactive`)\n> > where Git asks the user for an answer. In preparation for fixing a bug\n> > shared by all of them, and also to DRY up the code, let's refactor it.\n> >\n> > Please note that most of these callers trimmed white-space both at the\n> > beginning and at the end of the answer, instead of trimming only the\n> > end (as the caller in `add-patch.c` does).\n>\n> add-patch also only trims the newline! This is still a good change.\n>\n> > THerefore, technically speaking, we change behavior in this patch. At\n>\n> Strange capitalization here.\n\nI fixed it and force-pushed, waiting a little with submitting it in case\nthere are more things reviewers point out.\n\n> > the same time, it can be argued that this is actually a bug fix.\n> >\n>\n> > @@ -1158,9 +1159,8 @@ static int read_single_character(struct add_p_state *s)\n> >  \t\treturn res;\n> >  \t}\n> >\n> > -\tif (strbuf_getline(&s->answer, stdin) == EOF)\n> > +\tif (git_read_line_interactively(&s->answer) == EOF)\n> >  \t\treturn EOF;\n> > -\tstrbuf_trim_trailing_newline(&s->answer);\n>\n> (Pointing out the trailing newline trim here.)\n>\n> > +\n> > +int git_read_line_interactively(struct strbuf *line)\n> > +{\n> > +\tint ret = strbuf_getline_lf(line, stdin);\n> > +\n> > +\tif (ret != EOF)\n> > +\t\tstrbuf_trim_trailing_newline(line);\n> > +\n> > +\treturn ret;\n> > +}\n>\n> This looks good. Do we need a trailing newline or something?\n> The way the diff ends abruptly after the \"}\" line made me\n> think so.\n\nNo, this file ends in that line, therefore it ends abruptly ;-)\n\nIf I add another newline, `git diff` shows a red `+` at the end, i.e. we\nconsider it a white-space problem.\n\nThank you for your review!\nDscho\n\n>\n> Thanks,\n> -Stolee\n>\n>\n"},{"id":"395187","messageId":"nycvar.QRO.7.76.6.2004101602330.46@tvgsbejvaqbjf.bet","threadId":"53193","inReplyTo":"20200408201454.GB2270445@coredump.intra.peff.net","subject":"Re: [PATCH] clean: explicitly `fflush` stdout","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2020-04-10T14:03:26Z","receivedAt":"2020-04-10T14:03:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Peff,\n\nOn Wed, 8 Apr 2020, Jeff King wrote:\n\n> On Wed, Apr 08, 2020 at 07:33:00PM +0000, Johannes Schindelin via GitGitGadget wrote:\n>\n> > From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n> >\n> > For performance reasons `stdout` is buffered by default. That leads to\n> > problems if after printing to `stdout` a read on `stdin` is performed.\n>\n> This first paragraph left me scratching my head. It's only a problem for\n> interactive uses, right? Would:\n>\n>   This can lead to problems for interactive commands which write a\n>   prompt to `stdout` and then read user input on `stdin`. If the prompt\n>   is left in the buffer, the user will not realize the program is\n>   waiting for their input.\n>\n> make sense?\n\nThank you, yes, that makes sense.\n\nBased on another suggestion of yours, I did refactor the code a bit more\nand already sent out the result as v2.\n\nThank you,\nDscho\n\n>\n> > For that reason interactive commands like `git clean -i` do not function\n> > properly anymore if the `stdout` is not flushed by `fflush(stdout)` before\n> > trying to read from `stdin`.\n>\n> I'm not sure I understand this \"anymore\". Did the buffering change at\n> some point, introducing a regression?\n>\n> > So let's precede all reads on `stdin` in `git clean -i` by flushing\n> > `stdout`.\n>\n> This (and the patch) make sense to me. It might be worth factoring out a\n> \"read input from user\" function and putting the flush there, but with\n> only three affected call sites, I'm OK with it either way.\n>\n> >     This is yet another patch that was funneled through a Git for Windows\n> >     PR. It has served us well for almost five years now, and it is beyond\n> >     time that it find its final home in core Git.\n>\n> Agreed. I guess it didn't affect people on other platforms much because\n> stdout to a terminal is generally line-buffered on POSIX systems. But\n> it's better not to rely on that, plus it could create confusion if\n> somebody tried to manipulate the interactive operation through a pipe\n> (e.g., driving it from a GUI or something).\n>\n> -Peff\n>\n"},{"id":"395191","messageId":"20200410150753.GA68344@coredump.intra.peff.net","threadId":"53193","inReplyTo":"9d2ee78a9e414c0b6aacbc9c878ab08eb70703d5.1586518072.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/2] Refactor code asking the user for input interactively","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-04-10T15:07:53Z","receivedAt":"2020-04-10T15:07:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 10, 2020 at 11:27:50AM +0000, Johannes Schindelin via GitGitGadget wrote:\n\n> diff --git a/prompt.h b/prompt.h\n> index e04cced030c..e294e93541c 100644\n> --- a/prompt.h\n> +++ b/prompt.h\n> @@ -6,4 +6,6 @@\n>  \n>  char *git_prompt(const char *prompt, int flags);\n>  \n> +int git_read_line_interactively(struct strbuf *line);\n> +\n\nIt might be worth adding some comments discussing why one would use\ngit_prompt() versus git_read_line_interactively().\n\nOther than that, both patches look good to me. Thanks for calling out\nthe changed trimming behavior preemptively. I agree it should not be a\nbig deal either way.\n\n-Peff\n"},{"id":"395220","messageId":"xmqqftdbjkv8.fsf@gitster.c.googlers.com","threadId":"53193","inReplyTo":"9d2ee78a9e414c0b6aacbc9c878ab08eb70703d5.1586518072.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/2] Refactor code asking the user for input interactively","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-10T17:44:59Z","receivedAt":"2020-04-10T17:45:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> -\t\tif (strbuf_getline(&input, stdin) == EOF) {\n> +\t\tif (git_read_line_interactively(&input) == EOF) {\n\nIt's not like we are mimicking or giving a thin wrapper to improve\nan existing read_line_interactively() from a third-party, so I do\nnot see much point in giving \"git_\" prefix here.  On the other hand,\n\"strbuf_\" prefix may not hurt (but the type of its first parameter\nis sufficient so it is not exactly required).\n\n>  \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n> -\t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n> -\t\t\t\tstrbuf_trim(&confirm);\n> -\t\t\t} else {\n> +\t\t\tif (git_read_line_interactively(&confirm) == EOF) {\n>  \t\t\t\tputchar('\\n');\n>  \t\t\t\teof = 1;\n\nA fat-finger that gave an answer \" yes <RET>\" used to be still taken\nas a yes but now it is interpreted as \"no\", because the new helper\ntrims a lot less.  In general, the existing code should be already\nchoosing the safer default, so such a change in behaviour brought in\nby this change, even if they were not intentional, should probably\nbe safe.\n\nThanks.\n"},{"id":"395226","messageId":"pull.755.v3.git.git.1586542614.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.v2.git.git.1586518072.gitgitgadget@gmail.com","subject":"[PATCH v3 0/2] Explicitly fflush stdout in git clean","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T18:16:52Z","receivedAt":"2020-04-10T18:17:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This is yet another patch that was funneled through a Git for Windows PR,\nread: it has been battle-tested.\n\nOf course, the current iteration of this patch series has not been\nbattle-tested, so please do review carefully, so that we can prevent bugs\nfrom slipping in during the review process.\n\nChanges since v2:\n\n * Fixed the capitalization of \"THerefore\" in the commit message.\n\nChanges since v1:\n\n * Added a preparatory patch that refactors all interactive input reading\n   via strbuf_getline(..., stdin).\n * Adjusted the patch and its commit message accordingly.\n\nJohannes Schindelin (1):\n  Refactor code asking the user for input interactively\n\n마누엘 (1):\n  Explicitly `fflush` stdout before expecting interactive input\n\n add-interactive.c |  4 ++--\n add-patch.c       |  4 ++--\n builtin/clean.c   | 14 ++++----------\n prompt.c          | 12 ++++++++++++\n prompt.h          |  2 ++\n shell.c           |  4 ++--\n 6 files changed, 24 insertions(+), 16 deletions(-)\n\n\nbase-commit: 9fadedd637b312089337d73c3ed8447e9f0aa775\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-755%2Fdscho%2Ffflush-in-git-clean-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-755/dscho/fflush-in-git-clean-v3\nPull-Request: https://github.com/git/git/pull/755\n\nRange-diff vs v2:\n\n 1:  9d2ee78a9e4 ! 1:  072f95090ae Refactor code asking the user for input interactively\n     @@ Commit message\n          beginning and at the end of the answer, instead of trimming only the\n          end (as the caller in `add-patch.c` does).\n      \n     -    THerefore, technically speaking, we change behavior in this patch. At\n     +    Therefore, technically speaking, we change behavior in this patch. At\n          the same time, it can be argued that this is actually a bug fix.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n 2:  d3949e42004 = 2:  063d2aaa401 Explicitly `fflush` stdout before expecting interactive input\n\n-- \ngitgitgadget\n"},{"id":"395227","messageId":"072f95090aef69d7bdb2f270aea9d88ca27f68b1.1586542614.git.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.v3.git.git.1586542614.gitgitgadget@gmail.com","subject":"[PATCH v3 1/2] Refactor code asking the user for input interactively","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T18:16:53Z","receivedAt":"2020-04-10T18:17:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThere are quite a few code locations (e.g. `git clean --interactive`)\nwhere Git asks the user for an answer. In preparation for fixing a bug\nshared by all of them, and also to DRY up the code, let's refactor it.\n\nPlease note that most of these callers trimmed white-space both at the\nbeginning and at the end of the answer, instead of trimming only the\nend (as the caller in `add-patch.c` does).\n\nTherefore, technically speaking, we change behavior in this patch. At\nthe same time, it can be argued that this is actually a bug fix.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n add-interactive.c |  4 ++--\n add-patch.c       |  4 ++--\n builtin/clean.c   | 14 ++++----------\n prompt.c          | 10 ++++++++++\n prompt.h          |  2 ++\n shell.c           |  4 ++--\n 6 files changed, 22 insertions(+), 16 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 4a9bf85cac0..29cd2fe0201 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -9,6 +9,7 @@\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"run-command.h\"\n+#include \"prompt.h\"\n \n static void init_color(struct repository *r, struct add_i_state *s,\n \t\t       const char *slot_name, char *dst,\n@@ -289,13 +290,12 @@ static ssize_t list_and_choose(struct add_i_state *s,\n \t\tfputs(singleton ? \"> \" : \">> \", stdout);\n \t\tfflush(stdout);\n \n-\t\tif (strbuf_getline(&input, stdin) == EOF) {\n+\t\tif (git_read_line_interactively(&input) == EOF) {\n \t\t\tputchar('\\n');\n \t\t\tif (immediate)\n \t\t\t\tres = LIST_AND_CHOOSE_QUIT;\n \t\t\tbreak;\n \t\t}\n-\t\tstrbuf_trim(&input);\n \n \t\tif (!input.len)\n \t\t\tbreak;\ndiff --git a/add-patch.c b/add-patch.c\nindex d8dafa8168d..d8bfe379be4 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -7,6 +7,7 @@\n #include \"color.h\"\n #include \"diff.h\"\n #include \"compat/terminal.h\"\n+#include \"prompt.h\"\n \n enum prompt_mode_type {\n \tPROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,\n@@ -1158,9 +1159,8 @@ static int read_single_character(struct add_p_state *s)\n \t\treturn res;\n \t}\n \n-\tif (strbuf_getline(&s->answer, stdin) == EOF)\n+\tif (git_read_line_interactively(&s->answer) == EOF)\n \t\treturn EOF;\n-\tstrbuf_trim_trailing_newline(&s->answer);\n \treturn 0;\n }\n \ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 5abf087e7c4..c8c011d2ddf 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -18,6 +18,7 @@\n #include \"color.h\"\n #include \"pathspec.h\"\n #include \"help.h\"\n+#include \"prompt.h\"\n \n static int force = -1; /* unset */\n static int interactive;\n@@ -420,7 +421,6 @@ static int find_unique(const char *choice, struct menu_stuff *menu_stuff)\n \treturn found;\n }\n \n-\n /*\n  * Parse user input, and return choice(s) for menu (menu_stuff).\n  *\n@@ -580,9 +580,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t       clean_get_color(CLEAN_COLOR_RESET));\n \t\t}\n \n-\t\tif (strbuf_getline_lf(&choice, stdin) != EOF) {\n-\t\t\tstrbuf_trim(&choice);\n-\t\t} else {\n+\t\tif (git_read_line_interactively(&choice) == EOF) {\n \t\t\teof = 1;\n \t\t\tbreak;\n \t\t}\n@@ -662,9 +660,7 @@ static int filter_by_patterns_cmd(void)\n \t\tclean_print_color(CLEAN_COLOR_PROMPT);\n \t\tprintf(_(\"Input ignore patterns>> \"));\n \t\tclean_print_color(CLEAN_COLOR_RESET);\n-\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF)\n-\t\t\tstrbuf_trim(&confirm);\n-\t\telse\n+\t\tif (git_read_line_interactively(&confirm) == EOF)\n \t\t\tputchar('\\n');\n \n \t\t/* quit filter_by_pattern mode if press ENTER or Ctrl-D */\n@@ -760,9 +756,7 @@ static int ask_each_cmd(void)\n \t\t\tqname = quote_path_relative(item->string, NULL, &buf);\n \t\t\t/* TRANSLATORS: Make sure to keep [y/N] as is */\n \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n-\t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n-\t\t\t\tstrbuf_trim(&confirm);\n-\t\t\t} else {\n+\t\t\tif (git_read_line_interactively(&confirm) == EOF) {\n \t\t\t\tputchar('\\n');\n \t\t\t\teof = 1;\n \t\t\t}\ndiff --git a/prompt.c b/prompt.c\nindex 6d5885d0096..098dcfb7cf9 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -74,3 +74,13 @@ char *git_prompt(const char *prompt, int flags)\n \t}\n \treturn r;\n }\n+\n+int git_read_line_interactively(struct strbuf *line)\n+{\n+\tint ret = strbuf_getline_lf(line, stdin);\n+\n+\tif (ret != EOF)\n+\t\tstrbuf_trim_trailing_newline(line);\n+\n+\treturn ret;\n+}\ndiff --git a/prompt.h b/prompt.h\nindex e04cced030c..e294e93541c 100644\n--- a/prompt.h\n+++ b/prompt.h\n@@ -6,4 +6,6 @@\n \n char *git_prompt(const char *prompt, int flags);\n \n+int git_read_line_interactively(struct strbuf *line);\n+\n #endif /* PROMPT_H */\ndiff --git a/shell.c b/shell.c\nindex 54cca7439de..cef7ffdc9e1 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"alias.h\"\n+#include \"prompt.h\"\n \n #define COMMAND_DIR \"git-shell-commands\"\n #define HELP_COMMAND COMMAND_DIR \"/help\"\n@@ -76,12 +77,11 @@ static void run_shell(void)\n \t\tint count;\n \n \t\tfprintf(stderr, \"git> \");\n-\t\tif (strbuf_getline_lf(&line, stdin) == EOF) {\n+\t\tif (git_read_line_interactively(&line) == EOF) {\n \t\t\tfprintf(stderr, \"\\n\");\n \t\t\tstrbuf_release(&line);\n \t\t\tbreak;\n \t\t}\n-\t\tstrbuf_trim(&line);\n \t\trawargs = strbuf_detach(&line, NULL);\n \t\tsplit_args = xstrdup(rawargs);\n \t\tcount = split_cmdline(split_args, &argv);\n-- \ngitgitgadget\n\n"},{"id":"395228","messageId":"063d2aaa4016bd6d98d2ce6695e24865e93b0ed3.1586542614.git.gitgitgadget@gmail.com","threadId":"53193","inReplyTo":"pull.755.v3.git.git.1586542614.gitgitgadget@gmail.com","subject":"[PATCH v3 2/2] Explicitly `fflush` stdout before expecting interactive input","fromName":"마누엘 via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2020-04-10T18:16:54Z","receivedAt":"2020-04-10T18:17:01Z","isPatch":true,"sender":{"key":"name:마누엘","avatar":null},"body":"From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= <nalla@hamal.uberspace.de>\n\nAt least one interactive command writes a prompt to `stdout` and then\nreads user input on `stdin`: `git clean --interactive`. If the prompt is\nleft in the buffer, the user will not realize the program is waiting for\ntheir input.\n\nSo let's just flush `stdout` before reading the user's input.\n\nSigned-off-by: 마누엘 <nalla@hamal.uberspace.de>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n prompt.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/prompt.c b/prompt.c\nindex 098dcfb7cf9..5ded21a017f 100644\n--- a/prompt.c\n+++ b/prompt.c\n@@ -77,8 +77,10 @@ char *git_prompt(const char *prompt, int flags)\n \n int git_read_line_interactively(struct strbuf *line)\n {\n-\tint ret = strbuf_getline_lf(line, stdin);\n+\tint ret;\n \n+\tfflush(stdout);\n+\tret = strbuf_getline_lf(line, stdin);\n \tif (ret != EOF)\n \t\tstrbuf_trim_trailing_newline(line);\n \n-- \ngitgitgadget\n"}]}