#include "commit-slab.h"
#include "commit-graph.h"
#include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
static struct ref_msg {
const char *gone;
struct object_info info;
} oi, oi_deref;
+struct ref_to_worktree_entry {
+ struct hashmap_entry ent; /* must be the first member! */
+ struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+ const void *existing_hashmap_entry_to_test,
+ const void *key,
+ const void *keydata_aka_refname)
+{
+ const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+ const struct ref_to_worktree_entry *k = key;
+ return strcmp(e->wt->head_ref,
+ keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+ struct hashmap map;
+ struct worktree **worktrees;
+} ref_to_worktree_map;
+
/*
* An atom is a valid field atom listed below, possibly prefixed with
* a "*" to denote deref_tag().
{ "flag", SOURCE_NONE },
{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+ { "worktreepath", SOURCE_NONE },
{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
{ "end", SOURCE_NONE },
{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
{ "then", SOURCE_NONE },
{ "else", SOURCE_NONE },
+ /*
+ * Please update $__git_ref_fieldlist in git-completion.bash
+ * when you add new atoms
+ */
};
#define REF_FORMATTING_STATE_INIT { 0, NULL }
}
/* See grab_values */
-static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
{
int i;
struct tag *tag = (struct tag *) obj;
}
/* See grab_values */
-static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
{
int i;
struct commit *commit = (struct commit *) obj;
}
}
-static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
+static const char *find_wholine(const char *who, int wholen, const char *buf)
{
const char *eol;
while (*buf) {
}
/* See grab_values */
-static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
{
int i;
int wholen = strlen(who);
!starts_with(name + wholen, "date"))
continue;
if (!wholine)
- wholine = find_wholine(who, wholen, buf, sz);
+ wholine = find_wholine(who, wholen, buf);
if (!wholine)
return; /* no point looking for it */
if (name[wholen] == 0)
if (strcmp(who, "tagger") && strcmp(who, "committer"))
return; /* "author" for commit object is not wanted */
if (!wholine)
- wholine = find_wholine(who, wholen, buf, sz);
+ wholine = find_wholine(who, wholen, buf);
if (!wholine)
return;
for (i = 0; i < used_atom_cnt; i++) {
}
}
-static void find_subpos(const char *buf, unsigned long sz,
+static void find_subpos(const char *buf,
const char **sub, unsigned long *sublen,
const char **body, unsigned long *bodylen,
unsigned long *nonsiglen,
}
/* See grab_values */
-static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
{
int i;
const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
!starts_with(name, "contents"))
continue;
if (!subpos)
- find_subpos(buf, sz,
+ find_subpos(buf,
&subpos, &sublen,
&bodypos, &bodylen, &nonsiglen,
&sigpos, &siglen);
* pointed at by the ref itself; otherwise it is the object the
* ref (which is a tag) refers to.
*/
-static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf)
{
switch (obj->type) {
case OBJ_TAG:
- grab_tag_values(val, deref, obj, buf, sz);
- grab_sub_body_contents(val, deref, obj, buf, sz);
- grab_person("tagger", val, deref, obj, buf, sz);
+ grab_tag_values(val, deref, obj);
+ grab_sub_body_contents(val, deref, buf);
+ grab_person("tagger", val, deref, buf);
break;
case OBJ_COMMIT:
- grab_commit_values(val, deref, obj, buf, sz);
- grab_sub_body_contents(val, deref, obj, buf, sz);
- grab_person("author", val, deref, obj, buf, sz);
- grab_person("committer", val, deref, obj, buf, sz);
+ grab_commit_values(val, deref, obj);
+ grab_sub_body_contents(val, deref, buf);
+ grab_person("author", val, deref, buf);
+ grab_person("committer", val, deref, buf);
break;
case OBJ_TREE:
/* grab_tree_values(val, deref, obj, buf, sz); */
*s = show_ref(&atom->u.remote_ref.refname, refname);
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours, &num_theirs,
- NULL, AHEAD_BEHIND_FULL) < 0) {
+ NULL, atom->u.remote_ref.push,
+ AHEAD_BEHIND_FULL) < 0) {
*s = xstrdup(msgs.gone);
} else if (!num_ours && !num_theirs)
*s = xstrdup("");
}
} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, &num_ours, &num_theirs,
- NULL, AHEAD_BEHIND_FULL) < 0) {
+ NULL, atom->u.remote_ref.push,
+ AHEAD_BEHIND_FULL) < 0) {
*s = xstrdup("");
return;
}
return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
oid_to_hex(&oi->oid), ref->refname);
}
- grab_values(ref->value, deref, *obj, oi->content, oi->size);
+ grab_values(ref->value, deref, *obj, oi->content);
}
grab_common_values(ref->value, deref, oi);
return 0;
}
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+ int i;
+
+ for (i = 0; worktrees[i]; i++) {
+ if (worktrees[i]->head_ref) {
+ struct ref_to_worktree_entry *entry;
+ entry = xmalloc(sizeof(*entry));
+ entry->wt = worktrees[i];
+ hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+ hashmap_add(map, entry);
+ }
+ }
+}
+
+static void lazy_init_worktree_map(void)
+{
+ if (ref_to_worktree_map.worktrees)
+ return;
+
+ ref_to_worktree_map.worktrees = get_worktrees(0);
+ hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+ populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+ struct hashmap_entry entry;
+ struct ref_to_worktree_entry *lookup_result;
+
+ lazy_init_worktree_map();
+
+ hashmap_entry_init(&entry, strhash(ref->refname));
+ lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+ if (lookup_result)
+ return xstrdup(lookup_result->wt->path);
+ else
+ return xstrdup("");
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
if (starts_with(name, "refname"))
refname = get_refname(atom, ref);
+ else if (!strcmp(name, "worktreepath")) {
+ if (ref->kind == FILTER_REFS_BRANCHES)
+ v->s = get_worktree_path(atom, ref);
+ else
+ v->s = xstrdup("");
+ continue;
+ }
else if (starts_with(name, "symref"))
refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
free_array_item(array->items[i]);
FREE_AND_NULL(array->items);
array->nr = array->alloc = 0;
+ if (ref_to_worktree_map.worktrees) {
+ hashmap_free(&(ref_to_worktree_map.map), 1);
+ free_worktrees(ref_to_worktree_map.worktrees);
+ ref_to_worktree_map.worktrees = NULL;
+ }
}
static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
{
- if (!arg) /* should --no-sort void the list ? */
- return -1;
+ /*
+ * NEEDSWORK: We should probably clear the list in this case, but we've
+ * already munged the global used_atoms list, which would need to be
+ * undone.
+ */
+ BUG_ON_OPT_NEG(unset);
+
parse_ref_sorting(opt->value, arg);
return 0;
}