Factor out cursor moving
[tig] / tig.c
diff --git a/tig.c b/tig.c
index cfdf026..f744657 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -63,6 +63,7 @@
 
 static void die(const char *err, ...);
 static void report(const char *msg, ...);
+static int read_properties(const char *cmd, int separator, int (*read)(char *, int, char *, int));
 static void set_nonblocking_input(bool loading);
 static size_t utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed);
 
@@ -236,6 +237,8 @@ static int opt_num_interval = NUMBER_INTERVAL;
 static int opt_tab_size                = TABSIZE;
 static enum request opt_request = REQ_VIEW_MAIN;
 static char opt_cmd[SIZEOF_CMD]        = "";
+static char opt_encoding[20]   = "";
+static bool opt_utf8           = TRUE;
 static FILE *opt_pipe          = NULL;
 
 /* Returns the index of log or diff command or -1 to exit. */
@@ -434,6 +437,9 @@ parse_options(int argc, char *argv[])
 
        }
 
+       if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
+               opt_utf8 = FALSE;
+
        return TRUE;
 }
 
@@ -900,7 +906,6 @@ resize_display(void)
                        wresize(view->win, view->height, view->width);
                        mvwin(view->win,   offset, 0);
                        mvwin(view->title, offset + view->height, 0);
-                       wrefresh(view->win);
                }
 
                offset += view->height + 1;
@@ -919,6 +924,20 @@ redraw_display(void)
        }
 }
 
+static void
+update_display_cursor(void)
+{
+       struct view *view = display[current_view];
+
+       /* Move the cursor to the right-most column of the cursor line.
+        *
+        * XXX: This could turn out to be a bit expensive, but it ensures that
+        * the cursor does not jump around. */
+       if (view->lines) {
+               wmove(view->win, view->lineno - view->offset, view->width - 1);
+               wrefresh(view->win);
+       }
+}
 
 /*
  * Navigation
@@ -1338,17 +1357,15 @@ open_view(struct view *prev, enum request request, enum open_flags flags)
        }
 
        if (prev && view != prev) {
-               /* Continue loading split views in the background. */
-               if (!split)
-                       end_update(prev);
-               else if (!backgrounded)
+               if (split && !backgrounded) {
                        /* "Blur" the previous view. */
                        update_view_title(prev);
+               }
 
                view->parent = prev;
        }
 
-       if (view->pipe) {
+       if (view->pipe && view->lines == 0) {
                /* Clear the old view and let the incremental updating refill
                 * the screen. */
                wclear(view->win);
@@ -1615,8 +1632,8 @@ pager_enter(struct view *view, struct line *line)
        scroll_view(view, REQ_SCROLL_LINE_DOWN);
 
        /* FIXME: A minor workaround. Scrolling the view will call report("")
-        * but if we are scolling a non-current view this won't properly update
-        * the view title. */
+        * but if we are scrolling a non-current view this won't properly
+        * update the view title. */
        if (split)
                update_view_title(view);
 
@@ -1652,7 +1669,7 @@ main_draw(struct view *view, struct line *line, unsigned int lineno)
        int col = 0;
        size_t timelen;
        size_t authorlen;
-       int trimmed;
+       int trimmed = 1;
 
        if (!*commit->author)
                return FALSE;
@@ -1680,8 +1697,15 @@ main_draw(struct view *view, struct line *line, unsigned int lineno)
        if (type != LINE_CURSOR)
                wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
 
-       /* FIXME: Make this optional, and add i18n.commitEncoding support. */
-       authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
+       if (opt_utf8) {
+               authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed);
+       } else {
+               authorlen = strlen(commit->author);
+               if (authorlen > AUTHOR_COLS - 2) {
+                       authorlen = AUTHOR_COLS - 2;
+                       trimmed = 1;
+               }
+       }
 
        if (trimmed) {
                waddnstr(view->win, commit->author, authorlen);
@@ -2194,15 +2218,7 @@ report(const char *msg, ...)
        }
 
        update_view_title(view);
-
-       /* Move the cursor to the right-most column of the cursor line.
-        *
-        * XXX: This could turn out to be a bit expensive, but it ensures that
-        * the cursor does not jump around. */
-       if (view->lines) {
-               wmove(view->win, view->lineno - view->offset, view->width - 1);
-               wrefresh(view->win);
-       }
+       update_display_cursor();
 }
 
 /* Controls when nodelay should be in effect when polling user input. */
@@ -2314,73 +2330,118 @@ get_refs(char *id)
 }
 
 static int
