Skip to content

Commit 573f9f4

Browse files
slavicaDjdscho
authored andcommitted
built-in add -i: show unique prefixes of the commands
Just like in the Perl script `git-add--interactive.perl`, for each command a unique prefix is determined (if there exists any within the given parameters), and shown in the list, and accepted as a shortcut for the command. We use the prefix map implementation that we just added in the previous commit for that purpose. Signed-off-by: Slavica Djukic <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent d7245b9 commit 573f9f4

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed

add-interactive.c

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "diffcore.h"
66
#include "revision.h"
77
#include "refs.h"
8+
#include "prefix-map.h"
89

910
struct add_i_state {
1011
struct repository *r;
@@ -46,18 +47,32 @@ static int init_add_i_state(struct repository *r, struct add_i_state *s)
4647
return 0;
4748
}
4849

49-
struct item {
50-
const char *name;
51-
};
50+
static ssize_t find_unique(const char *string,
51+
struct prefix_item **list, size_t nr)
52+
{
53+
ssize_t found = -1, i;
54+
55+
for (i = 0; i < nr; i++) {
56+
struct prefix_item *item = list[i];
57+
if (!starts_with(item->name, string))
58+
continue;
59+
if (found >= 0)
60+
return -1;
61+
found = i;
62+
}
63+
64+
return found;
65+
}
5266

5367
struct list_options {
5468
int columns;
5569
const char *header;
56-
void (*print_item)(int i, struct item *item, void *print_item_data);
70+
void (*print_item)(int i, struct prefix_item *item,
71+
void *print_item_data);
5772
void *print_item_data;
5873
};
5974

60-
static void list(struct item **list, size_t nr,
75+
static void list(struct prefix_item **list, size_t nr,
6176
struct add_i_state *s, struct list_options *opts)
6277
{
6378
int i, last_lf = 0;
@@ -94,13 +109,15 @@ struct list_and_choose_options {
94109
/*
95110
* Returns the selected index.
96111
*/
97-
static ssize_t list_and_choose(struct item **items, size_t nr,
112+
static ssize_t list_and_choose(struct prefix_item **items, size_t nr,
98113
struct add_i_state *s,
99114
struct list_and_choose_options *opts)
100115
{
101116
struct strbuf input = STRBUF_INIT;
102117
ssize_t res = -1;
103118

119+
find_unique_prefixes(items, nr, 1, 4);
120+
104121
for (;;) {
105122
char *p, *endp;
106123

@@ -140,6 +157,9 @@ static ssize_t list_and_choose(struct item **items, size_t nr,
140157
}
141158

142159
p[sep] = '\0';
160+
if (index < 0)
161+
index = find_unique(p, items, nr);
162+
143163
if (index < 0 || index >= nr)
144164
printf(_("Huh (%s)?\n"), p);
145165
else {
@@ -165,7 +185,7 @@ struct adddel {
165185

166186
struct file_list {
167187
struct file_item {
168-
struct item item;
188+
struct prefix_item item;
169189
struct adddel index, worktree;
170190
} **file;
171191
size_t nr, alloc;
@@ -331,12 +351,29 @@ static void populate_wi_changes(struct strbuf *buf,
331351
strbuf_addstr(buf, no_changes);
332352
}
333353

354+
/* filters out prefixes which have special meaning to list_and_choose() */
355+
static int is_valid_prefix(const char *prefix, size_t prefix_len)
356+
{
357+
return prefix_len && prefix &&
358+
/*
359+
* We expect `prefix` to be NUL terminated, therefore this
360+
* `strcspn()` call is okay, even if it might do much more
361+
* work than strictly necessary.
362+
*/
363+
strcspn(prefix, " \t\r\n,") >= prefix_len && /* separators */
364+
*prefix != '-' && /* deselection */
365+
!isdigit(*prefix) && /* selection */
366+
(prefix_len != 1 ||
367+
(*prefix != '*' && /* "all" wildcard */
368+
*prefix != '?')); /* prompt help */
369+
}
370+
334371
struct print_file_item_data {
335372
const char *modified_fmt;
336373
struct strbuf buf, index, worktree;
337374
};
338375

339-
static void print_file_item(int i, struct item *item,
376+
static void print_file_item(int i, struct prefix_item *item,
340377
void *print_file_item_data)
341378
{
342379
struct file_item *c = (struct file_item *)item;
@@ -363,20 +400,26 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps,
363400
return -1;
364401

365402
if (files->nr)
366-
list((struct item **)files->file, files->nr, s, opts);
403+
list((struct prefix_item **)files->file, files->nr, s, opts);
367404
putchar('\n');
368405

369406
return 0;
370407
}
371408

372-
static void print_command_item(int i, struct item *item,
409+
static void print_command_item(int i, struct prefix_item *item,
373410
void *print_command_item_data)
374411
{
375-
printf(" %2d: %s", i + 1, item->name);
412+
if (!item->prefix_length ||
413+
!is_valid_prefix(item->name, item->prefix_length))
414+
printf(" %2d: %s", i + 1, item->name);
415+
else
416+
printf(" %3d: [%.*s]%s", i + 1,
417+
(int)item->prefix_length, item->name,
418+
item->name + item->prefix_length);
376419
}
377420

378421
struct command_item {
379-
struct item item;
422+
struct prefix_item item;
380423
int (*command)(struct add_i_state *s, const struct pathspec *ps,
381424
struct file_list *files, struct list_options *opts);
382425
};
@@ -418,7 +461,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
418461
res = -1;
419462

420463
for (;;) {
421-
i = list_and_choose((struct item **)commands,
464+
i = list_and_choose((struct prefix_item **)commands,
422465
ARRAY_SIZE(commands), &s, &main_loop_opts);
423466
if (i < -1) {
424467
printf(_("Bye.\n"));

0 commit comments

Comments
 (0)