index b20fb1bfa49bb4c9ac9b1bd24481b4df3dea5a8f..c1dd51366a2694bffe61de408c9e3f2c0ce37e61 100644 (file)
--- a/tig.c
+++ b/tig.c
static void report(const char *msg, ...);
static void set_nonblocking_input(bool loading);
static size_t utf8_length(const char **string, size_t col, int *width, size_t max_width, int *trimmed, bool reserve);
static void report(const char *msg, ...);
static void set_nonblocking_input(bool loading);
static size_t utf8_length(const char **string, size_t col, int *width, size_t max_width, int *trimmed, bool reserve);
+static inline unsigned char utf8_char_length(const char *string, const char *end);
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -107,6 +108,7 @@ static size_t utf8_length(const char **string, size_t col, int *width, size_t ma
#define DATE_SHORT_COLS STRING_SIZE("2006-04-29 ")
#define ID_COLS 8
#define DATE_SHORT_COLS STRING_SIZE("2006-04-29 ")
#define ID_COLS 8
+#define AUTHOR_COLS 19
#define MIN_VIEW_HEIGHT 4
#define MIN_VIEW_HEIGHT 4
};
static struct ref_list *get_ref_list(const char *id);
};
static struct ref_list *get_ref_list(const char *id);
-static void foreach_ref(bool (*visitor)(void *data, struct ref *ref), void *data);
+static void foreach_ref(bool (*visitor)(void *data, const struct ref *ref), void *data);
static int load_refs(void);
enum format_flags {
static int load_refs(void);
enum format_flags {
return 0;
}
return 0;
}
+#define enum_equals(entry, str, len) \
+ ((entry).namelen == (len) && !string_enum_compare((entry).name, str, len))
+
struct enum_map {
const char *name;
int namelen;
struct enum_map {
const char *name;
int namelen;
#define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
#define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
+static char *
+enum_map_name(const char *name, size_t namelen)
+{
+ static char buf[SIZEOF_STR];
+ int bufpos;
+
+ for (bufpos = 0; bufpos <= namelen; bufpos++) {
+ buf[bufpos] = tolower(name[bufpos]);
+ if (buf[bufpos] == '_')
+ buf[bufpos] = '-';
+ }
+
+ buf[bufpos] = 0;
+ return buf;
+}
+
+#define enum_name(entry) enum_map_name((entry).name, (entry).namelen)
+
static bool
map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
{
static bool
map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
{
int i;
for (i = 0; i < map_size; i++)
int i;
for (i = 0; i < map_size; i++)
- if (namelen == map[i].namelen &&
- !string_enum_compare(name, map[i].name, namelen)) {
+ if (enum_equals(map[i], name, namelen)) {
*value = map[i].value;
return TRUE;
}
*value = map[i].value;
return TRUE;
}
}
}
-/*
- * What value of "tz" was in effect back then at "time" in the
- * local timezone?
- */
-static int local_tzoffset(time_t time)
-{
- time_t t, t_local;
- struct tm tm;
- int offset, eastwest;
+#define DATE_INFO \
+ DATE_(NO), \
+ DATE_(DEFAULT), \
+ DATE_(RELATIVE), \
+ DATE_(SHORT)
- t = time;
- localtime_r(&t, &tm);
- t_local = mktime(&tm);
+enum date {
+#define DATE_(name) DATE_##name
+ DATE_INFO
+#undef DATE_
+};
- if (t_local < t) {
- eastwest = -1;
- offset = t - t_local;
- } else {
- eastwest = 1;
- offset = t_local - t;
- }
- offset /= 60; /* in minutes */
- offset = (offset % 60) + ((offset / 60) * 100);
- return offset * eastwest;
-}
+static const struct enum_map date_map[] = {
+#define DATE_(name) ENUM_MAP(#name, DATE_##name)
+ DATE_INFO
+#undef DATE_
+};
-enum date {
- DATE_NONE = 0,
- DATE_DEFAULT,
- DATE_RELATIVE,
- DATE_SHORT
+struct time {
+ time_t sec;
+ int tz;
};
};
-static char *
-string_date(const time_t *time, enum date date)
+static inline int timecmp(const struct time *t1, const struct time *t2)
+{
+ return t1->sec - t2->sec;
+}
+
+static const char *
+string_date(const struct time *time, enum date date)
{
static char buf[DATE_COLS + 1];
static const struct enum_map reldate[] = {
{
static char buf[DATE_COLS + 1];
static const struct enum_map reldate[] = {
if (date == DATE_RELATIVE) {
struct timeval now;
if (date == DATE_RELATIVE) {
struct timeval now;
- time_t date = *time + local_tzoffset(*time);
+ time_t date = time->sec + time->tz;
time_t seconds;
int i;
time_t seconds;
int i;
}
}
}
}
- gmtime_r(time, &tm);
+ gmtime_r(&time->sec, &tm);
return strftime(buf, sizeof(buf), DATE_FORMAT, &tm) ? buf : NULL;
}
return strftime(buf, sizeof(buf), DATE_FORMAT, &tm) ? buf : NULL;
}
+#define AUTHOR_VALUES \
+ AUTHOR_(NO), \
+ AUTHOR_(FULL), \
+ AUTHOR_(ABBREVIATED)
+
+enum author {
+#define AUTHOR_(name) AUTHOR_##name
+ AUTHOR_VALUES,
+#undef AUTHOR_
+ AUTHOR_DEFAULT = AUTHOR_FULL
+};
+
+static const struct enum_map author_map[] = {
+#define AUTHOR_(name) ENUM_MAP(#name, AUTHOR_##name)
+ AUTHOR_VALUES
+#undef AUTHOR_
+};
+
+static const char *
+get_author_initials(const char *author)
+{
+ static char initials[AUTHOR_COLS * 6 + 1];
+ size_t pos = 0;
+ const char *end = strchr(author, '\0');
+
+#define is_initial_sep(c) (isspace(c) || ispunct(c) || (c) == '@' || (c) == '-')
+
+ memset(initials, 0, sizeof(initials));
+ while (author < end) {
+ unsigned char bytes;
+ size_t i;
+
+ while (is_initial_sep(*author))
+ author++;
+
+ bytes = utf8_char_length(author, end);
+ if (bytes < sizeof(initials) - 1 - pos) {
+ while (bytes--) {
+ initials[pos++] = *author++;
+ }
+ }
+
+ for (i = pos; author < end && !is_initial_sep(*author); author++) {
+ if (i < sizeof(initials) - 1)
+ initials[i++] = *author;
+ }
+
+ initials[i++] = 0;
+ }
+
+ return initials;
+}
+
+
static bool
argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
{
static bool
argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
{
int i;
for (i = 0; i < ARRAY_SIZE(req_info); i++)
int i;
for (i = 0; i < ARRAY_SIZE(req_info); i++)
- if (req_info[i].namelen == namelen &&
- !string_enum_compare(req_info[i].name, name, namelen))
+ if (enum_equals(req_info[i], name, namelen))
return req_info[i].request;
return REQ_NONE;
return req_info[i].request;
return REQ_NONE;
/* Option and state variables. */
static enum date opt_date = DATE_DEFAULT;
/* Option and state variables. */
static enum date opt_date = DATE_DEFAULT;
-static bool opt_author = TRUE;
+static enum author opt_author = AUTHOR_DEFAULT;
static bool opt_line_number = FALSE;
static bool opt_line_graphics = TRUE;
static bool opt_rev_graph = FALSE;
static bool opt_line_number = FALSE;
static bool opt_line_graphics = TRUE;
static bool opt_rev_graph = FALSE;
static double opt_hscroll = 0.50;
static double opt_scale_split_view = 2.0 / 3.0;
static int opt_tab_size = 8;
static double opt_hscroll = 0.50;
static double opt_scale_split_view = 2.0 / 3.0;
static int opt_tab_size = 8;
-static int opt_author_cols = 19;
+static int opt_author_cols = AUTHOR_COLS;
static char opt_path[SIZEOF_STR] = "";
static char opt_file[SIZEOF_STR] = "";
static char opt_ref[SIZEOF_REF] = "";
static char opt_path[SIZEOF_STR] = "";
static char opt_file[SIZEOF_STR] = "";
static char opt_ref[SIZEOF_REF] = "";
static char opt_head_rev[SIZEOF_REV] = "";
static char opt_remote[SIZEOF_REF] = "";
static char opt_encoding[20] = "UTF-8";
static char opt_head_rev[SIZEOF_REV] = "";
static char opt_remote[SIZEOF_REF] = "";
static char opt_encoding[20] = "UTF-8";
-static bool opt_utf8 = TRUE;
static char opt_codeset[20] = "UTF-8";
static char opt_codeset[20] = "UTF-8";
-static iconv_t opt_iconv = ICONV_NONE;
+static iconv_t opt_iconv_in = ICONV_NONE;
+static iconv_t opt_iconv_out = ICONV_NONE;
static char opt_search[SIZEOF_STR] = "";
static char opt_cdup[SIZEOF_STR] = "";
static char opt_prefix[SIZEOF_STR] = "";
static char opt_search[SIZEOF_STR] = "";
static char opt_cdup[SIZEOF_STR] = "";
static char opt_prefix[SIZEOF_STR] = "";
enum line_type type;
for (type = 0; type < ARRAY_SIZE(line_info); type++)
enum line_type type;
for (type = 0; type < ARRAY_SIZE(line_info); type++)
- if (namelen == line_info[type].namelen &&
- !string_enum_compare(line_info[type].name, name, namelen))
+ if (enum_equals(line_info[type], name, namelen))
return &line_info[type];
return NULL;
return &line_info[type];
return NULL;
return OK;
}
return OK;
}
+static int parse_enum_do(unsigned int *opt, const char *arg,
+ const struct enum_map *map, size_t map_size)
+{
+ bool is_true;
+
+ assert(map_size > 1);
+
+ if (map_enum_do(map, map_size, (int *) opt, arg))
+ return OK;
+
+ if (parse_bool(&is_true, arg) != OK)
+ return ERR;
+
+ *opt = is_true ? map[1].value : map[0].value;
+ return OK;
+}
+
+#define parse_enum(opt, arg, map) \
+ parse_enum_do(opt, arg, map, ARRAY_SIZE(map))
+
static int
parse_string(char *opt, const char *arg, size_t optsize)
{
static int
parse_string(char *opt, const char *arg, size_t optsize)
{
}
if (!strcmp(argv[0], "show-author"))
}
if (!strcmp(argv[0], "show-author"))
- return parse_bool(&opt_author, argv[2]);
-
- if (!strcmp(argv[0], "show-date")) {
- bool show_date;
-
- if (!strcmp(argv[2], "relative")) {
- opt_date = DATE_RELATIVE;
- return OK;
- } else if (!strcmp(argv[2], "short")) {
- opt_date = DATE_SHORT;
- return OK;
- } else if (parse_bool(&show_date, argv[2])) {
- opt_date = show_date ? DATE_DEFAULT : DATE_NONE;
- }
- return ERR;
- }
+ return parse_enum(&opt_author, argv[2], author_map);
+
+ if (!strcmp(argv[0], "show-date"))
+ return parse_enum(&opt_date, argv[2], date_map);
if (!strcmp(argv[0], "show-rev-graph"))
return parse_bool(&opt_rev_graph, argv[2]);
if (!strcmp(argv[0], "show-rev-graph"))
return parse_bool(&opt_rev_graph, argv[2]);
draw_chars(struct view *view, enum line_type type, const char *string,
int max_len, bool use_tilde)
{
draw_chars(struct view *view, enum line_type type, const char *string,
int max_len, bool use_tilde)
{
+ static char out_buffer[BUFSIZ * 2];
int len = 0;
int col = 0;
int trimmed = FALSE;
int len = 0;
int col = 0;
int trimmed = FALSE;
if (max_len <= 0)
return 0;
if (max_len <= 0)
return 0;
- if (opt_utf8) {
- len = utf8_length(&string, skip, &col, max_len, &trimmed, use_tilde);
- } else {
- col = len = strlen(string);
- if (len > max_len) {
- if (use_tilde) {
- max_len -= 1;
+ len = utf8_length(&string, skip, &col, max_len, &trimmed, use_tilde);
+
+ set_view_attr(view, type);
+ if (len > 0) {
+ if (opt_iconv_out != ICONV_NONE) {
+ ICONV_CONST char *inbuf = (ICONV_CONST char *) string;
+ size_t inlen = len + 1;
+
+ char *outbuf = out_buffer;
+ size_t outlen = sizeof(out_buffer);
+
+ size_t ret;
+
+ ret = iconv(opt_iconv_out, &inbuf, &inlen, &outbuf, &outlen);
+ if (ret != (size_t) -1) {
+ string = out_buffer;
+ len = sizeof(out_buffer) - outlen;
}
}
- col = len = max_len;
- trimmed = TRUE;
}
}
- }
- set_view_attr(view, type);
- if (len > 0)
waddnstr(view->win, string, len);
waddnstr(view->win, string, len);
+ }
if (trimmed && use_tilde) {
set_view_attr(view, LINE_DELIMITER);
waddch(view->win, '~');
if (trimmed && use_tilde) {
set_view_attr(view, LINE_DELIMITER);
waddch(view->win, '~');
@@ -2159,9 +2243,9 @@ draw_field(struct view *view, enum line_type type, const char *text, int len, bo
}
static bool
}
static bool
-draw_date(struct view *view, time_t *time)
+draw_date(struct view *view, struct time *time)
{
{
- const char *date = time ? mkdate(time) : "";
+ const char *date = time && time->sec ? mkdate(time) : "";
int cols = opt_date == DATE_SHORT ? DATE_SHORT_COLS : DATE_COLS;
return draw_field(view, LINE_DATE, date, cols, FALSE);
int cols = opt_date == DATE_SHORT ? DATE_SHORT_COLS : DATE_COLS;
return draw_field(view, LINE_DATE, date, cols, FALSE);
static bool
draw_author(struct view *view, const char *author)
{
static bool
draw_author(struct view *view, const char *author)
{
- bool trim = opt_author_cols == 0 || opt_author_cols > 5 || !author;
+ bool trim = opt_author_cols == 0 || opt_author_cols > 5;
+ bool abbreviate = opt_author == AUTHOR_ABBREVIATED || !trim;
- if (!trim) {
- static char initials[10];
- size_t pos;
-
-#define is_initial_sep(c) (isspace(c) || ispunct(c) || (c) == '@')
-
- memset(initials, 0, sizeof(initials));
- for (pos = 0; *author && pos < opt_author_cols - 1; author++, pos++) {
- while (is_initial_sep(*author))
- author++;
- strncpy(&initials[pos], author, sizeof(initials) - 1 - pos);
- while (*author && !is_initial_sep(author[1]))
- author++;
- }
-
- author = initials;
- }
+ if (abbreviate && author)
+ author = get_author_initials(author);
return draw_field(view, LINE_AUTHOR, author, opt_author_cols, trim);
}
return draw_field(view, LINE_AUTHOR, author, opt_author_cols, trim);
}
}
static void
}
static void
-toggle_date_option(enum date *date)
+toggle_enum_option_do(unsigned int *opt, const char *help,
+ const struct enum_map *map, size_t size)
{
{
- static const char *help[] = {
- "no",
- "default",
- "relative",
- "short"
- };
-
- opt_date = (opt_date + 1) % ARRAY_SIZE(help);
+ *opt = (*opt + 1) % size;
redraw_display(FALSE);
redraw_display(FALSE);
- report("Displaying %s dates", help[opt_date]);
+ report("Displaying %s %s", enum_name(map[*opt]), help);
}
}
+#define toggle_enum_option(opt, help, map) \
+ toggle_enum_option_do(opt, help, map, ARRAY_SIZE(map))
+
+#define toggle_date() toggle_enum_option(&opt_date, "dates", date_map)
+#define toggle_author() toggle_enum_option(&opt_author, "author names", author_map)
+
static void
toggle_view_option(bool *option, const char *help)
{
static void
toggle_view_option(bool *option, const char *help)
{
if (prompt_menu("Toggle option", menu, &selected)) {
if (menu[selected].data == &opt_date)
if (prompt_menu("Toggle option", menu, &selected)) {
if (menu[selected].data == &opt_date)
- toggle_date_option(menu[selected].data);
+ toggle_date();
+ else if (menu[selected].data == &opt_author)
+ toggle_author();
else
toggle_view_option(menu[selected].data, menu[selected].text);
}
else
toggle_view_option(menu[selected].data, menu[selected].text);
}
free((void *) argv[argc]);
}
free((void *) argv[argc]);
}
+static const char *
+format_arg(const char *name)
+{
+ static struct {
+ const char *name;
+ size_t namelen;
+ const char *value;
+ const char *value_if_empty;
+ } vars[] = {
+#define FORMAT_VAR(name, value, value_if_empty) \
+ { name, STRING_SIZE(name), value, value_if_empty }
+ FORMAT_VAR("%(directory)", opt_path, ""),
+ FORMAT_VAR("%(file)", opt_file, ""),
+ FORMAT_VAR("%(ref)", opt_ref, "HEAD"),
+ FORMAT_VAR("%(head)", ref_head, ""),
+ FORMAT_VAR("%(commit)", ref_commit, ""),
+ FORMAT_VAR("%(blob)", ref_blob, ""),
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vars); i++)
+ if (!strncmp(name, vars[i].name, vars[i].namelen))
+ return *vars[i].value ? vars[i].value : vars[i].value_if_empty;
+
+ return NULL;
+}
static bool
format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags flags)
{
static bool
format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags flags)
{
@@ -2895,27 +2993,13 @@ format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags fl
len = strlen(arg);
value = "";
len = strlen(arg);
value = "";
- } else if (!prefixcmp(next, "%(directory)")) {
- value = opt_path;
-
- } else if (!prefixcmp(next, "%(file)")) {
- value = opt_file;
-
- } else if (!prefixcmp(next, "%(ref)")) {
- value = *opt_ref ? opt_ref : "HEAD";
-
- } else if (!prefixcmp(next, "%(head)")) {
- value = ref_head;
-
- } else if (!prefixcmp(next, "%(commit)")) {
- value = ref_commit;
-
- } else if (!prefixcmp(next, "%(blob)")) {
- value = ref_blob;
-
} else {
} else {
- report("Unknown replacement: `%s`", next);
- return FALSE;
+ value = format_arg(next);
+
+ if (!value) {
+ report("Unknown replacement: `%s`", next);
+ return FALSE;
+ }
}
if (!string_format_from(buf, &bufpos, "%.*s%s", len, arg, value))
}
if (!string_format_from(buf, &bufpos, "%.*s%s", len, arg, value))
{
if (view->pipe)
end_update(view, TRUE);
{
if (view->pipe)
end_update(view, TRUE);
- return io_open(&view->io, "%s", name);
+ return io_open(&view->io, "%s/%s", opt_cdup[0] ? opt_cdup : ".", name);
}
static bool
}
static bool
}
for (; (line = io_get(view->pipe, '\n', can_read)); can_read = FALSE) {
}
for (; (line = io_get(view->pipe, '\n', can_read)); can_read = FALSE) {
- if (opt_iconv != ICONV_NONE) {
+ if (opt_iconv_in != ICONV_NONE) {
ICONV_CONST char *inbuf = line;
size_t inlen = strlen(line) + 1;
ICONV_CONST char *inbuf = line;
size_t inlen = strlen(line) + 1;
size_t ret;
size_t ret;
- ret = iconv(opt_iconv, &inbuf, &inlen, &outbuf, &outlen);
+ ret = iconv(opt_iconv_in, &inbuf, &inlen, &outbuf, &outlen);
if (ret != (size_t) -1)
line = out_buffer;
}
if (ret != (size_t) -1)
line = out_buffer;
}
do_scroll_view(prev, lines);
}
do_scroll_view(prev, lines);
}
- if (prev && view != prev) {
- if (split) {
- /* "Blur" the previous view. */
- update_view_title(prev);
- }
+ if (prev && view != prev && split && view_is_displayed(prev)) {
+ /* "Blur" the previous view. */
+ update_view_title(prev);
}
if (view->pipe && view->lines == 0) {
}
if (view->pipe && view->lines == 0) {
}
static void
}
static void
-open_editor(bool from_root, const char *file)
+open_editor(const char *file)
{
const char *editor_argv[] = { "vi", file, NULL };
const char *editor;
{
const char *editor_argv[] = { "vi", file, NULL };
const char *editor;
editor = "vi";
editor_argv[0] = editor;
editor = "vi";
editor_argv[0] = editor;
- open_external_viewer(editor_argv, from_root ? opt_cdup : NULL);
+ open_external_viewer(editor_argv, opt_cdup);
}
static void
}
static void
break;
case REQ_TOGGLE_DATE:
break;
case REQ_TOGGLE_DATE:
- toggle_date_option(&opt_date);
+ toggle_date();
break;
case REQ_TOGGLE_AUTHOR:
break;
case REQ_TOGGLE_AUTHOR:
- toggle_view_option(&opt_author, "author display");
+ toggle_author();
break;
case REQ_TOGGLE_REV_GRAPH:
break;
case REQ_TOGGLE_REV_GRAPH:
}
static void
}
static void
-parse_timezone(time_t *time, const char *zone)
+parse_timesec(struct time *time, const char *sec)
+{
+ time->sec = (time_t) atol(sec);
+}
+
+static void
+parse_timezone(struct time *time, const char *zone)
{
long tz;
{
long tz;
if (zone[0] == '-')
tz = -tz;
if (zone[0] == '-')
tz = -tz;
- *time -= tz;
+ time->tz = tz;
+ time->sec -= tz;
}
/* Parse author lines where the name may be empty:
* author <email@address.tld> 1138474660 +0100
*/
static void
}
/* Parse author lines where the name may be empty:
* author <email@address.tld> 1138474660 +0100
*/
static void
-parse_author_line(char *ident, const char **author, time_t *time)
+parse_author_line(char *ident, const char **author, struct time *time)
{
char *nameend = strchr(ident, '<');
char *emailend = strchr(ident, '>');
{
char *nameend = strchr(ident, '<');
char *emailend = strchr(ident, '>');
char *secs = emailend + 2;
char *zone = strchr(secs, ' ');
char *secs = emailend + 2;
char *zone = strchr(secs, ' ');
- *time = (time_t) atol(secs);
+ parse_timesec(time, secs);
if (zone && strlen(zone) == STRING_SIZE(" +0700"))
parse_timezone(time, zone + 1);
if (zone && strlen(zone) == STRING_SIZE(" +0700"))
parse_timezone(time, zone + 1);
static bool help_keymap_hidden[ARRAY_SIZE(keymap_table)];
static bool help_keymap_hidden[ARRAY_SIZE(keymap_table)];
-static char *
-help_name(char buf[SIZEOF_STR], const char *name, size_t namelen)
-{
- int bufpos;
-
- for (bufpos = 0; bufpos <= namelen; bufpos++) {
- buf[bufpos] = tolower(name[bufpos]);
- if (buf[bufpos] == '_')
- buf[bufpos] = '-';
- }
-
- buf[bufpos] = 0;
- return buf;
-}
-
-#define help_keymap_name(buf, keymap) \
- help_name(buf, keymap_table[keymap].name, keymap_table[keymap].namelen)
-
static bool
help_open_keymap_title(struct view *view, enum keymap keymap)
{
static bool
help_open_keymap_title(struct view *view, enum keymap keymap)
{
- char buf[SIZEOF_STR];
struct line *line;
line = add_line_format(view, LINE_HELP_KEYMAP, "[%c] %s bindings",
help_keymap_hidden[keymap] ? '+' : '-',
struct line *line;
line = add_line_format(view, LINE_HELP_KEYMAP, "[%c] %s bindings",
help_keymap_hidden[keymap] ? '+' : '-',
- help_keymap_name(buf, keymap));
+ enum_name(keymap_table[keymap]));
if (line)
line->other = keymap;
if (line)
line->other = keymap;
if (add_title && help_open_keymap_title(view, keymap))
return;
if (add_title && help_open_keymap_title(view, keymap))
return;
- add_title = false;
+ add_title = FALSE;
if (group) {
add_line_text(view, group, LINE_HELP_GROUP);
if (group) {
add_line_text(view, group, LINE_HELP_GROUP);
}
add_line_format(view, LINE_DEFAULT, " %-25s %-20s %s", key,
}
add_line_format(view, LINE_DEFAULT, " %-25s %-20s %s", key,
- help_name(buf, req_info[i].name, req_info[i].namelen),
- req_info[i].help);
+ enum_name(req_info[i]), req_info[i].help);
}
group = "External commands:";
}
group = "External commands:";
struct tree_entry {
char id[SIZEOF_REV];
mode_t mode;
struct tree_entry {
char id[SIZEOF_REV];
mode_t mode;
- time_t time; /* Date from the author ident. */
+ struct time time; /* Date from the author ident. */
const char *author; /* Author of the commit. */
char name[1];
};
const char *author; /* Author of the commit. */
char name[1];
};
switch (get_sort_field(tree_sort_state)) {
case ORDERBY_DATE:
switch (get_sort_field(tree_sort_state)) {
case ORDERBY_DATE:
- return sort_order(tree_sort_state, entry1->time - entry2->time);
+ return sort_order(tree_sort_state, timecmp(&entry1->time, &entry2->time));
case ORDERBY_AUTHOR:
return sort_order(tree_sort_state, strcmp(entry1->author, entry2->author));
case ORDERBY_AUTHOR:
return sort_order(tree_sort_state, strcmp(entry1->author, entry2->author));
tree_read_date(struct view *view, char *text, bool *read_date)
{
static const char *author_name;
tree_read_date(struct view *view, char *text, bool *read_date)
{
static const char *author_name;
- static time_t author_time;
+ static struct time author_time;
if (!text && *read_date) {
*read_date = FALSE;
if (!text && *read_date) {
*read_date = FALSE;
if (opt_author && draw_author(view, entry->author))
return TRUE;
if (opt_author && draw_author(view, entry->author))
return TRUE;
- if (opt_date && draw_date(view, entry->author ? &entry->time : NULL))
+ if (opt_date && draw_date(view, &entry->time))
return TRUE;
}
if (draw_text(view, line->type, entry->name, TRUE))
return TRUE;
}
if (draw_text(view, line->type, entry->name, TRUE))
else if (!run_io_append(blob_ops.argv, FORMAT_ALL, fd))
report("Failed to save blob data to file");
else
else if (!run_io_append(blob_ops.argv, FORMAT_ALL, fd))
report("Failed to save blob data to file");
else
- open_editor(FALSE, file);
+ open_editor(file);
if (fd != -1)
unlink(file);
}
if (fd != -1)
unlink(file);
}
} else if (!is_head_commit(view->vid)) {
open_blob_editor();
} else {
} else if (!is_head_commit(view->vid)) {
open_blob_editor();
} else {
- open_editor(TRUE, opt_file);
+ open_editor(opt_file);
}
return REQ_NONE;
}
return REQ_NONE;
char id[SIZEOF_REV]; /* SHA1 ID. */
char title[128]; /* First line of the commit message. */
const char *author; /* Author of the commit. */
char id[SIZEOF_REV]; /* SHA1 ID. */
char title[128]; /* First line of the commit message. */
const char *author; /* Author of the commit. */
- time_t time; /* Date from the author ident. */
+ struct time time; /* Date from the author ident. */
char filename[128]; /* Name of file. */
bool has_previous; /* Was a "previous" line detected. */
};
char filename[128]; /* Name of file. */
bool has_previous; /* Was a "previous" line detected. */
};
commit->author = get_author(line);
} else if (match_blame_header("author-time ", &line)) {
commit->author = get_author(line);
} else if (match_blame_header("author-time ", &line)) {
- commit->time = (time_t) atol(line);
+ parse_timesec(&commit->time, line);
} else if (match_blame_header("author-tz ", &line)) {
parse_timezone(&commit->time, line);
} else if (match_blame_header("author-tz ", &line)) {
parse_timezone(&commit->time, line);
blame_draw(struct view *view, struct line *line, unsigned int lineno)
{
struct blame *blame = line->data;
blame_draw(struct view *view, struct line *line, unsigned int lineno)
{
struct blame *blame = line->data;
- time_t *time = NULL;
+ struct time *time = NULL;
const char *id = NULL, *author = NULL;
char text[SIZEOF_STR];
const char *id = NULL, *author = NULL;
char text[SIZEOF_STR];
struct branch {
const char *author; /* Author of the last commit. */
struct branch {
const char *author; /* Author of the last commit. */
- time_t time; /* Date of the last activity. */
- struct ref *ref; /* Name and commit ID information. */
+ struct time time; /* Date of the last activity. */
+ const struct ref *ref; /* Name and commit ID information. */
};
};
+static const struct ref branch_all;
+
static const enum sort_field branch_sort_fields[] = {
ORDERBY_NAME, ORDERBY_DATE, ORDERBY_AUTHOR
};
static const enum sort_field branch_sort_fields[] = {
ORDERBY_NAME, ORDERBY_DATE, ORDERBY_AUTHOR
};
switch (get_sort_field(branch_sort_state)) {
case ORDERBY_DATE:
switch (get_sort_field(branch_sort_state)) {
case ORDERBY_DATE:
- return sort_order(branch_sort_state, branch1->time - branch2->time);
+ return sort_order(branch_sort_state, timecmp(&branch1->time, &branch2->time));
case ORDERBY_AUTHOR:
return sort_order(branch_sort_state, strcmp(branch1->author, branch2->author));
case ORDERBY_AUTHOR:
return sort_order(branch_sort_state, strcmp(branch1->author, branch2->author));
struct branch *branch = line->data;
enum line_type type = branch->ref->head ? LINE_MAIN_HEAD : LINE_DEFAULT;
struct branch *branch = line->data;
enum line_type type = branch->ref->head ? LINE_MAIN_HEAD : LINE_DEFAULT;
- if (opt_date && draw_date(view, branch->author ? &branch->time : NULL))
+ if (opt_date && draw_date(view, &branch->time))
return TRUE;
if (opt_author && draw_author(view, branch->author))
return TRUE;
return TRUE;
if (opt_author && draw_author(view, branch->author))
return TRUE;
- draw_text(view, type, branch->ref->name, TRUE);
+ draw_text(view, type, branch->ref == &branch_all ? "All branches" : branch->ref->name, TRUE);
return TRUE;
}
static enum request
branch_request(struct view *view, enum request request, struct line *line)
{
return TRUE;
}
static enum request
branch_request(struct view *view, enum request request, struct line *line)
{
+ struct branch *branch = line->data;
+
switch (request) {
case REQ_REFRESH:
load_refs();
switch (request) {
case REQ_REFRESH:
load_refs();
return REQ_NONE;
case REQ_ENTER:
return REQ_NONE;
case REQ_ENTER:
- open_view(view, REQ_VIEW_MAIN, OPEN_SPLIT);
+ if (branch->ref == &branch_all) {
+ const char *all_branches_argv[] = {
+ "git", "log", "--no-color", "--pretty=raw", "--parents",
+ "--topo-order", "--all", NULL
+ };
+ struct view *main_view = VIEW(REQ_VIEW_MAIN);
+
+ if (!prepare_update(main_view, all_branches_argv, NULL, FORMAT_NONE)) {
+ report("Failed to load view of all branches");
+ return REQ_NONE;
+ }
+ open_view(view, REQ_VIEW_MAIN, OPEN_PREPARED | OPEN_SPLIT);
+ } else {
+ open_view(view, REQ_VIEW_MAIN, OPEN_SPLIT);
+ }
return REQ_NONE;
default:
return REQ_NONE;
default:
}
static bool
}
static bool
-branch_open_visitor(void *data, struct ref *ref)
+branch_open_visitor(void *data, const struct ref *ref)
{
struct view *view = data;
struct branch *branch;
{
struct view *view = data;
struct branch *branch;
}
setup_update(view, view->id);
}
setup_update(view, view->id);
+ branch_open_visitor(view, &branch_all);
foreach_ref(branch_open_visitor, view);
view->p_restore = TRUE;
foreach_ref(branch_open_visitor, view);
view->p_restore = TRUE;
@@ -5287,7 +5375,7 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty
char *buf;
struct io io = {};
char *buf;
struct io io = {};
- if (!run_io(&io, argv, NULL, IO_RD))
+ if (!run_io(&io, argv, opt_cdup, IO_RD))
return FALSE;
add_line_data(view, NULL, type);
return FALSE;
add_line_data(view, NULL, type);
};
static const char *status_list_other_argv[] = {
};
static const char *status_list_other_argv[] = {
- "git", "ls-files", "-z", "--others", "--exclude-standard", NULL
+ "git", "ls-files", "-z", "--others", "--exclude-standard", opt_prefix, NULL
};
static const char *status_list_no_head_argv[] = {
};
static const char *status_list_no_head_argv[] = {
return run_io(io, staged_argv, opt_cdup, IO_WR);
case LINE_STAT_UNSTAGED:
return run_io(io, staged_argv, opt_cdup, IO_WR);
case LINE_STAT_UNSTAGED:
- return run_io(io, others_argv, opt_cdup, IO_WR);
-
case LINE_STAT_UNTRACKED:
case LINE_STAT_UNTRACKED:
- return run_io(io, others_argv, NULL, IO_WR);
+ return run_io(io, others_argv, opt_cdup, IO_WR);
default:
die("line type %d not handled in switch", type);
default:
die("line type %d not handled in switch", type);
return REQ_NONE;
}
return REQ_NONE;
}
- open_editor(status->status != '?', status->new.name);
+ open_editor(status->new.name);
break;
case REQ_VIEW_BLAME:
break;
case REQ_VIEW_BLAME:
return REQ_NONE;
}
return REQ_NONE;
}
- open_editor(stage_status.status != '?', stage_status.new.name);
+ open_editor(stage_status.new.name);
break;
case REQ_REFRESH:
break;
case REQ_REFRESH:
char id[SIZEOF_REV]; /* SHA1 ID. */
char title[128]; /* First line of the commit message. */
const char *author; /* Author of the commit. */
char id[SIZEOF_REV]; /* SHA1 ID. */
char title[128]; /* First line of the commit message. */
const char *author; /* Author of the commit. */
- time_t time; /* Date from the author ident. */
+ struct time time; /* Date from the author ident. */
struct ref_list *refs; /* Repository references. */
chtype graph[SIZEOF_REVGRAPH]; /* Ancestry chain graphics. */
size_t graph_size; /* The width of the graph array. */
struct ref_list *refs; /* Repository references. */
chtype graph[SIZEOF_REVGRAPH]; /* Ancestry chain graphics. */
size_t graph_size; /* The width of the graph array. */
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
};
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
};
+static inline unsigned char
+utf8_char_length(const char *string, const char *end)
+{
+ int c = *(unsigned char *) string;
+
+ return utf8_bytes[c];
+}
+
/* Decode UTF-8 multi-byte representation into a Unicode character. */
static inline unsigned long
utf8_to_unicode(const char *string, size_t length)
/* Decode UTF-8 multi-byte representation into a Unicode character. */
static inline unsigned long
utf8_to_unicode(const char *string, size_t length)
@@ -6782,8 +6876,7 @@ utf8_length(const char **start, size_t skip, int *width, size_t max_width, int *
*trimmed = 0;
while (string < end) {
*trimmed = 0;
while (string < end) {
- int c = *(unsigned char *) string;
- unsigned char bytes = utf8_bytes[c];
+ unsigned char bytes = utf8_char_length(string, end);
size_t ucwidth;
unsigned long unicode;
size_t ucwidth;
unsigned long unicode;
}
static void
}
static void
-foreach_ref(bool (*visitor)(void *data, struct ref *ref), void *data)
+foreach_ref(bool (*visitor)(void *data, const struct ref *ref), void *data)
{
size_t i;
{
size_t i;
if (!opt_git_dir[0] && request != REQ_VIEW_PAGER)
die("Not a git repository");
if (!opt_git_dir[0] && request != REQ_VIEW_PAGER)
die("Not a git repository");
- if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
- opt_utf8 = FALSE;
+ if (*opt_encoding && strcmp(opt_codeset, "UTF-8")) {
+ opt_iconv_in = iconv_open("UTF-8", opt_encoding);
+ if (opt_iconv_in == ICONV_NONE)
+ die("Failed to initialize character set conversion");
+ }
- if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
- opt_iconv = iconv_open(opt_codeset, opt_encoding);
- if (opt_iconv == ICONV_NONE)
+ if (*opt_codeset && strcmp(opt_codeset, "UTF-8")) {
+ opt_iconv_out = iconv_open(opt_codeset, "UTF-8");
+ if (opt_iconv_out == ICONV_NONE)
die("Failed to initialize character set conversion");
}
die("Failed to initialize character set conversion");
}