From: Mark Jamsek Subject: Re: [rfc] compound keymaps with prefixed count modifier like vi(1) To: gameoftrees@openbsd.org Date: Thu, 23 Jun 2022 00:18:03 +1000 On 22-06-22 02:51pm, Stefan Sperling wrote: > On Wed, Jun 22, 2022 at 10:42:02PM +1000, Mark Jamsek wrote: > > I'm happy to add an explicit abort key, or do you think documenting the > > timeout and how that cancels a preceding count modifier would suffice? > > If we add an abort key, what should we use if not backspace? > > Yes, just documenting the timeout seems fine. I entirely missed that the > number prompt will time out when I did my initial quick review. > > The timeout should probably be configurable via env vars, but we can > add this later. ok, sounds good! The updated diff adds the timeout to the man page and a couple minor fixes: left-behind typo and ensuring that we scroll all the way up with C-u in blame view if the count modifier is large enough diff refs/heads/main refs/heads/nkeymap blob - a89f36bf163bbb820b19ad56b23223e7e6078bc1 blob + 728ba5ee9e20edbde20ed7f0c2ff1cbabad89c0b --- tog/tog.1 +++ tog/tog.1 @@ -55,6 +55,15 @@ 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. +When the first integer for a count modifier is entered, +.Nm +will wait 500 milliseconds for each successive integer or the compound sequence +to complete. +If this sequence should timeout or does not conclude with a valid key binding, +the command is aborted and any preceding count is reset. The global key bindings are: .Bl -tag -width Ds .It Cm Q @@ -98,30 +107,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, 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 cursor to the newest commit. .It Cm End, G @@ -152,12 +163,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 +234,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 +321,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 +375,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 +417,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. +Move the selection cursor up N lines (default: 1). .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 entry. .It Cm End, G @@ -431,7 +451,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 +463,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 +493,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. +Move the selection cursor up N lines (default: 1). .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 reference. .It Cm End, G @@ -513,9 +535,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 - cb01bcd4c601aae790a8c7ed5467fd7dc9bc7f1b blob + 06a2c43c08564378df49023a7b6ae4bdb8a9e22a --- 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,38 @@ 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 >= 9999999) + n = 9999999; + else + n = n * 10 + (c - '0'); + } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR); + + /* Massage excessive or inapplicable values at the input handler. */ + 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 +931,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 +955,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 +992,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 +1013,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 +1045,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 +2641,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 +2676,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 +2692,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 +2711,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); @@ -2688,8 +2748,10 @@ input_log_view(struct tog_view **new_view, struct tog_ 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; @@ -2701,6 +2763,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: @@ -2718,6 +2783,7 @@ input_log_view(struct tog_view **new_view, struct tog_ break; case KEY_ENTER: case '\r': + view->count = 0; if (s->selected_entry == NULL) break; if (view_is_parent_view(view)) @@ -2741,6 +2807,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 +2833,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 +2895,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 +2921,7 @@ input_log_view(struct tog_view **new_view, struct tog_ *new_view = ref_view; break; default: + view->count = 0; break; } @@ -4017,15 +4087,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 +4114,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 +4135,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 +4145,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 +4158,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 +4169,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 +4198,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 +4207,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 +4241,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 +4269,7 @@ input_diff_view(struct tog_view **new_view, struct tog err = create_diff(s); break; default: + view->count = 0; break; } @@ -4964,15 +5059,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 +5081,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 +5093,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 +5103,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': @@ -5010,7 +5114,10 @@ input_blame_view(struct tog_view **new_view, struct to case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { + if (view->count > 1) + nscroll += nscroll; s->selected_line = MAX(1, s->selected_line - nscroll); + view->count = 0; break; } if (s->first_displayed_line > nscroll) @@ -5028,10 +5135,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 +5210,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 +5234,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 +5287,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 +5309,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 +6002,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 +6025,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 +6053,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 +6063,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 +6087,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 +6108,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 +6121,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'): @@ -6010,6 +6142,8 @@ input_tree_view(struct tog_view **new_view, struct tog 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); @@ -6020,8 +6154,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); @@ -6036,6 +6172,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) @@ -6056,6 +6193,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)) { @@ -6073,8 +6211,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; } @@ -6757,12 +6897,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); @@ -6778,6 +6921,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)) @@ -6798,6 +6942,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)) @@ -6822,11 +6967,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) @@ -6845,6 +6992,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': @@ -6856,6 +7005,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: @@ -6864,9 +7015,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'): @@ -6882,11 +7035,15 @@ input_ref_view(struct tog_view **new_view, struct tog_ 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) @@ -6899,6 +7056,7 @@ input_ref_view(struct tog_view **new_view, struct tog_ s->selected = view->nlines - 2; break; default: + view->count = 0; break; } -- Mark Jamsek GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68