commit - 41496140bd5c2fd2df772feec4b1eee2cbf0073a
commit + 15a087fe57324ab65b6527daace23842e1012306
blob - 52786231728d4b2061e98aa0073b0ac6ef585257
blob + bcece92cbc0a7fe3f89ffdf13c42951cd758d5ed
--- TODO
+++ TODO
- make diff view generate diffs in a background thread
- implement horizonal scrolling in all views
- implement horizonal split view mode
-- make it possible to move between commit diffs with a single key press
- implement search feature
blob - 2716958a93edd0cd2dd442cad2fa95093928383a
blob + 1ab6e36e950a8e5047ad602808a8e4dd51158283
--- tog/tog.1
+++ tog/tog.1
Reduce the amount of diff context lines.
.It Cm ]
Increase the amount of diff context lines.
+.It Cm <, Comma
+If the diff view was opened via the log view, move to the previous (younger)
+commit.
+.It Cm >, Full stop
+If the diff view was opened via the log view, move to the next (older) commit.
.El
.It Cm blame [ Fl c Ar commit ] [ Fl r Ar repository-path ] Ar path
Display line-by-line history of a file at the specified path.
blob - dfcd7578dc2c6fec0889929b939addb4f743f132
blob + 336187b3c54e4924e866a5793764ae26ae6de7ea
--- tog/tog.c
+++ tog/tog.c
TOG_VIEW_TREE
};
-struct tog_diff_view_state {
- struct got_object_id *id1, *id2;
- FILE *f;
- int first_displayed_line;
- int last_displayed_line;
- int eof;
- int diff_context;
- struct got_repository *repo;
-};
-
struct commit_queue_entry {
TAILQ_ENTRY(commit_queue_entry) entry;
struct got_object_id *id;
struct commit_queue {
int ncommits;
struct commit_queue_head head;
+};
+
+struct tog_diff_view_state {
+ struct got_object_id *id1, *id2;
+ FILE *f;
+ int first_displayed_line;
+ int last_displayed_line;
+ int eof;
+ int diff_context;
+ struct got_repository *repo;
+
+ /* passed from log view; may be NULL */
+ struct commit_queue_entry *selected_entry;
+ struct commit_queue *commits;
+ int *log_complete;
+ pthread_cond_t *need_commits;
+ int *commits_needed;
};
pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER;
};
static const struct got_error *open_diff_view(struct tog_view *,
- struct got_object_id *, struct got_object_id *, struct got_repository *);
+ struct got_object_id *, struct got_object_id *, struct commit_queue_entry *,
+ struct commit_queue *, int *, pthread_cond_t *, int *,
+ struct got_repository *);
static const struct got_error *show_diff_view(struct tog_view *);
static const struct got_error *input_diff_view(struct tog_view **,
struct tog_view **, struct tog_view **, struct tog_view *, int);
static const struct got_error *
open_diff_view_for_commit(struct tog_view **new_view, int begin_x,
- struct got_object_id *commit_id, struct got_commit_object *commit,
+ struct commit_queue_entry *selected_entry,
+ struct commit_queue *commits, int *log_complete,
+ pthread_cond_t *need_commits, int *commits_needed,
struct got_repository *repo)
{
const struct got_error *err;
struct got_object_qid *parent_id;
struct tog_view *diff_view;
+ struct got_commit_object *commit = selected_entry->commit;
+ struct got_object_id *commit_id = selected_entry->id;
diff_view = view_open(0, 0, 0, begin_x, TOG_VIEW_DIFF);
if (diff_view == NULL)
parent_id = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
err = open_diff_view(diff_view, parent_id ? parent_id->id : NULL,
- commit_id, repo);
+ commit_id, selected_entry, commits, log_complete, need_commits,
+ commits_needed, repo);
if (err == NULL)
*new_view = diff_view;
return err;
if (view_is_parent_view(view))
begin_x = view_split_begin_x(view->begin_x);
err = open_diff_view_for_commit(&diff_view, begin_x,
- s->selected_entry->id, s->selected_entry->commit,
- s->repo);
+ s->selected_entry, &s->commits,
+ &s->thread_args.log_complete,
+ &s->thread_args.need_commits,
+ &s->thread_args.commits_needed, s->repo);
if (err)
break;
if (view_is_parent_view(view)) {
err = got_object_open_as_commit(&commit2, s->repo, s->id2);
if (err)
break;
- /* Show commit info if we're diffing to a parent commit. */
- parent_ids = got_object_commit_get_parent_ids(commit2);
- SIMPLEQ_FOREACH(pid, parent_ids, entry) {
- if (got_object_id_cmp(s->id1, pid->id) == 0) {
- write_commit_info(s->id2, s->repo, f);
- break;
+ /* Show commit info if we're diffing to a parent/root commit. */
+ if (s->id1 == NULL)
+ write_commit_info(s->id2, s->repo, f);
+ else {
+ parent_ids = got_object_commit_get_parent_ids(commit2);
+ SIMPLEQ_FOREACH(pid, parent_ids, entry) {
+ if (got_object_id_cmp(s->id1, pid->id) == 0) {
+ write_commit_info(s->id2, s->repo, f);
+ break;
+ }
}
}
got_object_commit_close(commit2);
static const struct got_error *
open_diff_view(struct tog_view *view, struct got_object_id *id1,
- struct got_object_id *id2, struct got_repository *repo)
+ struct got_object_id *id2, struct commit_queue_entry *selected_entry,
+ struct commit_queue *commits, int *log_complete,
+ pthread_cond_t *need_commits, int *commits_needed,
+ struct got_repository *repo)
{
const struct got_error *err;
view->state.diff.first_displayed_line = 1;
view->state.diff.last_displayed_line = view->nlines;
view->state.diff.diff_context = 3;
+ view->state.diff.selected_entry = selected_entry;
+ view->state.diff.commits = commits;
+ view->state.diff.log_complete = log_complete;
+ view->state.diff.need_commits = need_commits;
+ view->state.diff.commits_needed = commits_needed;
view->state.diff.repo = repo;
err = create_diff(&view->state.diff);
return draw_file(view, s->f, &s->first_displayed_line,
&s->last_displayed_line, &s->eof, view->nlines,
header);
+}
+
+static const struct got_error *
+set_selected_commit(struct tog_diff_view_state *s,
+ struct commit_queue_entry *entry)
+{
+ struct commit_queue_entry *pentry;
+
+ free(s->id2);
+ s->id2 = got_object_id_dup(entry->id);
+ if (s->id2 == NULL)
+ return got_error_from_errno();
+
+ free(s->id1);
+ s->id1 = NULL;
+ pentry = TAILQ_NEXT(entry, entry);
+ if (pentry) {
+ s->id1 = got_object_id_dup(pentry->id);
+ if (s->id1 == NULL)
+ return got_error_from_errno();
+ }
+
+ s->selected_entry = entry;
+ return NULL;
}
static const struct got_error *
{
const struct got_error *err = NULL;
struct tog_diff_view_state *s = &view->state.diff;
+ struct commit_queue_entry *entry, *pentry;
int i;
switch (ch) {
if (s->diff_context < GOT_DIFF_MAX_CONTEXT) {
s->diff_context++;
err = create_diff(s);
+ }
+ break;
+ case '<':
+ case ',':
+ if (s->commits == NULL)
+ break;
+ entry = TAILQ_PREV(s->selected_entry,
+ commit_queue_head, entry);
+ if (entry == NULL)
+ break;
+
+ err = set_selected_commit(s, entry);
+ if (err)
+ break;
+
+ s->first_displayed_line = 1;
+ s->last_displayed_line = view->nlines;
+
+ err = create_diff(s);
+ break;
+ case '>':
+ case '.':
+ if (s->commits == NULL)
+ break;
+ entry = TAILQ_NEXT(s->selected_entry, entry);
+ if (entry)
+ pentry = TAILQ_NEXT(entry, entry);
+ if (entry == NULL || pentry == NULL) {
+ if (!*s->log_complete)
+ *s->commits_needed = 2;
}
+ while (entry == NULL || pentry == NULL) {
+ int errcode;
+ if (*s->log_complete)
+ break;
+ errcode = pthread_cond_signal(s->need_commits);
+ if (errcode)
+ return got_error_set_errno(errcode);
+ errcode = pthread_mutex_unlock(&tog_mutex);
+ if (errcode)
+ return got_error_set_errno(errcode);
+ pthread_yield();
+ errcode = pthread_mutex_lock(&tog_mutex);
+ if (errcode)
+ return got_error_set_errno(errcode);
+ entry = TAILQ_NEXT(s->selected_entry, entry);
+ if (entry)
+ pentry = TAILQ_NEXT(entry, entry);
+ }
+
+ if (entry == NULL)
+ break;
+
+ err = set_selected_commit(s, entry);
+ if (err)
+ break;
+
+ s->first_displayed_line = 1;
+ s->last_displayed_line = view->nlines;
+
+ err = create_diff(s);
break;
default:
break;
error = got_error_from_errno();
goto done;
}
- error = open_diff_view(view, id1, id2, repo);
+ error = open_diff_view(view, id1, id2, NULL, NULL, NULL, NULL, NULL,
+ repo);
if (error)
goto done;
error = view_loop(view);
break;
}
err = open_diff_view(diff_view, pid ? pid->id : NULL,
- id, s->repo);
+ id, NULL, NULL, NULL, NULL, NULL, s->repo);
got_object_commit_close(commit);
if (err) {
view_close(diff_view);