Code

Add support for displaying relative dates
authorJonas Fonseca <fonseca@diku.dk>
Tue, 17 Feb 2009 11:32:51 +0000 (12:32 +0100)
committerJonas Fonseca <fonseca@diku.dk>
Fri, 13 Nov 2009 11:55:21 +0000 (06:55 -0500)
Also unifies all date formats to use the show-date option and the
toggle-date action.

NEWS
tig.c
tigrc.5.txt

diff --git a/NEWS b/NEWS
index e56ecf7e096be54cd931ae2f62fba468b9577d2c..dffb43d11b8411a898f465419610b7011a579e49 100644 (file)
--- 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 54821405ed627ab290c3c5b366b3710151703ffa..f43ec7f7db4074fb0d1d5966d2590579be6b639e 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -36,6 +36,7 @@
 #include <sys/stat.h>
 #include <sys/select.h>
 #include <unistd.h>
+#include <sys/time.h>
 #include <time.h>
 #include <fcntl.h>
 
@@ -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:
index 618761d91014662dc8c6192933cdb9d4289993e2..3ead320ee54e3bc4d05f4526e1ea226cf22595f8 100644 (file)
@@ -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