Refactor add_line_text parts into add_line_data; use it in main_read
[tig] / tig.c
diff --git a/tig.c b/tig.c
index 5e75b5a..ca380a3 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -173,6 +173,9 @@ string_ncopy_do(char *dst, size_t dstlen, const char *src, size_t srclen)
 #define string_ncopy(dst, src, srclen) \
        string_ncopy_do(dst, sizeof(dst), src, srclen)
 
+#define string_copy_rev(dst, src) \
+       string_ncopy_do(dst, SIZEOF_REV, src, SIZEOF_REV - 1)
+
 static char *
 chomp_string(char *name)
 {
@@ -870,7 +873,7 @@ get_key(enum request request)
        static char buf[BUFSIZ];
        static char key_char[] = "'X'";
        size_t pos = 0;
-       char *sep = "    ";
+       char *sep = "";
        int i;
 
        buf[pos] = 0;
@@ -1231,10 +1234,12 @@ struct view {
 struct view_ops {
        /* What type of content being displayed. Used in the title bar. */
        const char *type;
-       /* Draw one line; @lineno must be < view->height. */
-       bool (*draw)(struct view *view, struct line *line, unsigned int lineno, bool selected);
+       /* Open and reads in all view content. */
+       bool (*open)(struct view *view);
        /* Read one line; updates view->line. */
        bool (*read)(struct view *view, char *data);
+       /* Draw one line; @lineno must be < view->height. */
+       bool (*draw)(struct view *view, struct line *line, unsigned int lineno, bool selected);
        /* Depending on view, change display based on current line. */
        bool (*enter)(struct view *view, struct line *line);
        /* Search for regex in a line. */
@@ -1247,6 +1252,7 @@ static struct view_ops pager_ops;
 static struct view_ops main_ops;
 static struct view_ops tree_ops;
 static struct view_ops blob_ops;
+static struct view_ops help_ops;
 
 #define VIEW_STR(name, cmd, env, ref, ops, map) \
        { name, cmd, #env, ref, ops, map}
@@ -1261,8 +1267,8 @@ static struct view views[] = {
        VIEW_(LOG,   "log",   &pager_ops, ref_head),
        VIEW_(TREE,  "tree",  &tree_ops,  ref_commit),
        VIEW_(BLOB,  "blob",  &blob_ops,  ref_blob),
-       VIEW_(HELP,  "help",  &pager_ops, "static"),
-       VIEW_(PAGER, "pager", &pager_ops, "static"),
+       VIEW_(HELP,  "help",  &help_ops,  ""),
+       VIEW_(PAGER, "pager", &pager_ops, ""),
 };
 
 #define VIEW(req) (&views[(req) - REQ_OFFSET - 1])
@@ -1783,9 +1789,10 @@ begin_update(struct view *view)
        if (opt_cmd[0]) {
                string_copy(view->cmd, opt_cmd);
                opt_cmd[0] = 0;
-               /* When running random commands, the view ref could have become
-                * invalid so clear it. */
-               view->ref[0] = 0;
+               /* When running random commands, initially show the
+                * command in the title. However, it maybe later be
+                * overwritten if a commit line is selected. */
+               string_copy(view->ref, view->cmd);
 
        } else if (view == VIEW(REQ_VIEW_TREE)) {
                const char *format = view->cmd_env ? view->cmd_env : view->cmd_fmt;
@@ -1804,6 +1811,12 @@ begin_update(struct view *view)
 
                if (!string_format(view->cmd, format, id, id, id, id, id))
                        return FALSE;
+
+               /* Put the current ref_* value to the view title ref
+                * member. This is needed by the blob view. Most other
+                * views sets it automatically after loading because the
+                * first line is a commit line. */
+               string_copy(view->ref, id);
        }
 
        /* Special case for the pager view. */
@@ -1822,7 +1835,7 @@ begin_update(struct view *view)
        view->offset = 0;
        view->lines  = 0;
        view->lineno = 0;
-       string_copy(view->vid, id);
+       string_copy_rev(view->vid, id);
 
        if (view->line) {
                int i;
@@ -1970,65 +1983,30 @@ end:
 }
 
 static struct line *
-add_line_text(struct view *view, char *data, enum line_type type)
+add_line_data(struct view *view, void *data, enum line_type type)
 {
-       struct line *line = &view->line[view->lines];
-
-       if (!data)
-               return NULL;
-
-       line->data = strdup(data);
-       if (!line->data)
-               return NULL;
+       struct line *line = &view->line[view->lines++];
 
+       memset(line, 0, sizeof(*line));
        line->type = type;
-       view->lines++;
+       line->data = data;
 
        return line;
 }
 
-
-/*
- * View opening
- */
-
-static void open_help_view(struct view *view)
+static struct line *
+add_line_text(struct view *view, char *data, enum line_type type)
 {
-       char buf[BUFSIZ];
-       int lines = ARRAY_SIZE(req_info) + 2;
-       int i;
+       if (data)
+               data = strdup(data);
 
-       if (view->lines > 0)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(req_info); i++)
-               if (!req_info[i].request)
-                       lines++;
-
-       view->line = calloc(lines, sizeof(*view->line));
-       if (!view->line) {
-               report("Allocation failure");
-               return;
-       }
-
-       add_line_text(view, "Quick reference for tig keybindings:", LINE_DEFAULT);
-
-       for (i = 0; i < ARRAY_SIZE(req_info); i++) {
-               char *key;
-
-               if (!req_info[i].request) {
-                       add_line_text(view, "", LINE_DEFAULT);
-                       add_line_text(view, req_info[i].help, LINE_DEFAULT);
-                       continue;
-               }
+       return data ? add_line_data(view, data, type) : NULL;
+}
 
-               key = get_key(req_info[i].request);
-               if (!string_format(buf, "%-25s %s", key, req_info[i].help))
-                       continue;
 
-               add_line_text(view, buf, LINE_DEFAULT);
-       }
-}
+/*
+ * View opening
+ */
 
 enum open_flags {
        OPEN_DEFAULT = 0,       /* Use default view switching. */
@@ -2052,8 +2030,11 @@ open_view(struct view *prev, enum request request, enum open_flags flags)
                return;
        }
 
-       if (view == VIEW(REQ_VIEW_HELP)) {
-               open_help_view(view);
+       if (view->ops->open) {
+               if (!view->ops->open(view)) {
+                       report("Failed to load %s view", view->name);
+                       return;
+               }
 
        } else if ((reload || strcmp(view->vid, view->id)) &&
                   !begin_update(view)) {
@@ -2141,16 +2122,27 @@ view_driver(struct view *view, enum request request)
 
        case REQ_VIEW_BLOB:
                if (!ref_blob[0]) {
-                       report("No file chosen, press 't' to open tree view");
+                       report("No file chosen, press %s to open tree view",
+                              get_key(REQ_VIEW_TREE));
                        break;
                }
-               /* Fall-through */
+               open_view(view, request, OPEN_DEFAULT);
+               break;
+
+       case REQ_VIEW_PAGER:
+               if (!VIEW(REQ_VIEW_PAGER)->lines) {
+                       report("No pager content, press %s to run command from prompt",
+                              get_key(REQ_PROMPT));
+                       break;
+               }
+               open_view(view, request, OPEN_DEFAULT);
+               break;
+
        case REQ_VIEW_MAIN:
        case REQ_VIEW_DIFF:
        case REQ_VIEW_LOG:
        case REQ_VIEW_TREE:
        case REQ_VIEW_HELP:
-       case REQ_VIEW_PAGER:
                open_view(view, request, OPEN_DEFAULT);
                break;
 
@@ -2486,17 +2478,73 @@ static void
 pager_select(struct view *view, struct line *line)
 {
        if (line->type == LINE_COMMIT) {
-               char *text = line->data;
+               char *text = line->data + STRING_SIZE("commit ");
 
-               string_copy(view->ref, text + STRING_SIZE("commit "));
-               string_copy(ref_commit, view->ref);
+               if (view != VIEW(REQ_VIEW_PAGER))
+                       string_copy_rev(view->ref, text);
+               string_copy_rev(ref_commit, text);
        }
 }
 
 static struct view_ops pager_ops = {
        "line",
-       pager_draw,
+       NULL,
        pager_read,
+       pager_draw,
+       pager_enter,
+       pager_grep,
+       pager_select,
+};
+
+
+/*
+ * Help backend
+ */
+
+static bool
+help_open(struct view *view)
+{
+       char buf[BUFSIZ];
+       int lines = ARRAY_SIZE(req_info) + 2;
+       int i;
+
+       if (view->lines > 0)
+               return TRUE;
+
+       for (i = 0; i < ARRAY_SIZE(req_info); i++)
+               if (!req_info[i].request)
+                       lines++;
+
+       view->line = calloc(lines, sizeof(*view->line));
+       if (!view->line)
+               return FALSE;
+
+       add_line_text(view, "Quick reference for tig keybindings:", LINE_DEFAULT);
+
+       for (i = 0; i < ARRAY_SIZE(req_info); i++) {
+               char *key;
+
+               if (!req_info[i].request) {
+                       add_line_text(view, "", LINE_DEFAULT);
+                       add_line_text(view, req_info[i].help, LINE_DEFAULT);
+                       continue;
+               }
+
+               key = get_key(req_info[i].request);
+               if (!string_format(buf, "    %-25s %s", key, req_info[i].help))
+                       continue;
+
+               add_line_text(view, buf, LINE_DEFAULT);
+       }
+
+       return TRUE;
+}
+
+static struct view_ops help_ops = {
+       "line",
+       help_open,
+       NULL,
+       pager_draw,
        pager_enter,
        pager_grep,
        pager_select,
@@ -2664,27 +2712,23 @@ tree_enter(struct view *view, struct line *line)
 static void
 tree_select(struct view *view, struct line *line)
 {
-       char *text = line->data;
-
-       text += STRING_SIZE("100644 blob ");
+       char *text = line->data + STRING_SIZE("100644 blob ");
 
        if (line->type == LINE_TREE_FILE) {
-               string_ncopy(ref_blob, text, 40);
-               /* Also update the blob view's ref, since all there must always
-                * be in sync. */
-               string_copy(VIEW(REQ_VIEW_BLOB)->ref, ref_blob);
+               string_copy_rev(ref_blob, text);
 
        } else if (line->type != LINE_TREE_DIR) {
                return;
        }
 
-       string_ncopy(view->ref, text, 40);
+       string_copy_rev(view->ref, text);
 }
 
 static struct view_ops tree_ops = {
        "file",
-       pager_draw,
+       NULL,
        tree_read,
+       pager_draw,
        tree_enter,
        pager_grep,
        tree_select,
@@ -2698,8 +2742,9 @@ blob_read(struct view *view, char *line)
 
 static struct view_ops blob_ops = {
        "line",
-       pager_draw,
+       NULL,
        blob_read,
+       pager_draw,
        pager_enter,
        pager_grep,
        pager_select,
@@ -3046,10 +3091,10 @@ main_read(struct view *view, char *line)
 
                line += STRING_SIZE("commit ");
 
-               view->line[view->lines++].data = commit;
-               string_copy(commit->id, line);
+               string_copy_rev(commit->id, line);
                commit->refs = get_refs(commit->id);
                graph->commit = commit;
+               add_line_data(view, commit, LINE_MAIN_COMMIT);
                break;
 
        case LINE_PARENT:
@@ -3182,14 +3227,15 @@ main_select(struct view *view, struct line *line)
 {
        struct commit *commit = line->data;
 
-       string_copy(view->ref, commit->id);
-       string_copy(ref_commit, view->ref);
+       string_copy_rev(view->ref, commit->id);
+       string_copy_rev(ref_commit, view->ref);
 }
 
 static struct view_ops main_ops = {
        "commit",
-       main_draw,
+       NULL,
        main_read,
+       main_draw,
        main_enter,
        main_grep,
        main_select,
@@ -3620,7 +3666,7 @@ read_ref(char *id, int idlen, char *name, int namelen)
        ref->name[namelen] = 0;
        ref->tag = tag;
        ref->remote = remote;
-       string_copy(ref->id, id);
+       string_copy_rev(ref->id, id);
 
        return OK;
 }