implement cleaner cancellation of tog's blame view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
diff --git a/include/got_blame.h b/include/got_blame.h
index c787aad..5255d07 100644
--- a/include/got_blame.h
+++ b/include/got_blame.h
@@ -28,6 +28,15 @@ const struct got_error *got_blame(const char *, struct got_object_id *,
* The callback receives the provided void * argument, the total number
* of lines of the annotated file, a line number, and the ID of the commit
* which last changed this line.
+ *
+ * The callback is invoked for each commit as history is traversed.
+ * If no changes to the file were made in a commit, line number -1 and
+ * commit ID NULL will be reported.
+ *
+ * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation
+ * will be aborted and this function returns NULL.
+ * If the callback returns any other error, the blame operation will be
+ * aborted and the callback's error is returned from this function.
*/
const struct got_error *got_blame_incremental(const char *,
struct got_object_id *, struct got_repository *,
diff --git a/lib/blame.c b/lib/blame.c
index c57eaab..a6ac4fe 100644
--- a/lib/blame.c
+++ b/lib/blame.c
@@ -132,7 +132,8 @@ blame_commit(struct got_blame *blame, struct got_object_id *id,
goto done;
}
}
- }
+ } else if (cb)
+ err = cb(arg, blame->nlines, -1, NULL);
done:
if (obj)
got_object_close(obj);
diff --git a/tog/tog.c b/tog/tog.c
index 5819996..400eda3 100644
--- a/tog/tog.c
+++ b/tog/tog.c
@@ -1136,16 +1136,25 @@ blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
struct tog_blame_line *line;
int eof;
- if (*a->done)
- return got_error(GOT_ERR_ITER_COMPLETED);
-
- if (nlines != a->nlines || lineno < 1 || lineno > a->nlines)
+ if (nlines != a->nlines ||
+ (lineno != -1 && lineno < 1) || lineno > a->nlines)
return got_error(GOT_ERR_RANGE);
if (pthread_mutex_lock(a->mutex) != 0)
return got_error_from_errno();
+ if (*a->done) { /* user has quit the blame view */
+ err = got_error(GOT_ERR_ITER_COMPLETED);
+ goto done;
+ }
+
+ if (lineno == -1)
+ goto done; /* no change in this commit */
+
line = &a->lines[lineno - 1];
+ if (line->annotated)
+ goto done;
+
line->id = got_object_id_dup(id);
if (line->id == NULL) {
err = got_error_from_errno();