"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Jasper Lievisse Adriaanse <j@jasper.la>
Subject:
Re: tog: handle Home/End for log and diff views
To:
gameoftrees@openbsd.org
Date:
Mon, 30 Aug 2021 14:19:10 +0200

Download raw body.

Thread
On Mon, Aug 30, 2021 at 12:53:29PM +0200, Stefan Sperling wrote:
> On Sun, Aug 29, 2021 at 10:14:38PM +0200, Jasper Lievisse Adriaanse wrote:
> > Hi,
> > 
> > Here's a diff that allows one to quickly navigate to the first or last
> > item of a particular view. Currently I've implemented it for the diff and
> > log views as these are the ones I use most often.
> > 
> > The 'End' handling for the log view was the trickiest because of the
> > way new commits are progressively discovered. I think the approach below
> > might be the quickest way we currently can do.
> > 
> > Is this an acceptable approach or did I miss anything?
> 
> Adding an alias for the Home key would be nice for use with keyboards
> which lack a Home key.
We've settled on 'ctrl-u' to somewhat resemble vi and to mirror 'G'.

> As we discussed over lunch, there should be a way for users to abort
> loading in case they hit the key by accident. Backspace is already
> bound for this purpose while searching. Perhaps we can generalize
> Backspace to abort loading in general? In any case, if we want to
> support cancellation it could be added in a follow-up patch.

Generalizing that would be preferable so we don't add individual hacks
for all future additions. Also we could make it so that any operation
involving the logger thread could be canceled.

> > @@ -2432,6 +2440,23 @@ input_log_view(struct tog_view **new_view, struct tog_view *view, int ch)
> >  		}
> >  		select_commit(s);
> >  		break;
> > +	case 'G':
> > +	case KEY_END: {
> > +		/* We don't know yet how many commits, so we're forced to
> > +		 * traverse them all. */
> > +		while (1) {
> > +			if (s->thread_args.log_complete)
> > +				break;
> > +
> > +			s->thread_args.commits_needed++;
> > +			trigger_log_thread(view, 1);
> 
> Does this run any faster if we ask the log thread for multiple commits?
> I'd imagine that just loading one commit at a time could lead to a lot
> of ping-pong between the two threads that could perhaps be avoided?

I've had a look at using view->nlines and variations of that however I
didn't observe a noticeable speed-up.

diff --git a/tog/tog.1 b/tog/tog.1
index 4296b08..fe5ccc0 100644
--- a/tog/tog.1
+++ b/tog/tog.1
@@ -108,6 +108,12 @@ Move the selection cursor up.
 Move the selection cursor down one page.
 .It Cm Page-up, Ctrl+b
 Move the selection cursor up one page.
+.It Cm Home, Ctrl-u
+Move the cursor to the newest commit.
+.It Cm End, G
+Move the cursor to the oldest commit.
+This will iterate over all commit objects in the repository and may take
+a long time depending on the size of the repository.
 .It Cm Enter, Space
 Open a
 .Cm diff
@@ -210,6 +216,10 @@ Scroll up.
 Scroll down one page.
 .It Cm Page-up, Ctrl+b
 Scroll up one page.
+.It Cm Home, Ctrl-u
+Scroll to the top of the view.
+.It Cm End, G
+Scroll to the bottom of the view.
 .It Cm \&[
 Reduce the amount of diff context lines.
 .It Cm \&]
diff --git a/tog/tog.c b/tog/tog.c
index 2f62fb3..93179cb 100644
--- a/tog/tog.c
+++ b/tog/tog.c
@@ -2406,6 +2406,15 @@ input_log_view(struct tog_view **new_view, struct tog_view *view, int ch)
 			log_scroll_up(s, 1);
 		select_commit(s);
 		break;
+	case CTRL('u'):
+	case KEY_HOME:
+		if (s->first_displayed_entry == NULL)
+			break;
+
+		s->selected = 0;
+		log_scroll_up(s, s->commits.ncommits);
+		select_commit(s);
+		break;
 	case KEY_PPAGE:
 	case CTRL('b'):
 		if (s->first_displayed_entry == NULL)
@@ -2432,6 +2441,25 @@ input_log_view(struct tog_view **new_view, struct tog_view *view, int ch)
 		}
 		select_commit(s);
 		break;
+	case 'G':
+	case KEY_END: {
+		/* We don't know yet how many commits, so we're forced to
+		 * traverse them all. */
+		while (1) {
+			if (s->thread_args.log_complete)
+				break;
+
+			s->thread_args.commits_needed++;
+			err = trigger_log_thread(view, 1);
+			if (err)
+				return err;
+		}
+
+		log_scroll_down(view, s->commits.ncommits);
+		s->selected = MIN(view->nlines - 2, s->commits.ncommits - 1);
+		select_commit(s);
+		break;
+	}
 	case KEY_NPAGE:
 	case CTRL('f'): {
 		struct commit_queue_entry *first;
@@ -3633,6 +3661,18 @@ input_diff_view(struct tog_view **new_view, struct tog_view *view, int ch)
 		diff_view_indicate_progress(view);
 		err = create_diff(s);
 		break;
+	case CTRL('u'):
+	case KEY_HOME:
+		s->first_displayed_line = 1;
+		break;
+	case 'G':
+	case KEY_END:
+		if (s->eof)
+			break;
+
+		s->first_displayed_line = (s->nlines - view->nlines) + 2;
+		s->eof = 1;
+		break;
 	case 'k':
 	case KEY_UP:
 		if (s->first_displayed_line > 1)
-- 
jasper