char *name; /* Ref name; tag or head names are shortened. */
char id[SIZEOF_REV]; /* Commit SHA1 ID */
unsigned int tag:1; /* Is it a tag? */
+ unsigned int ltag:1; /* If so, is the tag local? */
unsigned int remote:1; /* Is it a remote ref? */
unsigned int next:1; /* For ref lists: are there more refs? */
};
REQ_(SHOW_VERSION, "Show version information"), \
REQ_(STOP_LOADING, "Stop all loading views"), \
REQ_(TOGGLE_LINENO, "Toggle line numbers"), \
+ REQ_(TOGGLE_DATE, "Toggle date display"), \
+ REQ_(TOGGLE_AUTHOR, "Toggle author display"), \
REQ_(TOGGLE_REV_GRAPH, "Toggle revision graph visualization"), \
+ REQ_(TOGGLE_REFS, "Toggle reference display (tags/branches)"), \
REQ_(STATUS_UPDATE, "Update file status"), \
REQ_(STATUS_MERGE, "Merge file using external tool"), \
REQ_(TREE_PARENT, "Switch to parent directory in tree view"), \
" -h, --help Show help message and exit\n";
/* Option and state variables. */
+static bool opt_date = TRUE;
+static bool opt_author = TRUE;
static bool opt_line_number = FALSE;
static bool opt_rev_graph = FALSE;
+static bool opt_show_refs = TRUE;
static int opt_num_interval = NUMBER_INTERVAL;
static int opt_tab_size = TABSIZE;
static enum request opt_request = REQ_VIEW_MAIN;
opt_cmd[buf_size] = 0;
}
- if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
- opt_utf8 = FALSE;
-
return TRUE;
}
LINE(MAIN_COMMIT, "", COLOR_DEFAULT, COLOR_DEFAULT, 0), \
LINE(MAIN_DELIM, "", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
LINE(MAIN_TAG, "", COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD), \
+LINE(MAIN_LOCAL_TAG,"", COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD), \
LINE(MAIN_REMOTE, "", COLOR_YELLOW, COLOR_DEFAULT, A_BOLD), \
LINE(MAIN_REF, "", COLOR_CYAN, COLOR_DEFAULT, A_BOLD), \
LINE(MAIN_REVGRAPH,"", COLOR_MAGENTA, COLOR_DEFAULT, 0), \
{ 'v', REQ_SHOW_VERSION },
{ 'r', REQ_SCREEN_REDRAW },
{ '.', REQ_TOGGLE_LINENO },
+ { 'D', REQ_TOGGLE_DATE },
+ { 'A', REQ_TOGGLE_AUTHOR },
{ 'g', REQ_TOGGLE_REV_GRAPH },
+ { 'F', REQ_TOGGLE_REFS },
{ ':', REQ_PROMPT },
{ 'u', REQ_STATUS_UPDATE },
{ 'M', REQ_STATUS_MERGE },
return OK;
}
+static bool parse_bool(const char *s)
+{
+ return (!strcmp(s, "1") || !strcmp(s, "true") ||
+ !strcmp(s, "yes")) ? TRUE : FALSE;
+}
+
/* Wants: name = value */
static int
option_set_command(int argc, char *argv[])
return ERR;
}
+ if (!strcmp(argv[0], "show-author")) {
+ opt_author = parse_bool(argv[2]);
+ return OK;
+ }
+
+ if (!strcmp(argv[0], "show-date")) {
+ opt_date = parse_bool(argv[2]);
+ return OK;
+ }
+
if (!strcmp(argv[0], "show-rev-graph")) {
- opt_rev_graph = (!strcmp(argv[2], "1") ||
- !strcmp(argv[2], "true") ||
- !strcmp(argv[2], "yes"));
+ opt_rev_graph = parse_bool(argv[2]);
+ return OK;
+ }
+
+ if (!strcmp(argv[0], "show-refs")) {
+ opt_show_refs = parse_bool(argv[2]);
+ return OK;
+ }
+
+ if (!strcmp(argv[0], "show-line-numbers")) {
+ opt_line_number = parse_bool(argv[2]);
return OK;
}
struct view *parent;
/* Buffering */
- unsigned long lines; /* Total number of lines */
+ size_t lines; /* Total number of lines */
struct line *line; /* Line index */
- unsigned long line_size;/* Total number of allocated lines */
+ size_t line_alloc; /* Total number of allocated lines */
+ size_t line_size; /* Total number of used lines */
unsigned int digits; /* Number of digits in the lines member. */
/* Loading */
return TRUE;
}
+#define ITEM_CHUNK_SIZE 256
+static void *
+realloc_items(void *mem, size_t *size, size_t new_size, size_t item_size)
+{
+ size_t num_chunks = *size / ITEM_CHUNK_SIZE;
+ size_t num_chunks_new = (new_size + ITEM_CHUNK_SIZE - 1) / ITEM_CHUNK_SIZE;
+
+ if (mem == NULL || num_chunks != num_chunks_new) {
+ *size = num_chunks_new * ITEM_CHUNK_SIZE;
+ mem = realloc(mem, *size * item_size);
+ }
+
+ return mem;
+}
+
static struct line *
realloc_lines(struct view *view, size_t line_size)
{
- struct line *tmp = realloc(view->line, sizeof(*view->line) * line_size);
+ size_t alloc = view->line_alloc;
+ struct line *tmp = realloc_items(view->line, &alloc, line_size,
+ sizeof(*view->line));
if (!tmp)
return NULL;
view->line = tmp;
+ view->line_alloc = alloc;
view->line_size = line_size;
return view->line;
}
redraw_display();
break;
+ case REQ_TOGGLE_DATE:
+ opt_date = !opt_date;
+ redraw_display();
+ break;
+
+ case REQ_TOGGLE_AUTHOR:
+ opt_author = !opt_author;
+ redraw_display();
+ break;
+
case REQ_TOGGLE_REV_GRAPH:
opt_rev_graph = !opt_rev_graph;
redraw_display();
break;
+ case REQ_TOGGLE_REFS:
+ opt_show_refs = !opt_show_refs;
+ redraw_display();
+ break;
+
case REQ_PROMPT:
/* Always reload^Wrerun commands from the prompt. */
open_view(view, opt_request, OPEN_RELOAD);
for (i = 0; i < view->lines; i++)
free(view->line[i].data);
free(view->line);
- view->lines = view->line_size = view->lineno = 0;
+ view->lines = view->line_alloc = view->line_size = view->lineno = 0;
view->line = NULL;
if (!realloc_lines(view, view->line_size + 6))
tilde_attr = get_line_attr(LINE_MAIN_DELIM);
}
- {
+ if (opt_date) {
int n;
timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
if (type != LINE_CURSOR)
wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
- {
+ if (opt_author) {
int max_len;
max_len = view->width - col;
wmove(view->win, lineno, col);
- if (commit->refs) {
+ if (opt_show_refs && commit->refs) {
size_t i = 0;
do {
if (type == LINE_CURSOR)
;
+ else if (commit->refs[i]->ltag)
+ wattrset(view->win, get_line_attr(LINE_MAIN_LOCAL_TAG));
else if (commit->refs[i]->tag)
wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
else if (commit->refs[i]->remote)
* Repository references
*/
-static struct ref *refs;
-static size_t refs_size;
+static struct ref *refs = NULL;
+static size_t refs_alloc = 0;
+static size_t refs_size = 0;
/* Id <-> ref store */
-static struct ref ***id_refs;
-static size_t id_refs_size;
+static struct ref ***id_refs = NULL;
+static size_t id_refs_alloc = 0;
+static size_t id_refs_size = 0;
static struct ref **
get_refs(char *id)
{
struct ref ***tmp_id_refs;
struct ref **ref_list = NULL;
+ size_t ref_list_alloc = 0;
size_t ref_list_size = 0;
size_t i;
if (!strcmp(id, id_refs[i][0]->id))
return id_refs[i];
- tmp_id_refs = realloc(id_refs, (id_refs_size + 1) * sizeof(*id_refs));
+ tmp_id_refs = realloc_items(id_refs, &id_refs_alloc, id_refs_size + 1,
+ sizeof(*id_refs));
if (!tmp_id_refs)
return NULL;
if (strcmp(id, refs[i].id))
continue;
- tmp = realloc(ref_list, (ref_list_size + 1) * sizeof(*ref_list));
+ tmp = realloc_items(ref_list, &ref_list_alloc,
+ ref_list_size + 1, sizeof(*ref_list));
if (!tmp) {
if (ref_list)
free(ref_list);
{
struct ref *ref;
bool tag = FALSE;
+ bool ltag = FALSE;
bool remote = FALSE;
+ bool check_replace = FALSE;
if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
- /* Commits referenced by tags has "^{}" appended. */
- if (name[namelen - 1] != '}')
- return OK;
-
- while (namelen > 0 && name[namelen] != '^')
- namelen--;
+ if (!strcmp(name + namelen - 3, "^{}")) {
+ namelen -= 3;
+ name[namelen] = 0;
+ if (refs_size > 0 && refs[refs_size - 1].ltag == TRUE)
+ check_replace = TRUE;
+ } else {
+ ltag = TRUE;
+ }
tag = TRUE;
namelen -= STRING_SIZE("refs/tags/");
return OK;
}
- refs = realloc(refs, sizeof(*refs) * (refs_size + 1));
+ if (check_replace && !strcmp(name, refs[refs_size - 1].name)) {
+ /* it's an annotated tag, replace the previous sha1 with the
+ * resolved commit id; relies on the fact git-ls-remote lists
+ * the commit id of an annotated tag right beofre the commit id
+ * it points to. */
+ refs[refs_size - 1].ltag = ltag;
+ string_copy_rev(refs[refs_size - 1].id, id);
+
+ return OK;
+ }
+ refs = realloc_items(refs, &refs_alloc, refs_size + 1, sizeof(*refs));
if (!refs)
return ERR;
strncpy(ref->name, name, namelen);
ref->name[namelen] = 0;
ref->tag = tag;
+ ref->ltag = ltag;
ref->remote = remote;
string_copy_rev(ref->id, id);
if (!opt_git_dir[0])
die("Not a git repository");
+ if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
+ opt_utf8 = FALSE;
+
if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
opt_iconv = iconv_open(opt_codeset, opt_encoding);
if (opt_iconv == ICONV_NONE)