Code

Eliminate unneeded calls to redrawwin
[tig.git] / tig.c
diff --git a/tig.c b/tig.c
index f72932144b4d893db73720d3946da34d15b97ee7..4fac53286e2beeecda9b688d90fda3bac10f3eec 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -69,7 +69,6 @@ static void warn(const char *msg, ...);
 static void report(const char *msg, ...);
 static void set_nonblocking_input(bool loading);
 static size_t utf8_length(const char *string, int *width, size_t max_width, int *trimmed, bool reserve);
-static bool prompt_yesno(const char *prompt);
 static int load_refs(void);
 
 #define ABS(x)         ((x) >= 0  ? (x) : -(x))
@@ -171,6 +170,17 @@ set_from_int_map(struct int_map *map, size_t map_size,
        return ERR;
 }
 
+enum input_status {
+       INPUT_OK,
+       INPUT_SKIP,
+       INPUT_STOP,
+       INPUT_CANCEL
+};
+
+typedef enum input_status (*input_handler)(void *data, char *buf, int c);
+
+static char *prompt_input(const char *prompt, input_handler handler, void *data);
+static bool prompt_yesno(const char *prompt);
 
 /*
  * String helpers
@@ -2051,7 +2061,6 @@ redraw_view_dirty(struct view *view)
 
        if (!dirty)
                return;
-       redrawwin(view->win);
        if (input_mode)
                wnoutrefresh(view->win);
        else
@@ -2068,7 +2077,6 @@ redraw_view_from(struct view *view, int lineno)
                        break;
        }
 
-       redrawwin(view->win);
        if (input_mode)
                wnoutrefresh(view->win);
        else
@@ -2275,7 +2283,6 @@ do_scroll_view(struct view *view, int lines)
                        draw_view_line(view, view->lineno - view->offset);
        }
 
-       redrawwin(view->win);
        wrefresh(view->win);
        report("");
 }
@@ -2409,7 +2416,6 @@ move_view(struct view *view, enum request request)
        /* Draw the current line */
        draw_view_line(view, view->lineno - view->offset);
 
-       redrawwin(view->win);
        wrefresh(view->win);
        report("");
 }
@@ -2437,7 +2443,6 @@ select_view_line(struct view *view, unsigned long lineno)
                if (view_is_displayed(view)) {
                        draw_view_line(view, old_lineno);
                        draw_view_line(view, view->lineno - view->offset);
-                       redrawwin(view->win);
                        wrefresh(view->win);
                } else {
                        view->ops->select(view, &view->line[view->lineno]);
@@ -3327,6 +3332,60 @@ parse_author_line(char *ident, char *author, size_t authorsize, struct tm *tm)
        }
 }
 
+static enum input_status
+select_commit_parent_handler(void *data, char *buf, int c)
+{
+       size_t parents = *(size_t *) data;
+       int parent = 0;
+
+       if (!isdigit(c))
+               return INPUT_SKIP;
+
+       if (*buf)
+               parent = atoi(buf) * 10;
+       parent += c - '0';
+
+       if (parent > parents)
+               return INPUT_SKIP;
+       return INPUT_OK;
+}
+
+static bool
+select_commit_parent(const char *id, char rev[SIZEOF_REV])
+{
+       char buf[SIZEOF_STR * 4];
+       const char *revlist_argv[] = {
+               "git", "rev-list", "-1", "--parents", id, NULL
+       };
+       int parents;
+
+       if (!run_io_buf(revlist_argv, buf, sizeof(buf)) ||
+           !*chomp_string(buf) ||
+           (parents = (strlen(buf) / 40) - 1) < 0) {
+               report("Failed to get parent information");
+               return FALSE;
+
+       } else if (parents == 0) {
+               report("The selected commit has no parents");
+               return FALSE;
+       }
+
+       if (parents > 1) {
+               char prompt[SIZEOF_STR];
+               char *result;
+
+               if (!string_format(prompt, "Which parent? [1..%d] ", parents))
+                       return FALSE;
+               result = prompt_input(prompt, select_commit_parent_handler, &parents);
+               if (!result)
+                       return FALSE;
+               parents = atoi(result);
+       }
+
+       string_copy_rev(rev, &buf[41 * parents]);
+       return TRUE;
+}
+
 /*
  * Pager backend
  */