+read_ref(char *id, int idlen, char *name, int namelen)
+{
+       struct ref *ref;
+       bool tag = FALSE;
+       bool tag_commit = FALSE;
+
+       /* Commits referenced by tags has "^{}" appended. */
+       if (name[namelen - 1] == '}') {
+               while (namelen > 0 && name[namelen] != '^')
+                       namelen--;
+               if (namelen > 0)
+                       tag_commit = TRUE;
+               name[namelen] = 0;
+       }
+
+       if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
+               if (!tag_commit)
+                       return OK;
+               name += STRING_SIZE("refs/tags/");
+               tag = TRUE;
+
+       } else if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) {
+               name += STRING_SIZE("refs/heads/");
+
+       } else if (!strcmp(name, "HEAD")) {
+               return OK;
+       }
+
+       refs = realloc(refs, sizeof(*refs) * (refs_size + 1));
+       if (!refs)
+               return ERR;
+
+       ref = &refs[refs_size++];
+       ref->name = strdup(name);
+       if (!ref->name)
+               return ERR;
+
+       ref->tag = tag;
+       string_copy(ref->id, id);
+
+       return OK;
+}
+
+static int
 load_refs(void)
 {
        const char *cmd_env = getenv("TIG_LS_REMOTE");
        const char *cmd = cmd_env && *cmd_env ? cmd_env : TIG_LS_REMOTE;
+
+       return read_properties(cmd, '\t', read_ref);
+}
+
+static int
+read_config_option(char *name, int namelen, char *value, int valuelen)
+{
+       if (!strcmp(name, "i18n.commitencoding")) {
+               string_copy(opt_encoding, value);
+       }
+
+       return OK;
+}
+
+static int
+load_config(void)
+{
+       return read_properties("git repo-config --list", '=',
+                              read_config_option);
+}
+
+static int
+read_properties(const char *cmd, int separator,
+               int (*read_property)(char *, int, char *, int))
+{
        FILE *pipe = popen(cmd, "r");
        char buffer[BUFSIZ];
-       char *line;
+       char *name;
+       int state = OK;
 
        if (!pipe)
                return ERR;
 
-       while ((line = fgets(buffer, sizeof(buffer), pipe))) {
-               char *name = strchr(line, '\t');
-               struct ref *ref;
+       while (state == OK && (name = fgets(buffer, sizeof(buffer), pipe))) {
+               char *value = strchr(name, separator);
                int namelen;
-               bool tag = FALSE;
-               bool tag_commit = FALSE;
-
-               if (!name)
-                       continue;
-
-               *name++ = 0;
-               namelen = strlen(name) - 1;
-
-               /* Commits referenced by tags has "^{}" appended. */
-               if (name[namelen - 1] == '}') {
-                       while (namelen > 0 && name[namelen] != '^')
-                               namelen--;
-                       if (namelen > 0)
-                               tag_commit = TRUE;
-               }
-               name[namelen] = 0;
-
-               if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
-                       if (!tag_commit)
-                               continue;
-                       name += STRING_SIZE("refs/tags/");
-                       tag = TRUE;
+               int valuelen;
 
-               } else if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) {
-                       name += STRING_SIZE("refs/heads/");
+               if (value) {
+                       namelen = value - name;
+                       *value++ = 0;
+                       valuelen = strlen(value);
+                       if (valuelen > 0)
+                               value[valuelen - 1] = 0;
 
-               } else if (!strcmp(name, "HEAD")) {
-                       continue;
+               } else {
+                       namelen = strlen(name);
+                       value = "";
+                       valuelen = 0;
                }
 
-               refs = realloc(refs, sizeof(*refs) * (refs_size + 1));
-               if (!refs)
-                       return ERR;
-
-               ref = &refs[refs_size++];
-               ref->tag = tag;
-               ref->name = strdup(name);
-               if (!ref->name)
-                       return ERR;
-
-               string_copy(ref->id, line);
+               if (namelen)
+                       state = read_property(name, namelen, value, valuelen);
        }
 
-       if (ferror(pipe))
-               return ERR;
+       if (state != ERR && ferror(pipe))
+               state = ERR;
 
        pclose(pipe);
 
-       return OK;
+       return state;
 }
 
+
 /*
  * Main
  */
@@ -2425,6 +2486,11 @@ main(int argc, char *argv[])
 
        signal(SIGINT, quit);
 
+       /* Load the repo config file first so options can be overwritten from
+        * the command line.  */
+       if (load_config() == ERR)
+               die("Failed to load repo config.");
+
        if (!parse_options(argc, argv))
                return 0;
 
@@ -2624,10 +2690,12 @@ main(int argc, char *argv[])
  *
  * SEE ALSO
  * --------
- * [verse]
- * link:http://www.kernel.org/pub/software/scm/git/docs/[git(7)],
- * link:http://www.kernel.org/pub/software/scm/cogito/docs/[cogito(7)]
- * gitk(1): git repository browser written using tcl/tk,
- * qgit(1): git repository browser written using c++/Qt,
- * gitview(1): git repository browser written using python/gtk.
+ * - link:http://www.kernel.org/pub/software/scm/git/docs/[git(7)],
+ * - link:http://www.kernel.org/pub/software/scm/cogito/docs/[cogito(7)]
+ *
+ * Other git repository browsers:
+*
+ *  - gitk(1)
+ *  - qgit(1)
+ *  - gitview(1)
  **/