git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v5 04/10] add-interactive.c: implement list_and_choose

From
SDSlavica Djukic <slavicadj.ip2018@gmail.com>
Date
Mar 1, 2019, 11:20 UTC
Message-ID
<25f71e47-acad-e985-4f3f-ecde77f883d6@gmail.com>
In-Reply-To
<xmqqd0njpkd5.fsf@gitster-ct.c.googlers.com>
On 22-Feb-19 10:46 PM, Junio C Hamano wrote:
Show 84 quoted lines
> "Slavica Djukic via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> +#define HEADER_INDENT "      "
>> +
>>   enum collection_phase {
>>   	WORKTREE,
>>   	INDEX
>> @@ -27,6 +29,61 @@ struct collection_status {
>>   	struct hashmap file_map;
>>   };
>>   
>> +struct list_and_choose_options {
>> +	int column_n;
>> +	unsigned singleton:1;
>> +	unsigned list_flat:1;
>> +	unsigned list_only:1;
>> +	unsigned list_only_file_names:1;
>> +	unsigned immediate:1;
>> +	char *header;
>> +	const char *prompt;
> Makes a reader wonder if "header" can also be const (not to be taken
> as a suggestion to bend backwards to make it so).
>
>> +	void (*on_eof_fn)(void);
>> +};
>> +
>> +struct choice {
>> +	struct hashmap_entry e;
>> +	char type;
> If this is for choosing among the member of union, possible value(s)
> for the type member and which value corresponds to which union
> member must be documented somewhere, perhaps as a comment around
> here.
>
>> +	union {
>> +		void (*command_fn)(void);
>> +		struct {
>> +			struct {
>> +				uintmax_t added, deleted;
>> +			} index, worktree;
>> +		} file;
>> +	} u;
>> +	size_t prefix_length;
>> +	const char *name;
>> +};
>> +
>> +struct choices {
>> +	struct choice **choices;
> In general, do not name an array in plural.  An exception is when
> the code mostly refers to the array as a whole.
>
> When most accesses are to individual elements, then it would be a
> big win to be able to see choice[2] and pronounce it "the second
> choice" (you do not say "the second choices").
>
>> +	size_t alloc, nr;
>> +};
>> +#define CHOICES_INIT { NULL, 0, 0 }
>> +
>> +static int use_color = -1;
>> +enum color_add_i {
>> +	COLOR_PROMPT,
>> +	COLOR_HEADER,
>> +	COLOR_HELP,
>> +	COLOR_ERROR
>> +};
>> +
>> +static char colors[][COLOR_MAXLEN] = {
> Do not be overly selfish to assume that this will stay to be the
> only color pallette in this file.  If this is the color palette for
> list_and_choose, then have it in its name, e.g. list_and_choose_color[]
> or something like that.
>
>> +	GIT_COLOR_BOLD_BLUE, /* Prompt */
>> +	GIT_COLOR_BOLD,      /* Header */
>> +	GIT_COLOR_BOLD_RED,  /* Help */
>> +	GIT_COLOR_RESET      /* Reset */
>> +};
> Is the above list of values and comments correct?
>
> Doesn't each member of enum correspond to each element in
> list_and_choose_color[][COLOR_MAXLEN] array?  It does not exactly
> match my intuition to have help text in red and error messages in
> plain color.

I noticed I didn't add colors in corresponding commits, but list is correct -- later on in patch series there is

GIT_COLOR_BOLD_RED, /* Error*/
added so that error messages are shown in red.

Help text is also in red following up what is happening in git-add--interactive.perl.

Show 42 quoted lines
>> @@ -186,3 +243,73 @@ static struct collection_status *list_modified(struct repository *r, const char
>>   	free(files);
>>   	return s;
>>   }
>> +
>> +static struct choices *list_and_choose(struct choices *data,
>> +				       struct list_and_choose_options *opts)
>> +{
>> +	if (!data)
>> +		return NULL;
>> +
>> +	while (1) {
>> +		int last_lf = 0;
>> +
>> +		if (opts->header) {
>> +			const char *header_color = get_color(COLOR_HEADER);
>> +			if (!opts->list_flat)
>> +				printf(HEADER_INDENT);
> I won't complain if this is sufficient for the application, but the
> above would not allow different level of indentation depending on
> what header is being shown.  It may make sense to get rid of list_flat
> boolean and instead allow a new "const char *header_indent" member
> in the opts structure supplied by the caller.
>
> Don't use printf() when you _know_ you want to show a simple string
> without any % interpolation.  fputs(HEADER_INDENT, stdout) would suffice.
>
>> +			color_fprintf_ln(stdout, header_color, "%s", opts->header);
>> +		}
>> +
>> +		for (int i = 0; i < data->nr; i++) {
> We do not say "for (int i" (see a previous review).
>
>> +			struct choice *c = data->choices[i];
>> +			char *print;
>> +			const char *modified_fmt = _("%12s %12s %s");
>> +			char worktree_changes[50];
>> +			char index_changes[50];
>> +			char print_buf[100];
> It appears that many of these variables are only needed inside "we
> are showing 'f' and not just names" block.  Can their scope be
> narrowed?
Yes, I will change this.
Show 70 quoted lines
>
>> +			print = (char *)c->name;
> Yuck.  Stuff c->name into print_buf[] instead and get rid of "print"
> pointer.
>
>> +			if ((data->choices[i]->type == 'f') && (!opts->list_only_file_names)) {
>> +				uintmax_t worktree_added = c->u.file.worktree.added;
>> +				uintmax_t worktree_deleted = c->u.file.worktree.deleted;
>> +				uintmax_t index_added = c->u.file.index.added;
>> +				uintmax_t index_deleted = c->u.file.index.deleted;
>> +
>> +				if (worktree_added || worktree_deleted)
>> +					snprintf(worktree_changes, 50, "+%"PRIuMAX"/-%"PRIuMAX,
>> +						 worktree_added, worktree_deleted);
>> +				else
>> +					snprintf(worktree_changes, 50, "%s", _("nothing"));
>> +				if (index_added || index_deleted)
>> +					snprintf(index_changes, 50, "+%"PRIuMAX"/-%"PRIuMAX,
>> +						 index_added, index_deleted);
>> +				else
>> +					snprintf(index_changes, 50, "%s", _("unchanged"));
>> +
>> +				snprintf(print_buf, 100, modified_fmt, index_changes,
>> +					 worktree_changes, print);
> All of the above look overly repetitious; a helper function that
> takes a pointer to "struct { uintmax_t a, d; }" and populates
> changes[] buffer would cut them down by half, but other than that
> I do not see a room for drastic improvement here X-<.
>
> Oh, it would greatly help to use two strbuf for wt/ix_changes that
> are defined outside the loop that is strbuf_reset() after each
> iteration and use things like strbuf_addf().
>
>> +				print = xmalloc(strlen(print_buf) + 1);
>> +				snprintf(print, 100, "%s", print_buf);
> Likewise.
>
>> +			}
>> +
>> +			printf(" %2d: %s", i + 1, print);
>> +			if ((opts->list_flat) && ((i + 1) % (opts->column_n))) {
>> +				printf("\t");
>> +				last_lf = 0;
>> +			}
>> +			else {
>> +				printf("\n");
>> +				last_lf = 1;
>> +			}
>> +
>> +		}
>> +
>> +		if (!last_lf)
>> +			printf("\n");
>> +
>> +		return NULL;
>> +	}
>> +}
> This obviously only lists but does not let you choose at this step
> in the series, but that is OK.
>
> But I see a deeper problem with the design of this helper.  The
> things this helper can list is quite limited.
>
> The original was designed so that the shown strings are prepared by
> the caller and this helper is solely responsible for showing the
> choices, giving prompt, and accepting choice (in various abbreviated
> forms), all _WITHOUT_ having to know the meaning of what is in the
> list.  It gave us a much better separation of labor and
> responsibility between the caller and the callee, I would think.
>

Thanks for pointing this out. I talked to my mentor and I'm now working on making list_and_choose more "type-independent".

I didn't reply to all suggestions in this message, but I did apply them in the code.

>
Previous: Junio C HamanoNext: Slavica Djukic via GitGitGadget
Message 63 of 76 in “Turn git add-i into built-in”
  1. 0/7 Turn git add-i into built-inJohannes Schindelin, Dec 20, 2018
  2. 1/7 diff: export diffstat interfaceDaniel Ferreira via GitGitGadget, Dec 20, 2018
  3. 2/7 add--helper: create builtin helper for interactive addDaniel Ferreira via GitGitGadget, Dec 20, 2018
  4. 4/7 add--interactive.perl: use add--helper --status for status_cmdDaniel Ferreira via GitGitGadget, Dec 20, 2018
  5. 3/7 add-interactive.c: implement status commandDaniel Ferreira via GitGitGadget, Dec 20, 2018
  6. 5/7 add-interactive.c: implement show-help commandSlavica Djukic via GitGitGadget, Dec 20, 2018
  7. Phillip WoodJan 14, 2019
  8. 6/7 Git.pm: introduce environment variable GIT_TEST_PRETEND_TTYSlavica Djukic via GitGitGadget, Dec 20, 2018
  9. Phillip WoodJan 14, 2019
  10. Slavica DjukicJan 15, 2019
  11. Johannes SchindelinJan 15, 2019
  12. Phillip WoodJan 15, 2019
  13. 7/7 add--interactive.perl: use add--helper --show-help for help_cmdSlavica Djukic via GitGitGadget, Dec 20, 2018
  14. Phillip WoodJan 14, 2019
  15. Johannes SchindelinDec 20, 2018
  16. Slavica DjukicJan 11, 2019
  17. 0/7 Turn git add-i into built-inSlavica Đukić via GitGitGadget, Jan 18, 2019
  18. 1/7 diff: export diffstat interfaceDaniel Ferreira via GitGitGadget, Jan 18, 2019
  19. 2/7 add--helper: create builtin helper for interactive addDaniel Ferreira via GitGitGadget, Jan 18, 2019
  20. 4/7 add--interactive.perl: use add--helper --status for status_cmdDaniel Ferreira via GitGitGadget, Jan 18, 2019
  21. 5/7 add-interactive.c: implement show-help commandSlavica Djukic via GitGitGadget, Jan 18, 2019
  22. Phillip WoodJan 18, 2019
  23. Slavica DjukicJan 18, 2019
  24. 3/7 add-interactive.c: implement status commandDaniel Ferreira via GitGitGadget, Jan 18, 2019
  25. 7/7 add--interactive.perl: use add--helper --show-help for help_cmdSlavica Djukic via GitGitGadget, Jan 18, 2019
  26. 6/7 t3701-add-interactive: test add_i_show_help()Slavica Djukic via GitGitGadget, Jan 18, 2019
  27. Phillip WoodJan 18, 2019
  28. 0/7 Turn git add-i into built-inSlavica Đukić via GitGitGadget, Jan 21, 2019
  29. 1/7 diff: export diffstat interfaceDaniel Ferreira via GitGitGadget, Jan 21, 2019
  30. 2/7 add--helper: create builtin helper for interactive addDaniel Ferreira via GitGitGadget, Jan 21, 2019
  31. 4/7 add--interactive.perl: use add--helper --status for status_cmdDaniel Ferreira via GitGitGadget, Jan 21, 2019
  32. 5/7 add-interactive.c: implement show-help commandSlavica Djukic via GitGitGadget, Jan 21, 2019
  33. 6/7 t3701-add-interactive: test add_i_show_help()Slavica Djukic via GitGitGadget, Jan 21, 2019
  34. Phillip WoodJan 25, 2019
  35. Slavica DjukicJan 25, 2019
  36. 7/7 add--interactive.perl: use add--helper --show-help for help_cmdSlavica Djukic via GitGitGadget, Jan 21, 2019
  37. Ævar Arnfjörð BjarmasonJan 21, 2019
  38. Slavica DjukicJan 21, 2019
  39. 3/7 add-interactive.c: implement status commandDaniel Ferreira via GitGitGadget, Jan 21, 2019
  40. 0/7 Turn git add-i into built-inSlavica Đukić via GitGitGadget, Jan 25, 2019
  41. 1/7 diff: export diffstat interfaceDaniel Ferreira via GitGitGadget, Jan 25, 2019
  42. 2/7 add--helper: create builtin helper for interactive addDaniel Ferreira via GitGitGadget, Jan 25, 2019
  43. 3/7 add-interactive.c: implement status commandDaniel Ferreira via GitGitGadget, Jan 25, 2019
  44. 6/7 t3701-add-interactive: test add_i_show_help()Slavica Djukic via GitGitGadget, Jan 25, 2019
  45. 5/7 add-interactive.c: implement show-help commandSlavica Djukic via GitGitGadget, Jan 25, 2019
  46. 4/7 add--interactive.perl: use add--helper --status for status_cmdDaniel Ferreira via GitGitGadget, Jan 25, 2019
  47. 7/7 add--interactive.perl: use add--helper --show-help for help_cmdSlavica Djukic via GitGitGadget, Jan 25, 2019
  48. Slavica DjukicJan 25, 2019
  49. Phillip WoodFeb 1, 2019
  50. 00/10 Turn git add-i into built-inSlavica Đukić via GitGitGadget, Feb 20, 2019
  51. 01/10 diff: export diffstat interfaceDaniel Ferreira via GitGitGadget, Feb 20, 2019
  52. Junio C HamanoFeb 21, 2019
  53. Slavica DjukicFeb 22, 2019
  54. 02/10 add--helper: create builtin helper for interactive addDaniel Ferreira via GitGitGadget, Feb 20, 2019
  55. Junio C HamanoFeb 21, 2019
  56. Johannes SchindelinMar 8, 2019
  57. 08/10 add-interactive.c: implement show-help commandSlavica Djukic via GitGitGadget, Feb 20, 2019
  58. 10/10 add--interactive.perl: use add--helper --show-help for help_cmdSlavica Djukic via GitGitGadget, Feb 20, 2019
  59. 09/10 t3701-add-interactive: test add_i_show_help()Slavica Djukic via GitGitGadget, Feb 20, 2019
  60. 06/10 add--interactive.perl: use add--helper --status for status_cmdDaniel Ferreira via GitGitGadget, Feb 20, 2019
  61. 04/10 add-interactive.c: implement list_and_chooseSlavica Djukic via GitGitGadget, Feb 20, 2019
  62. Junio C HamanoFeb 22, 2019
  63. Slavica DjukicMar 1, 2019
  64. 07/10 add-interactive.c: add support for list_only optionSlavica Djukic via GitGitGadget, Feb 20, 2019
  65. 05/10 add-interactive.c: implement status commandSlavica Djukic via GitGitGadget, Feb 20, 2019
  66. Junio C HamanoFeb 22, 2019
  67. Slavica DjukicMar 1, 2019
  68. 03/10 add-interactive.c: implement list_modifiedSlavica Djukic via GitGitGadget, Feb 20, 2019
  69. Junio C HamanoFeb 21, 2019
  70. Junio C HamanoFeb 21, 2019
  71. Slavica DjukicFeb 22, 2019
  72. Slavica DjukicFeb 22, 2019
  73. Junio C HamanoFeb 22, 2019
  74. End of Outreachy internshipSlavica Djukic, Mar 4, 2019
  75. Phillip WoodJan 18, 2019
  76. Johannes SchindelinJan 18, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.