From b9247a4639adcfa4e8f816d75c62917575757619 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Tue, 17 Feb 2009 12:32:51 +0100 Subject: [PATCH] Add support for displaying relative dates Also unifies all date formats to use the show-date option and the toggle-date action. --- NEWS | 4 +- tig.c | 123 ++++++++++++++++++++++++++++++++++++++++++++-------- tigrc.5.txt | 13 +++--- 3 files changed, 113 insertions(+), 27 deletions(-) diff --git a/NEWS b/NEWS index e56ecf7..dffb43d 100644 --- a/NEWS +++ b/NEWS @@ -11,8 +11,8 @@ Incompatibilities: Improvements: - - Add ability to shorten the date column to just show the date and not - the date and time. Bound to 'T' by default. + - Add ability to toggle between showing shorter dates (without time + info) and relative dates. Use 'D' to toggle between date formats. - Show the active (instead of the default) keybindings in the help view. Furthermore, honor the keymap when suggesting actions in the help messages. diff --git a/tig.c b/tig.c index 5482140..f43ec7f 100644 --- a/tig.c +++ b/tig.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -340,12 +341,75 @@ suffixcmp(const char *str, int slen, const char *suffix) } -static const char * -mkdate(const time_t *time) +/* + * 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; + + t = time; + localtime_r(&t, &tm); + t_local = mktime(&tm); + + 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; +} + +enum date { + DATE_NONE = 0, + DATE_DEFAULT, + DATE_RELATIVE, + DATE_SHORT +}; + +static char * +string_date(const time_t *time, enum date date) { static char buf[DATE_COLS + 1]; + static const struct enum_map reldate[] = { + { "second", 1, 60 * 2 }, + { "minute", 60, 60 * 60 * 2 }, + { "hour", 60 * 60, 60 * 60 * 24 * 2 }, + { "day", 60 * 60 * 24, 60 * 60 * 24 * 7 * 2 }, + { "week", 60 * 60 * 24 * 7, 60 * 60 * 24 * 7 * 5 }, + { "month", 60 * 60 * 24 * 30, 60 * 60 * 24 * 30 * 12 }, + }; struct tm tm; + if (date == DATE_RELATIVE) { + struct timeval now; + time_t date = *time + local_tzoffset(*time); + time_t seconds; + int i; + + gettimeofday(&now, NULL); + seconds = now.tv_sec < date ? date - now.tv_sec : now.tv_sec - date; + for (i = 0; i < ARRAY_SIZE(reldate); i++) { + if (seconds >= reldate[i].value) + continue; + + seconds /= reldate[i].namelen; + if (!string_format(buf, "%ld %s%s %s", + seconds, reldate[i].name, + seconds > 1 ? "s" : "", + now.tv_sec >= date ? "ago" : "ahead")) + break; + return buf; + } + } + gmtime_r(time, &tm); return strftime(buf, sizeof(buf), DATE_FORMAT, &tm) ? buf : NULL; } @@ -902,8 +966,7 @@ get_request(const char *name) */ /* Option and state variables. */ -static bool opt_date = TRUE; -static bool opt_date_short = FALSE; +static enum date opt_date = DATE_DEFAULT; static bool opt_author = TRUE; static bool opt_line_number = FALSE; static bool opt_line_graphics = TRUE; @@ -934,6 +997,7 @@ static FILE *opt_tty = NULL; #define is_initial_commit() (!*opt_head_rev) #define is_head_commit(rev) (!strcmp((rev), "HEAD") || !strcmp(opt_head_rev, (rev))) +#define mkdate(time) string_date(time, opt_date) /* @@ -1160,7 +1224,6 @@ static const struct keybinding default_keybindings[] = { { 'o', REQ_OPTIONS }, { '.', REQ_TOGGLE_LINENO }, { 'D', REQ_TOGGLE_DATE }, - { 'T', REQ_TOGGLE_DATE_SHORT }, { 'A', REQ_TOGGLE_AUTHOR }, { 'g', REQ_TOGGLE_REV_GRAPH }, { 'F', REQ_TOGGLE_REFS }, @@ -1621,11 +1684,20 @@ option_set_command(int argc, const char *argv[]) if (!strcmp(argv[0], "show-author")) return parse_bool(&opt_author, argv[2]); - if (!strcmp(argv[0], "show-date")) - return parse_bool(&opt_date, argv[2]); - - if (!strcmp(argv[0], "date-short")) - return parse_bool(&opt_date_short, 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; + } if (!strcmp(argv[0], "show-rev-graph")) return parse_bool(&opt_rev_graph, argv[2]); @@ -2078,7 +2150,7 @@ static bool draw_date(struct view *view, time_t *time) { const char *date = mkdate(time); - int cols = opt_date_short ? DATE_SHORT_COLS : DATE_COLS; + int cols = opt_date == DATE_SHORT ? DATE_SHORT_COLS : DATE_COLS; return draw_field(view, LINE_DATE, date, cols, FALSE); } @@ -2357,6 +2429,21 @@ redraw_display(bool clear) } } +static void +toggle_date_option(enum date *date) +{ + static const char *help[] = { + "no", + "default", + "relative", + "short" + }; + + opt_date = (opt_date + 1) % ARRAY_SIZE(help); + redraw_display(FALSE); + report("Displaying %s dates", help[opt_date]); +} + static void toggle_view_option(bool *option, const char *help) { @@ -2378,8 +2465,12 @@ open_option_menu(void) }; int selected = 0; - if (prompt_menu("Toggle option", menu, &selected)) - toggle_view_option(menu[selected].data, menu[selected].text); + if (prompt_menu("Toggle option", menu, &selected)) { + if (menu[selected].data == &opt_date) + toggle_date_option(menu[selected].data); + else + toggle_view_option(menu[selected].data, menu[selected].text); + } } static void @@ -3372,11 +3463,7 @@ view_driver(struct view *view, enum request request) break; case REQ_TOGGLE_DATE: - toggle_view_option(&opt_date, "date display"); - break; - - case REQ_TOGGLE_DATE_SHORT: - toggle_view_option(&opt_date_short, "date shortening"); + toggle_date_option(&opt_date); break; case REQ_TOGGLE_AUTHOR: diff --git a/tigrc.5.txt b/tigrc.5.txt index 618761d..3ead320 100644 --- a/tigrc.5.txt +++ b/tigrc.5.txt @@ -42,6 +42,7 @@ Examples: -------------------------------------------------------------------------- set show-author = yes # Show author? +set show-date = relative # Show relative commit date. set show-rev-graph = yes # Show revision graph? set show-refs = yes # Show references? set show-line-numbers = no # Show line numbers? @@ -86,18 +87,18 @@ Variables The following variables can be set: 'show-author' (bool):: -'show-date' (bool):: 'show-rev-graph' (bool):: 'show-refs' (bool):: - Whether to show author, date, revision graph, and references + Whether to show author, revision graph, and references (branches, tags, and remotes) in the main view on start-up. Can all be toggled. -'date-short' (bool):: +'show-date' (bool or "relative" or "short"):: - Whether to shorten the date column in the main view to just the date - on startup. Can be toggled. + Whether and how to show date. If set to "relative" a relative date will be + used, e.g. "2 minutes ago". If set to "short" no time information is + shown. Can be toggled. 'author-width' (int):: @@ -139,7 +140,6 @@ The following variables can be set: The encoding used for commits. The default is UTF-8. Not this option is shadowed by the "i18n.commitencoding" option in `.git/config`. - Bind command ------------ @@ -345,7 +345,6 @@ stop-loading Stop all loading views options Open options menu toggle-lineno Toggle line numbers toggle-date Toggle date display -toggle-date-short Toggle short (date-only) dates toggle-author Toggle author display toggle-rev-graph Toggle revision graph visualization toggle-refs Toggle reference display -- 2.30.2