Download raw body.
tog: nG key map like vi(1) and less(1)
On 22-07-24 03:08pm, Christian Weisgerber wrote: > Mark Jamsek: > > > We use A_STANDOUT (or A_REVERSE in the previous diff as I've had issues > > with A_STANDOUT in tmux in the past, otherwise they both appear to do > > the same thing?), but because the text is coloured, we get the coloured > > highlight. Like we currently do with highlighted search terms in diff > > views. > > Yes, and I think that's fine. > My suggestion was to replace A_BOLD|A_REVERSE with a simple A_STANDOUT. Sorry, naddy! My mistake--I thought you were referring to the coloured highlight. At first, I found it a bit jarring so I tried it without the colour, but I liked that less. And then the coloured highlight grew on me :) Rebased and revised diff drops the A_BOLD so it's just A_STANDOUT now. > > diff refs/heads/main refs/heads/dev/gline > > commit - c3821befbed0b67d1b48a5cfa3aaa2e022c58430 > > commit + 6aba0b5044ca3682899309aea1d763a451120360 > > Works fine in my testing. Thank you! diff refs/heads/main refs/heads/dev/gline commit - 10a16316a03005a07c45b2bbf1b5644b64e846fb commit + 0822ba705f5de920d06a583df07678d70be35107 blob - c09dbe11bb6e0224ed0138a35da047947c82f41d blob + ff238905b35da47efd5533334d11290e37f51345 --- tog/tog.1 +++ tog/tog.1 @@ -93,6 +93,10 @@ N increments (default: 1). .It Cm + When in a split-screen view, increase the size of the focussed split N increments (default: 1). +.It Cm G +Go to line N in the view (default: last line). +.It Cm g +Go to line N in the view (default: first line). .El .Pp Global options must precede the command name, and are as follows: blob - aaca1ae9bd59788b771d3797213ce44b033f50a8 blob + c8ba3dd30932400e33436e51fce150c7b8c63546 --- tog/tog.c +++ tog/tog.c @@ -518,6 +518,7 @@ struct tog_view { int maxx, x; /* max column and current start column */ int lines, cols; /* copies of LINES and COLS */ int nscrolled, offset; /* lines scrolled and hsplit line offset */ + int gline, hiline; /* navigate to and highlight this nG line */ int ch, count; /* current keymap and count prefix */ int resized; /* set when in a resize event */ int focussed; /* Only set on one parent or child view at a time. */ @@ -1279,6 +1280,7 @@ get_compound_key(struct tog_view *view, int c) view->count = 0; cbreak(); /* block for input */ + nodelay(view->window, FALSE); wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); waddch(v->window, ':'); @@ -1300,6 +1302,12 @@ get_compound_key(struct tog_view *view, int c) n = n * 10 + (c - '0'); } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR); + if (c == 'G' || c == 'g') { /* nG key map */ + view->gline = view->hiline = n; + n = 0; + c = 0; + } + /* Massage excessive or inapplicable values at the input handler. */ view->count = n; @@ -1337,7 +1345,6 @@ view_input(struct tog_view **new, int *done, struct to return NULL; } - nodelay(view->window, FALSE); /* Allow threads to make progress while we are waiting for input. */ errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) @@ -1356,10 +1363,12 @@ view_input(struct tog_view **new, int *done, struct to if (ch >= '1' && ch <= '9') view->ch = ch = get_compound_key(view, ch); } + if (view->hiline && ch != ERR && ch != 0) + view->hiline = 0; /* key pressed, clear line highlight */ + nodelay(view->window, TRUE); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); - nodelay(view->window, TRUE); if (tog_sigwinch_received || tog_sigcont_received) { tog_resizeterm(); @@ -2494,7 +2503,8 @@ log_scroll_down(struct tog_view *view, int maxscroll) /* * Ask the log thread for required amount of commits. */ - s->thread_args.commits_needed += maxscroll; + s->thread_args.commits_needed += + ncommits_needed - s->commits.ncommits; err = trigger_log_thread(view, 1); if (err) return err; @@ -3247,6 +3257,42 @@ view_init_hsplit(struct tog_view *view, int y) } static const struct got_error * +log_goto_line(struct tog_view *view, int nlines) +{ + const struct got_error *err = NULL; + struct tog_log_view_state *s = &view->state.log; + int g, idx = s->selected_entry->idx; + + g = view->gline; + view->gline = 0; + + if (g >= s->first_displayed_entry->idx + 1 && + g <= s->last_displayed_entry->idx + 1 && + g - s->first_displayed_entry->idx - 1 < nlines) { + s->selected = g - s->first_displayed_entry->idx - 1; + select_commit(s); + return NULL; + } + + if (idx + 1 < g) { + err = log_move_cursor_down(view, g - idx - 1); + if (!err && g > s->selected_entry->idx + 1) + err = log_move_cursor_down(view, + g - s->first_displayed_entry->idx - 1); + if (err) + return err; + } else if (idx + 1 > g) + log_move_cursor_up(view, idx - g + 1, 0); + + if (g < nlines && s->first_displayed_entry->idx == 0) + s->selected = g - 1; + + select_commit(s); + return NULL; + +} + +static const struct got_error * input_log_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; @@ -3268,6 +3314,9 @@ input_log_view(struct tog_view **new_view, struct tog_ if (view_is_hsplit_top(view)) --eos; /* border */ + if (view->gline) + return log_goto_line(view, eos); + switch (ch) { case 'q': s->quit = 1; @@ -3835,13 +3884,55 @@ done: return err; } +static int +gotoline(struct tog_view *view, int *lineno, int *nprinted) +{ + FILE *f = NULL; + int *eof, *first, *selected; + + if (view->type == TOG_VIEW_DIFF) { + struct tog_diff_view_state *s = &view->state.diff; + + first = &s->first_displayed_line; + selected = first; + eof = &s->eof; + f = s->f; + } else if (view->type == TOG_VIEW_BLAME) { + struct tog_blame_view_state *s = &view->state.blame; + + first = &s->first_displayed_line; + selected = &s->selected_line; + eof = &s->eof; + f = s->blame.f; + } else + return 0; + + /* Center gline in the middle of the page like vi(1). */ + if (*lineno < view->gline - (view->nlines - 3) / 2) + return 0; + if (*first != 1 && (*lineno > view->gline - (view->nlines - 3) / 2)) { + rewind(f); + *eof = 0; + *first = 1; + *lineno = 0; + *nprinted = 0; + return 0; + } + + *selected = view->gline <= (view->nlines - 3) / 2 ? + view->gline : (view->nlines - 3) / 2 + 1; + view->gline = 0; + + return 1; +} + static const struct got_error * draw_file(struct tog_view *view, const char *header) { struct tog_diff_view_state *s = &view->state.diff; regmatch_t *regmatch = &view->regmatch; const struct got_error *err; - int nprinted = 0; + int lineno, nprinted = 0; char *line; size_t linesize = 0; ssize_t linelen; @@ -3851,17 +3942,24 @@ draw_file(struct tog_view *view, const char *header) int max_lines = view->nlines; int nlines = s->nlines; off_t line_offset; + attr_t attr; + lineno = s->first_displayed_line - 1; line_offset = s->line_offsets[s->first_displayed_line - 1]; if (fseeko(s->f, line_offset, SEEK_SET) == -1) return got_error_from_errno("fseek"); werase(view->window); + if (view->gline > s->nlines - 1) + view->gline = s->nlines - 1; + if (header) { - if (asprintf(&line, "[%d/%d] %s", - s->first_displayed_line - 1 + s->selected_line, nlines, - header) == -1) + int ln = view->gline ? view->gline <= (view->nlines - 3) / 2 ? + 1 : view->gline - (view->nlines - 3) / 2 : + lineno + s->selected_line; + + if (asprintf(&line, "[%d/%d] %s", ln, nlines, header) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); @@ -3898,6 +3996,14 @@ draw_file(struct tog_view *view, const char *header) return got_ferror(s->f, GOT_ERR_IO); } + attr = 0; + if (++lineno < s->first_displayed_line) + continue; + if (view->gline && !gotoline(view, &lineno, &nprinted)) + continue; + if (lineno == view->hiline) + attr = A_STANDOUT; + /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, view->x ? 1 : 0); @@ -3911,8 +4017,9 @@ draw_file(struct tog_view *view, const char *header) tc = match_color(&s->colors, line); if (tc) - wattr_on(view->window, - COLOR_PAIR(tc->colorpair), NULL); + attr |= COLOR_PAIR(tc->colorpair); + if (attr) + wattron(view->window, attr); if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols, 0, @@ -3933,12 +4040,18 @@ draw_file(struct tog_view *view, const char *header) free(wline); wline = NULL; } - if (tc) - wattr_off(view->window, - COLOR_PAIR(tc->colorpair), NULL); - if (width <= view->ncols - 1) - waddch(view->window, '\n'); - nprinted++; + if (lineno == view->hiline) { + /* highlight full gline length */ + while (width++ < view->ncols) + waddch(view->window, ' '); + } else { + if (width <= view->ncols - 1) + waddch(view->window, '\n'); + } + if (attr) + wattroff(view->window, attr); + if (++nprinted == 1) + s->first_displayed_line = lineno; } free(line); if (nprinted >= 1) @@ -5055,7 +5168,10 @@ draw_blame(struct tog_view *view) if (width < view->ncols - 1) waddch(view->window, '\n'); - if (asprintf(&line, "[%d/%d] %s%s", + if (view->gline > blame->nlines) + view->gline = blame->nlines; + + if (asprintf(&line, "[%d/%d] %s%s", view->gline ? view->gline : s->first_displayed_line - 1 + s->selected_line, blame->nlines, s->blame_complete ? "" : "annotating... ", s->path) == -1) { free(id_str); @@ -5087,6 +5203,8 @@ draw_blame(struct tog_view *view) } if (++lineno < s->first_displayed_line) continue; + if (view->gline && !gotoline(view, &lineno, &nprinted)) + continue; /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 9, 1); @@ -6171,7 +6289,7 @@ draw_tree_entries(struct tog_view *view, const char *p struct got_tree_entry *te; wchar_t *wline; struct tog_color *tc; - int width, n, i, nentries; + int width, n, nentries, i = 1; int limit = view->nlines; s->ndisplayed = 0; @@ -6201,6 +6319,15 @@ draw_tree_entries(struct tog_view *view, const char *p wstandend(view->window); free(wline); wline = NULL; + + if (s->selected_entry) { + i = got_tree_entry_get_index(s->selected_entry); + i += s->tree == s->root ? 1 : 2; /* account for ".." entry */ + } + nentries = got_object_tree_get_nentries(s->tree); + wprintw(view->window, " [%d/%d]", i, + nentries + (s->tree == s->root ? 0 : 1)); /* ".." in !root tree */ + if (width < view->ncols - 1) waddch(view->window, '\n'); if (--limit <= 0) @@ -6239,7 +6366,6 @@ draw_tree_entries(struct tog_view *view, const char *p te = s->first_displayed_entry; } - nentries = got_object_tree_get_nentries(s->tree); for (i = got_tree_entry_get_index(te); i < nentries; i++) { char *line = NULL, *id_str = NULL, *link_target = NULL; const char *modestr = ""; @@ -6359,8 +6485,10 @@ tree_scroll_down(struct tog_view *view, int maxscroll) last = s->last_displayed_entry; while (next && n++ < maxscroll) { - if (last) + if (last) { + s->last_displayed_entry = last; last = got_tree_entry_get_next(s->tree, last); + } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN && next)) { s->first_displayed_entry = next; next = got_tree_entry_get_next(s->tree, next); @@ -6701,6 +6829,67 @@ show_tree_view(struct tog_view *view) } static const struct got_error * +tree_goto_line(struct tog_view *view, int nlines) +{ + const struct got_error *err = NULL; + struct tog_tree_view_state *s = &view->state.tree; + struct got_tree_entry **fte, **lte, **ste; + int g, last, first = 1, i = 1; + int root = s->tree == s->root; + int off = root ? 1 : 2; + + g = view->gline; + view->gline = 0; + + if (g == 0) + g = 1; + else if (g > got_object_tree_get_nentries(s->tree)) + g = got_object_tree_get_nentries(s->tree) + (root ? 0 : 1); + + fte = &s->first_displayed_entry; + lte = &s->last_displayed_entry; + ste = &s->selected_entry; + + if (*fte != NULL) { + first = got_tree_entry_get_index(*fte); + first += off; /* account for ".." */ + } + last = got_tree_entry_get_index(*lte); + last += off; + + if (g >= first && g <= last && g - first < nlines) { + s->selected = g - first; + return NULL; /* gline is on the current page */ + } + + if (*ste != NULL) { + i = got_tree_entry_get_index(*ste); + i += off; + } + + if (i < g) { + err = tree_scroll_down(view, g - i); + if (err) + return err; + if (got_tree_entry_get_index(*lte) >= + got_object_tree_get_nentries(s->tree) - 1 && + first + s->selected < g && + s->selected < s->ndisplayed - 1) { + first = got_tree_entry_get_index(*fte); + first += off; + s->selected = g - first; + } + } else if (i > g) + tree_scroll_up(s, i - g); + + if (g < nlines && + (*fte == NULL || (root && !got_tree_entry_get_index(*fte)))) + s->selected = g - 1; + + return NULL; +} + +static const struct got_error * input_tree_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; @@ -6708,6 +6897,9 @@ input_tree_view(struct tog_view **new_view, struct tog struct got_tree_entry *te; int n, nscroll = view->nlines - 3; + if (view->gline) + return tree_goto_line(view, nscroll); + switch (ch) { case 'i': s->show_ids = !s->show_ids; @@ -7269,8 +7461,10 @@ ref_scroll_down(struct tog_view *view, int maxscroll) last = s->last_displayed_entry; while (next && n++ < maxscroll) { - if (last) + if (last) { + s->last_displayed_entry = last; last = TAILQ_NEXT(last, entry); + } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN)) { s->first_displayed_entry = next; next = TAILQ_NEXT(next, entry); @@ -7551,7 +7745,48 @@ done: free(commit_id); return err; } + static const struct got_error * +ref_goto_line(struct tog_view *view, int nlines) +{ + const struct got_error *err = NULL; + struct tog_ref_view_state *s = &view->state.ref; + int g, idx = s->selected_entry->idx; + + g = view->gline; + view->gline = 0; + + if (g == 0) + g = 1; + else if (g > s->nrefs) + g = s->nrefs; + + if (g >= s->first_displayed_entry->idx + 1 && + g <= s->last_displayed_entry->idx + 1 && + g - s->first_displayed_entry->idx - 1 < nlines) { + s->selected = g - s->first_displayed_entry->idx - 1; + return NULL; + } + + if (idx + 1 < g) { + err = ref_scroll_down(view, g - idx - 1); + if (err) + return err; + if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL && + s->first_displayed_entry->idx + s->selected < g && + s->selected < s->ndisplayed - 1) + s->selected = g - s->first_displayed_entry->idx - 1; + } else if (idx + 1 > g) + ref_scroll_up(s, idx - g + 1); + + if (g < nlines && s->first_displayed_entry->idx == 0) + s->selected = g - 1; + + return NULL; + +} + +static const struct got_error * input_ref_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; @@ -7559,6 +7794,9 @@ input_ref_view(struct tog_view **new_view, struct tog_ struct tog_reflist_entry *re; int n, nscroll = view->nlines - 1; + if (view->gline) + return ref_goto_line(view, nscroll); + switch (ch) { case 'i': s->show_ids = !s->show_ids; -- Mark Jamsek <fnc.bsdbox.org> GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68
tog: nG key map like vi(1) and less(1)