stage: disable whitespace warnings from git apply when staging updates
[tig] / tig.c
diff --git a/tig.c b/tig.c
index a54e57a..466fc2d 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -2278,18 +2278,6 @@ open_view(struct view *prev, enum request request, enum open_flags flags)
                return;
        }
 
-       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)) {
-               report("Failed to load %s view", view->name);
-               return;
-       }
-
        if (split) {
                display[1] = view;
                if (!backgrounded)
@@ -2307,6 +2295,18 @@ open_view(struct view *prev, enum request request, enum open_flags flags)
            (nviews == 1 && base_view != display[0]))
                resize_display();
 
+       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)) {
+               report("Failed to load %s view", view->name);
+               return;
+       }
+
        if (split && prev->lineno - prev->offset >= prev->height) {
                /* Take the title line into account. */
                int lines = prev->lineno - prev->offset - prev->height + 1;
@@ -3414,9 +3414,9 @@ parse_blame_commit(struct view *view, char *text, int *blamed)
 
                blame = line->data;
                blame->commit = commit;
+               blame->header = !group;
                line->dirty = 1;
        }
-       blame->header = 1;
 
        return commit;
 }
@@ -3964,6 +3964,8 @@ status_open(struct view *view)
                prev_lineno = view->lines - 1;
        while (prev_lineno < view->lines && !view->line[prev_lineno].data)
                prev_lineno++;
+       while (prev_lineno > 0 && !view->line[prev_lineno].data)
+               prev_lineno--;
 
        /* If the above fails, always skip the "On branch" line. */
        if (prev_lineno < view->lines)
@@ -3971,6 +3973,11 @@ status_open(struct view *view)
        else
                view->lineno = 1;
 
+       if (view->lineno < view->offset)
+               view->offset = view->lineno;
+       else if (view->offset + view->height <= view->lineno)
+               view->offset = view->lineno - view->height + 1;
+
        return TRUE;
 }
 
@@ -4136,61 +4143,110 @@ status_enter(struct view *view, struct line *line)
 }
 
 
-static bool
-status_update_file(struct view *view, struct status *status, enum line_type type)
+static FILE *
+status_update_prepare(enum line_type type)
 {
        char cmd[SIZEOF_STR];
-       char buf[SIZEOF_STR];
        size_t cmdsize = 0;
-       size_t bufsize = 0;
-       size_t written = 0;
-       FILE *pipe;
 
        if (opt_cdup[0] &&
            type != LINE_STAT_UNTRACKED &&
            !string_format_from(cmd, &cmdsize, "cd %s;", opt_cdup))
-               return FALSE;
+               return NULL;
+
+       switch (type) {
+       case LINE_STAT_STAGED:
+               string_add(cmd, cmdsize, "git update-index -z --index-info");
+               break;
+
+       case LINE_STAT_UNSTAGED:
+       case LINE_STAT_UNTRACKED:
+               string_add(cmd, cmdsize, "git update-index -z --add --remove --stdin");
+               break;
+
+       default:
+               die("line type %d not handled in switch", type);
+       }
+
+       return popen(cmd, "w");
+}
+
+static bool
+status_update_write(FILE *pipe, struct status *status, enum line_type type)
+{
+       char buf[SIZEOF_STR];
+       size_t bufsize = 0;
+       size_t written = 0;
 
        switch (type) {
        case LINE_STAT_STAGED:
                if (!string_format_from(buf, &bufsize, "%06o %s\t%s%c",
-                                       status->old.mode,
+                                       status->old.mode,
                                        status->old.rev,
                                        status->old.name, 0))
                        return FALSE;
-
-               string_add(cmd, cmdsize, "git update-index -z --index-info");
                break;
 
        case LINE_STAT_UNSTAGED:
        case LINE_STAT_UNTRACKED:
                if (!string_format_from(buf, &bufsize, "%s%c", status->new.name, 0))
                        return FALSE;
-
-               string_add(cmd, cmdsize, "git update-index -z --add --remove --stdin");
                break;
 
-       case LINE_STAT_HEAD:
-               return TRUE;
-
        default:
                die("line type %d not handled in switch", type);
        }
 
-       pipe = popen(cmd, "w");
-       if (!pipe)
-               return FALSE;
-
        while (!ferror(pipe) && written < bufsize) {
                written += fwrite(buf + written, 1, bufsize - written, pipe);
        }
 
+       return written == bufsize;
+}
+
+static bool
+status_update_file(struct status *status, enum line_type type)
+{
+       FILE *pipe = status_update_prepare(type);
+       bool result;
+
+       if (!pipe)
+               return FALSE;
+
+       result = status_update_write(pipe, status, type);
        pclose(pipe);
+       return result;
+}
+
+static bool
+status_update_files(struct view *view, struct line *line)
+{
+       FILE *pipe = status_update_prepare(line->type);
+       bool result = TRUE;
+       struct line *pos = view->line + view->lines;
+       int files = 0;
+       int file, done;
 
-       if (written != bufsize)
+       if (!pipe)
                return FALSE;
 
-       return TRUE;
+       for (pos = line; pos < view->line + view->lines && pos->data; pos++)
+               files++;
+
+       for (file = 0, done = 0; result && file < files; line++, file++) {
+               int almost_done = file * 100 / files;
+
+               if (almost_done > done) {
+                       done = almost_done;
+                       string_format(view->ref, "updating file %u of %u (%d%% done)",
+                                     file, files, done);
+                       update_view_title(view);
+               }
+               result = status_update_write(pipe, line->data, line->type);
+       }
+
+       pclose(pipe);
+       return result;
 }
 
 static bool
@@ -4201,17 +4257,16 @@ status_update(struct view *view)
        assert(view->lines);
 
        if (!line->data) {
-               while (++line < view->line + view->lines && line->data) {
-                       if (!status_update_file(view, line->data, line->type))
-                               report("Failed to update file status");
-               }
-
-               if (!line[-1].data) {
+               /* This should work even for the "On branch" line. */
+               if (line < view->line + view->lines && !line[1].data) {
                        report("Nothing to update");
                        return FALSE;
                }
 
-       } else if (!status_update_file(view, line->data, line->type)) {
+               if (!status_update_files(view, line + 1))
+                       report("Failed to update file status");
+
+       } else if (!status_update_file(line->data, line->type)) {
                report("Failed to update file status");
        }
 
@@ -4415,7 +4470,7 @@ stage_update_chunk(struct view *view, struct line *line)
                return FALSE;
 
        if (!string_format_from(cmd, &cmdsize,
-                               "git apply --cached %s - && "
+                               "git apply --whitespace=nowarn --cached %s - && "
                                "git update-index -q --unmerged --refresh 2>/dev/null",
                                stage_line_type == LINE_STAT_STAGED ? "-R" : ""))
                return FALSE;
@@ -4477,7 +4532,7 @@ stage_update(struct view *view, struct line *line)
                        return;
                }
 
-       } else if (!status_update_file(view, &stage_status, stage_line_type)) {
+       } else if (!status_update_file(&stage_status, stage_line_type)) {
                report("Failed to update file");
                return;
        }