46
}
47
48
struct list_options {
49
+ int columns;
50
const char *header;
51
void (*print_item)(int i, struct string_list_item *item, void *print_item_data);
52
void *print_item_data;
55
static void list(struct add_i_state *s, struct string_list *list,
56
struct list_options *opts)
57
{
57
- int i;
58
+ int i, last_lf = 0;
59
60
if (!list->nr)
61
return;
66
67
for (i = 0; i < list->nr; i++) {
68
opts->print_item(i, list->items + i, opts->print_item_data);
69
+
70
+ if ((opts->columns) && ((i + 1) % (opts->columns))) {
71
+ putchar('\t');
72
+ last_lf = 0;
73
+ }
74
+ else {
75
+ putchar('\n');
76
+ last_lf = 1;
77
+ }
78
+ }
79
+
80
+ if (!last_lf)
81
putchar('\n');
82
+}
83
+struct list_and_choose_options {
84
+ struct list_options list_opts;
85
+
86
+ const char *prompt;
87
+};
88
+
89
+#define LIST_AND_CHOOSE_ERROR (-1)
90
+#define LIST_AND_CHOOSE_QUIT (-2)
91
+
92
+/*
93
+ * Returns the selected index.
94
+ *
95
+ * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
96
+ * `LIST_AND_CHOOSE_QUIT` is returned.
97
+ */
98
+static ssize_t list_and_choose(struct add_i_state *s, struct string_list *items,
99
+ struct list_and_choose_options *opts)
100
+{
101
+ struct strbuf input = STRBUF_INIT;
102
+ ssize_t res = LIST_AND_CHOOSE_ERROR;
103
+
104
+ for (;;) {
105
+ char *p;
106
+
107
+ strbuf_reset(&input);
108
+
109
+ list(s, items, &opts->list_opts);
110
+
111
+ printf("%s%s", opts->prompt, "> ");
112
+ fflush(stdout);
113
+
114
+ if (strbuf_getline(&input, stdin) == EOF) {
115
+ putchar('\n');
116
+ res = LIST_AND_CHOOSE_QUIT;
117
+ break;
118
+ }
119
+ strbuf_trim(&input);
120
+
121
+ if (!input.len)
122
+ break;
123
+
124
+ p = input.buf;
125
+ for (;;) {
126
+ size_t sep = strcspn(p, " \t\r\n,");
127
+ ssize_t index = -1;
128
+
129
+ if (!sep) {
130
+ if (!*p)
131
+ break;
132
+ p++;
133
+ continue;
134
+ }
135
+
136
+ if (isdigit(*p)) {
137
+ char *endp;
138
+ index = strtoul(p, &endp, 10) - 1;
139
+ if (endp != p + sep)
140
+ index = -1;
141
+ }
142
+
143
+ if (p[sep])
144
+ p[sep++] = '\0';
145
+ if (index < 0 || index >= items->nr)
146
+ printf(_("Huh (%s)?\n"), p);
147
+ else {
148
+ res = index;
149
+ break;
150
+ }
151
+
152
+ p += sep;
153
+ }
154
+
155
+ if (res != LIST_AND_CHOOSE_ERROR)
156
+ break;
157
}
158
+
159
+ strbuf_release(&input);
160
+ return res;
161
}
162
163
struct adddel {
343
return 0;
344
}
345
346
+typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
347
+ struct string_list *files,
348
+ struct list_options *opts);
349
+
350
+static void print_command_item(int i, struct string_list_item *item,
351
+ void *print_command_item_data)
352
+{
353
+ printf(" %2d: %s", i + 1, item->string);
354
+}
355
+
356
int run_add_i(struct repository *r, const struct pathspec *ps)
357
{
358
struct add_i_state s = { NULL };
359
+ struct list_and_choose_options main_loop_opts = {
360
+ { 4, N_("*** Commands ***"), print_command_item, NULL },
361
+ N_("What now")
362
+ };
363
+ struct {
364
+ const char *string;
365
+ command_t command;
366
+ } command_list[] = {
367
+ { "status", run_status },
368
+ };
369
+ struct string_list commands = STRING_LIST_INIT_NODUP;
370
+
371
struct print_file_item_data print_file_item_data = {
372
"%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
373
};
374
struct list_options opts = {
262
- NULL, print_file_item, &print_file_item_data
375
+ 0, NULL, print_file_item, &print_file_item_data
376
};
377
struct strbuf header = STRBUF_INIT;
378
struct string_list files = STRING_LIST_INIT_DUP;
379
+ ssize_t i;
380
int res = 0;
381
382
+ for (i = 0; i < ARRAY_SIZE(command_list); i++)
383
+ string_list_append(&commands, command_list[i].string)
384
+ ->util = command_list[i].command;
385
+
386
init_add_i_state(&s, r);
387
+
388
strbuf_addstr(&header, " ");
389
strbuf_addf(&header, print_file_item_data.modified_fmt,
390
_("staged"), _("unstaged"), _("path"));
398
399
res = run_status(&s, ps, &files, &opts);
400
401
+ for (;;) {
402
+ i = list_and_choose(&s, &commands, &main_loop_opts);
403
+ if (i == LIST_AND_CHOOSE_QUIT) {
404
+ printf(_("Bye.\n"));
405
+ res = 0;
406
+ break;
407
+ }
408
+ if (i != LIST_AND_CHOOSE_ERROR) {
409
+ command_t command = commands.items[i].util;
410
+ res = command(&s, ps, &files, &opts);
411
+ }
412
+ }
413
+
414
string_list_clear(&files, 1);
415
strbuf_release(&print_file_item_data.buf);
416
strbuf_release(&print_file_item_data.index);
417
strbuf_release(&print_file_item_data.worktree);
418
strbuf_release(&header);
419
+ string_list_clear(&commands, 0);
420
421
return res;
422
}