X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=tig.c;h=f9d23ab53026e12236854ab0c168ebb783b6f91b;hb=0007343a51f71b0fa74c6874fb81f86b5c3b0df9;hp=fa0c806fffe9a76f93426ed0fbacf236029e0c97;hpb=a0ab665dc528e4314da21b5cb3a2c2ba953b6c89;p=tig.git diff --git a/tig.c b/tig.c index fa0c806..f9d23ab 100644 --- a/tig.c +++ b/tig.c @@ -519,6 +519,7 @@ utf8_length(const char **start, size_t skip, int *width, size_t max_width, int * #define DATE_INFO \ DATE_(NO), \ DATE_(DEFAULT), \ + DATE_(LOCAL), \ DATE_(RELATIVE), \ DATE_(SHORT) @@ -583,7 +584,13 @@ mkdate(const struct time *time, enum date date) } } - gmtime_r(&time->sec, &tm); + if (date == DATE_LOCAL) { + time_t date = time->sec + time->tz; + localtime_r(&date, &tm); + } + else { + gmtime_r(&time->sec, &tm); + } return strftime(buf, sizeof(buf), DATE_FORMAT, &tm) ? buf : NULL; } @@ -671,6 +678,15 @@ argv_from_env(const char **argv, const char *name) return !env || argv_from_string(argv, &argc, env); } +static void +argv_free(const char *argv[]) +{ + int argc; + + for (argc = 0; argv[argc]; argc++) + free((void *) argv[argc]); +} + /* * Executing external commands. @@ -1166,7 +1182,8 @@ enum request { #define REQ_(req, help) REQ_##req /* Offset all requests to avoid conflicts with ncurses getch values. */ - REQ_OFFSET = KEY_MAX + 1, + REQ_UNKNOWN = KEY_MAX + 1, + REQ_OFFSET, REQ_INFO #undef REQ_GROUP @@ -1198,7 +1215,7 @@ get_request(const char *name) if (enum_equals(req_info[i], name, namelen)) return req_info[i].request; - return REQ_NONE; + return REQ_UNKNOWN; } @@ -1271,6 +1288,8 @@ LINE(AUTHOR, "author ", COLOR_GREEN, COLOR_DEFAULT, 0), \ LINE(COMMITTER, "committer ", COLOR_MAGENTA, COLOR_DEFAULT, 0), \ LINE(SIGNOFF, " Signed-off-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \ LINE(ACKED, " Acked-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \ +LINE(TESTED, " Tested-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \ +LINE(REVIEWED, " Reviewed-by", COLOR_YELLOW, COLOR_DEFAULT, 0), \ LINE(DEFAULT, "", COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), \ LINE(CURSOR, "", COLOR_WHITE, COLOR_GREEN, A_BOLD), \ LINE(STATUS, "", COLOR_GREEN, COLOR_DEFAULT, 0), \ @@ -1404,7 +1423,7 @@ struct keybinding { enum request request; }; -static const struct keybinding default_keybindings[] = { +static struct keybinding default_keybindings[] = { /* View switching */ { 'm', REQ_VIEW_MAIN }, { 'd', REQ_VIEW_DIFF }, @@ -1514,12 +1533,28 @@ static void add_keybinding(enum keymap keymap, enum request request, int key) { struct keybinding_table *table = &keybindings[keymap]; + size_t i; + + for (i = 0; i < keybindings[keymap].size; i++) { + if (keybindings[keymap].data[i].alias == key) { + keybindings[keymap].data[i].request = request; + return; + } + } table->data = realloc(table->data, (table->size + 1) * sizeof(*table->data)); if (!table->data) die("Failed to allocate keybinding"); table->data[table->size].alias = key; table->data[table->size++].request = request; + + if (request == REQ_NONE && keymap == KEYMAP_GENERIC) { + int i; + + for (i = 0; i < ARRAY_SIZE(default_keybindings); i++) + if (default_keybindings[i].alias == key) + default_keybindings[i].request = REQ_NONE; + } } /* Looks for a key binding first in the given map, then in the generic map, and @@ -1746,8 +1781,10 @@ add_builtin_run_requests(void) int i; for (i = 0; i < ARRAY_SIZE(reqs); i++) { - enum request req; + enum request req = get_keybinding(reqs[i].keymap, reqs[i].key); + if (req != reqs[i].key) + continue; req = add_run_request(reqs[i].keymap, reqs[i].key, reqs[i].argc, reqs[i].argv); if (req != REQ_NONE) add_keybinding(reqs[i].keymap, req, reqs[i].key); @@ -1993,7 +2030,7 @@ option_bind_command(int argc, const char *argv[]) return ERR; } - if (set_keymap(&keymap, argv[0]) == ERR) { + if (!set_keymap(&keymap, argv[0])) { config_msg = "Unknown key map"; return ERR; } @@ -2005,7 +2042,7 @@ option_bind_command(int argc, const char *argv[]) } request = get_request(argv[2]); - if (request == REQ_NONE) { + if (request == REQ_UNKNOWN) { static const struct enum_map obsolete[] = { ENUM_MAP("cherry-pick", REQ_NONE), ENUM_MAP("screen-resize", REQ_NONE), @@ -2020,9 +2057,9 @@ option_bind_command(int argc, const char *argv[]) return ERR; } } - if (request == REQ_NONE && *argv[2]++ == '!') + if (request == REQ_UNKNOWN && *argv[2]++ == '!') request = add_run_request(keymap, key, argc - 2, argv + 2); - if (request == REQ_NONE) { + if (request == REQ_UNKNOWN) { config_msg = "Unknown request name"; return ERR; } @@ -2121,8 +2158,6 @@ load_options(void) const char *tigrc_system = getenv("TIGRC_SYSTEM"); char buf[SIZEOF_STR]; - add_builtin_run_requests(); - if (!tigrc_system) tigrc_system = SYSCONFDIR "/tigrc"; load_option_file(tigrc_system); @@ -2134,6 +2169,10 @@ load_options(void) } load_option_file(tigrc_user); + /* Add _after_ loading config files to avoid adding run requests + * that conflict with keybindings. */ + add_builtin_run_requests(); + return OK; } @@ -2160,7 +2199,22 @@ static char ref_commit[SIZEOF_REF] = "HEAD"; static char ref_head[SIZEOF_REF] = "HEAD"; static char ref_branch[SIZEOF_REF] = ""; +enum view_type { + VIEW_MAIN, + VIEW_DIFF, + VIEW_LOG, + VIEW_TREE, + VIEW_BLOB, + VIEW_BLAME, + VIEW_BRANCH, + VIEW_HELP, + VIEW_PAGER, + VIEW_STATUS, + VIEW_STAGE, +}; + struct view { + enum view_type type; /* View type */ const char *name; /* View name */ const char *cmd_env; /* Command line set via environment */ const char *id; /* Points to either of ref_{head,commit,blob} */ @@ -2194,6 +2248,7 @@ struct view { /* If non-NULL, points to the view that opened this view. If this view * is closed tig will switch back to the parent view. */ struct view *parent; + struct view *prev; /* Buffering */ size_t lines; /* Total number of lines */ @@ -2246,11 +2301,11 @@ static struct view_ops status_ops; static struct view_ops tree_ops; static struct view_ops branch_ops; -#define VIEW_STR(name, env, ref, ops, map, git, refresh) \ - { name, #env, ref, ops, map, git, refresh } +#define VIEW_STR(type, name, env, ref, ops, map, git, refresh) \ + { type, name, #env, ref, ops, map, git, refresh } #define VIEW_(id, name, ops, git, refresh, ref) \ - VIEW_STR(name, TIG_##id##_CMD, ref, ops, KEYMAP_##id, git, refresh) + VIEW_STR(VIEW_##id, name, TIG_##id##_CMD, ref, ops, KEYMAP_##id, git, refresh) static struct view views[] = { VIEW_(MAIN, "main", &main_ops, TRUE, TRUE, ref_head), @@ -2274,6 +2329,18 @@ static struct view views[] = { #define view_is_displayed(view) \ (view == display[0] || view == display[1]) +static enum request +view_request(struct view *view, enum request request) +{ + if (!view || !view->lines) + return request; + return view->ops->request(view, request, &view->line[view->lineno]); +} + + +/* + * View drawing. + */ static inline void set_view_attr(struct view *view, enum line_type type) @@ -2542,7 +2609,7 @@ update_view_title(struct view *view) assert(view_is_displayed(view)); - if (view != VIEW(REQ_VIEW_STATUS) && view->lines) { + if (view->type != VIEW_STATUS && view->lines) { unsigned int view_lines = view->offset + view->height; unsigned int lines = view->lines ? MIN(view_lines, view->lines) * 100 / view->lines @@ -2664,6 +2731,11 @@ redraw_display(bool clear) } } + +/* + * Option management + */ + static void toggle_enum_option_do(unsigned int *opt, const char *help, const struct enum_map *map, size_t size) @@ -3087,15 +3159,6 @@ reset_view(struct view *view) view->update_secs = 0; } -static void -free_argv(const char *argv[]) -{ - int argc; - - for (argc = 0; argv[argc]; argc++) - free((void *) argv[argc]); -} - static const char * format_arg(const char *name) { @@ -3132,7 +3195,7 @@ format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags fl int argc; bool noreplace = flags == FORMAT_NONE; - free_argv(dst_argv); + argv_free(dst_argv); for (argc = 0; src_argv[argc]; argc++) { const char *arg = src_argv[argc]; @@ -3321,7 +3384,7 @@ update_view(struct view *view) /* Keep the displayed view in sync with line number scaling. */ if (digits != view->digits) { view->digits = digits; - if (opt_line_number || view == VIEW(REQ_VIEW_BLAME)) + if (opt_line_number || view->type == VIEW_BLAME) redraw = TRUE; } } @@ -3331,7 +3394,8 @@ update_view(struct view *view) end_update(view, TRUE); } else if (io_eof(view->pipe)) { - report(""); + if (view_is_displayed(view)) + report(""); end_update(view, FALSE); } @@ -3428,6 +3492,7 @@ open_view(struct view *prev, enum request request, enum open_flags flags) if (split) { display[1] = view; current_view = 1; + view->parent = prev; } else if (!nomaximize) { /* Maximize the current view. */ memset(display, 0, sizeof(display)); @@ -3435,9 +3500,9 @@ open_view(struct view *prev, enum request request, enum open_flags flags) display[current_view] = view; } - /* No parent signals that this is the first loaded view. */ + /* No prev signals that this is the first loaded view. */ if (prev && view != prev) { - view->parent = prev; + view->prev = prev; } /* Resize the view when switching between split- and full-screen, @@ -3540,7 +3605,7 @@ open_run_request(enum request request) if (format_argv(argv, req->argv, FORMAT_ALL)) open_external_viewer(argv, NULL); - free_argv(argv); + argv_free(argv); } /* @@ -3564,11 +3629,9 @@ view_driver(struct view *view, enum request request) return TRUE; } - if (view && view->lines) { - request = view->ops->request(view, request, &view->line[view->lineno]); - if (request == REQ_NONE) - return TRUE; - } + request = view_request(view, request); + if (request == REQ_NONE) + return TRUE; switch (request) { case REQ_MOVE_UP: @@ -3646,16 +3709,7 @@ view_driver(struct view *view, enum request request) case REQ_PREVIOUS: request = request == REQ_NEXT ? REQ_MOVE_DOWN : REQ_MOVE_UP; - if ((view == VIEW(REQ_VIEW_DIFF) && - view->parent == VIEW(REQ_VIEW_MAIN)) || - (view == VIEW(REQ_VIEW_DIFF) && - view->parent == VIEW(REQ_VIEW_BLAME)) || - (view == VIEW(REQ_VIEW_STAGE) && - view->parent == VIEW(REQ_VIEW_STATUS)) || - (view == VIEW(REQ_VIEW_BLOB) && - view->parent == VIEW(REQ_VIEW_TREE)) || - (view == VIEW(REQ_VIEW_MAIN) && - view->parent == VIEW(REQ_VIEW_BRANCH))) { + if (view->parent) { int line; view = view->parent; @@ -3664,9 +3718,7 @@ view_driver(struct view *view, enum request request) if (view_is_displayed(view)) update_view_title(view); if (line != view->lineno) - view->ops->request(view, REQ_ENTER, - &view->line[view->lineno]); - + view_request(view, REQ_ENTER); } else { move_view(view, request); } @@ -3761,13 +3813,12 @@ view_driver(struct view *view, enum request request) break; case REQ_VIEW_CLOSE: - /* XXX: Mark closed views by letting view->parent point to the + /* XXX: Mark closed views by letting view->prev point to the * view itself. Parents to closed view should never be * followed. */ - if (view->parent && - view->parent->parent != view->parent) { - maximize_view(view->parent); - view->parent = view; + if (view->prev && view->prev != view) { + maximize_view(view->prev); + view->prev = view; break; } /* Fall-through */ @@ -3875,8 +3926,8 @@ parse_timezone(struct time *time, const char *zone) tz = ('0' - zone[1]) * 60 * 60 * 10; tz += ('0' - zone[2]) * 60 * 60; - tz += ('0' - zone[3]) * 60; - tz += ('0' - zone[4]); + tz += ('0' - zone[3]) * 60 * 10; + tz += ('0' - zone[4]) * 60; if (zone[0] == '-') tz = -tz; @@ -3976,7 +4027,9 @@ select_commit_parent(const char *id, char rev[SIZEOF_REV], const char *path) return FALSE; } - if (parents > 1 && !open_commit_parent_menu(buf, &parents)) + if (parents == 1) + parents = 0; + else if (!open_commit_parent_menu(buf, &parents)) return FALSE; string_copy_rev(rev, &buf[41 * parents]); @@ -4030,7 +4083,7 @@ add_pager_refs(struct view *view, struct line *line) list = get_ref_list(commit_id); if (!list) { - if (view == VIEW(REQ_VIEW_DIFF)) + if (view->type == VIEW_DIFF) goto try_add_describe_ref; return; } @@ -4047,7 +4100,7 @@ add_pager_refs(struct view *view, struct line *line) is_tag = TRUE; } - if (!is_tag && view == VIEW(REQ_VIEW_DIFF)) { + if (!is_tag && view->type == VIEW_DIFF) { try_add_describe_ref: /* Add -g "fake" reference. */ if (!add_describe_ref(buf, &bufpos, commit_id, sep)) @@ -4073,8 +4126,8 @@ pager_read(struct view *view, char *data) return FALSE; if (line->type == LINE_COMMIT && - (view == VIEW(REQ_VIEW_DIFF) || - view == VIEW(REQ_VIEW_LOG))) + (view->type == VIEW_DIFF || + view->type == VIEW_LOG)) add_pager_refs(view, line); return TRUE; @@ -4089,8 +4142,8 @@ pager_request(struct view *view, enum request request, struct line *line) return request; if (line->type == LINE_COMMIT && - (view == VIEW(REQ_VIEW_LOG) || - view == VIEW(REQ_VIEW_PAGER))) { + (view->type == VIEW_LOG || + view->type == VIEW_PAGER)) { open_view(view, REQ_VIEW_DIFF, OPEN_SPLIT); split = 1; } @@ -4123,7 +4176,7 @@ pager_select(struct view *view, struct line *line) if (line->type == LINE_COMMIT) { char *text = (char *)line->data + STRING_SIZE("commit "); - if (view != VIEW(REQ_VIEW_PAGER)) + if (view->type != VIEW_PAGER) string_copy_rev(view->ref, text); string_copy_rev(ref_commit, text); } @@ -4613,14 +4666,15 @@ tree_draw(struct view *view, struct line *line, unsigned int lineno) } static void -open_blob_editor() +open_blob_editor(const char *id) { + const char *blob_argv[] = { "git", "cat-file", "blob", id, NULL }; char file[SIZEOF_STR] = "/tmp/tigblob.XXXXXX"; int fd = mkstemp(file); if (fd == -1) report("Failed to create temporary file"); - else if (!io_run_append(blob_ops.argv, FORMAT_ALL, fd)) + else if (!io_run_append(blob_argv, FORMAT_NONE, fd)) report("Failed to save blob data to file"); else open_editor(file); @@ -4632,6 +4686,7 @@ static enum request tree_request(struct view *view, enum request request, struct line *line) { enum open_flags flags; + struct tree_entry *entry = line->data; switch (request) { case REQ_VIEW_BLAME: @@ -4647,7 +4702,7 @@ tree_request(struct view *view, enum request request, struct line *line) if (line->type != LINE_TREE_FILE) { report("Edit only supported for files"); } else if (!is_head_commit(view->vid)) { - open_blob_editor(); + open_blob_editor(entry->id); } else { open_editor(opt_file); } @@ -4698,7 +4753,7 @@ tree_request(struct view *view, enum request request, struct line *line) break; case LINE_TREE_FILE: - flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT; + flags = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; request = REQ_VIEW_BLOB; break; @@ -4798,7 +4853,7 @@ blob_request(struct view *view, enum request request, struct line *line) { switch (request) { case REQ_EDIT: - open_blob_editor(); + open_blob_editor(view->vid); return REQ_NONE; default: return pager_request(view, request, line); @@ -4863,7 +4918,7 @@ blame_open(struct view *view) { char path[SIZEOF_STR]; - if (!view->parent && *opt_prefix) { + if (!view->prev && *opt_prefix) { string_copy(path, opt_file); if (!string_format(opt_file, "%s%s", opt_prefix, path)) return FALSE; @@ -4963,7 +5018,7 @@ blame_read_file(struct view *view, const char *line, bool *read_file) const char **argv = *opt_ref ? blame_ref_argv : blame_head_argv; struct io io = {}; - if (view->lines == 0 && !view->parent) + if (view->lines == 0 && !view->prev) die("No blame exist for %s", view->vid); if (view->lines == 0 || !io_run_rd(&io, argv, opt_cdup, FORMAT_ALL)) { @@ -5135,7 +5190,7 @@ setup_blame_parent_line(struct view *view, struct blame *blame) static enum request blame_request(struct view *view, enum request request, struct line *line) { - enum open_flags flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT; + enum open_flags flags = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; struct blame *blame = line->data; switch (request) { @@ -5861,7 +5916,7 @@ status_enter(struct view *view, struct line *line) die("line type %d not handled in switch", line->type); } - split = view_is_displayed(view) ? OPEN_SPLIT : 0; + split = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; open_view(view, REQ_VIEW_STAGE, OPEN_PREPARED | split); if (view_is_displayed(VIEW(REQ_VIEW_STAGE))) { if (status) { @@ -6741,7 +6796,7 @@ main_read(struct view *view, char *line) if (!line) { int i; - if (!view->lines && !view->parent) + if (!view->lines && !view->prev) die("No revisions match the given arguments."); if (view->lines > 0) { commit = view->line[view->lines - 1].data; @@ -6831,7 +6886,7 @@ main_read(struct view *view, char *line) static enum request main_request(struct view *view, enum request request, struct line *line) { - enum open_flags flags = display[0] == view ? OPEN_SPLIT : OPEN_DEFAULT; + enum open_flags flags = view_is_displayed(view) ? OPEN_SPLIT : OPEN_DEFAULT; switch (request) { case REQ_ENTER: @@ -7797,6 +7852,10 @@ main(int argc, const char *argv[]) /* Some low-level request handling. This keeps access to * status_win restricted. */ switch (request) { + case REQ_NONE: + report("Unknown key, press %s for help", + get_key(view->keymap, REQ_VIEW_HELP)); + break; case REQ_PROMPT: { char *cmd = read_prompt(":");