@@ -3545,22 +3604,13 @@ static struct view_ops diff_ops = {
 static bool
 help_open(struct view *view)
 {
-       int lines = ARRAY_SIZE(req_info) + 2;
+       char buf[SIZEOF_STR];
+       size_t bufpos;
        int i;
 
        if (view->lines > 0)
                return TRUE;
 
-       for (i = 0; i < ARRAY_SIZE(req_info); i++)
-               if (!req_info[i].request)
-                       lines++;
-
-       lines += run_requests + 1;
-
-       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++) {
@@ -3579,8 +3629,14 @@ help_open(struct view *view)
                if (!*key)
                        key = "(no key defined)";
 
-               add_line_format(view, LINE_DEFAULT, "    %-25s %s",
-                               key, req_info[i].help);
+               for (bufpos = 0; bufpos <= req_info[i].namelen; bufpos++) {
+                       buf[bufpos] = tolower(req_info[i].name[bufpos]);
+                       if (buf[bufpos] == '_')
+                               buf[bufpos] = '-';
+               }
+
+               add_line_format(view, LINE_DEFAULT, "    %-25s %-20s %s",
+                               key, buf, req_info[i].help);
        }
 
        if (run_requests) {
@@ -3591,8 +3647,6 @@ help_open(struct view *view)
        for (i = 0; i < run_requests; i++) {
                struct run_request *req = get_run_request(REQ_NONE + i + 1);
                const char *key;
-               char cmd[SIZEOF_STR];
-               size_t bufpos;
                int argc;
 
                if (!req)
@@ -3603,12 +3657,12 @@ help_open(struct view *view)
                        key = "(no key defined)";
 
                for (bufpos = 0, argc = 0; req->argv[argc]; argc++)
-                       if (!string_format_from(cmd, &bufpos, "%s%s",
+                       if (!string_format_from(buf, &bufpos, "%s%s",
                                                argc ? " " : "", req->argv[argc]))
                                return REQ_NONE;
 
                add_line_format(view, LINE_DEFAULT, "    %-10s %-14s `%s`",
-                               keymap_table[req->keymap].name, key, cmd);
+                               keymap_table[req->keymap].name, key, buf);
        }
 
        return TRUE;
@@ -4355,6 +4409,12 @@ blame_request(struct view *view, enum request request, struct line *line)
                }
                break;
 
+       case REQ_PARENT:
+               if (check_blame_commit(blame) &&
+                   select_commit_parent(blame->commit->id, opt_ref))
+                       open_view(view, REQ_VIEW_BLAME, OPEN_REFRESH);
+               break;
+
        case REQ_ENTER:
                if (!blame->commit) {
                        report("No commit loaded yet");
@@ -6195,54 +6255,16 @@ get_input(bool prompting)
        }
 }
 
-static bool
-prompt_yesno(const char *prompt)
-{
-       enum { WAIT, STOP, CANCEL  } status = WAIT;
-       bool answer = FALSE;
-
-       while (status == WAIT) {
-               int key;
-
-               mvwprintw(status_win, 0, 0, "%s [Yy]/[Nn]", prompt);
-               wclrtoeol(status_win);
-
-               key = get_input(TRUE);
-               switch (key) {
-               case 'y':
-               case 'Y':
-                       answer = TRUE;
-                       status = STOP;
-                       break;
-
-               case KEY_ESC:
-               case KEY_RETURN:
-               case KEY_ENTER:
-               case KEY_BACKSPACE:
-               case 'n':
-               case 'N':
-               case '\n':
-               default:
-                       answer = FALSE;
-                       status = CANCEL;
-               }
-       }
-
-       /* Clear the status window */
-       status_empty = FALSE;
-       report("");
-
-       return answer;
-}
-
 static char *
-read_prompt(const char *prompt)
+prompt_input(const char *prompt, input_handler handler, void *data)
 {
-       enum { READING, STOP, CANCEL } status = READING;
+       enum input_status status = INPUT_OK;
        static char buf[SIZEOF_STR];
-       int pos = 0;
+       size_t pos = 0;
+
+       buf[pos] = 0;
 
-       while (status == READING) {
+       while (status == INPUT_OK || status == INPUT_SKIP) {
                int key;
 
                mvwprintw(status_win, 0, 0, "%s%.*s", prompt, pos, buf);
@@ -6253,18 +6275,18 @@ read_prompt(const char *prompt)
                case KEY_RETURN:
                case KEY_ENTER:
                case '\n':
-                       status = pos ? STOP : CANCEL;
+                       status = pos ? INPUT_STOP : INPUT_CANCEL;
                        break;
 
                case KEY_BACKSPACE:
                        if (pos > 0)
-                               pos--;
+                               buf[--pos] = 0;
                        else
-                               status = CANCEL;
+                               status = INPUT_CANCEL;
                        break;
 
                case KEY_ESC:
-                       status = CANCEL;
+                       status = INPUT_CANCEL;
                        break;
 
                default:
@@ -6273,7 +6295,8 @@ read_prompt(const char *prompt)
                                return NULL;
                        }
 
-                       if (isprint(key))
+                       status = handler(data, buf, key);
+                       if (status == INPUT_OK)
                                buf[pos++] = (char) key;
                }
        }
@@ -6282,7 +6305,7 @@ read_prompt(const char *prompt)
        status_empty = FALSE;
        report("");
 
-       if (status == CANCEL)
+       if (status == INPUT_CANCEL)
                return NULL;
 
        buf[pos++] = 0;
@@ -6290,6 +6313,39 @@ read_prompt(const char *prompt)
        return buf;
 }
 
+static enum input_status
+prompt_yesno_handler(void *data, char *buf, int c)
+{
+       if (c == 'y' || c == 'Y')
+               return INPUT_STOP;
+       if (c == 'n' || c == 'N')
+               return INPUT_CANCEL;
+       return INPUT_SKIP;
+}
+
+static bool
+prompt_yesno(const char *prompt)
+{
+       char prompt2[SIZEOF_STR];
+
+       if (!string_format(prompt2, "%s [Yy/Nn]", prompt))
+               return FALSE;
+
+       return !!prompt_input(prompt2, prompt_yesno_handler, NULL);
+}
+
+static enum input_status
+read_prompt_handler(void *data, char *buf, int c)
+{
+       return isprint(c) ? INPUT_OK : INPUT_SKIP;
+}
+
+static char *
+read_prompt(const char *prompt)
+{
+       return prompt_input(prompt, read_prompt_handler, NULL);
+}
+
 /*
  * Repository properties
  */