@@ -6,6 +6,7 @@
#include "revision.h"
#include "refs.h"
#include "string-list.h"
+#include "lockfile.h"
struct add_i_state {
struct repository *r;
@@ -376,6 +377,7 @@ struct adddel {
};
struct file_item {
+ size_t prefix_length;
struct adddel index, worktree;
};
@@ -470,7 +472,7 @@ enum modified_files_filter {
static int get_modified_files(struct repository *r,
enum modified_files_filter filter,
- struct string_list *files,
+ struct prefix_item_list *files,
const struct pathspec *ps)
{
struct object_id head_oid;
@@ -483,8 +485,8 @@ static int get_modified_files(struct repository *r,
repo_read_index_preload(r, ps, 0) < 0)
return error(_("could not read index"));
- string_list_clear(files, 1);
- s.files = files;
+ prefix_item_list_clear(files);
+ s.files = &files->items;
hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
for (i = 0; i < 2; i++) {
@@ -520,7 +522,7 @@ static int get_modified_files(struct repository *r,
hashmap_free_entries(&s.file_map, struct pathname_entry, ent);
/* While the diffs are ordered already, we ran *two* diffs... */
- string_list_sort(files);
+ string_list_sort(&files->items);
return 0;
}
@@ -555,8 +557,8 @@ static int is_valid_prefix(const char *prefix, size_t prefix_len)
}
struct print_file_item_data {
- const char *modified_fmt;
- struct strbuf buf, index, worktree;
+ const char *modified_fmt, *color, *reset;
+ struct strbuf buf, name, index, worktree;
};
static void print_file_item(int i, int selected, struct string_list_item *item,
@@ -564,34 +566,96 @@ static void print_file_item(int i, int selected, struct string_list_item *item,
{
struct file_item *c = item->util;
struct print_file_item_data *d = print_file_item_data;
+ const char *highlighted = NULL;
strbuf_reset(&d->index);
strbuf_reset(&d->worktree);
strbuf_reset(&d->buf);
+ /* Format the item with the prefix highlighted. */
+ if (c->prefix_length > 0 &&
+ is_valid_prefix(item->string, c->prefix_length)) {
+ strbuf_reset(&d->name);
+ strbuf_addf(&d->name, "%s%.*s%s%s", d->color,
+ (int)c->prefix_length, item->string, d->reset,
+ item->string + c->prefix_length);
+ highlighted = d->name.buf;
+ }
+
render_adddel(&d->worktree, &c->worktree, _("nothing"));
render_adddel(&d->index, &c->index, _("unchanged"));
- strbuf_addf(&d->buf, d->modified_fmt,
- d->index.buf, d->worktree.buf, item->string);
+
+ strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf,
+ highlighted ? highlighted : item->string);
printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf);
}
static int run_status(struct add_i_state *s, const struct pathspec *ps,
- struct string_list *files, struct list_options *opts)
+ struct prefix_item_list *files,
+ struct list_and_choose_options *opts)
{
if (get_modified_files(s->r, NO_FILTER, files, ps) < 0)
return -1;
- list(s, files, NULL, opts);
+ list(s, &files->items, NULL, &opts->list_opts);
putchar('\n');
return 0;
}
+static int run_update(struct add_i_state *s, const struct pathspec *ps,
+ struct prefix_item_list *files,
+ struct list_and_choose_options *opts)
+{
+ int res = 0, fd;
+ size_t count, i;
+ struct lock_file index_lock;
+
+ if (get_modified_files(s->r, WORKTREE_ONLY, files, ps) < 0)
+ return -1;
+
+ if (!files->items.nr) {
+ putchar('\n');
+ return 0;
+ }
+
+ opts->prompt = N_("Update");
+ count = list_and_choose(s, files, opts);
+ if (count <= 0) {
+ putchar('\n');
+ return 0;
+ }
+
+ fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+ if (fd < 0) {
+ putchar('\n');
+ return -1;
+ }
+
+ for (i = 0; i < files->items.nr; i++) {
+ const char *name = files->items.items[i].string;
+ if (files->selected[i] &&
+ add_file_to_index(s->r->index, name, 0) < 0) {
+ res = error(_("could not stage '%s'"), name);
+ break;
+ }
+ }
+
+ if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
+ res = error(_("could not write index"));
+
+ if (!res)
+ printf(Q_("updated %d path\n",
+ "updated %d paths\n", count), (int)count);
+
+ putchar('\n');
+ return res;
+}
+
static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
- struct string_list *unused_files,
- struct list_options *unused_opts)
+ struct prefix_item_list *unused_files,
+ struct list_and_choose_options *unused_opts)
{
color_fprintf_ln(stdout, s->help_color, "status - %s",
_("show paths with changes"));
@@ -609,9 +673,29 @@ static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
return 0;
}
+static void choose_prompt_help(struct add_i_state *s)
+{
+ color_fprintf_ln(stdout, s->help_color, "%s",
+ _("Prompt help:"));
+ color_fprintf_ln(stdout, s->help_color, "1 - %s",
+ _("select a single item"));
+ color_fprintf_ln(stdout, s->help_color, "3-5 - %s",
+ _("select a range of items"));
+ color_fprintf_ln(stdout, s->help_color, "2-3,6-9 - %s",
+ _("select multiple ranges"));
+ color_fprintf_ln(stdout, s->help_color, "foo - %s",
+ _("select item based on unique prefix"));
+ color_fprintf_ln(stdout, s->help_color, "-... - %s",
+ _("unselect specified items"));
+ color_fprintf_ln(stdout, s->help_color, "* - %s",
+ _("choose all items"));
+ color_fprintf_ln(stdout, s->help_color, " - %s",
+ _("(empty) finish selecting"));
+}
+
typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
- struct string_list *files,
- struct list_options *opts);
+ struct prefix_item_list *files,
+ struct list_and_choose_options *opts);
struct command_item {
size_t prefix_length;
@@ -663,18 +747,21 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
command_t command;
} command_list[] = {
{ "status", run_status },
+ { "update", run_update },
{ "help", run_help },
};
struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
struct print_file_item_data print_file_item_data = {
- "%12s %12s %s", STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+ "%12s %12s %s", NULL, NULL,
+ STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
};
- struct list_options opts = {
- 0, NULL, print_file_item, &print_file_item_data
+ struct list_and_choose_options opts = {
+ { 0, NULL, print_file_item, &print_file_item_data },
+ NULL, 0, choose_prompt_help
};
struct strbuf header = STRBUF_INIT;
- struct string_list files = STRING_LIST_INIT_DUP;
+ struct prefix_item_list files = PREFIX_ITEM_LIST_INIT;
ssize_t i;
int res = 0;
@@ -695,11 +782,13 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
data.color = s.prompt_color;
data.reset = s.reset_color;
}
+ print_file_item_data.color = data.color;
+ print_file_item_data.reset = data.reset;
strbuf_addstr(&header, " ");
strbuf_addf(&header, print_file_item_data.modified_fmt,
_("staged"), _("unstaged"), _("path"));
- opts.header = header.buf;
+ opts.list_opts.header = header.buf;
if (discard_index(r->index) < 0 ||
repo_read_index(r) < 0 ||
@@ -723,8 +812,9 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
}
}
- string_list_clear(&files, 1);
+ prefix_item_list_clear(&files);
strbuf_release(&print_file_item_data.buf);
+ strbuf_release(&print_file_item_data.name);
strbuf_release(&print_file_item_data.index);
strbuf_release(&print_file_item_data.worktree);
strbuf_release(&header);