+static bool
+status_update_file(struct view *view, struct status *status, 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;
+
+ switch (type) {
+ case LINE_STAT_STAGED:
+ if (!string_format_from(buf, &bufsize, "%06o %s\t%s%c",
+ status->old.mode,
+ status->old.rev,
+ status->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->name, 0))
+ return FALSE;
+
+ string_add(cmd, cmdsize, "git update-index -z --add --remove --stdin");
+ break;
+
+ default:
+ die("w00t");
+ }
+
+ pipe = popen(cmd, "w");
+ if (!pipe)
+ return FALSE;
+
+ while (!ferror(pipe) && written < bufsize) {
+ written += fwrite(buf + written, 1, bufsize - written, pipe);
+ }
+
+ pclose(pipe);
+
+ if (written != bufsize)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+status_update(struct view *view)
+{
+ if (view == VIEW(REQ_VIEW_STATUS)) {
+ struct line *line = &view->line[view->lineno];
+
+ assert(view->lines);
+
+ if (!line->data) {
+ if (line[1].type == LINE_STAT_NONE) {
+ report("Nothing to update");
+ return;
+ }
+
+ while (++line < view->line + view->lines && line->data) {
+ if (!status_update_file(view, line->data, line->type))
+ report("Failed to update file status");
+ }
+
+ } else if (!status_update_file(view, line->data, line->type)) {
+ report("Failed to update file status");
+ }
+
+ open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD);
+ } else {
+ report("This action is only valid for the status view");
+ }
+}
+
+static void
+status_select(struct view *view, struct line *line)
+{
+ char *text;
+
+ switch (line->type) {
+ case LINE_STAT_STAGED:
+ text = "Press %s to unstage file for commit";
+ break;
+
+ case LINE_STAT_UNSTAGED:
+ text = "Press %s to stage file for commit ";
+ break;
+
+ case LINE_STAT_UNTRACKED:
+ text = "Press %s to stage file for addition";
+ break;
+
+ case LINE_STAT_NONE:
+ return;
+
+ default:
+ die("w00t");
+ }
+
+ string_format(view->ref, text, get_key(REQ_STATUS_UPDATE));
+}
+
+static bool
+status_grep(struct view *view, struct line *line)
+{
+ struct status *status = line->data;
+ enum { S_STATUS, S_NAME, S_END } state;
+ char buf[2] = "?";
+ regmatch_t pmatch;
+
+ if (!status)
+ return FALSE;
+
+ for (state = S_STATUS; state < S_END; state++) {
+ char *text;
+
+ switch (state) {
+ case S_NAME: text = status->name; break;
+ case S_STATUS:
+ buf[0] = status->status;
+ text = buf;
+ break;
+
+ default:
+ return FALSE;
+ }