Code

get_author_initials: various fixes
[tig.git] / tig.c
diff --git a/tig.c b/tig.c
index ac053b3510349b777f604a6bf13cb63d986387de..b0032ea67a9fd869b658fa3e984c38007a6250d6 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -61,38 +61,21 @@ struct menu_item {
 
 static bool prompt_menu(const char *prompt, const struct menu_item *items, int *selected);
 
-enum graphic {
-       GRAPHIC_ASCII = 0,
-       GRAPHIC_DEFAULT,
-       GRAPHIC_UTF8
-};
+#define GRAPHIC_ENUM(_) \
+       _(GRAPHIC, ASCII), \
+       _(GRAPHIC, DEFAULT), \
+       _(GRAPHIC, UTF_8)
 
-static const struct enum_map graphic_map[] = {
-#define GRAPHIC_(name) ENUM_MAP(#name, GRAPHIC_##name)
-       GRAPHIC_(ASCII),
-       GRAPHIC_(DEFAULT),
-       GRAPHIC_(UTF8)
-#undef GRAPHIC_
-};
+DEFINE_ENUM(graphic, GRAPHIC_ENUM);
 
-#define DATE_INFO \
-       DATE_(NO), \
-       DATE_(DEFAULT), \
-       DATE_(LOCAL), \
-       DATE_(RELATIVE), \
-       DATE_(SHORT)
-
-enum date {
-#define DATE_(name) DATE_##name
-       DATE_INFO
-#undef DATE_
-};
+#define DATE_ENUM(_) \
+       _(DATE, NO), \
+       _(DATE, DEFAULT), \
+       _(DATE, LOCAL), \
+       _(DATE, RELATIVE), \
+       _(DATE, SHORT)
 
-static const struct enum_map date_map[] = {
-#define DATE_(name) ENUM_MAP(#name, DATE_##name)
-       DATE_INFO
-#undef DATE_
-};
+DEFINE_ENUM(date, DATE_ENUM);
 
 struct time {
        time_t sec;
@@ -154,23 +137,12 @@ mkdate(const struct time *time, enum date date)
 }
 
 
-#define AUTHOR_VALUES \
-       AUTHOR_(NO), \
-       AUTHOR_(FULL), \
-       AUTHOR_(ABBREVIATED)
+#define AUTHOR_ENUM(_) \
+       _(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_
-};
+DEFINE_ENUM(author, AUTHOR_ENUM);
 
 static const char *
 get_author_initials(const char *author)
@@ -186,19 +158,27 @@ get_author_initials(const char *author)
                unsigned char bytes;
                size_t i;
 
-               while (is_initial_sep(*author))
+               while (author < end && is_initial_sep(*author))
                        author++;
 
                bytes = utf8_char_length(author, end);
-               if (bytes < sizeof(initials) - 1 - pos) {
-                       while (bytes--) {
-                               initials[pos++] = *author++;
-                       }
+               if (bytes >= sizeof(initials) - 1 - pos)
+                       break;
+               while (bytes--) {
+                       initials[pos++] = *author++;
                }
 
-               for (i = pos; author < end && !is_initial_sep(*author); author++) {
-                       if (i < sizeof(initials) - 1)
-                               initials[i++] = *author;
+               i = pos;
+               while (author < end && !is_initial_sep(*author)) {
+                       bytes = utf8_char_length(author, end);
+                       if (bytes >= sizeof(initials) - 1 - i) {
+                               while (author < end && !is_initial_sep(*author))
+                                       author++;
+                               break;
+                       }
+                       while (bytes--) {
+                               initials[i++] = *author++;
+                       }
                }
 
                initials[i++] = 0;
@@ -207,6 +187,38 @@ get_author_initials(const char *author)
        return initials;
 }
 
+#define author_trim(cols) (cols == 0 || cols > 5)
+
+static const char *
+mkauthor(const char *text, int cols, enum author author)
+{
+       bool trim = author_trim(cols);
+       bool abbreviate = author == AUTHOR_ABBREVIATED || !trim;
+
+       if (author == AUTHOR_NO)
+               return "";
+       if (abbreviate && text)
+               return get_author_initials(text);
+       return text;
+}
+
+static const char *
+mkmode(mode_t mode)
+{
+       if (S_ISDIR(mode))
+               return "drwxr-xr-x";
+       else if (S_ISLNK(mode))
+               return "lrwxrwxrwx";
+       else if (S_ISGITLINK(mode))
+               return "m---------";
+       else if (S_ISREG(mode) && mode & S_IXUSR)
+               return "-rwxr-xr-x";
+       else if (S_ISREG(mode))
+               return "-rw-r--r--";
+       else
+               return "----------";
+}
+
 
 /*
  * User requests
@@ -337,7 +349,7 @@ get_request(const char *name)
 /* Option and state variables. */
 static enum graphic opt_line_graphics  = GRAPHIC_DEFAULT;
 static enum date opt_date              = DATE_DEFAULT;
-static enum author opt_author          = AUTHOR_DEFAULT;
+static enum author opt_author          = AUTHOR_FULL;
 static bool opt_rev_graph              = TRUE;
 static bool opt_line_number            = FALSE;
 static bool opt_show_refs              = TRUE;
@@ -627,40 +639,30 @@ static struct keybinding default_keybindings[] = {
        { 'e',          REQ_EDIT },
 };
 
-#define KEYMAP_INFO \
-       KEYMAP_(GENERIC), \
-       KEYMAP_(MAIN), \
-       KEYMAP_(DIFF), \
-       KEYMAP_(LOG), \
-       KEYMAP_(TREE), \
-       KEYMAP_(BLOB), \
-       KEYMAP_(BLAME), \
-       KEYMAP_(BRANCH), \
-       KEYMAP_(PAGER), \
-       KEYMAP_(HELP), \
-       KEYMAP_(STATUS), \
-       KEYMAP_(STAGE)
-
-enum keymap {
-#define KEYMAP_(name) KEYMAP_##name
-       KEYMAP_INFO
-#undef KEYMAP_
-};
+#define KEYMAP_ENUM(_) \
+       _(KEYMAP, GENERIC), \
+       _(KEYMAP, MAIN), \
+       _(KEYMAP, DIFF), \
+       _(KEYMAP, LOG), \
+       _(KEYMAP, TREE), \
+       _(KEYMAP, BLOB), \
+       _(KEYMAP, BLAME), \
+       _(KEYMAP, BRANCH), \
+       _(KEYMAP, PAGER), \
+       _(KEYMAP, HELP), \
+       _(KEYMAP, STATUS), \
+       _(KEYMAP, STAGE)
 
-static const struct enum_map keymap_table[] = {
-#define KEYMAP_(name) ENUM_MAP(#name, KEYMAP_##name)
-       KEYMAP_INFO
-#undef KEYMAP_
-};
+DEFINE_ENUM(keymap, KEYMAP_ENUM);
 
-#define set_keymap(map, name) map_enum(map, keymap_table, name)
+#define set_keymap(map, name) map_enum(map, keymap_map, name)
 
 struct keybinding_table {
        struct keybinding *data;
        size_t size;
 };
 
-static struct keybinding_table keybindings[ARRAY_SIZE(keymap_table)];
+static struct keybinding_table keybindings[ARRAY_SIZE(keymap_map)];
 
 static void
 add_keybinding(enum keymap keymap, enum request request, int key)
@@ -1483,7 +1485,7 @@ static struct view views[] = {
        VIEW_(BRANCH, "branch", &branch_ops, TRUE,  ref_head),
        VIEW_(HELP,   "help",   &help_ops,   FALSE, ""),
        VIEW_(PAGER,  "pager",  &pager_ops,  FALSE, ""),
-       VIEW_(STATUS, "status", &status_ops, TRUE,  ""),
+       VIEW_(STATUS, "status", &status_ops, TRUE,  "status"),
        VIEW_(STAGE,  "stage",  &stage_ops,  TRUE,  ""),
 };
 
@@ -1654,35 +1656,19 @@ draw_date(struct view *view, struct time *time)
 static bool
 draw_author(struct view *view, const char *author)
 {
-       bool trim = opt_author_cols == 0 || opt_author_cols > 5;
-       bool abbreviate = opt_author == AUTHOR_ABBREVIATED || !trim;
+       bool trim = author_trim(opt_author_cols);
+       const char *text = mkauthor(author, opt_author_cols, opt_author);
 
        if (opt_author == AUTHOR_NO)
                return FALSE;
 
-       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, text, opt_author_cols, trim);
 }
 
 static bool
 draw_mode(struct view *view, mode_t mode)
 {
-       const char *str;
-
-       if (S_ISDIR(mode))
-               str = "drwxr-xr-x";
-       else if (S_ISLNK(mode))
-               str = "lrwxrwxrwx";
-       else if (S_ISGITLINK(mode))
-               str = "m---------";
-       else if (S_ISREG(mode) && mode & S_IXUSR)
-               str = "-rwxr-xr-x";
-       else if (S_ISREG(mode))
-               str = "-rw-r--r--";
-       else
-               str = "----------";
+       const char *str = mkmode(mode);
 
        return draw_field(view, LINE_MODE, str, STRING_SIZE("-rw-r--r-- "), FALSE);
 }
@@ -1711,6 +1697,43 @@ draw_lineno(struct view *view, unsigned int lineno)
        return draw_graphic(view, LINE_DEFAULT, &separator, 1, TRUE);
 }
 
