1 #include "cache.h"
2 #include "add-interactive.h"
3 #include "color.h"
4 #include "config.h"
5 #include "diffcore.h"
6 #include "revision.h"
7 #include "refs.h"
8 #include "string-list.h"
9 #include "lockfile.h"
10 #include "dir.h"
11 #include "run-command.h"
12 #include "prompt.h"
13 
init_color(struct repository * r,struct add_i_state * s,const char * section_and_slot,char * dst,const char * default_color)14 static void init_color(struct repository *r, struct add_i_state *s,
15 		       const char *section_and_slot, char *dst,
16 		       const char *default_color)
17 {
18 	char *key = xstrfmt("color.%s", section_and_slot);
19 	const char *value;
20 
21 	if (!s->use_color)
22 		dst[0] = '\0';
23 	else if (repo_config_get_value(r, key, &value) ||
24 		 color_parse(value, dst))
25 		strlcpy(dst, default_color, COLOR_MAXLEN);
26 
27 	free(key);
28 }
29 
init_add_i_state(struct add_i_state * s,struct repository * r)30 void init_add_i_state(struct add_i_state *s, struct repository *r)
31 {
32 	const char *value;
33 
34 	s->r = r;
35 
36 	if (repo_config_get_value(r, "color.interactive", &value))
37 		s->use_color = -1;
38 	else
39 		s->use_color =
40 			git_config_colorbool("color.interactive", value);
41 	s->use_color = want_color(s->use_color);
42 
43 	init_color(r, s, "interactive.header", s->header_color, GIT_COLOR_BOLD);
44 	init_color(r, s, "interactive.help", s->help_color, GIT_COLOR_BOLD_RED);
45 	init_color(r, s, "interactive.prompt", s->prompt_color,
46 		   GIT_COLOR_BOLD_BLUE);
47 	init_color(r, s, "interactive.error", s->error_color,
48 		   GIT_COLOR_BOLD_RED);
49 
50 	init_color(r, s, "diff.frag", s->fraginfo_color,
51 		   diff_get_color(s->use_color, DIFF_FRAGINFO));
52 	init_color(r, s, "diff.context", s->context_color, "fall back");
53 	if (!strcmp(s->context_color, "fall back"))
54 		init_color(r, s, "diff.plain", s->context_color,
55 			   diff_get_color(s->use_color, DIFF_CONTEXT));
56 	init_color(r, s, "diff.old", s->file_old_color,
57 		diff_get_color(s->use_color, DIFF_FILE_OLD));
58 	init_color(r, s, "diff.new", s->file_new_color,
59 		diff_get_color(s->use_color, DIFF_FILE_NEW));
60 
61 	strlcpy(s->reset_color,
62 		s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
63 
64 	FREE_AND_NULL(s->interactive_diff_filter);
65 	git_config_get_string("interactive.difffilter",
66 			      &s->interactive_diff_filter);
67 
68 	FREE_AND_NULL(s->interactive_diff_algorithm);
69 	git_config_get_string("diff.algorithm",
70 			      &s->interactive_diff_algorithm);
71 
72 	git_config_get_bool("interactive.singlekey", &s->use_single_key);
73 }
74 
clear_add_i_state(struct add_i_state * s)75 void clear_add_i_state(struct add_i_state *s)
76 {
77 	FREE_AND_NULL(s->interactive_diff_filter);
78 	FREE_AND_NULL(s->interactive_diff_algorithm);
79 	memset(s, 0, sizeof(*s));
80 	s->use_color = -1;
81 }
82 
83 /*
84  * A "prefix item list" is a list of items that are identified by a string, and
85  * a unique prefix (if any) is determined for each item.
86  *
87  * It is implemented in the form of a pair of `string_list`s, the first one
88  * duplicating the strings, with the `util` field pointing at a structure whose
89  * first field must be `size_t prefix_length`.
90  *
91  * That `prefix_length` field will be computed by `find_unique_prefixes()`; It
92  * will be set to zero if no valid, unique prefix could be found.
93  *
94  * The second `string_list` is called `sorted` and does _not_ duplicate the
95  * strings but simply reuses the first one's, with the `util` field pointing at
96  * the `string_item_list` of the first `string_list`. It  will be populated and
97  * sorted by `find_unique_prefixes()`.
98  */
99 struct prefix_item_list {
100 	struct string_list items;
101 	struct string_list sorted;
102 	int *selected; /* for multi-selections */
103 	size_t min_length, max_length;
104 };
105 #define PREFIX_ITEM_LIST_INIT { \
106 	.items = STRING_LIST_INIT_DUP, \
107 	.sorted = STRING_LIST_INIT_NODUP, \
108 	.min_length = 1, \
109 	.max_length = 4, \
110 }
111 
prefix_item_list_clear(struct prefix_item_list * list)112 static void prefix_item_list_clear(struct prefix_item_list *list)
113 {
114 	string_list_clear(&list->items, 1);
115 	string_list_clear(&list->sorted, 0);
116 	FREE_AND_NULL(list->selected);
117 }
118 
extend_prefix_length(struct string_list_item * p,const char * other_string,size_t max_length)119 static void extend_prefix_length(struct string_list_item *p,
120 				 const char *other_string, size_t max_length)
121 {
122 	size_t *len = p->util;
123 
124 	if (!*len || memcmp(p->string, other_string, *len))
125 		return;
126 
127 	for (;;) {
128 		char c = p->string[*len];
129 
130 		/*
131 		 * Is `p` a strict prefix of `other`? Or have we exhausted the
132 		 * maximal length of the prefix? Or is the current character a
133 		 * multi-byte UTF-8 one? If so, there is no valid, unique
134 		 * prefix.
135 		 */
136 		if (!c || ++*len > max_length || !isascii(c)) {
137 			*len = 0;
138 			break;
139 		}
140 
141 		if (c != other_string[*len - 1])
142 			break;
143 	}
144 }
145 
find_unique_prefixes(struct prefix_item_list * list)146 static void find_unique_prefixes(struct prefix_item_list *list)
147 {
148 	size_t i;
149 
150 	if (list->sorted.nr == list->items.nr)
151 		return;
152 
153 	string_list_clear(&list->sorted, 0);
154 	/* Avoid reallocating incrementally */
155 	list->sorted.items = xmalloc(st_mult(sizeof(*list->sorted.items),
156 					     list->items.nr));
157 	list->sorted.nr = list->sorted.alloc = list->items.nr;
158 
159 	for (i = 0; i < list->items.nr; i++) {
160 		list->sorted.items[i].string = list->items.items[i].string;
161 		list->sorted.items[i].util = list->items.items + i;
162 	}
163 
164 	string_list_sort(&list->sorted);
165 
166 	for (i = 0; i < list->sorted.nr; i++) {
167 		struct string_list_item *sorted_item = list->sorted.items + i;
168 		struct string_list_item *item = sorted_item->util;
169 		size_t *len = item->util;
170 
171 		*len = 0;
172 		while (*len < list->min_length) {
173 			char c = item->string[(*len)++];
174 
175 			if (!c || !isascii(c)) {
176 				*len = 0;
177 				break;
178 			}
179 		}
180 
181 		if (i > 0)
182 			extend_prefix_length(item, sorted_item[-1].string,
183 					     list->max_length);
184 		if (i + 1 < list->sorted.nr)
185 			extend_prefix_length(item, sorted_item[1].string,
186 					     list->max_length);
187 	}
188 }
189 
find_unique(const char * string,struct prefix_item_list * list)190 static ssize_t find_unique(const char *string, struct prefix_item_list *list)
191 {
192 	int index = string_list_find_insert_index(&list->sorted, string, 1);
193 	struct string_list_item *item;
194 
195 	if (list->items.nr != list->sorted.nr)
196 		BUG("prefix_item_list in inconsistent state (%"PRIuMAX
197 		    " vs %"PRIuMAX")",
198 		    (uintmax_t)list->items.nr, (uintmax_t)list->sorted.nr);
199 
200 	if (index < 0)
201 		item = list->sorted.items[-1 - index].util;
202 	else if (index > 0 &&
203 		 starts_with(list->sorted.items[index - 1].string, string))
204 		return -1;
205 	else if (index + 1 < list->sorted.nr &&
206 		 starts_with(list->sorted.items[index + 1].string, string))
207 		return -1;
208 	else if (index < list->sorted.nr &&
209 		 starts_with(list->sorted.items[index].string, string))
210 		item = list->sorted.items[index].util;
211 	else
212 		return -1;
213 	return item - list->items.items;
214 }
215 
216 struct list_options {
217 	int columns;
218 	const char *header;
219 	void (*print_item)(int i, int selected, struct string_list_item *item,
220 			   void *print_item_data);
221 	void *print_item_data;
222 };
223 
list(struct add_i_state * s,struct string_list * list,int * selected,struct list_options * opts)224 static void list(struct add_i_state *s, struct string_list *list, int *selected,
225 		 struct list_options *opts)
226 {
227 	int i, last_lf = 0;
228 
229 	if (!list->nr)
230 		return;
231 
232 	if (opts->header)
233 		color_fprintf_ln(stdout, s->header_color,
234 				 "%s", opts->header);
235 
236 	for (i = 0; i < list->nr; i++) {
237 		opts->print_item(i, selected ? selected[i] : 0, list->items + i,
238 				 opts->print_item_data);
239 
240 		if ((opts->columns) && ((i + 1) % (opts->columns))) {
241 			putchar('\t');
242 			last_lf = 0;
243 		}
244 		else {
245 			putchar('\n');
246 			last_lf = 1;
247 		}
248 	}
249 
250 	if (!last_lf)
251 		putchar('\n');
252 }
253 struct list_and_choose_options {
254 	struct list_options list_opts;
255 
256 	const char *prompt;
257 	enum {
258 		SINGLETON = (1<<0),
259 		IMMEDIATE = (1<<1),
260 	} flags;
261 	void (*print_help)(struct add_i_state *s);
262 };
263 
264 #define LIST_AND_CHOOSE_ERROR (-1)
265 #define LIST_AND_CHOOSE_QUIT  (-2)
266 
267 /*
268  * Returns the selected index in singleton mode, the number of selected items
269  * otherwise.
270  *
271  * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
272  * `LIST_AND_CHOOSE_QUIT` is returned.
273  */
list_and_choose(struct add_i_state * s,struct prefix_item_list * items,struct list_and_choose_options * opts)274 static ssize_t list_and_choose(struct add_i_state *s,
275 			       struct prefix_item_list *items,
276 			       struct list_and_choose_options *opts)
277 {
278 	int singleton = opts->flags & SINGLETON;
279 	int immediate = opts->flags & IMMEDIATE;
280 
281 	struct strbuf input = STRBUF_INIT;
282 	ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0;
283 
284 	if (!singleton) {
285 		free(items->selected);
286 		CALLOC_ARRAY(items->selected, items->items.nr);
287 	}
288 
289 	if (singleton && !immediate)
290 		BUG("singleton requires immediate");
291 
292 	find_unique_prefixes(items);
293 
294 	for (;;) {
295 		char *p;
296 
297 		strbuf_reset(&input);
298 
299 		list(s, &items->items, items->selected, &opts->list_opts);
300 
301 		color_fprintf(stdout, s->prompt_color, "%s", opts->prompt);
302 		fputs(singleton ? "> " : ">> ", stdout);
303 		fflush(stdout);
304 
305 		if (git_read_line_interactively(&input) == EOF) {
306 			putchar('\n');
307 			if (immediate)
308 				res = LIST_AND_CHOOSE_QUIT;
309 			break;
310 		}
311 
312 		if (!input.len)
313 			break;
314 
315 		if (!strcmp(input.buf, "?")) {
316 			opts->print_help(s);
317 			continue;
318 		}
319 
320 		p = input.buf;
321 		for (;;) {
322 			size_t sep = strcspn(p, " \t\r\n,");
323 			int choose = 1;
324 			/* `from` is inclusive, `to` is exclusive */
325 			ssize_t from = -1, to = -1;
326 
327 			if (!sep) {
328 				if (!*p)
329 					break;
330 				p++;
331 				continue;
332 			}
333 
334 			/* Input that begins with '-'; de-select */
335 			if (*p == '-') {
336 				choose = 0;
337 				p++;
338 				sep--;
339 			}
340 
341 			if (sep == 1 && *p == '*') {
342 				from = 0;
343 				to = items->items.nr;
344 			} else if (isdigit(*p)) {
345 				char *endp;
346 				/*
347 				 * A range can be specified like 5-7 or 5-.
348 				 *
349 				 * Note: `from` is 0-based while the user input
350 				 * is 1-based, hence we have to decrement by
351 				 * one. We do not have to decrement `to` even
352 				 * if it is 0-based because it is an exclusive
353 				 * boundary.
354 				 */
355 				from = strtoul(p, &endp, 10) - 1;
356 				if (endp == p + sep)
357 					to = from + 1;
358 				else if (*endp == '-') {
359 					if (isdigit(*(++endp)))
360 						to = strtoul(endp, &endp, 10);
361 					else
362 						to = items->items.nr;
363 					/* extra characters after the range? */
364 					if (endp != p + sep)
365 						from = -1;
366 				}
367 			}
368 
369 			if (p[sep])
370 				p[sep++] = '\0';
371 			if (from < 0) {
372 				from = find_unique(p, items);
373 				if (from >= 0)
374 					to = from + 1;
375 			}
376 
377 			if (from < 0 || from >= items->items.nr ||
378 			    (singleton && from + 1 != to)) {
379 				color_fprintf_ln(stderr, s->error_color,
380 						 _("Huh (%s)?"), p);
381 				break;
382 			} else if (singleton) {
383 				res = from;
384 				break;
385 			}
386 
387 			if (to > items->items.nr)
388 				to = items->items.nr;
389 
390 			for (; from < to; from++)
391 				if (items->selected[from] != choose) {
392 					items->selected[from] = choose;
393 					res += choose ? +1 : -1;
394 				}
395 
396 			p += sep;
397 		}
398 
399 		if ((immediate && res != LIST_AND_CHOOSE_ERROR) ||
400 		    !strcmp(input.buf, "*"))
401 			break;
402 	}
403 
404 	strbuf_release(&input);
405 	return res;
406 }
407 
408 struct adddel {
409 	uintmax_t add, del;
410 	unsigned seen:1, unmerged:1, binary:1;
411 };
412 
413 struct file_item {
414 	size_t prefix_length;
415 	struct adddel index, worktree;
416 };
417 
add_file_item(struct string_list * files,const char * name)418 static void add_file_item(struct string_list *files, const char *name)
419 {
420 	struct file_item *item = xcalloc(1, sizeof(*item));
421 
422 	string_list_append(files, name)->util = item;
423 }
424 
425 struct pathname_entry {
426 	struct hashmap_entry ent;
427 	const char *name;
428 	struct file_item *item;
429 };
430 
pathname_entry_cmp(const void * unused_cmp_data,const struct hashmap_entry * he1,const struct hashmap_entry * he2,const void * name)431 static int pathname_entry_cmp(const void *unused_cmp_data,
432 			      const struct hashmap_entry *he1,
433 			      const struct hashmap_entry *he2,
434 			      const void *name)
435 {
436 	const struct pathname_entry *e1 =
437 		container_of(he1, const struct pathname_entry, ent);
438 	const struct pathname_entry *e2 =
439 		container_of(he2, const struct pathname_entry, ent);
440 
441 	return strcmp(e1->name, name ? (const char *)name : e2->name);
442 }
443 
444 struct collection_status {
445 	enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } mode;
446 
447 	const char *reference;
448 
449 	unsigned skip_unseen:1;
450 	size_t unmerged_count, binary_count;
451 	struct string_list *files;
452 	struct hashmap file_map;
453 };
454 
collect_changes_cb(struct diff_queue_struct * q,struct diff_options * options,void * data)455 static void collect_changes_cb(struct diff_queue_struct *q,
456 			       struct diff_options *options,
457 			       void *data)
458 {
459 	struct collection_status *s = data;
460 	struct diffstat_t stat = { 0 };
461 	int i;
462 
463 	if (!q->nr)
464 		return;
465 
466 	compute_diffstat(options, &stat, q);
467 
468 	for (i = 0; i < stat.nr; i++) {
469 		const char *name = stat.files[i]->name;
470 		int hash = strhash(name);
471 		struct pathname_entry *entry;
472 		struct file_item *file_item;
473 		struct adddel *adddel, *other_adddel;
474 
475 		entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
476 						    struct pathname_entry, ent);
477 		if (!entry) {
478 			if (s->skip_unseen)
479 				continue;
480 
481 			add_file_item(s->files, name);
482 
483 			CALLOC_ARRAY(entry, 1);
484 			hashmap_entry_init(&entry->ent, hash);
485 			entry->name = s->files->items[s->files->nr - 1].string;
486 			entry->item = s->files->items[s->files->nr - 1].util;
487 			hashmap_add(&s->file_map, &entry->ent);
488 		}
489 
490 		file_item = entry->item;
491 		adddel = s->mode == FROM_INDEX ?
492 			&file_item->index : &file_item->worktree;
493 		other_adddel = s->mode == FROM_INDEX ?
494 			&file_item->worktree : &file_item->index;
495 		adddel->seen = 1;
496 		adddel->add = stat.files[i]->added;
497 		adddel->del = stat.files[i]->deleted;
498 		if (stat.files[i]->is_binary) {
499 			if (!other_adddel->binary)
500 				s->binary_count++;
501 			adddel->binary = 1;
502 		}
503 		if (stat.files[i]->is_unmerged) {
504 			if (!other_adddel->unmerged)
505 				s->unmerged_count++;
506 			adddel->unmerged = 1;
507 		}
508 	}
509 	free_diffstat_info(&stat);
510 }
511 
512 enum modified_files_filter {
513 	NO_FILTER = 0,
514 	WORKTREE_ONLY = 1,
515 	INDEX_ONLY = 2,
516 };
517 
get_modified_files(struct repository * r,enum modified_files_filter filter,struct prefix_item_list * files,const struct pathspec * ps,size_t * unmerged_count,size_t * binary_count)518 static int get_modified_files(struct repository *r,
519 			      enum modified_files_filter filter,
520 			      struct prefix_item_list *files,
521 			      const struct pathspec *ps,
522 			      size_t *unmerged_count,
523 			      size_t *binary_count)
524 {
525 	struct object_id head_oid;
526 	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
527 					     &head_oid, NULL);
528 	struct collection_status s = { 0 };
529 	int i;
530 
531 	if (discard_index(r->index) < 0 ||
532 	    repo_read_index_preload(r, ps, 0) < 0)
533 		return error(_("could not read index"));
534 
535 	prefix_item_list_clear(files);
536 	s.files = &files->items;
537 	hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
538 
539 	for (i = 0; i < 2; i++) {
540 		struct rev_info rev;
541 		struct setup_revision_opt opt = { 0 };
542 
543 		if (filter == INDEX_ONLY)
544 			s.mode = (i == 0) ? FROM_INDEX : FROM_WORKTREE;
545 		else
546 			s.mode = (i == 0) ? FROM_WORKTREE : FROM_INDEX;
547 		s.skip_unseen = filter && i;
548 
549 		opt.def = is_initial ?
550 			empty_tree_oid_hex() : oid_to_hex(&head_oid);
551 
552 		init_revisions(&rev, NULL);
553 		setup_revisions(0, NULL, &rev, &opt);
554 
555 		rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
556 		rev.diffopt.format_callback = collect_changes_cb;
557 		rev.diffopt.format_callback_data = &s;
558 
559 		if (ps)
560 			copy_pathspec(&rev.prune_data, ps);
561 
562 		if (s.mode == FROM_INDEX)
563 			run_diff_index(&rev, 1);
564 		else {
565 			rev.diffopt.flags.ignore_dirty_submodules = 1;
566 			run_diff_files(&rev, 0);
567 		}
568 
569 		if (ps)
570 			clear_pathspec(&rev.prune_data);
571 	}
572 	hashmap_clear_and_free(&s.file_map, struct pathname_entry, ent);
573 	if (unmerged_count)
574 		*unmerged_count = s.unmerged_count;
575 	if (binary_count)
576 		*binary_count = s.binary_count;
577 
578 	/* While the diffs are ordered already, we ran *two* diffs... */
579 	string_list_sort(&files->items);
580 
581 	return 0;
582 }
583 
render_adddel(struct strbuf * buf,struct adddel * ad,const char * no_changes)584 static void render_adddel(struct strbuf *buf,
585 				struct adddel *ad, const char *no_changes)
586 {
587 	if (ad->binary)
588 		strbuf_addstr(buf, _("binary"));
589 	else if (ad->seen)
590 		strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX,
591 			    (uintmax_t)ad->add, (uintmax_t)ad->del);
592 	else
593 		strbuf_addstr(buf, no_changes);
594 }
595 
596 /* filters out prefixes which have special meaning to list_and_choose() */
is_valid_prefix(const char * prefix,size_t prefix_len)597 static int is_valid_prefix(const char *prefix, size_t prefix_len)
598 {
599 	return prefix_len && prefix &&
600 		/*
601 		 * We expect `prefix` to be NUL terminated, therefore this
602 		 * `strcspn()` call is okay, even if it might do much more
603 		 * work than strictly necessary.
604 		 */
605 		strcspn(prefix, " \t\r\n,") >= prefix_len &&	/* separators */
606 		*prefix != '-' &&				/* deselection */
607 		!isdigit(*prefix) &&				/* selection */
608 		(prefix_len != 1 ||
609 		 (*prefix != '*' &&				/* "all" wildcard */
610 		  *prefix != '?'));				/* prompt help */
611 }
612 
613 struct print_file_item_data {
614 	const char *modified_fmt, *color, *reset;
615 	struct strbuf buf, name, index, worktree;
616 	unsigned only_names:1;
617 };
618 
print_file_item(int i,int selected,struct string_list_item * item,void * print_file_item_data)619 static void print_file_item(int i, int selected, struct string_list_item *item,
620 			    void *print_file_item_data)
621 {
622 	struct file_item *c = item->util;
623 	struct print_file_item_data *d = print_file_item_data;
624 	const char *highlighted = NULL;
625 
626 	strbuf_reset(&d->index);
627 	strbuf_reset(&d->worktree);
628 	strbuf_reset(&d->buf);
629 
630 	/* Format the item with the prefix highlighted. */
631 	if (c->prefix_length > 0 &&
632 	    is_valid_prefix(item->string, c->prefix_length)) {
633 		strbuf_reset(&d->name);
634 		strbuf_addf(&d->name, "%s%.*s%s%s", d->color,
635 			    (int)c->prefix_length, item->string, d->reset,
636 			    item->string + c->prefix_length);
637 		highlighted = d->name.buf;
638 	}
639 
640 	if (d->only_names) {
641 		printf("%c%2d: %s", selected ? '*' : ' ', i + 1,
642 		       highlighted ? highlighted : item->string);
643 		return;
644 	}
645 
646 	render_adddel(&d->worktree, &c->worktree, _("nothing"));
647 	render_adddel(&d->index, &c->index, _("unchanged"));
648 
649 	strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf,
650 		    highlighted ? highlighted : item->string);
651 
652 	printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf);
653 }
654 
run_status(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)655 static int run_status(struct add_i_state *s, const struct pathspec *ps,
656 		      struct prefix_item_list *files,
657 		      struct list_and_choose_options *opts)
658 {
659 	if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0)
660 		return -1;
661 
662 	list(s, &files->items, NULL, &opts->list_opts);
663 	putchar('\n');
664 
665 	return 0;
666 }
667 
run_update(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)668 static int run_update(struct add_i_state *s, const struct pathspec *ps,
669 		      struct prefix_item_list *files,
670 		      struct list_and_choose_options *opts)
671 {
672 	int res = 0, fd;
673 	size_t count, i;
674 	struct lock_file index_lock;
675 
676 	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0)
677 		return -1;
678 
679 	if (!files->items.nr) {
680 		putchar('\n');
681 		return 0;
682 	}
683 
684 	opts->prompt = N_("Update");
685 	count = list_and_choose(s, files, opts);
686 	if (count <= 0) {
687 		putchar('\n');
688 		return 0;
689 	}
690 
691 	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
692 	if (fd < 0) {
693 		putchar('\n');
694 		return -1;
695 	}
696 
697 	for (i = 0; i < files->items.nr; i++) {
698 		const char *name = files->items.items[i].string;
699 		if (files->selected[i] &&
700 		    add_file_to_index(s->r->index, name, 0) < 0) {
701 			res = error(_("could not stage '%s'"), name);
702 			break;
703 		}
704 	}
705 
706 	if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
707 		res = error(_("could not write index"));
708 
709 	if (!res)
710 		printf(Q_("updated %d path\n",
711 			  "updated %d paths\n", count), (int)count);
712 
713 	putchar('\n');
714 	return res;
715 }
716 
revert_from_diff(struct diff_queue_struct * q,struct diff_options * opt,void * data)717 static void revert_from_diff(struct diff_queue_struct *q,
718 			     struct diff_options *opt, void *data)
719 {
720 	int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
721 
722 	for (i = 0; i < q->nr; i++) {
723 		struct diff_filespec *one = q->queue[i]->one;
724 		struct cache_entry *ce;
725 
726 		if (!(one->mode && !is_null_oid(&one->oid))) {
727 			remove_file_from_index(opt->repo->index, one->path);
728 			printf(_("note: %s is untracked now.\n"), one->path);
729 		} else {
730 			ce = make_cache_entry(opt->repo->index, one->mode,
731 					      &one->oid, one->path, 0, 0);
732 			if (!ce)
733 				die(_("make_cache_entry failed for path '%s'"),
734 				    one->path);
735 			add_index_entry(opt->repo->index, ce, add_flags);
736 		}
737 	}
738 }
739 
run_revert(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)740 static int run_revert(struct add_i_state *s, const struct pathspec *ps,
741 		      struct prefix_item_list *files,
742 		      struct list_and_choose_options *opts)
743 {
744 	int res = 0, fd;
745 	size_t count, i, j;
746 
747 	struct object_id oid;
748 	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
749 					     NULL);
750 	struct lock_file index_lock;
751 	const char **paths;
752 	struct tree *tree;
753 	struct diff_options diffopt = { NULL };
754 
755 	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
756 		return -1;
757 
758 	if (!files->items.nr) {
759 		putchar('\n');
760 		return 0;
761 	}
762 
763 	opts->prompt = N_("Revert");
764 	count = list_and_choose(s, files, opts);
765 	if (count <= 0)
766 		goto finish_revert;
767 
768 	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
769 	if (fd < 0) {
770 		res = -1;
771 		goto finish_revert;
772 	}
773 
774 	if (is_initial)
775 		oidcpy(&oid, s->r->hash_algo->empty_tree);
776 	else {
777 		tree = parse_tree_indirect(&oid);
778 		if (!tree) {
779 			res = error(_("Could not parse HEAD^{tree}"));
780 			goto finish_revert;
781 		}
782 		oidcpy(&oid, &tree->object.oid);
783 	}
784 
785 	ALLOC_ARRAY(paths, count + 1);
786 	for (i = j = 0; i < files->items.nr; i++)
787 		if (files->selected[i])
788 			paths[j++] = files->items.items[i].string;
789 	paths[j] = NULL;
790 
791 	parse_pathspec(&diffopt.pathspec, 0,
792 		       PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH,
793 		       NULL, paths);
794 
795 	diffopt.output_format = DIFF_FORMAT_CALLBACK;
796 	diffopt.format_callback = revert_from_diff;
797 	diffopt.flags.override_submodule_config = 1;
798 	diffopt.repo = s->r;
799 
800 	if (do_diff_cache(&oid, &diffopt))
801 		res = -1;
802 	else {
803 		diffcore_std(&diffopt);
804 		diff_flush(&diffopt);
805 	}
806 	free(paths);
807 	clear_pathspec(&diffopt.pathspec);
808 
809 	if (!res && write_locked_index(s->r->index, &index_lock,
810 				       COMMIT_LOCK) < 0)
811 		res = -1;
812 	else
813 		res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1,
814 						   NULL, NULL, NULL);
815 
816 	if (!res)
817 		printf(Q_("reverted %d path\n",
818 			  "reverted %d paths\n", count), (int)count);
819 
820 finish_revert:
821 	putchar('\n');
822 	return res;
823 }
824 
get_untracked_files(struct repository * r,struct prefix_item_list * files,const struct pathspec * ps)825 static int get_untracked_files(struct repository *r,
826 			       struct prefix_item_list *files,
827 			       const struct pathspec *ps)
828 {
829 	struct dir_struct dir = { 0 };
830 	size_t i;
831 	struct strbuf buf = STRBUF_INIT;
832 
833 	if (repo_read_index(r) < 0)
834 		return error(_("could not read index"));
835 
836 	prefix_item_list_clear(files);
837 	setup_standard_excludes(&dir);
838 	add_pattern_list(&dir, EXC_CMDL, "--exclude option");
839 	fill_directory(&dir, r->index, ps);
840 
841 	for (i = 0; i < dir.nr; i++) {
842 		struct dir_entry *ent = dir.entries[i];
843 
844 		if (index_name_is_other(r->index, ent->name, ent->len)) {
845 			strbuf_reset(&buf);
846 			strbuf_add(&buf, ent->name, ent->len);
847 			add_file_item(&files->items, buf.buf);
848 		}
849 	}
850 
851 	strbuf_release(&buf);
852 	return 0;
853 }
854 
run_add_untracked(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)855 static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps,
856 		      struct prefix_item_list *files,
857 		      struct list_and_choose_options *opts)
858 {
859 	struct print_file_item_data *d = opts->list_opts.print_item_data;
860 	int res = 0, fd;
861 	size_t count, i;
862 	struct lock_file index_lock;
863 
864 	if (get_untracked_files(s->r, files, ps) < 0)
865 		return -1;
866 
867 	if (!files->items.nr) {
868 		printf(_("No untracked files.\n"));
869 		goto finish_add_untracked;
870 	}
871 
872 	opts->prompt = N_("Add untracked");
873 	d->only_names = 1;
874 	count = list_and_choose(s, files, opts);
875 	d->only_names = 0;
876 	if (count <= 0)
877 		goto finish_add_untracked;
878 
879 	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
880 	if (fd < 0) {
881 		res = -1;
882 		goto finish_add_untracked;
883 	}
884 
885 	for (i = 0; i < files->items.nr; i++) {
886 		const char *name = files->items.items[i].string;
887 		if (files->selected[i] &&
888 		    add_file_to_index(s->r->index, name, 0) < 0) {
889 			res = error(_("could not stage '%s'"), name);
890 			break;
891 		}
892 	}
893 
894 	if (!res &&
895 	    write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
896 		res = error(_("could not write index"));
897 
898 	if (!res)
899 		printf(Q_("added %d path\n",
900 			  "added %d paths\n", count), (int)count);
901 
902 finish_add_untracked:
903 	putchar('\n');
904 	return res;
905 }
906 
run_patch(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)907 static int run_patch(struct add_i_state *s, const struct pathspec *ps,
908 		     struct prefix_item_list *files,
909 		     struct list_and_choose_options *opts)
910 {
911 	int res = 0;
912 	ssize_t count, i, j;
913 	size_t unmerged_count = 0, binary_count = 0;
914 
915 	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps,
916 			       &unmerged_count, &binary_count) < 0)
917 		return -1;
918 
919 	if (unmerged_count || binary_count) {
920 		for (i = j = 0; i < files->items.nr; i++) {
921 			struct file_item *item = files->items.items[i].util;
922 
923 			if (item->index.binary || item->worktree.binary) {
924 				free(item);
925 				free(files->items.items[i].string);
926 			} else if (item->index.unmerged ||
927 				 item->worktree.unmerged) {
928 				color_fprintf_ln(stderr, s->error_color,
929 						 _("ignoring unmerged: %s"),
930 						 files->items.items[i].string);
931 				free(item);
932 				free(files->items.items[i].string);
933 			} else
934 				files->items.items[j++] = files->items.items[i];
935 		}
936 		files->items.nr = j;
937 	}
938 
939 	if (!files->items.nr) {
940 		if (binary_count)
941 			fprintf(stderr, _("Only binary files changed.\n"));
942 		else
943 			fprintf(stderr, _("No changes.\n"));
944 		return 0;
945 	}
946 
947 	opts->prompt = N_("Patch update");
948 	count = list_and_choose(s, files, opts);
949 	if (count > 0) {
950 		struct strvec args = STRVEC_INIT;
951 		struct pathspec ps_selected = { 0 };
952 
953 		for (i = 0; i < files->items.nr; i++)
954 			if (files->selected[i])
955 				strvec_push(&args,
956 					    files->items.items[i].string);
957 		parse_pathspec(&ps_selected,
958 			       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
959 			       PATHSPEC_LITERAL_PATH, "", args.v);
960 		res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
961 		strvec_clear(&args);
962 		clear_pathspec(&ps_selected);
963 	}
964 
965 	return res;
966 }
967 
run_diff(struct add_i_state * s,const struct pathspec * ps,struct prefix_item_list * files,struct list_and_choose_options * opts)968 static int run_diff(struct add_i_state *s, const struct pathspec *ps,
969 		    struct prefix_item_list *files,
970 		    struct list_and_choose_options *opts)
971 {
972 	int res = 0;
973 	ssize_t count, i;
974 
975 	struct object_id oid;
976 	int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
977 					     NULL);
978 	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
979 		return -1;
980 
981 	if (!files->items.nr) {
982 		putchar('\n');
983 		return 0;
984 	}
985 
986 	opts->prompt = N_("Review diff");
987 	opts->flags = IMMEDIATE;
988 	count = list_and_choose(s, files, opts);
989 	opts->flags = 0;
990 	if (count > 0) {
991 		struct strvec args = STRVEC_INIT;
992 
993 		strvec_pushl(&args, "git", "diff", "-p", "--cached",
994 			     oid_to_hex(!is_initial ? &oid :
995 					s->r->hash_algo->empty_tree),
996 			     "--", NULL);
997 		for (i = 0; i < files->items.nr; i++)
998 			if (files->selected[i])
999 				strvec_push(&args,
1000 					    files->items.items[i].string);
1001 		res = run_command_v_opt(args.v, 0);
1002 		strvec_clear(&args);
1003 	}
1004 
1005 	putchar('\n');
1006 	return res;
1007 }
1008 
run_help(struct add_i_state * s,const struct pathspec * unused_ps,struct prefix_item_list * unused_files,struct list_and_choose_options * unused_opts)1009 static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
1010 		    struct prefix_item_list *unused_files,
1011 		    struct list_and_choose_options *unused_opts)
1012 {
1013 	color_fprintf_ln(stdout, s->help_color, "status        - %s",
1014 			 _("show paths with changes"));
1015 	color_fprintf_ln(stdout, s->help_color, "update        - %s",
1016 			 _("add working tree state to the staged set of changes"));
1017 	color_fprintf_ln(stdout, s->help_color, "revert        - %s",
1018 			 _("revert staged set of changes back to the HEAD version"));
1019 	color_fprintf_ln(stdout, s->help_color, "patch         - %s",
1020 			 _("pick hunks and update selectively"));
1021 	color_fprintf_ln(stdout, s->help_color, "diff          - %s",
1022 			 _("view diff between HEAD and index"));
1023 	color_fprintf_ln(stdout, s->help_color, "add untracked - %s",
1024 			 _("add contents of untracked files to the staged set of changes"));
1025 
1026 	return 0;
1027 }
1028 
choose_prompt_help(struct add_i_state * s)1029 static void choose_prompt_help(struct add_i_state *s)
1030 {
1031 	color_fprintf_ln(stdout, s->help_color, "%s",
1032 			 _("Prompt help:"));
1033 	color_fprintf_ln(stdout, s->help_color, "1          - %s",
1034 			 _("select a single item"));
1035 	color_fprintf_ln(stdout, s->help_color, "3-5        - %s",
1036 			 _("select a range of items"));
1037 	color_fprintf_ln(stdout, s->help_color, "2-3,6-9    - %s",
1038 			 _("select multiple ranges"));
1039 	color_fprintf_ln(stdout, s->help_color, "foo        - %s",
1040 			 _("select item based on unique prefix"));
1041 	color_fprintf_ln(stdout, s->help_color, "-...       - %s",
1042 			 _("unselect specified items"));
1043 	color_fprintf_ln(stdout, s->help_color, "*          - %s",
1044 			 _("choose all items"));
1045 	color_fprintf_ln(stdout, s->help_color, "           - %s",
1046 			 _("(empty) finish selecting"));
1047 }
1048 
1049 typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
1050 			 struct prefix_item_list *files,
1051 			 struct list_and_choose_options *opts);
1052 
1053 struct command_item {
1054 	size_t prefix_length;
1055 	command_t command;
1056 };
1057 
1058 struct print_command_item_data {
1059 	const char *color, *reset;
1060 };
1061 
print_command_item(int i,int selected,struct string_list_item * item,void * print_command_item_data)1062 static void print_command_item(int i, int selected,
1063 			       struct string_list_item *item,
1064 			       void *print_command_item_data)
1065 {
1066 	struct print_command_item_data *d = print_command_item_data;
1067 	struct command_item *util = item->util;
1068 
1069 	if (!util->prefix_length ||
1070 	    !is_valid_prefix(item->string, util->prefix_length))
1071 		printf(" %2d: %s", i + 1, item->string);
1072 	else
1073 		printf(" %2d: %s%.*s%s%s", i + 1,
1074 		       d->color, (int)util->prefix_length, item->string,
1075 		       d->reset, item->string + util->prefix_length);
1076 }
1077 
command_prompt_help(struct add_i_state * s)1078 static void command_prompt_help(struct add_i_state *s)
1079 {
1080 	const char *help_color = s->help_color;
1081 	color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:"));
1082 	color_fprintf_ln(stdout, help_color, "1          - %s",
1083 			 _("select a numbered item"));
1084 	color_fprintf_ln(stdout, help_color, "foo        - %s",
1085 			 _("select item based on unique prefix"));
1086 	color_fprintf_ln(stdout, help_color, "           - %s",
1087 			 _("(empty) select nothing"));
1088 }
1089 
run_add_i(struct repository * r,const struct pathspec * ps)1090 int run_add_i(struct repository *r, const struct pathspec *ps)
1091 {
1092 	struct add_i_state s = { NULL };
1093 	struct print_command_item_data data = { "[", "]" };
1094 	struct list_and_choose_options main_loop_opts = {
1095 		{ 4, N_("*** Commands ***"), print_command_item, &data },
1096 		N_("What now"), SINGLETON | IMMEDIATE, command_prompt_help
1097 	};
1098 	struct {
1099 		const char *string;
1100 		command_t command;
1101 	} command_list[] = {
1102 		{ "status", run_status },
1103 		{ "update", run_update },
1104 		{ "revert", run_revert },
1105 		{ "add untracked", run_add_untracked },
1106 		{ "patch", run_patch },
1107 		{ "diff", run_diff },
1108 		{ "quit", NULL },
1109 		{ "help", run_help },
1110 	};
1111 	struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
1112 
1113 	struct print_file_item_data print_file_item_data = {
1114 		"%12s %12s %s", NULL, NULL,
1115 		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
1116 	};
1117 	struct list_and_choose_options opts = {
1118 		{ 0, NULL, print_file_item, &print_file_item_data },
1119 		NULL, 0, choose_prompt_help
1120 	};
1121 	struct strbuf header = STRBUF_INIT;
1122 	struct prefix_item_list files = PREFIX_ITEM_LIST_INIT;
1123 	ssize_t i;
1124 	int res = 0;
1125 
1126 	for (i = 0; i < ARRAY_SIZE(command_list); i++) {
1127 		struct command_item *util = xcalloc(1, sizeof(*util));
1128 		util->command = command_list[i].command;
1129 		string_list_append(&commands.items, command_list[i].string)
1130 			->util = util;
1131 	}
1132 
1133 	init_add_i_state(&s, r);
1134 
1135 	/*
1136 	 * When color was asked for, use the prompt color for
1137 	 * highlighting, otherwise use square brackets.
1138 	 */
1139 	if (s.use_color) {
1140 		data.color = s.prompt_color;
1141 		data.reset = s.reset_color;
1142 	}
1143 	print_file_item_data.color = data.color;
1144 	print_file_item_data.reset = data.reset;
1145 
1146 	strbuf_addstr(&header, "     ");
1147 	strbuf_addf(&header, print_file_item_data.modified_fmt,
1148 		    _("staged"), _("unstaged"), _("path"));
1149 	opts.list_opts.header = header.buf;
1150 
1151 	if (discard_index(r->index) < 0 ||
1152 	    repo_read_index(r) < 0 ||
1153 	    repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
1154 					 NULL, NULL, NULL) < 0)
1155 		warning(_("could not refresh index"));
1156 
1157 	res = run_status(&s, ps, &files, &opts);
1158 
1159 	for (;;) {
1160 		struct command_item *util;
1161 
1162 		i = list_and_choose(&s, &commands, &main_loop_opts);
1163 		if (i < 0 || i >= commands.items.nr)
1164 			util = NULL;
1165 		else
1166 			util = commands.items.items[i].util;
1167 
1168 		if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) {
1169 			printf(_("Bye.\n"));
1170 			res = 0;
1171 			break;
1172 		}
1173 
1174 		if (util)
1175 			res = util->command(&s, ps, &files, &opts);
1176 	}
1177 
1178 	prefix_item_list_clear(&files);
1179 	strbuf_release(&print_file_item_data.buf);
1180 	strbuf_release(&print_file_item_data.name);
1181 	strbuf_release(&print_file_item_data.index);
1182 	strbuf_release(&print_file_item_data.worktree);
1183 	strbuf_release(&header);
1184 	prefix_item_list_clear(&commands);
1185 	clear_add_i_state(&s);
1186 
1187 	return res;
1188 }
1189