2019-11-13 20:40:57 +08:00
|
|
|
#include "cache.h"
|
|
|
|
#include "add-interactive.h"
|
2019-11-13 20:41:00 +08:00
|
|
|
#include "color.h"
|
|
|
|
#include "config.h"
|
2019-11-13 20:40:59 +08:00
|
|
|
#include "diffcore.h"
|
|
|
|
#include "revision.h"
|
|
|
|
#include "refs.h"
|
|
|
|
#include "string-list.h"
|
2019-11-30 05:11:44 +08:00
|
|
|
#include "lockfile.h"
|
2019-11-30 05:11:46 +08:00
|
|
|
#include "dir.h"
|
2019-11-30 05:11:47 +08:00
|
|
|
#include "run-command.h"
|
2020-04-10 19:27:50 +08:00
|
|
|
#include "prompt.h"
|
2019-11-13 20:40:59 +08:00
|
|
|
|
2019-11-13 20:41:00 +08:00
|
|
|
static void init_color(struct repository *r, struct add_i_state *s,
|
2020-11-11 20:28:19 +08:00
|
|
|
const char *section_and_slot, char *dst,
|
2019-11-13 20:41:00 +08:00
|
|
|
const char *default_color)
|
|
|
|
{
|
2020-11-11 20:28:19 +08:00
|
|
|
char *key = xstrfmt("color.%s", section_and_slot);
|
2019-11-13 20:41:00 +08:00
|
|
|
const char *value;
|
|
|
|
|
|
|
|
if (!s->use_color)
|
|
|
|
dst[0] = '\0';
|
|
|
|
else if (repo_config_get_value(r, key, &value) ||
|
|
|
|
color_parse(value, dst))
|
|
|
|
strlcpy(dst, default_color, COLOR_MAXLEN);
|
|
|
|
|
|
|
|
free(key);
|
|
|
|
}
|
|
|
|
|
built-in add -p: adjust hunk headers as needed
When skipping a hunk that adds a different number of lines than it
removes, we need to adjust the subsequent hunk headers of non-skipped
hunks: in pathological cases, the context is not enough to determine
precisely where the patch should be applied.
This problem was identified in 23fea4c240 (t3701: add failing test for
pathological context lines, 2018-03-01) and fixed in the Perl version in
fecc6f3a68 (add -p: adjust offsets of subsequent hunks when one is
skipped, 2018-03-01).
And this patch fixes it in the C version of `git add -p`.
In contrast to the Perl version, we try to keep the extra text on the
hunk header (which typically contains the signature of the function
whose code is changed in the hunk) intact.
Note: while the C version does not support staging mode changes at this
stage, we already prepare for this by simply skipping the hunk header if
both old and new offset is 0 (this cannot happen for regular hunks, and
we will use this as an indicator that we are looking at a special hunk).
Likewise, we already prepare for hunk splitting by handling the absence
of extra text in the hunk header gracefully: only the first split hunk
will have that text, the others will not (indicated by an empty extra
text start/end range). Preparing for hunk splitting already at this
stage avoids an indentation change of the entire hunk header-printing
block later, and is almost as easy to review as without that handling.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-13 16:07:51 +08:00
|
|
|
void init_add_i_state(struct add_i_state *s, struct repository *r)
|
2019-11-13 20:40:59 +08:00
|
|
|
{
|
2019-11-13 20:41:00 +08:00
|
|
|
const char *value;
|
|
|
|
|
|
|
|
s->r = r;
|
|
|
|
|
|
|
|
if (repo_config_get_value(r, "color.interactive", &value))
|
|
|
|
s->use_color = -1;
|
|
|
|
else
|
|
|
|
s->use_color =
|
|
|
|
git_config_colorbool("color.interactive", value);
|
|
|
|
s->use_color = want_color(s->use_color);
|
|
|
|
|
2020-11-11 20:28:19 +08:00
|
|
|
init_color(r, s, "interactive.header", s->header_color, GIT_COLOR_BOLD);
|
|
|
|
init_color(r, s, "interactive.help", s->help_color, GIT_COLOR_BOLD_RED);
|
|
|
|
init_color(r, s, "interactive.prompt", s->prompt_color,
|
|
|
|
GIT_COLOR_BOLD_BLUE);
|
|
|
|
init_color(r, s, "interactive.error", s->error_color,
|
|
|
|
GIT_COLOR_BOLD_RED);
|
|
|
|
|
|
|
|
init_color(r, s, "diff.frag", s->fraginfo_color,
|
built-in add -p: adjust hunk headers as needed
When skipping a hunk that adds a different number of lines than it
removes, we need to adjust the subsequent hunk headers of non-skipped
hunks: in pathological cases, the context is not enough to determine
precisely where the patch should be applied.
This problem was identified in 23fea4c240 (t3701: add failing test for
pathological context lines, 2018-03-01) and fixed in the Perl version in
fecc6f3a68 (add -p: adjust offsets of subsequent hunks when one is
skipped, 2018-03-01).
And this patch fixes it in the C version of `git add -p`.
In contrast to the Perl version, we try to keep the extra text on the
hunk header (which typically contains the signature of the function
whose code is changed in the hunk) intact.
Note: while the C version does not support staging mode changes at this
stage, we already prepare for this by simply skipping the hunk header if
both old and new offset is 0 (this cannot happen for regular hunks, and
we will use this as an indicator that we are looking at a special hunk).
Likewise, we already prepare for hunk splitting by handling the absence
of extra text in the hunk header gracefully: only the first split hunk
will have that text, the others will not (indicated by an empty extra
text start/end range). Preparing for hunk splitting already at this
stage avoids an indentation change of the entire hunk header-printing
block later, and is almost as easy to review as without that handling.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-13 16:07:51 +08:00
|
|
|
diff_get_color(s->use_color, DIFF_FRAGINFO));
|
add -p: prefer color.diff.context over color.diff.plain
Git's diff machinery allows users to override the colors to use in
diffs, even the plain-colored context lines. As of 8dbf3eb6850 (diff.h:
rename DIFF_PLAIN color slot to DIFF_CONTEXT, 2015-05-27), the preferred
name of the config setting is `color.diff.context`, although Git still
allows `color.diff.plain`.
In the context of `git add -p`, this logic is a bit hard to replicate:
`git_diff_basic_config()` reads all config values sequentially and if it
sees _any_ `color.diff.context` or `color.diff.plain`, it accepts the
new color. The Perl version of `git add -p` needs to go through `git
config --get-color`, though, which allows only one key to be specified.
The same goes for the built-in version of `git add -p`, which has to go
through `repo_config_get_value()`.
The best we can do here is to look for `.context` and if none is found,
fall back to looking for `.plain`, and if still not found, fall back to
the hard-coded default (which in this case is simply the empty string,
as context lines are typically rendered without colored).
This still leads to inconsistencies when both config names are used: the
initial diff will be colored by the diff machinery. Once edited by a
user, a hunk has to be re-colored by `git add -p`, though, which would
then use the other setting to color the context lines.
In practice, this is not _all_ that bad. The `git config` manual says
this in the `color.diff.<slot>`:
`context` (context text - `plain` is a historical synonym)
We should therefore assume that users use either one or the other, but
not both names. Besides, it is relatively uncommon to look at a hunk
after editing it because it is immediately staged by default.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-17 00:08:31 +08:00
|
|
|
init_color(r, s, "diff.context", s->context_color, "fall back");
|
|
|
|
if (!strcmp(s->context_color, "fall back"))
|
|
|
|
init_color(r, s, "diff.plain", s->context_color,
|
|
|
|
diff_get_color(s->use_color, DIFF_CONTEXT));
|
2020-11-11 20:28:19 +08:00
|
|
|
init_color(r, s, "diff.old", s->file_old_color,
|
2019-12-13 16:08:01 +08:00
|
|
|
diff_get_color(s->use_color, DIFF_FILE_OLD));
|
2020-11-11 20:28:19 +08:00
|
|
|
init_color(r, s, "diff.new", s->file_new_color,
|
2019-12-13 16:08:01 +08:00
|
|
|
diff_get_color(s->use_color, DIFF_FILE_NEW));
|
2020-01-15 02:43:45 +08:00
|
|
|
|
2020-11-11 20:28:18 +08:00
|
|
|
strlcpy(s->reset_color,
|
|
|
|
s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
|
|
|
|
|
2020-01-15 02:43:45 +08:00
|
|
|
FREE_AND_NULL(s->interactive_diff_filter);
|
|
|
|
git_config_get_string("interactive.difffilter",
|
|
|
|
&s->interactive_diff_filter);
|
2020-01-15 02:43:46 +08:00
|
|
|
|
|
|
|
FREE_AND_NULL(s->interactive_diff_algorithm);
|
|
|
|
git_config_get_string("diff.algorithm",
|
|
|
|
&s->interactive_diff_algorithm);
|
2020-01-15 02:43:50 +08:00
|
|
|
|
|
|
|
git_config_get_bool("interactive.singlekey", &s->use_single_key);
|
2022-02-23 02:53:35 +08:00
|
|
|
if (s->use_single_key)
|
|
|
|
setbuf(stdin, NULL);
|
2020-01-15 02:43:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear_add_i_state(struct add_i_state *s)
|
|
|
|
{
|
|
|
|
FREE_AND_NULL(s->interactive_diff_filter);
|
2020-01-15 02:43:46 +08:00
|
|
|
FREE_AND_NULL(s->interactive_diff_algorithm);
|
2020-01-15 02:43:45 +08:00
|
|
|
memset(s, 0, sizeof(*s));
|
|
|
|
s->use_color = -1;
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
|
|
|
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
/*
|
|
|
|
* A "prefix item list" is a list of items that are identified by a string, and
|
|
|
|
* a unique prefix (if any) is determined for each item.
|
|
|
|
*
|
|
|
|
* It is implemented in the form of a pair of `string_list`s, the first one
|
|
|
|
* duplicating the strings, with the `util` field pointing at a structure whose
|
|
|
|
* first field must be `size_t prefix_length`.
|
|
|
|
*
|
|
|
|
* That `prefix_length` field will be computed by `find_unique_prefixes()`; It
|
|
|
|
* will be set to zero if no valid, unique prefix could be found.
|
|
|
|
*
|
|
|
|
* The second `string_list` is called `sorted` and does _not_ duplicate the
|
|
|
|
* strings but simply reuses the first one's, with the `util` field pointing at
|
|
|
|
* the `string_item_list` of the first `string_list`. It will be populated and
|
|
|
|
* sorted by `find_unique_prefixes()`.
|
|
|
|
*/
|
|
|
|
struct prefix_item_list {
|
|
|
|
struct string_list items;
|
|
|
|
struct string_list sorted;
|
2019-11-30 05:11:43 +08:00
|
|
|
int *selected; /* for multi-selections */
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
size_t min_length, max_length;
|
|
|
|
};
|
2021-09-27 20:54:27 +08:00
|
|
|
#define PREFIX_ITEM_LIST_INIT { \
|
|
|
|
.items = STRING_LIST_INIT_DUP, \
|
|
|
|
.sorted = STRING_LIST_INIT_NODUP, \
|
|
|
|
.min_length = 1, \
|
|
|
|
.max_length = 4, \
|
|
|
|
}
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
|
|
|
|
static void prefix_item_list_clear(struct prefix_item_list *list)
|
|
|
|
{
|
|
|
|
string_list_clear(&list->items, 1);
|
|
|
|
string_list_clear(&list->sorted, 0);
|
2019-11-30 05:11:43 +08:00
|
|
|
FREE_AND_NULL(list->selected);
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void extend_prefix_length(struct string_list_item *p,
|
|
|
|
const char *other_string, size_t max_length)
|
|
|
|
{
|
|
|
|
size_t *len = p->util;
|
|
|
|
|
|
|
|
if (!*len || memcmp(p->string, other_string, *len))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
char c = p->string[*len];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Is `p` a strict prefix of `other`? Or have we exhausted the
|
|
|
|
* maximal length of the prefix? Or is the current character a
|
|
|
|
* multi-byte UTF-8 one? If so, there is no valid, unique
|
|
|
|
* prefix.
|
|
|
|
*/
|
|
|
|
if (!c || ++*len > max_length || !isascii(c)) {
|
|
|
|
*len = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != other_string[*len - 1])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void find_unique_prefixes(struct prefix_item_list *list)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (list->sorted.nr == list->items.nr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
string_list_clear(&list->sorted, 0);
|
|
|
|
/* Avoid reallocating incrementally */
|
|
|
|
list->sorted.items = xmalloc(st_mult(sizeof(*list->sorted.items),
|
|
|
|
list->items.nr));
|
|
|
|
list->sorted.nr = list->sorted.alloc = list->items.nr;
|
|
|
|
|
|
|
|
for (i = 0; i < list->items.nr; i++) {
|
|
|
|
list->sorted.items[i].string = list->items.items[i].string;
|
|
|
|
list->sorted.items[i].util = list->items.items + i;
|
|
|
|
}
|
|
|
|
|
|
|
|
string_list_sort(&list->sorted);
|
|
|
|
|
|
|
|
for (i = 0; i < list->sorted.nr; i++) {
|
|
|
|
struct string_list_item *sorted_item = list->sorted.items + i;
|
|
|
|
struct string_list_item *item = sorted_item->util;
|
|
|
|
size_t *len = item->util;
|
|
|
|
|
|
|
|
*len = 0;
|
|
|
|
while (*len < list->min_length) {
|
|
|
|
char c = item->string[(*len)++];
|
|
|
|
|
|
|
|
if (!c || !isascii(c)) {
|
|
|
|
*len = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
extend_prefix_length(item, sorted_item[-1].string,
|
|
|
|
list->max_length);
|
|
|
|
if (i + 1 < list->sorted.nr)
|
|
|
|
extend_prefix_length(item, sorted_item[1].string,
|
|
|
|
list->max_length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t find_unique(const char *string, struct prefix_item_list *list)
|
|
|
|
{
|
|
|
|
int index = string_list_find_insert_index(&list->sorted, string, 1);
|
|
|
|
struct string_list_item *item;
|
|
|
|
|
|
|
|
if (list->items.nr != list->sorted.nr)
|
|
|
|
BUG("prefix_item_list in inconsistent state (%"PRIuMAX
|
|
|
|
" vs %"PRIuMAX")",
|
|
|
|
(uintmax_t)list->items.nr, (uintmax_t)list->sorted.nr);
|
|
|
|
|
|
|
|
if (index < 0)
|
|
|
|
item = list->sorted.items[-1 - index].util;
|
|
|
|
else if (index > 0 &&
|
|
|
|
starts_with(list->sorted.items[index - 1].string, string))
|
|
|
|
return -1;
|
|
|
|
else if (index + 1 < list->sorted.nr &&
|
|
|
|
starts_with(list->sorted.items[index + 1].string, string))
|
|
|
|
return -1;
|
2020-11-11 07:42:11 +08:00
|
|
|
else if (index < list->sorted.nr &&
|
|
|
|
starts_with(list->sorted.items[index].string, string))
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
item = list->sorted.items[index].util;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
return item - list->items.items;
|
|
|
|
}
|
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
struct list_options {
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
int columns;
|
2019-11-13 20:40:59 +08:00
|
|
|
const char *header;
|
2019-11-30 05:11:43 +08:00
|
|
|
void (*print_item)(int i, int selected, struct string_list_item *item,
|
|
|
|
void *print_item_data);
|
2019-11-13 20:40:59 +08:00
|
|
|
void *print_item_data;
|
|
|
|
};
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
static void list(struct add_i_state *s, struct string_list *list, int *selected,
|
2019-11-13 20:41:00 +08:00
|
|
|
struct list_options *opts)
|
2019-11-13 20:40:59 +08:00
|
|
|
{
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
int i, last_lf = 0;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
if (!list->nr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (opts->header)
|
2019-11-13 20:41:00 +08:00
|
|
|
color_fprintf_ln(stdout, s->header_color,
|
|
|
|
"%s", opts->header);
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
for (i = 0; i < list->nr; i++) {
|
2019-11-30 05:11:43 +08:00
|
|
|
opts->print_item(i, selected ? selected[i] : 0, list->items + i,
|
|
|
|
opts->print_item_data);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
|
|
|
if ((opts->columns) && ((i + 1) % (opts->columns))) {
|
|
|
|
putchar('\t');
|
|
|
|
last_lf = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
putchar('\n');
|
|
|
|
last_lf = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!last_lf)
|
2019-11-13 20:40:59 +08:00
|
|
|
putchar('\n');
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
}
|
|
|
|
struct list_and_choose_options {
|
|
|
|
struct list_options list_opts;
|
|
|
|
|
|
|
|
const char *prompt;
|
2019-11-30 05:11:43 +08:00
|
|
|
enum {
|
|
|
|
SINGLETON = (1<<0),
|
|
|
|
IMMEDIATE = (1<<1),
|
|
|
|
} flags;
|
2019-11-15 19:11:18 +08:00
|
|
|
void (*print_help)(struct add_i_state *s);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define LIST_AND_CHOOSE_ERROR (-1)
|
|
|
|
#define LIST_AND_CHOOSE_QUIT (-2)
|
|
|
|
|
|
|
|
/*
|
2019-11-30 05:11:43 +08:00
|
|
|
* Returns the selected index in singleton mode, the number of selected items
|
|
|
|
* otherwise.
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
*
|
|
|
|
* If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
|
|
|
|
* `LIST_AND_CHOOSE_QUIT` is returned.
|
|
|
|
*/
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
static ssize_t list_and_choose(struct add_i_state *s,
|
|
|
|
struct prefix_item_list *items,
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
struct list_and_choose_options *opts)
|
|
|
|
{
|
2019-11-30 05:11:43 +08:00
|
|
|
int singleton = opts->flags & SINGLETON;
|
|
|
|
int immediate = opts->flags & IMMEDIATE;
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
struct strbuf input = STRBUF_INIT;
|
2019-11-30 05:11:43 +08:00
|
|
|
ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0;
|
|
|
|
|
|
|
|
if (!singleton) {
|
|
|
|
free(items->selected);
|
|
|
|
CALLOC_ARRAY(items->selected, items->items.nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (singleton && !immediate)
|
|
|
|
BUG("singleton requires immediate");
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
find_unique_prefixes(items);
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
for (;;) {
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
strbuf_reset(&input);
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
list(s, &items->items, items->selected, &opts->list_opts);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
2019-11-15 19:11:19 +08:00
|
|
|
color_fprintf(stdout, s->prompt_color, "%s", opts->prompt);
|
2019-11-30 05:11:43 +08:00
|
|
|
fputs(singleton ? "> " : ">> ", stdout);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
fflush(stdout);
|
|
|
|
|
2020-04-10 19:27:50 +08:00
|
|
|
if (git_read_line_interactively(&input) == EOF) {
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
putchar('\n');
|
2019-11-30 05:11:43 +08:00
|
|
|
if (immediate)
|
|
|
|
res = LIST_AND_CHOOSE_QUIT;
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!input.len)
|
|
|
|
break;
|
|
|
|
|
2019-11-15 19:11:18 +08:00
|
|
|
if (!strcmp(input.buf, "?")) {
|
|
|
|
opts->print_help(s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
p = input.buf;
|
|
|
|
for (;;) {
|
|
|
|
size_t sep = strcspn(p, " \t\r\n,");
|
2019-11-30 05:11:43 +08:00
|
|
|
int choose = 1;
|
|
|
|
/* `from` is inclusive, `to` is exclusive */
|
|
|
|
ssize_t from = -1, to = -1;
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
|
|
|
if (!sep) {
|
|
|
|
if (!*p)
|
|
|
|
break;
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
/* Input that begins with '-'; de-select */
|
|
|
|
if (*p == '-') {
|
|
|
|
choose = 0;
|
|
|
|
p++;
|
|
|
|
sep--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sep == 1 && *p == '*') {
|
|
|
|
from = 0;
|
|
|
|
to = items->items.nr;
|
|
|
|
} else if (isdigit(*p)) {
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
char *endp;
|
2019-11-30 05:11:43 +08:00
|
|
|
/*
|
|
|
|
* A range can be specified like 5-7 or 5-.
|
|
|
|
*
|
|
|
|
* Note: `from` is 0-based while the user input
|
|
|
|
* is 1-based, hence we have to decrement by
|
|
|
|
* one. We do not have to decrement `to` even
|
|
|
|
* if it is 0-based because it is an exclusive
|
|
|
|
* boundary.
|
|
|
|
*/
|
|
|
|
from = strtoul(p, &endp, 10) - 1;
|
|
|
|
if (endp == p + sep)
|
|
|
|
to = from + 1;
|
|
|
|
else if (*endp == '-') {
|
2020-01-16 16:33:07 +08:00
|
|
|
if (isdigit(*(++endp)))
|
|
|
|
to = strtoul(endp, &endp, 10);
|
|
|
|
else
|
|
|
|
to = items->items.nr;
|
2019-11-30 05:11:43 +08:00
|
|
|
/* extra characters after the range? */
|
|
|
|
if (endp != p + sep)
|
|
|
|
from = -1;
|
|
|
|
}
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p[sep])
|
|
|
|
p[sep++] = '\0';
|
2019-11-30 05:11:43 +08:00
|
|
|
if (from < 0) {
|
|
|
|
from = find_unique(p, items);
|
|
|
|
if (from >= 0)
|
|
|
|
to = from + 1;
|
|
|
|
}
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
if (from < 0 || from >= items->items.nr ||
|
|
|
|
(singleton && from + 1 != to)) {
|
2020-11-11 07:42:12 +08:00
|
|
|
color_fprintf_ln(stderr, s->error_color,
|
2019-11-15 19:11:19 +08:00
|
|
|
_("Huh (%s)?"), p);
|
2019-11-30 05:11:43 +08:00
|
|
|
break;
|
|
|
|
} else if (singleton) {
|
|
|
|
res = from;
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
if (to > items->items.nr)
|
|
|
|
to = items->items.nr;
|
|
|
|
|
|
|
|
for (; from < to; from++)
|
|
|
|
if (items->selected[from] != choose) {
|
|
|
|
items->selected[from] = choose;
|
|
|
|
res += choose ? +1 : -1;
|
|
|
|
}
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
p += sep;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
if ((immediate && res != LIST_AND_CHOOSE_ERROR) ||
|
|
|
|
!strcmp(input.buf, "*"))
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
break;
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
|
|
|
strbuf_release(&input);
|
|
|
|
return res;
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct adddel {
|
|
|
|
uintmax_t add, del;
|
2019-11-30 05:11:47 +08:00
|
|
|
unsigned seen:1, unmerged:1, binary:1;
|
2019-11-13 20:40:59 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct file_item {
|
2019-11-30 05:11:44 +08:00
|
|
|
size_t prefix_length;
|
2019-11-13 20:40:59 +08:00
|
|
|
struct adddel index, worktree;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void add_file_item(struct string_list *files, const char *name)
|
|
|
|
{
|
2021-03-06 19:26:19 +08:00
|
|
|
struct file_item *item = xcalloc(1, sizeof(*item));
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
string_list_append(files, name)->util = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct pathname_entry {
|
|
|
|
struct hashmap_entry ent;
|
|
|
|
const char *name;
|
|
|
|
struct file_item *item;
|
|
|
|
};
|
|
|
|
|
2022-08-19 18:08:46 +08:00
|
|
|
static int pathname_entry_cmp(const void *UNUSED(cmp_data),
|
2019-11-13 20:40:59 +08:00
|
|
|
const struct hashmap_entry *he1,
|
|
|
|
const struct hashmap_entry *he2,
|
|
|
|
const void *name)
|
|
|
|
{
|
|
|
|
const struct pathname_entry *e1 =
|
|
|
|
container_of(he1, const struct pathname_entry, ent);
|
|
|
|
const struct pathname_entry *e2 =
|
|
|
|
container_of(he2, const struct pathname_entry, ent);
|
|
|
|
|
|
|
|
return strcmp(e1->name, name ? (const char *)name : e2->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct collection_status {
|
2019-11-30 05:11:42 +08:00
|
|
|
enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } mode;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
const char *reference;
|
|
|
|
|
2019-11-30 05:11:42 +08:00
|
|
|
unsigned skip_unseen:1;
|
2019-11-30 05:11:47 +08:00
|
|
|
size_t unmerged_count, binary_count;
|
2019-11-13 20:40:59 +08:00
|
|
|
struct string_list *files;
|
|
|
|
struct hashmap file_map;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void collect_changes_cb(struct diff_queue_struct *q,
|
|
|
|
struct diff_options *options,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct collection_status *s = data;
|
|
|
|
struct diffstat_t stat = { 0 };
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!q->nr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
compute_diffstat(options, &stat, q);
|
|
|
|
|
|
|
|
for (i = 0; i < stat.nr; i++) {
|
|
|
|
const char *name = stat.files[i]->name;
|
|
|
|
int hash = strhash(name);
|
|
|
|
struct pathname_entry *entry;
|
|
|
|
struct file_item *file_item;
|
2019-11-30 05:11:47 +08:00
|
|
|
struct adddel *adddel, *other_adddel;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
|
|
|
|
struct pathname_entry, ent);
|
|
|
|
if (!entry) {
|
2019-11-30 05:11:42 +08:00
|
|
|
if (s->skip_unseen)
|
|
|
|
continue;
|
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
add_file_item(s->files, name);
|
|
|
|
|
2021-03-14 00:17:22 +08:00
|
|
|
CALLOC_ARRAY(entry, 1);
|
2019-11-13 20:40:59 +08:00
|
|
|
hashmap_entry_init(&entry->ent, hash);
|
|
|
|
entry->name = s->files->items[s->files->nr - 1].string;
|
|
|
|
entry->item = s->files->items[s->files->nr - 1].util;
|
|
|
|
hashmap_add(&s->file_map, &entry->ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
file_item = entry->item;
|
2019-11-30 05:11:42 +08:00
|
|
|
adddel = s->mode == FROM_INDEX ?
|
2019-11-13 20:40:59 +08:00
|
|
|
&file_item->index : &file_item->worktree;
|
2019-11-30 05:11:47 +08:00
|
|
|
other_adddel = s->mode == FROM_INDEX ?
|
|
|
|
&file_item->worktree : &file_item->index;
|
2019-11-13 20:40:59 +08:00
|
|
|
adddel->seen = 1;
|
|
|
|
adddel->add = stat.files[i]->added;
|
|
|
|
adddel->del = stat.files[i]->deleted;
|
2019-11-30 05:11:47 +08:00
|
|
|
if (stat.files[i]->is_binary) {
|
|
|
|
if (!other_adddel->binary)
|
|
|
|
s->binary_count++;
|
2019-11-13 20:40:59 +08:00
|
|
|
adddel->binary = 1;
|
2019-11-30 05:11:47 +08:00
|
|
|
}
|
|
|
|
if (stat.files[i]->is_unmerged) {
|
|
|
|
if (!other_adddel->unmerged)
|
|
|
|
s->unmerged_count++;
|
|
|
|
adddel->unmerged = 1;
|
|
|
|
}
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
|
|
|
free_diffstat_info(&stat);
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:42 +08:00
|
|
|
enum modified_files_filter {
|
|
|
|
NO_FILTER = 0,
|
|
|
|
WORKTREE_ONLY = 1,
|
|
|
|
INDEX_ONLY = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int get_modified_files(struct repository *r,
|
|
|
|
enum modified_files_filter filter,
|
2019-11-30 05:11:44 +08:00
|
|
|
struct prefix_item_list *files,
|
2019-11-30 05:11:47 +08:00
|
|
|
const struct pathspec *ps,
|
|
|
|
size_t *unmerged_count,
|
|
|
|
size_t *binary_count)
|
2019-11-13 20:40:59 +08:00
|
|
|
{
|
|
|
|
struct object_id head_oid;
|
|
|
|
int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
|
|
|
|
&head_oid, NULL);
|
2019-11-30 05:11:42 +08:00
|
|
|
struct collection_status s = { 0 };
|
|
|
|
int i;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
if (discard_index(r->index) < 0 ||
|
|
|
|
repo_read_index_preload(r, ps, 0) < 0)
|
|
|
|
return error(_("could not read index"));
|
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
prefix_item_list_clear(files);
|
|
|
|
s.files = &files->items;
|
2019-11-13 20:40:59 +08:00
|
|
|
hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
|
|
|
|
|
2019-11-30 05:11:42 +08:00
|
|
|
for (i = 0; i < 2; i++) {
|
2019-11-13 20:40:59 +08:00
|
|
|
struct rev_info rev;
|
|
|
|
struct setup_revision_opt opt = { 0 };
|
|
|
|
|
2019-11-30 05:11:42 +08:00
|
|
|
if (filter == INDEX_ONLY)
|
|
|
|
s.mode = (i == 0) ? FROM_INDEX : FROM_WORKTREE;
|
|
|
|
else
|
|
|
|
s.mode = (i == 0) ? FROM_WORKTREE : FROM_INDEX;
|
|
|
|
s.skip_unseen = filter && i;
|
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
opt.def = is_initial ?
|
|
|
|
empty_tree_oid_hex() : oid_to_hex(&head_oid);
|
|
|
|
|
|
|
|
init_revisions(&rev, NULL);
|
|
|
|
setup_revisions(0, NULL, &rev, &opt);
|
|
|
|
|
|
|
|
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
|
|
|
|
rev.diffopt.format_callback = collect_changes_cb;
|
|
|
|
rev.diffopt.format_callback_data = &s;
|
|
|
|
|
|
|
|
if (ps)
|
|
|
|
copy_pathspec(&rev.prune_data, ps);
|
|
|
|
|
2019-11-30 05:11:42 +08:00
|
|
|
if (s.mode == FROM_INDEX)
|
2019-11-13 20:40:59 +08:00
|
|
|
run_diff_index(&rev, 1);
|
|
|
|
else {
|
|
|
|
rev.diffopt.flags.ignore_dirty_submodules = 1;
|
|
|
|
run_diff_files(&rev, 0);
|
|
|
|
}
|
2019-11-30 05:11:41 +08:00
|
|
|
|
2022-04-14 04:01:36 +08:00
|
|
|
release_revisions(&rev);
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
2020-11-03 02:55:05 +08:00
|
|
|
hashmap_clear_and_free(&s.file_map, struct pathname_entry, ent);
|
2019-11-30 05:11:47 +08:00
|
|
|
if (unmerged_count)
|
|
|
|
*unmerged_count = s.unmerged_count;
|
|
|
|
if (binary_count)
|
|
|
|
*binary_count = s.binary_count;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
/* While the diffs are ordered already, we ran *two* diffs... */
|
2019-11-30 05:11:44 +08:00
|
|
|
string_list_sort(&files->items);
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void render_adddel(struct strbuf *buf,
|
|
|
|
struct adddel *ad, const char *no_changes)
|
|
|
|
{
|
|
|
|
if (ad->binary)
|
|
|
|
strbuf_addstr(buf, _("binary"));
|
|
|
|
else if (ad->seen)
|
|
|
|
strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX,
|
|
|
|
(uintmax_t)ad->add, (uintmax_t)ad->del);
|
|
|
|
else
|
|
|
|
strbuf_addstr(buf, no_changes);
|
|
|
|
}
|
|
|
|
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
/* filters out prefixes which have special meaning to list_and_choose() */
|
|
|
|
static int is_valid_prefix(const char *prefix, size_t prefix_len)
|
|
|
|
{
|
|
|
|
return prefix_len && prefix &&
|
|
|
|
/*
|
|
|
|
* We expect `prefix` to be NUL terminated, therefore this
|
|
|
|
* `strcspn()` call is okay, even if it might do much more
|
|
|
|
* work than strictly necessary.
|
|
|
|
*/
|
|
|
|
strcspn(prefix, " \t\r\n,") >= prefix_len && /* separators */
|
|
|
|
*prefix != '-' && /* deselection */
|
|
|
|
!isdigit(*prefix) && /* selection */
|
|
|
|
(prefix_len != 1 ||
|
|
|
|
(*prefix != '*' && /* "all" wildcard */
|
|
|
|
*prefix != '?')); /* prompt help */
|
|
|
|
}
|
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
struct print_file_item_data {
|
2019-11-30 05:11:44 +08:00
|
|
|
const char *modified_fmt, *color, *reset;
|
|
|
|
struct strbuf buf, name, index, worktree;
|
2019-11-30 05:11:46 +08:00
|
|
|
unsigned only_names:1;
|
2019-11-13 20:40:59 +08:00
|
|
|
};
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
static void print_file_item(int i, int selected, struct string_list_item *item,
|
2019-11-13 20:40:59 +08:00
|
|
|
void *print_file_item_data)
|
|
|
|
{
|
|
|
|
struct file_item *c = item->util;
|
|
|
|
struct print_file_item_data *d = print_file_item_data;
|
2019-11-30 05:11:44 +08:00
|
|
|
const char *highlighted = NULL;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
strbuf_reset(&d->index);
|
|
|
|
strbuf_reset(&d->worktree);
|
|
|
|
strbuf_reset(&d->buf);
|
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:46 +08:00
|
|
|
if (d->only_names) {
|
|
|
|
printf("%c%2d: %s", selected ? '*' : ' ', i + 1,
|
|
|
|
highlighted ? highlighted : item->string);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
render_adddel(&d->worktree, &c->worktree, _("nothing"));
|
|
|
|
render_adddel(&d->index, &c->index, _("unchanged"));
|
2019-11-30 05:11:44 +08:00
|
|
|
|
|
|
|
strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf,
|
|
|
|
highlighted ? highlighted : item->string);
|
2019-11-13 20:40:59 +08:00
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf);
|
2019-11-13 20:40:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int run_status(struct add_i_state *s, const struct pathspec *ps,
|
2019-11-30 05:11:44 +08:00
|
|
|
struct prefix_item_list *files,
|
|
|
|
struct list_and_choose_options *opts)
|
2019-11-13 20:40:59 +08:00
|
|
|
{
|
2019-11-30 05:11:47 +08:00
|
|
|
if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0)
|
2019-11-13 20:40:59 +08:00
|
|
|
return -1;
|
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
list(s, &files->items, NULL, &opts->list_opts);
|
2019-11-13 20:40:59 +08:00
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-13 20:40:57 +08:00
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
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;
|
|
|
|
|
2019-11-30 05:11:47 +08:00
|
|
|
if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0)
|
2019-11-30 05:11:44 +08:00
|
|
|
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;
|
2022-06-29 06:22:44 +08:00
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!files->selected[i])
|
|
|
|
continue;
|
|
|
|
if (lstat(name, &st) && is_missing_file_error(errno)) {
|
|
|
|
if (remove_file_from_index(s->r->index, name) < 0) {
|
|
|
|
res = error(_("could not stage '%s'"), name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (add_file_to_index(s->r->index, name, 0) < 0) {
|
2019-11-30 05:11:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:45 +08:00
|
|
|
static void revert_from_diff(struct diff_queue_struct *q,
|
|
|
|
struct diff_options *opt, void *data)
|
|
|
|
{
|
|
|
|
int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
|
|
|
|
|
|
|
|
for (i = 0; i < q->nr; i++) {
|
|
|
|
struct diff_filespec *one = q->queue[i]->one;
|
|
|
|
struct cache_entry *ce;
|
|
|
|
|
|
|
|
if (!(one->mode && !is_null_oid(&one->oid))) {
|
|
|
|
remove_file_from_index(opt->repo->index, one->path);
|
|
|
|
printf(_("note: %s is untracked now.\n"), one->path);
|
|
|
|
} else {
|
|
|
|
ce = make_cache_entry(opt->repo->index, one->mode,
|
|
|
|
&one->oid, one->path, 0, 0);
|
|
|
|
if (!ce)
|
|
|
|
die(_("make_cache_entry failed for path '%s'"),
|
|
|
|
one->path);
|
|
|
|
add_index_entry(opt->repo->index, ce, add_flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int run_revert(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, j;
|
|
|
|
|
|
|
|
struct object_id oid;
|
|
|
|
int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
|
|
|
|
NULL);
|
|
|
|
struct lock_file index_lock;
|
|
|
|
const char **paths;
|
|
|
|
struct tree *tree;
|
|
|
|
struct diff_options diffopt = { NULL };
|
|
|
|
|
2019-11-30 05:11:47 +08:00
|
|
|
if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
|
2019-11-30 05:11:45 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!files->items.nr) {
|
|
|
|
putchar('\n');
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts->prompt = N_("Revert");
|
|
|
|
count = list_and_choose(s, files, opts);
|
|
|
|
if (count <= 0)
|
|
|
|
goto finish_revert;
|
|
|
|
|
|
|
|
fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
|
|
|
|
if (fd < 0) {
|
|
|
|
res = -1;
|
|
|
|
goto finish_revert;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_initial)
|
|
|
|
oidcpy(&oid, s->r->hash_algo->empty_tree);
|
|
|
|
else {
|
|
|
|
tree = parse_tree_indirect(&oid);
|
|
|
|
if (!tree) {
|
|
|
|
res = error(_("Could not parse HEAD^{tree}"));
|
|
|
|
goto finish_revert;
|
|
|
|
}
|
|
|
|
oidcpy(&oid, &tree->object.oid);
|
|
|
|
}
|
|
|
|
|
|
|
|
ALLOC_ARRAY(paths, count + 1);
|
|
|
|
for (i = j = 0; i < files->items.nr; i++)
|
|
|
|
if (files->selected[i])
|
|
|
|
paths[j++] = files->items.items[i].string;
|
|
|
|
paths[j] = NULL;
|
|
|
|
|
|
|
|
parse_pathspec(&diffopt.pathspec, 0,
|
|
|
|
PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH,
|
|
|
|
NULL, paths);
|
|
|
|
|
|
|
|
diffopt.output_format = DIFF_FORMAT_CALLBACK;
|
|
|
|
diffopt.format_callback = revert_from_diff;
|
|
|
|
diffopt.flags.override_submodule_config = 1;
|
|
|
|
diffopt.repo = s->r;
|
|
|
|
|
2022-02-16 18:56:28 +08:00
|
|
|
if (do_diff_cache(&oid, &diffopt)) {
|
|
|
|
diff_free(&diffopt);
|
2019-11-30 05:11:45 +08:00
|
|
|
res = -1;
|
2022-02-16 18:56:28 +08:00
|
|
|
} else {
|
2019-11-30 05:11:45 +08:00
|
|
|
diffcore_std(&diffopt);
|
|
|
|
diff_flush(&diffopt);
|
|
|
|
}
|
|
|
|
free(paths);
|
|
|
|
|
|
|
|
if (!res && write_locked_index(s->r->index, &index_lock,
|
|
|
|
COMMIT_LOCK) < 0)
|
|
|
|
res = -1;
|
|
|
|
else
|
|
|
|
res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (!res)
|
|
|
|
printf(Q_("reverted %d path\n",
|
|
|
|
"reverted %d paths\n", count), (int)count);
|
|
|
|
|
|
|
|
finish_revert:
|
|
|
|
putchar('\n');
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:46 +08:00
|
|
|
static int get_untracked_files(struct repository *r,
|
|
|
|
struct prefix_item_list *files,
|
|
|
|
const struct pathspec *ps)
|
|
|
|
{
|
|
|
|
struct dir_struct dir = { 0 };
|
|
|
|
size_t i;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (repo_read_index(r) < 0)
|
|
|
|
return error(_("could not read index"));
|
|
|
|
|
|
|
|
prefix_item_list_clear(files);
|
|
|
|
setup_standard_excludes(&dir);
|
|
|
|
add_pattern_list(&dir, EXC_CMDL, "--exclude option");
|
|
|
|
fill_directory(&dir, r->index, ps);
|
|
|
|
|
|
|
|
for (i = 0; i < dir.nr; i++) {
|
|
|
|
struct dir_entry *ent = dir.entries[i];
|
|
|
|
|
|
|
|
if (index_name_is_other(r->index, ent->name, ent->len)) {
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_add(&buf, ent->name, ent->len);
|
|
|
|
add_file_item(&files->items, buf.buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_release(&buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps,
|
|
|
|
struct prefix_item_list *files,
|
|
|
|
struct list_and_choose_options *opts)
|
|
|
|
{
|
|
|
|
struct print_file_item_data *d = opts->list_opts.print_item_data;
|
|
|
|
int res = 0, fd;
|
|
|
|
size_t count, i;
|
|
|
|
struct lock_file index_lock;
|
|
|
|
|
|
|
|
if (get_untracked_files(s->r, files, ps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!files->items.nr) {
|
|
|
|
printf(_("No untracked files.\n"));
|
|
|
|
goto finish_add_untracked;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts->prompt = N_("Add untracked");
|
|
|
|
d->only_names = 1;
|
|
|
|
count = list_and_choose(s, files, opts);
|
|
|
|
d->only_names = 0;
|
|
|
|
if (count <= 0)
|
|
|
|
goto finish_add_untracked;
|
|
|
|
|
|
|
|
fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
|
|
|
|
if (fd < 0) {
|
|
|
|
res = -1;
|
|
|
|
goto finish_add_untracked;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_("added %d path\n",
|
|
|
|
"added %d paths\n", count), (int)count);
|
|
|
|
|
|
|
|
finish_add_untracked:
|
|
|
|
putchar('\n');
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:47 +08:00
|
|
|
static int run_patch(struct add_i_state *s, const struct pathspec *ps,
|
|
|
|
struct prefix_item_list *files,
|
|
|
|
struct list_and_choose_options *opts)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
ssize_t count, i, j;
|
|
|
|
size_t unmerged_count = 0, binary_count = 0;
|
|
|
|
|
|
|
|
if (get_modified_files(s->r, WORKTREE_ONLY, files, ps,
|
|
|
|
&unmerged_count, &binary_count) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (unmerged_count || binary_count) {
|
|
|
|
for (i = j = 0; i < files->items.nr; i++) {
|
|
|
|
struct file_item *item = files->items.items[i].util;
|
|
|
|
|
|
|
|
if (item->index.binary || item->worktree.binary) {
|
|
|
|
free(item);
|
|
|
|
free(files->items.items[i].string);
|
|
|
|
} else if (item->index.unmerged ||
|
|
|
|
item->worktree.unmerged) {
|
|
|
|
color_fprintf_ln(stderr, s->error_color,
|
|
|
|
_("ignoring unmerged: %s"),
|
|
|
|
files->items.items[i].string);
|
|
|
|
free(item);
|
|
|
|
free(files->items.items[i].string);
|
|
|
|
} else
|
|
|
|
files->items.items[j++] = files->items.items[i];
|
|
|
|
}
|
|
|
|
files->items.nr = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!files->items.nr) {
|
|
|
|
if (binary_count)
|
|
|
|
fprintf(stderr, _("Only binary files changed.\n"));
|
|
|
|
else
|
|
|
|
fprintf(stderr, _("No changes.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts->prompt = N_("Patch update");
|
|
|
|
count = list_and_choose(s, files, opts);
|
2020-01-16 16:33:06 +08:00
|
|
|
if (count > 0) {
|
2020-07-29 04:24:53 +08:00
|
|
|
struct strvec args = STRVEC_INIT;
|
built-in add -i: wire up the new C code for the `patch` command
The code in `git-add--interactive.perl` that takes care of the `patch`
command can look quite intimidating. There are so many modes in which it
can be called, for example.
But for the `patch` command in `git add -i`, only one mode is relevant:
the `stage` mode. And we just implemented the beginnings of that mode in
C so far. So let's use it when `add.interactive.useBuiltin=true`.
Now, while the code in `add-patch.c` is far from reaching feature parity
with the code in `git-add--interactive.perl` (color is not implemented,
the diff algorithm cannot be configured, the colored diff cannot be
post-processed via `interactive.diffFilter`, many commands are
unimplemented yet, etc), hooking it all up with the part of `git add -i`
that is already converted to C makes it easier to test and develop it.
Note: at this stage, both the `add.interactive.useBuiltin` config
setting is still safely opt-in, and will probably be fore quite some
time, to allow for thorough testing "in the wild" without adversely
affecting existing users.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-13 16:07:49 +08:00
|
|
|
struct pathspec ps_selected = { 0 };
|
2019-11-30 05:11:47 +08:00
|
|
|
|
|
|
|
for (i = 0; i < files->items.nr; i++)
|
|
|
|
if (files->selected[i])
|
2020-07-29 04:24:53 +08:00
|
|
|
strvec_push(&args,
|
strvec: fix indentation in renamed calls
Code which split an argv_array call across multiple lines, like:
argv_array_pushl(&args, "one argument",
"another argument", "and more",
NULL);
was recently mechanically renamed to use strvec, which results in
mis-matched indentation like:
strvec_pushl(&args, "one argument",
"another argument", "and more",
NULL);
Let's fix these up to align the arguments with the opening paren. I did
this manually by sifting through the results of:
git jump grep 'strvec_.*,$'
and liberally applying my editor's auto-format. Most of the changes are
of the form shown above, though I also normalized a few that had
originally used a single-tab indentation (rather than our usual style of
aligning with the open paren). I also rewrapped a couple of obvious
cases (e.g., where previously too-long lines became short enough to fit
on one), but I wasn't aggressive about it. In cases broken to three or
more lines, the grouping of arguments is sometimes meaningful, and it
wasn't worth my time or reviewer time to ponder each case individually.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-29 04:26:31 +08:00
|
|
|
files->items.items[i].string);
|
built-in add -i: wire up the new C code for the `patch` command
The code in `git-add--interactive.perl` that takes care of the `patch`
command can look quite intimidating. There are so many modes in which it
can be called, for example.
But for the `patch` command in `git add -i`, only one mode is relevant:
the `stage` mode. And we just implemented the beginnings of that mode in
C so far. So let's use it when `add.interactive.useBuiltin=true`.
Now, while the code in `add-patch.c` is far from reaching feature parity
with the code in `git-add--interactive.perl` (color is not implemented,
the diff algorithm cannot be configured, the colored diff cannot be
post-processed via `interactive.diffFilter`, many commands are
unimplemented yet, etc), hooking it all up with the part of `git add -i`
that is already converted to C makes it easier to test and develop it.
Note: at this stage, both the `add.interactive.useBuiltin` config
setting is still safely opt-in, and will probably be fore quite some
time, to allow for thorough testing "in the wild" without adversely
affecting existing users.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-13 16:07:49 +08:00
|
|
|
parse_pathspec(&ps_selected,
|
|
|
|
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
|
2020-07-29 08:37:20 +08:00
|
|
|
PATHSPEC_LITERAL_PATH, "", args.v);
|
2019-12-22 05:57:10 +08:00
|
|
|
res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
|
2020-07-29 04:24:53 +08:00
|
|
|
strvec_clear(&args);
|
built-in add -i: wire up the new C code for the `patch` command
The code in `git-add--interactive.perl` that takes care of the `patch`
command can look quite intimidating. There are so many modes in which it
can be called, for example.
But for the `patch` command in `git add -i`, only one mode is relevant:
the `stage` mode. And we just implemented the beginnings of that mode in
C so far. So let's use it when `add.interactive.useBuiltin=true`.
Now, while the code in `add-patch.c` is far from reaching feature parity
with the code in `git-add--interactive.perl` (color is not implemented,
the diff algorithm cannot be configured, the colored diff cannot be
post-processed via `interactive.diffFilter`, many commands are
unimplemented yet, etc), hooking it all up with the part of `git add -i`
that is already converted to C makes it easier to test and develop it.
Note: at this stage, both the `add.interactive.useBuiltin` config
setting is still safely opt-in, and will probably be fore quite some
time, to allow for thorough testing "in the wild" without adversely
affecting existing users.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-13 16:07:49 +08:00
|
|
|
clear_pathspec(&ps_selected);
|
2019-11-30 05:11:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:48 +08:00
|
|
|
static int run_diff(struct add_i_state *s, const struct pathspec *ps,
|
|
|
|
struct prefix_item_list *files,
|
|
|
|
struct list_and_choose_options *opts)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
ssize_t count, i;
|
|
|
|
|
|
|
|
struct object_id oid;
|
|
|
|
int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
|
|
|
|
NULL);
|
|
|
|
if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!files->items.nr) {
|
|
|
|
putchar('\n');
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts->prompt = N_("Review diff");
|
|
|
|
opts->flags = IMMEDIATE;
|
|
|
|
count = list_and_choose(s, files, opts);
|
|
|
|
opts->flags = 0;
|
2020-01-16 16:33:06 +08:00
|
|
|
if (count > 0) {
|
2020-07-29 04:24:53 +08:00
|
|
|
struct strvec args = STRVEC_INIT;
|
2019-11-30 05:11:48 +08:00
|
|
|
|
2020-07-29 04:24:53 +08:00
|
|
|
strvec_pushl(&args, "git", "diff", "-p", "--cached",
|
strvec: fix indentation in renamed calls
Code which split an argv_array call across multiple lines, like:
argv_array_pushl(&args, "one argument",
"another argument", "and more",
NULL);
was recently mechanically renamed to use strvec, which results in
mis-matched indentation like:
strvec_pushl(&args, "one argument",
"another argument", "and more",
NULL);
Let's fix these up to align the arguments with the opening paren. I did
this manually by sifting through the results of:
git jump grep 'strvec_.*,$'
and liberally applying my editor's auto-format. Most of the changes are
of the form shown above, though I also normalized a few that had
originally used a single-tab indentation (rather than our usual style of
aligning with the open paren). I also rewrapped a couple of obvious
cases (e.g., where previously too-long lines became short enough to fit
on one), but I wasn't aggressive about it. In cases broken to three or
more lines, the grouping of arguments is sometimes meaningful, and it
wasn't worth my time or reviewer time to ponder each case individually.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-29 04:26:31 +08:00
|
|
|
oid_to_hex(!is_initial ? &oid :
|
|
|
|
s->r->hash_algo->empty_tree),
|
|
|
|
"--", NULL);
|
2019-11-30 05:11:48 +08:00
|
|
|
for (i = 0; i < files->items.nr; i++)
|
|
|
|
if (files->selected[i])
|
2020-07-29 04:24:53 +08:00
|
|
|
strvec_push(&args,
|
strvec: fix indentation in renamed calls
Code which split an argv_array call across multiple lines, like:
argv_array_pushl(&args, "one argument",
"another argument", "and more",
NULL);
was recently mechanically renamed to use strvec, which results in
mis-matched indentation like:
strvec_pushl(&args, "one argument",
"another argument", "and more",
NULL);
Let's fix these up to align the arguments with the opening paren. I did
this manually by sifting through the results of:
git jump grep 'strvec_.*,$'
and liberally applying my editor's auto-format. Most of the changes are
of the form shown above, though I also normalized a few that had
originally used a single-tab indentation (rather than our usual style of
aligning with the open paren). I also rewrapped a couple of obvious
cases (e.g., where previously too-long lines became short enough to fit
on one), but I wasn't aggressive about it. In cases broken to three or
more lines, the grouping of arguments is sometimes meaningful, and it
wasn't worth my time or reviewer time to ponder each case individually.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-07-29 04:26:31 +08:00
|
|
|
files->items.items[i].string);
|
2020-07-29 08:37:20 +08:00
|
|
|
res = run_command_v_opt(args.v, 0);
|
2020-07-29 04:24:53 +08:00
|
|
|
strvec_clear(&args);
|
2019-11-30 05:11:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-11-15 19:11:20 +08:00
|
|
|
static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
|
2019-11-30 05:11:44 +08:00
|
|
|
struct prefix_item_list *unused_files,
|
|
|
|
struct list_and_choose_options *unused_opts)
|
2019-11-15 19:11:20 +08:00
|
|
|
{
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "status - %s",
|
|
|
|
_("show paths with changes"));
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "update - %s",
|
|
|
|
_("add working tree state to the staged set of changes"));
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "revert - %s",
|
|
|
|
_("revert staged set of changes back to the HEAD version"));
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "patch - %s",
|
|
|
|
_("pick hunks and update selectively"));
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "diff - %s",
|
|
|
|
_("view diff between HEAD and index"));
|
|
|
|
color_fprintf_ln(stdout, s->help_color, "add untracked - %s",
|
|
|
|
_("add contents of untracked files to the staged set of changes"));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
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"));
|
|
|
|
}
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
|
2019-11-30 05:11:44 +08:00
|
|
|
struct prefix_item_list *files,
|
|
|
|
struct list_and_choose_options *opts);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
struct command_item {
|
|
|
|
size_t prefix_length;
|
|
|
|
command_t command;
|
|
|
|
};
|
|
|
|
|
2019-11-15 19:11:19 +08:00
|
|
|
struct print_command_item_data {
|
|
|
|
const char *color, *reset;
|
|
|
|
};
|
|
|
|
|
2019-11-30 05:11:43 +08:00
|
|
|
static void print_command_item(int i, int selected,
|
|
|
|
struct string_list_item *item,
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
void *print_command_item_data)
|
|
|
|
{
|
2019-11-15 19:11:19 +08:00
|
|
|
struct print_command_item_data *d = print_command_item_data;
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
struct command_item *util = item->util;
|
|
|
|
|
|
|
|
if (!util->prefix_length ||
|
|
|
|
!is_valid_prefix(item->string, util->prefix_length))
|
|
|
|
printf(" %2d: %s", i + 1, item->string);
|
|
|
|
else
|
2019-11-15 19:11:19 +08:00
|
|
|
printf(" %2d: %s%.*s%s%s", i + 1,
|
|
|
|
d->color, (int)util->prefix_length, item->string,
|
|
|
|
d->reset, item->string + util->prefix_length);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
}
|
|
|
|
|
2019-11-15 19:11:18 +08:00
|
|
|
static void command_prompt_help(struct add_i_state *s)
|
|
|
|
{
|
|
|
|
const char *help_color = s->help_color;
|
|
|
|
color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:"));
|
|
|
|
color_fprintf_ln(stdout, help_color, "1 - %s",
|
|
|
|
_("select a numbered item"));
|
|
|
|
color_fprintf_ln(stdout, help_color, "foo - %s",
|
|
|
|
_("select item based on unique prefix"));
|
|
|
|
color_fprintf_ln(stdout, help_color, " - %s",
|
|
|
|
_("(empty) select nothing"));
|
|
|
|
}
|
|
|
|
|
2019-11-13 20:40:57 +08:00
|
|
|
int run_add_i(struct repository *r, const struct pathspec *ps)
|
|
|
|
{
|
2019-11-13 20:40:59 +08:00
|
|
|
struct add_i_state s = { NULL };
|
2019-11-15 19:11:19 +08:00
|
|
|
struct print_command_item_data data = { "[", "]" };
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
struct list_and_choose_options main_loop_opts = {
|
2019-11-15 19:11:19 +08:00
|
|
|
{ 4, N_("*** Commands ***"), print_command_item, &data },
|
2019-11-30 05:11:43 +08:00
|
|
|
N_("What now"), SINGLETON | IMMEDIATE, command_prompt_help
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
};
|
|
|
|
struct {
|
|
|
|
const char *string;
|
|
|
|
command_t command;
|
|
|
|
} command_list[] = {
|
|
|
|
{ "status", run_status },
|
2019-11-30 05:11:44 +08:00
|
|
|
{ "update", run_update },
|
2019-11-30 05:11:45 +08:00
|
|
|
{ "revert", run_revert },
|
2019-11-30 05:11:46 +08:00
|
|
|
{ "add untracked", run_add_untracked },
|
2019-11-30 05:11:47 +08:00
|
|
|
{ "patch", run_patch },
|
2019-11-30 05:11:48 +08:00
|
|
|
{ "diff", run_diff },
|
2019-11-30 05:11:49 +08:00
|
|
|
{ "quit", NULL },
|
2019-11-15 19:11:20 +08:00
|
|
|
{ "help", run_help },
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
};
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
struct print_file_item_data print_file_item_data = {
|
2019-11-30 05:11:44 +08:00
|
|
|
"%12s %12s %s", NULL, NULL,
|
|
|
|
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
|
2019-11-13 20:40:59 +08:00
|
|
|
};
|
2019-11-30 05:11:44 +08:00
|
|
|
struct list_and_choose_options opts = {
|
|
|
|
{ 0, NULL, print_file_item, &print_file_item_data },
|
|
|
|
NULL, 0, choose_prompt_help
|
2019-11-13 20:40:59 +08:00
|
|
|
};
|
|
|
|
struct strbuf header = STRBUF_INIT;
|
2019-11-30 05:11:44 +08:00
|
|
|
struct prefix_item_list files = PREFIX_ITEM_LIST_INIT;
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
ssize_t i;
|
2019-11-13 20:40:59 +08:00
|
|
|
int res = 0;
|
|
|
|
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(command_list); i++) {
|
2021-03-06 19:26:19 +08:00
|
|
|
struct command_item *util = xcalloc(1, sizeof(*util));
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
util->command = command_list[i].command;
|
|
|
|
string_list_append(&commands.items, command_list[i].string)
|
|
|
|
->util = util;
|
|
|
|
}
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
2019-11-13 20:40:59 +08:00
|
|
|
init_add_i_state(&s, r);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
|
2019-11-15 19:11:19 +08:00
|
|
|
/*
|
|
|
|
* When color was asked for, use the prompt color for
|
|
|
|
* highlighting, otherwise use square brackets.
|
|
|
|
*/
|
|
|
|
if (s.use_color) {
|
|
|
|
data.color = s.prompt_color;
|
|
|
|
data.reset = s.reset_color;
|
|
|
|
}
|
2019-11-30 05:11:44 +08:00
|
|
|
print_file_item_data.color = data.color;
|
|
|
|
print_file_item_data.reset = data.reset;
|
2019-11-15 19:11:19 +08:00
|
|
|
|
2020-11-17 00:08:29 +08:00
|
|
|
strbuf_addstr(&header, " ");
|
2019-11-13 20:40:59 +08:00
|
|
|
strbuf_addf(&header, print_file_item_data.modified_fmt,
|
|
|
|
_("staged"), _("unstaged"), _("path"));
|
2019-11-30 05:11:44 +08:00
|
|
|
opts.list_opts.header = header.buf;
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
if (discard_index(r->index) < 0 ||
|
|
|
|
repo_read_index(r) < 0 ||
|
|
|
|
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
|
|
|
|
NULL, NULL, NULL) < 0)
|
|
|
|
warning(_("could not refresh index"));
|
|
|
|
|
|
|
|
res = run_status(&s, ps, &files, &opts);
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
for (;;) {
|
2019-11-30 05:11:49 +08:00
|
|
|
struct command_item *util;
|
|
|
|
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
i = list_and_choose(&s, &commands, &main_loop_opts);
|
2019-11-30 05:11:49 +08:00
|
|
|
if (i < 0 || i >= commands.items.nr)
|
|
|
|
util = NULL;
|
|
|
|
else
|
|
|
|
util = commands.items.items[i].util;
|
|
|
|
|
|
|
|
if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) {
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
printf(_("Bye.\n"));
|
|
|
|
res = 0;
|
|
|
|
break;
|
|
|
|
}
|
2019-11-30 05:11:49 +08:00
|
|
|
|
|
|
|
if (util)
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
res = util->command(&s, ps, &files, &opts);
|
built-in add -i: implement the main loop
The reason why we did not start with the main loop to begin with is that
it is the first user of `list_and_choose()`, which uses the `list()`
function that we conveniently introduced for use by the `status`
command.
In contrast to the Perl version, in the built-in interactive `add`, we
will keep the `list()` function (which only displays items) and the
`list_and_choose()` function (which uses `list()` to display the items,
and only takes care of the "and choose" part) separate.
The `list_and_choose()` function, as implemented in
`git-add--interactive.perl` knows a few more tricks than the function we
introduce in this patch:
- There is a flag to let the user select multiple items.
- In multi-select mode, the list of items is prefixed with a marker
indicating what items have been selected.
- Initially, for each item 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 selection.
These features will be implemented in the C version later.
This patch does not add any new main loop command, of course, the
built-in `git add -i` still only supports the `status` command. The
remaining commands to follow over the course of the next commits.
To accommodate for listing the commands in columns, preparing for the
commands that will be implemented over the course of the next
patches/patch series, we teach the `list()` function to do precisely
that.
Note that we only have a prompt ending in a single ">" at this stage;
later commits will add commands that display a double ">>" to indicate
that the user is in a different loop than the main one.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:16 +08:00
|
|
|
}
|
|
|
|
|
2019-11-30 05:11:44 +08:00
|
|
|
prefix_item_list_clear(&files);
|
2019-11-13 20:40:59 +08:00
|
|
|
strbuf_release(&print_file_item_data.buf);
|
2019-11-30 05:11:44 +08:00
|
|
|
strbuf_release(&print_file_item_data.name);
|
2019-11-13 20:40:59 +08:00
|
|
|
strbuf_release(&print_file_item_data.index);
|
|
|
|
strbuf_release(&print_file_item_data.worktree);
|
|
|
|
strbuf_release(&header);
|
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.
To determine the unique prefixes, as well as to look up the command in
question, we use a copy of the list and sort it.
While this might seem like overkill for a single command, it will make
much more sense when all the commands are implemented, and when we reuse
the same logic to present a list of files to edit, with convenient
unique prefixes.
At the start of the development of this patch series, a dedicated data
structure was introduced that imitated the Trie that the Perl version
implements. However, this was deemed overkill, and we now simply sort
the list before determining the length of the unique prefixes by looking
at each item's neighbor. As a bonus, we now use the same sorted list to
perform a binary search using the user-provided prefix as search key.
Original-patch-by: Slavica Đukić <slawica92@hotmail.com>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-11-15 19:11:17 +08:00
|
|
|
prefix_item_list_clear(&commands);
|
2020-01-15 02:43:45 +08:00
|
|
|
clear_add_i_state(&s);
|
2019-11-13 20:40:59 +08:00
|
|
|
|
|
|
|
return res;
|
2019-11-13 20:40:57 +08:00
|
|
|
}
|