+static bool
+draw_refs(struct view *view, struct ref_list *refs)
+{
+       size_t i;
+
+       if (!opt_show_refs || !refs)
+               return FALSE;
+
+       for (i = 0; i < refs->size; i++) {
+               struct ref *ref = refs->refs[i];
+               enum line_type type;
+
+               if (ref->head)
+                       type = LINE_MAIN_HEAD;
+               else if (ref->ltag)
+                       type = LINE_MAIN_LOCAL_TAG;
+               else if (ref->tag)
+                       type = LINE_MAIN_TAG;
+               else if (ref->tracked)
+                       type = LINE_MAIN_TRACKED;
+               else if (ref->remote)
+                       type = LINE_MAIN_REMOTE;
+               else
+                       type = LINE_MAIN_REF;
+
+               if (draw_text(view, type, "[") ||
+                   draw_text(view, type, ref->name) ||
+                   draw_text(view, type, "]"))
+                       return TRUE;
+
+               if (draw_text(view, LINE_DEFAULT, " "))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 static bool
 draw_view_line(struct view *view, unsigned int lineno)
 {
@@ -2500,15 +2523,6 @@ setup_update(struct view *view, const char *vid)
        view->start_time = time(NULL);
 }
 
-static bool
-prepare_update(struct view *view, const char *dir, const char *argv[])
-{
-       if (view->pipe)
-               io_done(view->pipe);
-       view->dir = dir;
-       return argv_copy(&view->argv, argv);
-}
-
 static bool
 begin_update(struct view *view, const char *dir, const char **argv, enum open_flags flags)
 {
@@ -2714,6 +2728,7 @@ load_view(struct view *view, enum open_flags flags)
 }
 
 #define refresh_view(view) load_view(view, OPEN_REFRESH)
+#define reload_view(view) load_view(view, OPEN_RELOAD)
 
 static void
 split_view(struct view *prev, struct view *view)
@@ -2777,7 +2792,11 @@ open_argv(struct view *prev, struct view *view, const char *argv[], const char *
 {
        enum request request = view - views + REQ_OFFSET + 1;
 
-       if (!prepare_update(view, dir, argv)) {
+       if (view->pipe)
+               end_update(view, TRUE);
+       view->dir = dir;
+       
+       if (!argv_copy(&view->argv, argv)) {
                report("Failed to open %s view: %s", view->name, io_strerror(&view->io));
        } else {
                open_view(prev, request, flags | OPEN_PREPARED);
@@ -2787,17 +2806,9 @@ open_argv(struct view *prev, struct view *view, const char *argv[], const char *
 static void
 open_file(struct view *prev, struct view *view, const char *file, enum open_flags flags)
 {
-       enum request request = view - views + REQ_OFFSET + 1;
        const char *file_argv[] = { opt_cdup, file , NULL };
 
-       if (view->pipe)
-               end_update(view, TRUE);
-       view->dir = opt_cdup;
-       if (!argv_copy(&view->argv, file_argv)) {
-               report("Failed to load %s: out of memory", file);
-       } else {
-               open_view(prev, request, flags | OPEN_PREPARED);
-       }
+       open_argv(prev, view, file_argv, opt_cdup, flags); 
 }
 
 static void
@@ -3449,7 +3460,7 @@ static struct view_ops diff_ops = {
  * Help backend
  */
 
-static bool help_keymap_hidden[ARRAY_SIZE(keymap_table)];
+static bool help_keymap_hidden[ARRAY_SIZE(keymap_map)];
 
 static bool
 help_open_keymap_title(struct view *view, enum keymap keymap)
@@ -3458,7 +3469,7 @@ help_open_keymap_title(struct view *view, enum keymap keymap)
 
        line = add_line_format(view, LINE_HELP_KEYMAP, "[%c] %s bindings",
                               help_keymap_hidden[keymap] ? '+' : '-',
-                              enum_name(keymap_table[keymap]));
+                              enum_name(keymap_map[keymap]));
        if (line)
                line->other = keymap;
 
@@ -3541,7 +3552,7 @@ help_open(struct view *view, enum open_flags flags)
        add_line_text(view, "Quick reference for tig keybindings:", LINE_DEFAULT);
        add_line_text(view, "", LINE_DEFAULT);
 
-       for (keymap = 0; keymap < ARRAY_SIZE(keymap_table); keymap++)
+       for (keymap = 0; keymap < ARRAY_SIZE(keymap_map); keymap++)
                help_open_keymap(view, keymap);
 
        return TRUE;
@@ -3976,7 +3987,7 @@ tree_grep(struct view *view, struct line *line)
        struct tree_entry *entry = line->data;
        const char *text[] = {
                entry->name,
-               opt_author ? entry->author : "",
+               mkauthor(entry->author, opt_author_cols, opt_author),
                mkdate(&entry->time, opt_date),
                NULL
        };
@@ -4122,11 +4133,10 @@ blame_open(struct view *view, enum open_flags flags)
 
        if (*opt_ref || !begin_update(view, opt_cdup, file_argv, flags)) {
                const char *blame_cat_file_argv[] = {
-                       "git", "cat-file", "blob", path, NULL
+                       "git", "cat-file", "blob", "%(ref):%(file)", NULL
                };
 
-               if (!string_format(path, "%s:%s", opt_ref, opt_file) ||
-                   !begin_update(view, opt_cdup, blame_cat_file_argv, flags))
+               if (!begin_update(view, opt_cdup, blame_cat_file_argv, flags))
                        return FALSE;
        }
 
@@ -4148,7 +4158,7 @@ blame_open(struct view *view, enum open_flags flags)
                        free(blame->commit);
        }
 
-       string_format(view->vid, "%s:%s", opt_ref, opt_file);
+       string_format(view->vid, "%s", opt_file);
        string_format(view->ref, "%s ...", opt_file);
 
        return TRUE;
@@ -4425,7 +4435,7 @@ blame_request(struct view *view, enum request request, struct line *line)
                        string_copy(opt_file, blame->commit->filename);
                        if (blame->lineno)
                                view->lineno = blame->lineno;
-                       refresh_view(view);
+                       reload_view(view);
                }
                break;
 
@@ -4438,7 +4448,7 @@ blame_request(struct view *view, enum request request, struct line *line)
                        string_copy_rev(opt_ref, blame->commit->parent_id);
                        string_copy(opt_file, blame->commit->parent_filename);
                        setup_blame_parent_line(view, blame);
-                       refresh_view(view);
+                       reload_view(view);
                }
                break;
 
@@ -4691,7 +4701,7 @@ branch_grep(struct view *view, struct line *line)
        struct branch *branch = line->data;
        const char *text[] = {
                branch->ref->name,
-               branch->author,
+               mkauthor(branch->author, opt_author_cols, opt_author),
                NULL
        };
 
@@ -5807,35 +5817,8 @@ main_draw(struct view *view, struct line *line, unsigned int lineno)
        if (opt_rev_graph && draw_graph(view, &commit->graph))
                return TRUE;
 
-       if (opt_show_refs && commit->refs) {
-               size_t i;
-
-               for (i = 0; i < commit->refs->size; i++) {
-                       struct ref *ref = commit->refs->refs[i];
-                       enum line_type type;
-
-                       if (ref->head)
-                               type = LINE_MAIN_HEAD;
-                       else if (ref->ltag)
-                               type = LINE_MAIN_LOCAL_TAG;
-                       else if (ref->tag)
-                               type = LINE_MAIN_TAG;
-                       else if (ref->tracked)
-                               type = LINE_MAIN_TRACKED;
-                       else if (ref->remote)
-                               type = LINE_MAIN_REMOTE;
-                       else
-                               type = LINE_MAIN_REF;
-
-                       if (draw_text(view, type, "[") ||
-                           draw_text(view, type, ref->name) ||
-                           draw_text(view, type, "]"))
-                               return TRUE;
-
-                       if (draw_text(view, LINE_DEFAULT, " "))
-                               return TRUE;
-               }
-       }
+       if (draw_refs(view, commit->refs))
+               return TRUE;
 
        draw_text(view, LINE_DEFAULT, commit->title);
        return TRUE;
@@ -5972,7 +5955,7 @@ main_grep(struct view *view, struct line *line)
        struct commit *commit = line->data;
        const char *text[] = {
                commit->title,
-               opt_author ? commit->author : "",
+               mkauthor(commit->author, opt_author_cols, opt_author),
                mkdate(&commit->time, opt_date),
                NULL
        };