#include "cache.h"
#include "add-interactive.h"
#include "color.h"
#include "config.h"
#include "diffcore.h"
#include "revision.h"
#include "refs.h"
#include "string-list.h"
#include "lockfile.h"
#include "dir.h"
#include "run-command.h"
#include "prompt.h"
static void init_color(struct repository *r, struct add_i_state *s,
const char *section_and_slot, char *dst,
const char *default_color)
{
char *key = xstrfmt("color.%s", section_and_slot);
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);
}
void init_add_i_state(struct add_i_state *s, struct repository *r)
{
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);
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,
diff_get_color(s->use_color, DIFF_FRAGINFO));
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));
init_color(r, s, "diff.old", s->file_old_color,
diff_get_color(s->use_color, DIFF_FILE_OLD));
init_color(r, s, "diff.new", s->file_new_color,
diff_get_color(s->use_color, DIFF_FILE_NEW));
strlcpy(s->reset_color,
s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
FREE_AND_NULL(s->interactive_diff_filter);
git_config_get_string("interactive.difffilter",
&s->interactive_diff_filter);
FREE_AND_NULL(s->interactive_diff_algorithm);
git_config_get_string("diff.algorithm",
&s->interactive_diff_algorithm);
git_config_get_bool("interactive.singlekey", &s->use_single_key);
}
void clear_add_i_state(struct add_i_state *s)
{
FREE_AND_NULL(s->interactive_diff_filter);
FREE_AND_NULL(s->interactive_diff_algorithm);
memset(s, 0, sizeof(*s));
s->use_color = -1;
}
/*
* 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;
int *selected; /* for multi-selections */
size_t min_length, max_length;
};
#define PREFIX_ITEM_LIST_INIT { \
.items = STRING_LIST_INIT_DUP, \
.sorted = STRING_LIST_INIT_NODUP, \
.min_length = 1, \
.max_length = 4, \
}
static void prefix_item_list_clear(struct prefix_item_list *list)
{
string_list_clear(&list->items, 1);
string_list_clear(&list->sorted, 0);
FREE_AND_NULL(list->selected);
}
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(
|