Commit d68a0a7de13af722c55099582019c03240e13320

Stefan Sperling 2018-07-10T13:47:25

implement cleaner cancellation of tog's blame view

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();