commit - 5fd747092ffe82320b62b9558c94e28f899f9c36
commit + 3aa55f1085484754656826a13fbb625b01dd06b4
blob - 0f8f83ded2fa834467a0c0bef5de29b3578ddcaa
blob + 6e0e4df78865c58469ef88303ebfa3222886178f
--- tog/tog.1
+++ tog/tog.1
If the diff was opened via the
.Cm blame
view, move to the Nth next line and load the corresponding commit (default: 1).
+.It Cm p
+Write the currently viewed diff to a patch file in
+.Pa /tmp .
+The patch pathname is drawn to the status line.
.It Cm /
Prompt for a search pattern and start searching for matching lines.
The search pattern is an extended regular expression.
blob - 0f56f886631ecd1dfdabbe67cf92f044e0cc49c4
blob + 098e4b046181f90210370e992a808076c688abc6
--- tog/tog.c
+++ tog/tog.c
struct tog_diff_view_state {
struct got_object_id *id1, *id2;
const char *label1, *label2;
+ char *action;
FILE *f, *f1, *f2;
int fd1, fd2;
int lineno;
KEY_("A", "Toggle between Myers and Patience diff algorithm"), \
KEY_("a", "Toggle treatment of file as ASCII irrespective of binary" \
" data"), \
+ KEY_("p", "Write diff to a patch file in /tmp"), \
KEY_("(", "Go to the previous file in the diff"), \
KEY_(")", "Go to the next file in the diff"), \
KEY_("{", "Go to the previous hunk in the diff"), \
/*
* Clear action status report. Only clear in blame view
* once annotating is complete, otherwise it's too fast.
+ * In diff view, let its state control view->action lifetime.
*/
if (view->type == TOG_VIEW_BLAME) {
if (view->state.blame.blame_complete)
view->action = NULL;
+ } else if (view->type == TOG_VIEW_DIFF) {
+ view->action = view->state.diff.action;
} else
view->action = NULL;
}
s->id1 = NULL;
free(s->id2);
s->id2 = NULL;
+ free(s->action);
+ s->action = NULL;
if (s->f && fclose(s->f) == EOF)
err = got_error_from_errno("fclose");
s->f = NULL;
}
static const struct got_error *
+diff_write_patch(struct tog_view *view)
+{
+ const struct got_error *err;
+ struct tog_diff_view_state *s = &view->state.diff;
+ FILE *f;
+ char buf[BUFSIZ];
+ char *path;
+ size_t r;
+ off_t pos;
+
+ if (s->action != NULL) {
+ free(s->action);
+ s->action = NULL;
+ }
+
+ pos = ftello(s->f);
+ if (pos == -1)
+ return got_error_from_errno("ftello");
+ if (fseeko(s->f, 0L, SEEK_SET) == -1)
+ return got_error_from_errno("fseeko");
+
+ err = got_opentemp_named(&path, &f, GOT_TMPDIR_STR "/tog", ".diff");
+ if (err != NULL)
+ return err;
+
+ while ((r = fread(buf, 1, sizeof(buf), s->f)) > 0) {
+ if (fwrite(buf, 1, r, f) != r) {
+ err = got_ferror(f, GOT_ERR_IO);
+ goto done;
+ }
+ }
+
+ if (ferror(s->f)) {
+ err = got_error_from_errno("fread");
+ goto done;
+ }
+ if (fseeko(s->f, pos, SEEK_SET) == -1) {
+ err = got_error_from_errno("fseeko");
+ goto done;
+ }
+
+ if (fflush(f) == EOF) {
+ err = got_error_from_errno2("fflush", path);
+ goto done;
+ }
+
+ if (asprintf(&s->action, "patch file written to %s", path) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+
+ view->action = s->action;
+
+done:
+ if (f != NULL && fclose(f) == EOF && err == NULL)
+ err = got_error_from_errno2("fclose", path);
+ free(path);
+ return err;
+}
+
+static const struct got_error *
set_selected_commit(struct tog_diff_view_state *s,
struct commit_queue_entry *entry)
{
s->first_displayed_line = 1;
s->last_displayed_line = view->nlines;
s->matched_line = 0;
+ if (s->action != NULL) {
+ free(s->action);
+ s->action = NULL;
+ }
diff_view_indicate_progress(view);
return create_diff(s);
}
s->lineno = s->first_displayed_line - 1 + s->selected_line;
+ if (s->action != NULL && ch != ERR) {
+ free(s->action);
+ s->action = NULL;
+ view->action = NULL;
+ }
+
switch (ch) {
case '0':
case '$':
diff_view_indicate_progress(view);
err = create_diff(s);
+ break;
+ case 'p':
+ err = diff_write_patch(view);
break;
default:
view->count = 0;