Download raw body.
[rfc] compound keymaps with prefixed count modifier like vi(1)
I got the idea from naddy the other day when he mentioned the behaviour
of less(1) in the discussion about C-d/C-u d/u. It's something I use in
vim a lot too, so I wanted to see how others feel about it.
I figured it'd be easier to explain with an example so the following
diff demonstrates the intended behaviour. Basically, for movement
keymaps, they can be prefixed with a count modifier, which determines
how many times the requested movement is performed.
For example, 123j will move down 123 lines, and 3f will scroll down
3 pages. I like the diff context where n] will increase context by
n lines, which is like the ^v context buttons in Fossil and GitHub to
expand the diff in large chunks.
This is just a feeler. I added some hints to the docs but if you use
this in less or vim it's pretty much the same behaviour except with
C-d/C-u: in less(1) and vi(1), nC-d or nC-u will scroll n lines--not
half pages. In vi(1), nC-b and nC-f will scroll n pages, but in less(1)
it will scroll n lines. I think it's more useful and consistent to
modify the normal scroll amount because we can already move n lines with
the normal jk and up/down keys.
The only thing I'm not sure is whether I prefer massaging view->count at
each keymap case in the input handlers or if I'd rather validate in one
routine at input but I wanted to get comments first.
diff refs/heads/main refs/heads/nkeymap
blob - ccc38d4c5d675293f415ff2696edfd596fbb3220
blob + fccd509f1d942aa5ba3cd20be4d5cc69450074f4
--- tog/tog.1
+++ tog/tog.1
@@ -55,6 +55,9 @@ Displays references in the repository.
.Pp
.Nm
provides global and command-specific key bindings and options.
+Some command-specific key bindings may be prefixed with an integer, which is
+denoted by N in the descriptions below, and is used as a modifier to the
+operation as indicated.
The global key bindings are:
.Bl -tag -width Ds
.It Cm Q
@@ -98,30 +101,32 @@ This command is also executed if no explicit command i
.Pp
The key bindings for
.Cm tog log
-are as follows:
+are as follows (N denotes optional prefixed count modifier):
.Bl -tag -width Ds
.It Cm Down-arrow, j, >, Full stop, Ctrl-n
-Move the selection cursor down.
+Move the selection cursor down N lines (default: 1).
.It Cm Up-arrow, k, <, Comma, Ctrl-p
-Move the selection cursor up.
+Move the selection cursor up N lines (default: 1).
.It Cm Right-arrow, l
-Scroll log message field to the right.
+Scroll log message field to the right N increments (default: 1).
+.br
Log message moves left on the screen.
.It Cm Left-arrow, h
-Scroll log message field to the left.
+Scroll log message field to the left N increments (default: 1).
+.br
Log message moves right on the screen.
.It Cm $
Scroll log message field to the rightmost position.
.It Cm 0
Scroll log message field to the leftmost position.
-.It Cm Page-down, Ctrl+f, f
-Move the selection cursor down one page.
+.It Cm Page-down, Space, Ctrl+f, f
+Move the selection cursor down N pages (default: 1).
.It Cm Page-up, Ctrl+b, b
-Move the selection cursor up one page.
+Move the selection cursor up N pages (default: 1).
.It Cm Ctrl+d, d
-Move the selection cursor down one half page.
+Move the selection cursor down N half pages (default: 1).
.It Cm Ctrl+u, u
-Move the selection cursor up one half page.
+Move the selection cursor up N half pages (default: 1).
.It Cm Home, g
Move the cursor to the newest commit.
.It Cm End, G
@@ -130,7 +135,7 @@ This will traverse all commits on the current branch w
a long time depending on the number of commits in branch history.
If needed, this operation can be cancelled with
.Cm Backspace .
-.It Cm Enter, Space
+.It Cm Enter
Open a
.Cm diff
view showing file changes made in the currently selected commit.
@@ -152,12 +157,15 @@ commit ID SHA1 hash.
Regular expression syntax is documented in
.Xr re_format 7 .
.It Cm n
-Find the next commit which matches the current search pattern.
+Find the Nth next commit which matches the current search pattern (default: 1).
+.br
Searching continues until either a match is found or the
.Cm Backspace
key is pressed.
.It Cm N
-Find the previous commit which matches the current search pattern.
+Find the Nth previous commit which matches the current search pattern
+(default: 1).
+.br
Searching continues until either a match is found or the
.Cm Backspace
key is pressed.
@@ -220,62 +228,65 @@ automatically, provided the abbreviation is unique.
.Pp
The key bindings for
.Cm tog diff
-are as follows:
+are as follows (N denotes optional prefixed count modifier):
.Bl -tag -width Ds
.It Cm a
Toggle treatment of file contents as ASCII text even if binary data was
detected.
.It Cm Down-arrow, j, Ctrl-n
-Scroll down.
+Scroll down N lines (default: 1).
.It Cm Up-arrow, k, Ctrl-p
-Scroll up.
+Scroll up N lines (default: 1).
.It Cm Right-arrow, l
-Scroll view to the right.
+Scroll view to the right N increments (default: 1).
+.br
Diff output moves left on the screen.
.It Cm Left-arrow, h
-Scroll view to the left.
+Scroll view to the left N increments (default: 1).
+.br
Diff output moves right on the screen.
.It Cm $
Scroll view to the rightmost position.
.It Cm 0
Scroll view left to the start of the line.
.It Cm Page-down, Space, Ctrl+f, f
-Scroll down one page.
+Scroll down N pages (default: 1).
.It Cm Page-up, Ctrl+b, b
-Scroll up one page.
+Scroll up N pages (default: 1).
.It Cm Ctrl+d, d
-Scroll down one half page.
+Scroll down N half pages (default: 1).
.It Cm Ctrl+u, u
-Scroll up one half page.
+Scroll up N half pages (default: 1).
.It Cm Home, g
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.
+Reduce diff context by N lines (default: 1).
.It Cm \&]
-Increase the amount of diff context lines.
+Increase diff context by N lines (default: 1).
.It Cm <, Comma
If the
.Cm diff
view was opened via the
.Cm log
-view, move to the previous (younger) commit.
+view, move to the Nth previous (younger) commit (default: 1).
.It Cm >, Full stop
If the
.Cm diff
view was opened via the
.Cm log
-view, move to the next (older) commit.
+view, move to the Nth next (older) commit (default: 1).
.It Cm /
Prompt for a search pattern and start searching for matching lines.
The search pattern is an extended regular expression.
Regular expression syntax is documented in
.Xr re_format 7 .
.It Cm n
-Find the next line which matches the current search pattern.
+Find the Nth next line which matches the current search pattern (default: 1).
.It Cm N
-Find the previous line which matches the current search pattern.
+Find the Nth previous line which matches the current search pattern
+(default: 1).
.It Cm w
Toggle display of whitespace-only changes.
.El
@@ -304,30 +315,32 @@ Display line-by-line history of a file at the specifie
.Pp
The key bindings for
.Cm tog blame
-are as follows:
+are as follows (N denotes optional prefixed count modifier):
.Bl -tag -width Ds
.It Cm Down-arrow, j, Ctrl-n
-Move the selection cursor down.
+Move the selection cursor down N pages (default: 1).
.It Cm Up-arrow, k, Ctrl-p
-Move the selection cursor up.
+Move the selection cursor up N pages (default: 1).
.It Cm Right-arrow, l
-Scroll view to the right.
+Scroll view to the right N increments (default: 1).
+.br
File output moves left on the screen.
.It Cm Left-arrow, h
-Scroll view to the left.
+Scroll view to the left N increments (default: 1).
+.br
File output moves right on the screen.
.It Cm $
Scroll view to the rightmost position.
.It Cm 0
Scroll view left to the start of the line.
.It Cm Page-down, Space, Ctrl+f, f
-Move the selection cursor down one page.
+Move the selection cursor down N pages (default: 1).
.It Cm Page-up, Ctrl+b, b
-Move the selection cursor up one page.
+Move the selection cursor up N pages (default: 1).
.It Cm Ctrl+d, d
-Move the selection cursor down one half page.
+Move the selection cursor down N half pages (default: 1).
.It Cm Ctrl+u, u
-Move the selection cursor up one half page.
+Move the selection cursor up N half pages (default: 1).
.It Cm Home, g
Move the selection cursor to the first line of the file.
.It Cm End, G
@@ -356,9 +369,10 @@ The search pattern is an extended regular expression.
Regular expression syntax is documented in
.Xr re_format 7 .
.It Cm n
-Find the next line which matches the current search pattern.
+Find the Nth next line which matches the current search pattern (default: 1).
.It Cm N
-Find the previous line which matches the current search pattern.
+Find the Nth previous line which matches the current search pattern
+(default: 1).
.El
.Pp
The options for
@@ -397,20 +411,20 @@ Symbolic link entries are also annotated with the targ
.Pp
The key bindings for
.Cm tog tree
-are as follows:
+are as follows (N denotes optional prefixed count modifier):
.Bl -tag -width Ds
.It Cm Down-arrow, j, Ctrl-n
-Move the selection cursor down.
+Move the selection cursor down N lines (default: 1).
.It Cm Up-arrow, k, Ctrl-p
-Move the selection cursor up.
-.It Cm Page-down, Ctrl+f, f
-Move the selection cursor down one page.
+Move the selection cursor up N lines (default: 1).
+.It Cm Page-down, Space, Ctrl+f, f
+Move the selection cursor down N pages (default: 1).
.It Cm Page-up, Ctrl+b, b
-Move the selection cursor up one page.
+Move the selection cursor up N pages (default: 1).
.It Cm Ctrl+d, d
-Move the selection cursor down one half page.
+Move the selection cursor down N half pages (default: 1).
.It Cm Ctrl+u, u
-Move the selection cursor up one half page.
+Move the selection cursor up N half pages (default: 1).
.It Cm Home, g
Move the selection cursor to the first entry.
.It Cm End, G
@@ -431,7 +445,7 @@ This can then be used to open a new
.Cm tree
view for arbitrary branches and tags.
.It Cm Backspace
-Move back to the parent directory.
+Move back to the Nth parent directory (default: 1).
.It Cm i
Show object IDs for all objects displayed in the
.Cm tree
@@ -443,9 +457,11 @@ against the tree entry's name.
Regular expression syntax is documented in
.Xr re_format 7 .
.It Cm n
-Find the next tree entry which matches the current search pattern.
+Find the Nth next tree entry which matches the current search pattern
+(default: 1).
.It Cm N
-Find the previous tree entry which matches the current search pattern.
+Find the Nth previous tree entry which matches the current search pattern
+(default: 1).
.El
.Pp
The options for
@@ -471,20 +487,20 @@ Display references in the repository.
.Pp
The key bindings for
.Cm tog ref
-are as follows:
+are as follows (N denotes optional prefixed count modifier):
.Bl -tag -width Ds
.It Cm Down-arrow, j, Ctrl-n
-Move the selection cursor down.
+Move the selection cursor down N lines (default: 1).
.It Cm Up-arrow, k, Ctrl-p
-Move the selection cursor up.
-.It Cm Page-down, Ctrl+f, f
-Move the selection cursor down one page.
+Move the selection cursor up N lines (default: 1).
+.It Cm Page-down, Space, Ctrl+f, f
+Move the selection cursor down N pages (default: 1).
.It Cm Page-up, Ctrl+b, b
-Move the selection cursor up one page.
+Move the selection cursor up N pages (default: 1).
.It Cm Ctrl+d, d
-Move the selection cursor down one half page.
+Move the selection cursor down N half pages (default: 1).
.It Cm Ctrl+u, u
-Move the selection cursor up one half page.
+Move the selection cursor up N half pages (default: 1).
.It Cm Home, g
Move the selection cursor to the first reference.
.It Cm End, G
@@ -513,9 +529,11 @@ against absolute reference names.
Regular expression syntax is documented in
.Xr re_format 7 .
.It Cm n
-Find the next reference which matches the current search pattern.
+Find the Nth next reference which matches the current search pattern
+(default: 1).
.It Cm N
-Find the previous reference which matches the current search pattern.
+Find the Nth previous reference which matches the current search pattern
+(default: 1).
.It Cm Ctrl+l
Reload the list of references displayed by the
.Cm ref
blob - 89cccde0f2eae2e05d0e8be40c9c6e25e6c7fabe
blob + 78e47e8a187dbacb55661c676692831b735039c4
--- tog/tog.c
+++ tog/tog.c
@@ -502,6 +502,7 @@ struct tog_view {
int nlines, ncols, begin_y, begin_x;
int maxx, x; /* max column and current start column */
int lines, cols; /* copies of LINES and COLS */
+ int ch, count; /* current keymap and count prefix */
int focussed; /* Only set on one parent or child view at a time. */
int dying;
struct tog_view *parent;
@@ -667,6 +668,8 @@ view_open(int nlines, int ncols, int begin_y, int begi
if (view == NULL)
return NULL;
+ view->ch = 0;
+ view->count = 0;
view->type = type;
view->lines = LINES;
view->cols = COLS;
@@ -884,6 +887,42 @@ view_search_start(struct tog_view *view)
return NULL;
}
+/*
+ * Compute view->count from numeric user input. User has five-tenths of a
+ * second to follow each numeric keypress with another number to form count.
+ * Return first non-numeric input or ERR and assign total to view->count.
+ * XXX Should we add support for user-defined timeout?
+ */
+static int
+get_compound_key(struct tog_view *view, int c)
+{
+ int n = 0;
+
+ view->count = 0;
+ halfdelay(5); /* block for half a second */
+
+ do {
+ /*
+ * Don't overflow. Max valid request should be the greatest
+ * between the longest and total lines; cap at 10 million.
+ */
+ if (n >= 9999999UL)
+ n = 9999999UL;
+ else
+ n = n * 10 + (c - '0');
+ } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR);
+
+ /*
+ * Massage value at the input handler if count is invalid.
+ * XXX Should we validate with a helper function here
+ * despite maintaining list of key maps in two places?
+ */
+ view->count = n;
+
+ cbreak(); /* return to blocking */
+ return c;
+}
+
static const struct got_error *
view_input(struct tog_view **new, int *done, struct tog_view *view,
struct tog_view_list_head *views)
@@ -896,8 +935,10 @@ view_input(struct tog_view **new, int *done, struct to
/* Clear "no matches" indicator. */
if (view->search_next_done == TOG_SEARCH_NO_MORE ||
- view->search_next_done == TOG_SEARCH_HAVE_NONE)
+ view->search_next_done == TOG_SEARCH_HAVE_NONE) {
view->search_next_done = TOG_SEARCH_HAVE_MORE;
+ view->count = 0;
+ }
if (view->searching && !view->search_next_done) {
errcode = pthread_mutex_unlock(&tog_mutex);
@@ -918,7 +959,13 @@ view_input(struct tog_view **new, int *done, struct to
errcode = pthread_mutex_unlock(&tog_mutex);
if (errcode)
return got_error_set_errno(errcode, "pthread_mutex_unlock");
- ch = wgetch(view->window);
+ /* If we have an unfinished count, don't get a new key map. */
+ ch = view->ch;
+ if ((view->count && --view->count == 0) || !view->count) {
+ ch = wgetch(view->window);
+ if (ch >= '1' && ch <= '9')
+ view->ch = ch = get_compound_key(view, ch);
+ }
errcode = pthread_mutex_lock(&tog_mutex);
if (errcode)
return got_error_set_errno(errcode, "pthread_mutex_lock");
@@ -949,6 +996,7 @@ view_input(struct tog_view **new, int *done, struct to
switch (ch) {
case '\t':
+ view->count = 0;
if (view->child) {
view->focussed = 0;
view->child->focussed = 1;
@@ -969,6 +1017,7 @@ view_input(struct tog_view **new, int *done, struct to
*done = 1;
break;
case 'F':
+ view->count = 0;
if (view_is_parent_view(view)) {
if (view->child == NULL)
break;
@@ -1000,6 +1049,7 @@ view_input(struct tog_view **new, int *done, struct to
case KEY_RESIZE:
break;
case '/':
+ view->count = 0;
if (view->search_start)
view_search_start(view);
else
@@ -2595,21 +2645,28 @@ input_log_view(struct tog_view **new_view, struct tog_
break;
case '$':
view->x = MAX(view->maxx - view->ncols / 2, 0);
+ view->count = 0;
break;
case KEY_RIGHT:
case 'l':
if (view->x + view->ncols / 2 < view->maxx)
view->x += 2; /* move two columns right */
+ else
+ view->count = 0;
break;
case KEY_LEFT:
case 'h':
view->x -= MIN(view->x, 2); /* move two columns back */
+ if (view->x <= 0)
+ view->count = 0;
break;
case 'k':
case KEY_UP:
case '<':
case ',':
case CTRL('p'):
+ if (s->selected_entry->idx == 0)
+ view->count = 0;
if (s->first_displayed_entry == NULL)
break;
if (s->selected > 0)
@@ -2623,6 +2680,7 @@ input_log_view(struct tog_view **new_view, struct tog_
s->selected = 0;
s->first_displayed_entry = TAILQ_FIRST(&s->commits.head);
select_commit(s);
+ view->count = 0;
break;
case CTRL('u'):
case 'u':
@@ -2638,6 +2696,8 @@ input_log_view(struct tog_view **new_view, struct tog_
else
log_scroll_up(s, nscroll);
select_commit(s);
+ if (s->selected_entry->idx == 0)
+ view->count = 0;
break;
case 'j':
case KEY_DOWN:
@@ -2655,11 +2715,15 @@ input_log_view(struct tog_view **new_view, struct tog_
break;
}
select_commit(s);
+ if (s->thread_args.log_complete &&
+ s->selected_entry->idx == s->commits.ncommits - 1)
+ view->count = 0;
break;
case 'G':
case KEY_END: {
/* We don't know yet how many commits, so we're forced to
* traverse them all. */
+ view->count = 0;
if (!s->thread_args.log_complete) {
s->thread_args.load_all = 1;
return trigger_log_thread(view, 0);
@@ -2684,11 +2748,14 @@ input_log_view(struct tog_view **new_view, struct tog_
/* FALL THROUGH */
case KEY_NPAGE:
case CTRL('f'):
- case 'f': {
+ case 'f':
+ case ' ': {
struct commit_queue_entry *first;
first = s->first_displayed_entry;
- if (first == NULL)
+ if (first == NULL) {
+ view->count = 0;
break;
+ }
err = log_scroll_down(view, nscroll);
if (err)
break;
@@ -2700,6 +2767,9 @@ input_log_view(struct tog_view **new_view, struct tog_
s->selected_entry->idx, nscroll + 1);
}
select_commit(s);
+ if (s->thread_args.log_complete &&
+ s->selected_entry->idx == s->commits.ncommits - 1)
+ view->count = 0;
break;
}
case KEY_RESIZE:
@@ -2716,8 +2786,8 @@ input_log_view(struct tog_view **new_view, struct tog_
}
break;
case KEY_ENTER:
- case ' ':
case '\r':
+ view->count = 0;
if (s->selected_entry == NULL)
break;
if (view_is_parent_view(view))
@@ -2741,6 +2811,7 @@ input_log_view(struct tog_view **new_view, struct tog_
*new_view = diff_view;
break;
case 't':
+ view->count = 0;
if (s->selected_entry == NULL)
break;
if (view_is_parent_view(view))
@@ -2766,6 +2837,7 @@ input_log_view(struct tog_view **new_view, struct tog_
case KEY_BACKSPACE:
case CTRL('l'):
case 'B':
+ view->count = 0;
if (ch == KEY_BACKSPACE &&
got_path_is_root_dir(s->in_repo_path))
break;
@@ -2827,6 +2899,7 @@ input_log_view(struct tog_view **new_view, struct tog_
s->search_entry = NULL;
break;
case 'r':
+ view->count = 0;
if (view_is_parent_view(view))
begin_x = view_split_begin_x(view->begin_x);
ref_view = view_open(view->nlines, view->ncols,
@@ -2852,6 +2925,7 @@ input_log_view(struct tog_view **new_view, struct tog_
*new_view = ref_view;
break;
default:
+ view->count = 0;
break;
}
@@ -4017,15 +4091,20 @@ input_diff_view(struct tog_view **new_view, struct tog
break;
case '$':
view->x = MAX(view->maxx - view->ncols / 3, 0);
+ view->count = 0;
break;
case KEY_RIGHT:
case 'l':
if (view->x + view->ncols / 3 < view->maxx)
view->x += 2; /* move two columns right */
+ else
+ view->count = 0;
break;
case KEY_LEFT:
case 'h':
view->x -= MIN(view->x, 2); /* move two columns back */
+ if (view->x <= 0)
+ view->count = 0;
break;
case 'a':
case 'w':
@@ -4039,13 +4118,16 @@ input_diff_view(struct tog_view **new_view, struct tog
s->matched_line = 0;
diff_view_indicate_progress(view);
err = create_diff(s);
+ view->count = 0;
break;
case 'g':
case KEY_HOME:
s->first_displayed_line = 1;
+ view->count = 0;
break;
case 'G':
case KEY_END:
+ view->count = 0;
if (s->eof)
break;
@@ -4057,6 +4139,8 @@ input_diff_view(struct tog_view **new_view, struct tog
case CTRL('p'):
if (s->first_displayed_line > 1)
s->first_displayed_line--;
+ else
+ view->count = 0;
break;
case CTRL('u'):
case 'u':
@@ -4065,8 +4149,10 @@ input_diff_view(struct tog_view **new_view, struct tog
case KEY_PPAGE:
case CTRL('b'):
case 'b':
- if (s->first_displayed_line == 1)
+ if (s->first_displayed_line == 1) {
+ view->count = 0;
break;
+ }
i = 0;
while (i++ < nscroll && s->first_displayed_line > 1)
s->first_displayed_line--;
@@ -4076,6 +4162,8 @@ input_diff_view(struct tog_view **new_view, struct tog
case CTRL('n'):
if (!s->eof)
s->first_displayed_line++;
+ else
+ view->count = 0;
break;
case CTRL('d'):
case 'd':
@@ -4085,8 +4173,10 @@ input_diff_view(struct tog_view **new_view, struct tog
case CTRL('f'):
case 'f':
case ' ':
- if (s->eof)
+ if (s->eof) {
+ view->count = 0;
break;
+ }
i = 0;
while (!s->eof && i++ < nscroll) {
linelen = getline(&line, &linesize, s->f);
@@ -4112,7 +4202,8 @@ input_diff_view(struct tog_view **new_view, struct tog
s->first_displayed_line = 1;
s->last_displayed_line = view->nlines;
}
- }
+ } else
+ view->count = 0;
break;
case ']':
if (s->diff_context < GOT_DIFF_MAX_CONTEXT) {
@@ -4120,15 +4211,19 @@ input_diff_view(struct tog_view **new_view, struct tog
s->matched_line = 0;
diff_view_indicate_progress(view);
err = create_diff(s);
- }
+ } else
+ view->count = 0;
break;
case '<':
case ',':
- if (s->log_view == NULL)
+ if (s->log_view == NULL) {
+ view->count = 0;
break;
+ }
ls = &s->log_view->state.log;
old_selected_entry = ls->selected_entry;
+ /* view->count handled in input_log_view() */
err = input_log_view(NULL, s->log_view, KEY_UP);
if (err)
break;
@@ -4150,11 +4245,14 @@ input_diff_view(struct tog_view **new_view, struct tog
break;
case '>':
case '.':
- if (s->log_view == NULL)
+ if (s->log_view == NULL) {
+ view->count = 0;
break;
+ }
ls = &s->log_view->state.log;
old_selected_entry = ls->selected_entry;
+ /* view->count handled in input_log_view() */
err = input_log_view(NULL, s->log_view, KEY_DOWN);
if (err)
break;
@@ -4175,6 +4273,7 @@ input_diff_view(struct tog_view **new_view, struct tog
err = create_diff(s);
break;
default:
+ view->count = 0;
break;
}
@@ -4964,15 +5063,20 @@ input_blame_view(struct tog_view **new_view, struct to
break;
case '$':
view->x = MAX(view->maxx - view->ncols / 3, 0);
+ view->count = 0;
break;
case KEY_RIGHT:
case 'l':
if (view->x + view->ncols / 3 < view->maxx)
view->x += 2; /* move two columns right */
+ else
+ view->count = 0;
break;
case KEY_LEFT:
case 'h':
view->x -= MIN(view->x, 2); /* move two columns back */
+ if (view->x <= 0)
+ view->count = 0;
break;
case 'q':
s->done = 1;
@@ -4981,6 +5085,7 @@ input_blame_view(struct tog_view **new_view, struct to
case KEY_HOME:
s->selected_line = 1;
s->first_displayed_line = 1;
+ view->count = 0;
break;
case 'G':
case KEY_END:
@@ -4992,6 +5097,7 @@ input_blame_view(struct tog_view **new_view, struct to
s->first_displayed_line = s->blame.nlines -
(view->nlines - 3);
}
+ view->count = 0;
break;
case 'k':
case KEY_UP:
@@ -5001,6 +5107,8 @@ input_blame_view(struct tog_view **new_view, struct to
else if (s->selected_line == 1 &&
s->first_displayed_line > 1)
s->first_displayed_line--;
+ else
+ view->count = 0;
break;
case CTRL('u'):
case 'u':
@@ -5011,6 +5119,7 @@ input_blame_view(struct tog_view **new_view, struct to
case 'b':
if (s->first_displayed_line == 1) {
s->selected_line = MAX(1, s->selected_line - nscroll);
+ view->count = 0;
break;
}
if (s->first_displayed_line > nscroll)
@@ -5028,10 +5137,14 @@ input_blame_view(struct tog_view **new_view, struct to
else if (s->last_displayed_line <
s->blame.nlines)
s->first_displayed_line++;
+ else
+ view->count = 0;
break;
case 'c':
case 'p': {
struct got_object_id *id = NULL;
+
+ view->count = 0;
id = get_selected_commit_id(s->blame.lines, s->blame.nlines,
s->first_displayed_line, s->selected_line);
if (id == NULL)
@@ -5099,6 +5212,8 @@ input_blame_view(struct tog_view **new_view, struct to
}
case 'C': {
struct got_object_qid *first;
+
+ view->count = 0;
first = STAILQ_FIRST(&s->blamed_commits);
if (!got_object_id_cmp(&first->id, s->commit_id))
break;
@@ -5121,6 +5236,8 @@ input_blame_view(struct tog_view **new_view, struct to
struct got_object_id *id = NULL;
struct got_object_qid *pid;
struct got_commit_object *commit = NULL;
+
+ view->count = 0;
id = get_selected_commit_id(s->blame.lines, s->blame.nlines,
s->first_displayed_line, s->selected_line);
if (id == NULL)
@@ -5172,6 +5289,7 @@ input_blame_view(struct tog_view **new_view, struct to
if (s->last_displayed_line >= s->blame.nlines &&
s->selected_line >= MIN(s->blame.nlines,
view->nlines - 2)) {
+ view->count = 0;
break;
}
if (s->last_displayed_line >= s->blame.nlines &&
@@ -5193,6 +5311,7 @@ input_blame_view(struct tog_view **new_view, struct to
}
break;
default:
+ view->count = 0;
break;
}
return thread_err ? thread_err : err;
@@ -5885,8 +6004,10 @@ input_tree_view(struct tog_view **new_view, struct tog
switch (ch) {
case 'i':
s->show_ids = !s->show_ids;
+ view->count = 0;
break;
case 'l':
+ view->count = 0;
if (!s->selected_entry)
break;
if (view_is_parent_view(view))
@@ -5906,6 +6027,7 @@ input_tree_view(struct tog_view **new_view, struct tog
*new_view = log_view;
break;
case 'r':
+ view->count = 0;
if (view_is_parent_view(view))
begin_x = view_split_begin_x(view->begin_x);
ref_view = view_open(view->nlines, view->ncols,
@@ -5933,6 +6055,7 @@ input_tree_view(struct tog_view **new_view, struct tog
case 'g':
case KEY_HOME:
s->selected = 0;
+ view->count = 0;
if (s->tree == s->root)
s->first_displayed_entry =
got_object_tree_get_first_entry(s->tree);
@@ -5942,6 +6065,7 @@ input_tree_view(struct tog_view **new_view, struct tog
case 'G':
case KEY_END:
s->selected = 0;
+ view->count = 0;
te = got_object_tree_get_last_entry(s->tree);
for (n = 0; n < view->nlines - 3; n++) {
if (te == NULL) {
@@ -5965,6 +6089,10 @@ input_tree_view(struct tog_view **new_view, struct tog
break;
}
tree_scroll_up(s, 1);
+ if (s->selected_entry == NULL ||
+ (s->tree == s->root && s->selected_entry ==
+ got_object_tree_get_first_entry(s->tree)))
+ view->count = 0;
break;
case CTRL('u'):
case 'u':
@@ -5982,6 +6110,10 @@ input_tree_view(struct tog_view **new_view, struct tog
s->selected -= MIN(s->selected, nscroll);
}
tree_scroll_up(s, MAX(0, nscroll));
+ if (s->selected_entry == NULL ||
+ (s->tree == s->root && s->selected_entry ==
+ got_object_tree_get_first_entry(s->tree)))
+ view->count = 0;
break;
case 'j':
case KEY_DOWN:
@@ -5991,9 +6123,11 @@ input_tree_view(struct tog_view **new_view, struct tog
break;
}
if (got_tree_entry_get_next(s->tree, s->last_displayed_entry)
- == NULL)
+ == NULL) {
/* can't scroll any further */
+ view->count = 0;
break;
+ }
tree_scroll_down(s, 1);
break;
case CTRL('d'):
@@ -6003,12 +6137,15 @@ input_tree_view(struct tog_view **new_view, struct tog
case KEY_NPAGE:
case CTRL('f'):
case 'f':
+ case ' ':
if (got_tree_entry_get_next(s->tree, s->last_displayed_entry)
== NULL) {
/* can't scroll any further; move cursor down */
if (s->selected < s->ndisplayed - 1)
s->selected += MIN(nscroll,
s->ndisplayed - s->selected - 1);
+ else
+ view->count = 0;
break;
}
tree_scroll_down(s, nscroll);
@@ -6019,8 +6156,10 @@ input_tree_view(struct tog_view **new_view, struct tog
if (s->selected_entry == NULL || ch == KEY_BACKSPACE) {
struct tog_parent_tree *parent;
/* user selected '..' */
- if (s->tree == s->root)
+ if (s->tree == s->root) {
+ view->count = 0;
break;
+ }
parent = TAILQ_FIRST(&s->parents);
TAILQ_REMOVE(&s->parents, parent,
entry);
@@ -6035,6 +6174,7 @@ input_tree_view(struct tog_view **new_view, struct tog
} else if (S_ISDIR(got_tree_entry_get_mode(
s->selected_entry))) {
struct got_tree_object *subtree;
+ view->count = 0;
err = got_object_open_as_tree(&subtree, s->repo,
got_tree_entry_get_id(s->selected_entry));
if (err)
@@ -6055,6 +6195,7 @@ input_tree_view(struct tog_view **new_view, struct tog
s->commit_id, s->repo);
if (err)
break;
+ view->count = 0;
view->focussed = 0;
blame_view->focussed = 1;
if (view_is_parent_view(view)) {
@@ -6072,8 +6213,10 @@ input_tree_view(struct tog_view **new_view, struct tog
case KEY_RESIZE:
if (view->nlines >= 4 && s->selected >= view->nlines - 3)
s->selected = view->nlines - 4;
+ view->count = 0;
break;
default:
+ view->count = 0;
break;
}
@@ -6756,12 +6899,15 @@ input_ref_view(struct tog_view **new_view, struct tog_
switch (ch) {
case 'i':
s->show_ids = !s->show_ids;
+ view->count = 0;
break;
case 'm':
s->show_date = !s->show_date;
+ view->count = 0;
break;
case 'o':
s->sort_by_date = !s->sort_by_date;
+ view->count = 0;
err = got_reflist_sort(&tog_refs, s->sort_by_date ?
got_ref_cmp_by_commit_timestamp_descending :
tog_ref_cmp_by_name, s->repo);
@@ -6777,6 +6923,7 @@ input_ref_view(struct tog_view **new_view, struct tog_
break;
case KEY_ENTER:
case '\r':
+ view->count = 0;
if (!s->selected_entry)
break;
if (view_is_parent_view(view))
@@ -6797,6 +6944,7 @@ input_ref_view(struct tog_view **new_view, struct tog_
*new_view = log_view;
break;
case 't':
+ view->count = 0;
if (!s->selected_entry)
break;
if (view_is_parent_view(view))
@@ -6821,11 +6969,13 @@ input_ref_view(struct tog_view **new_view, struct tog_
case 'g':
case KEY_HOME:
s->selected = 0;
+ view->count = 0;
s->first_displayed_entry = TAILQ_FIRST(&s->refs);
break;
case 'G':
case KEY_END:
s->selected = 0;
+ view->count = 0;
re = TAILQ_LAST(&s->refs, tog_reflist_head);
for (n = 0; n < view->nlines - 1; n++) {
if (re == NULL)
@@ -6844,6 +6994,8 @@ input_ref_view(struct tog_view **new_view, struct tog_
break;
}
ref_scroll_up(s, 1);
+ if (s->selected_entry == TAILQ_FIRST(&s->refs))
+ view->count = 0;
break;
case CTRL('u'):
case 'u':
@@ -6855,6 +7007,8 @@ input_ref_view(struct tog_view **new_view, struct tog_
if (s->first_displayed_entry == TAILQ_FIRST(&s->refs))
s->selected -= MIN(nscroll, s->selected);
ref_scroll_up(s, MAX(0, nscroll));
+ if (s->selected_entry == TAILQ_FIRST(&s->refs))
+ view->count = 0;
break;
case 'j':
case KEY_DOWN:
@@ -6863,9 +7017,11 @@ input_ref_view(struct tog_view **new_view, struct tog_
s->selected++;
break;
}
- if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL)
+ if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) {
/* can't scroll any further */
+ view->count = 0;
break;
+ }
ref_scroll_down(s, 1);
break;
case CTRL('d'):
@@ -6875,16 +7031,21 @@ input_ref_view(struct tog_view **new_view, struct tog_
case KEY_NPAGE:
case CTRL('f'):
case 'f':
+ case ' ':
if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) {
/* can't scroll any further; move cursor down */
if (s->selected < s->ndisplayed - 1)
s->selected += MIN(nscroll,
s->ndisplayed - s->selected - 1);
+ if (view->count > 1 && s->selected < s->ndisplayed - 1)
+ s->selected += s->ndisplayed - s->selected - 1;
+ view->count = 0;
break;
}
ref_scroll_down(s, nscroll);
break;
case CTRL('l'):
+ view->count = 0;
tog_free_refs();
err = tog_load_refs(s->repo, s->sort_by_date);
if (err)
@@ -6897,6 +7058,7 @@ input_ref_view(struct tog_view **new_view, struct tog_
s->selected = view->nlines - 2;
break;
default:
+ view->count = 0;
break;
}
--
Mark Jamsek <fnc.bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68
[rfc] compound keymaps with prefixed count modifier like vi(1)