From: Stefan Sperling Subject: tog: fix horizontal scrolling of unicode in the diff view To: gameoftrees@openbsd.org Date: Thu, 16 Jun 2022 16:32:33 +0200 Fix horizontal scrolling of unicode in the diff view. This makes the diff in my ja.git test repo scroll properly. Turns out we need another output parameter in format_line() for this case. draw_file() needs to know the width of the unscrolled version of each line in order to set view->maxx correctly. ok? diff 3a8eb03e7089a4869bb33afa6dc90d2b9d4c2c70 7c4eb5ef2ddd2fc6b8127a6b4746081efcb1411c blob - 285021accb225e5cc858097d09e1a68d4b32e1ca blob + 4b3a42b896e6f4177b004831b046fa812308b489 --- tog/tog.c +++ tog/tog.c @@ -1262,7 +1262,7 @@ expand_tab(char **ptr, const char *src) * Returns the index to the first character of the scrolled string. */ static const struct got_error * -scroll_wline(int *scrollx , wchar_t *wline, int nscroll, +scroll_wline(int *scrollx, int *widthp, wchar_t *wline, int nscroll, int col_tab_align) { int cols = 0; @@ -1301,27 +1301,34 @@ scroll_wline(int *scrollx , wchar_t *wline, int nscrol } *scrollx = i; + *widthp = cols; return NULL; } /* * Format a line for display, ensuring that it won't overflow a width limit. - * With scrolling, the width returned refers to the scrolled version of the - * line, which starts at (*wlinep)[*scrollxp]. The caller must free *wlinep. + * With scrolling, the width returned in *scrolled_widthp refers to the + * scrolled version of the line, which starts at (*wlinep)[*scrollxp]. + * The caller must free *wlinep. */ static const struct got_error * -format_line(wchar_t **wlinep, int *widthp, int *scrollxp, +format_line(wchar_t **wlinep, int *widthp, int *scrollxp, int *scrolled_widthp, const char *line, int nscroll, int wlimit, int col_tab_align, int expand) { const struct got_error *err = NULL; - int cols = 0; + int cols = 0, skipped_cols = 0; wchar_t *wline = NULL; char *exstr = NULL; size_t wlen; int i, scrollx = 0; *wlinep = NULL; - *widthp = 0; + if (widthp) + *widthp = 0; + if (scrollxp) + *scrollxp = 0; + if (scrolled_widthp) + *scrolled_widthp = 0; if (expand) { err = expand_tab(&exstr, line); @@ -1334,7 +1341,8 @@ format_line(wchar_t **wlinep, int *widthp, int *scroll if (err) return err; - err = scroll_wline(&scrollx, wline, nscroll, col_tab_align); + err = scroll_wline(&scrollx, &skipped_cols, wline, nscroll, + col_tab_align); if (err) goto done; @@ -1380,9 +1388,11 @@ format_line(wchar_t **wlinep, int *widthp, int *scroll } wline[i] = L'\0'; if (widthp) - *widthp = cols; + *widthp = skipped_cols + cols; if (scrollxp) *scrollxp = scrollx; + if (scrolled_widthp) + *scrolled_widthp = cols; done: if (err) free(wline); @@ -1469,7 +1479,7 @@ format_author(wchar_t **wauthor, int *author_width, ch if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; - return format_line(wauthor, author_width, NULL, author, 0, limit, + return format_line(wauthor, author_width, NULL, NULL, author, 0, limit, col_tab_align, 0); } @@ -1568,8 +1578,8 @@ draw_commit(struct tog_view *view, struct got_commit_o if (newline) *newline = '\0'; limit = avail - col; - err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, view->x, - limit, col, 1); + err = format_line(&wlogmsg, NULL, &scrollx, &logmsg_width, + logmsg, view->x, limit, col, 1); if (err) goto done; waddwstr(view->window, &wlogmsg[scrollx]); @@ -1810,7 +1820,8 @@ draw_commits(struct tog_view *view) header = NULL; goto done; } - err = format_line(&wline, &width, NULL, header, 0, view->ncols, 0, 0); + err = format_line(&wline, &width, NULL, NULL, header, 0, view->ncols, + 0, 0); if (err) goto done; @@ -1865,7 +1876,7 @@ draw_commits(struct tog_view *view) ++msg; if ((eol = strchr(msg, '\n'))) *eol = '\0'; - err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX, + err = format_line(&wmsg, &width, NULL, NULL, msg, 0, INT_MAX, date_display_cols + author_cols, 0); if (err) goto done; @@ -3126,7 +3137,7 @@ add_matched_line(int *wtotal, const char *line, int wl rms = regmatch->rm_so; rme = regmatch->rm_eo; - err = format_line(&wline, &width, NULL, line, 0, wlimit + skip, + err = format_line(&wline, &width, NULL, NULL, line, 0, wlimit + skip, col_tab_align, 1); if (err) return err; @@ -3196,8 +3207,8 @@ draw_file(struct tog_view *view, const char *header) s->first_displayed_line - 1 + s->selected_line, nlines, header) == -1) return got_error_from_errno("asprintf"); - err = format_line(&wline, &width, NULL, line, 0, view->ncols, - 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, + view->ncols, 0, 0); free(line); if (err) return err; @@ -3231,8 +3242,6 @@ draw_file(struct tog_view *view, const char *header) return got_ferror(s->f, GOT_ERR_IO); } - view->maxx = MAX(view->maxx, linelen); - tc = match_color(&s->colors, line); if (tc) wattr_on(view->window, @@ -3246,23 +3255,25 @@ draw_file(struct tog_view *view, const char *header) return err; } } else { - err = format_line(&wline, &width, NULL, line, 0, - view->x + view->ncols, 0, view->x ? 1 : 0); + int skip, fullwidth; + err = format_line(&wline, &fullwidth, &skip, &width, + line, view->x, view->ncols, 0, view->x ? 1 : 0); if (err) { free(line); return err; } - if (view->x < width) - waddwstr(view->window, wline + view->x); + view->maxx = MAX(view->maxx, fullwidth); + waddwstr(view->window, &wline[skip]); free(wline); wline = NULL; } if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); - if (width - view->x <= view->ncols - 1) + if (width <= view->ncols - 1) waddch(view->window, '\n'); nprinted++; + } free(line); if (nprinted >= 1) @@ -3279,7 +3290,7 @@ draw_file(struct tog_view *view, const char *header) nprinted++; } - err = format_line(&wline, &width, NULL, TOG_EOF_STRING, 0, + err = format_line(&wline, &width, NULL, NULL, TOG_EOF_STRING, 0, view->ncols, 0, 0); if (err) { return err; @@ -4279,7 +4290,8 @@ draw_blame(struct tog_view *view) return err; } - err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, view->ncols, + 0, 0); free(line); line = NULL; if (err) @@ -4308,7 +4320,8 @@ draw_blame(struct tog_view *view) return got_error_from_errno("asprintf"); } free(id_str); - err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, view->ncols, + 0, 0); free(line); line = NULL; if (err) @@ -4395,7 +4408,7 @@ draw_blame(struct tog_view *view) } width += 9; } else { - err = format_line(&wline, &width, NULL, line, 0, + err = format_line(&wline, &width, NULL, NULL, line, 0, view->x + view->ncols - 9, 9, 1); if (err) { free(line); @@ -5273,8 +5286,8 @@ draw_tree_entries(struct tog_view *view, const char *p if (limit == 0) return NULL; - err = format_line(&wline, &width, NULL, s->tree_label, 0, view->ncols, - 0, 0); + err = format_line(&wline, &width, NULL, NULL, s->tree_label, 0, + view->ncols, 0, 0); if (err) return err; if (view_needs_focus_indication(view)) @@ -5295,8 +5308,8 @@ draw_tree_entries(struct tog_view *view, const char *p waddch(view->window, '\n'); if (--limit <= 0) return NULL; - err = format_line(&wline, &width, NULL, parent_path, 0, view->ncols, - 0, 0); + err = format_line(&wline, &width, NULL, NULL, parent_path, 0, + view->ncols, 0, 0); if (err) return err; waddwstr(view->window, wline); @@ -5376,8 +5389,8 @@ draw_tree_entries(struct tog_view *view, const char *p } free(id_str); free(link_target); - err = format_line(&wline, &width, NULL, line, 0, view->ncols, - 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, + view->ncols, 0, 0); if (err) { free(line); break; @@ -6488,7 +6501,8 @@ show_ref_view(struct tog_view *view) s->nrefs) == -1) return got_error_from_errno("asprintf"); - err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, view->ncols, + 0, 0); if (err) { free(line); return err; @@ -6575,8 +6589,8 @@ show_ref_view(struct tog_view *view) got_ref_get_name(re->ref)) == -1) return got_error_from_errno("asprintf"); - err = format_line(&wline, &width, NULL, line, 0, view->ncols, - 0, 0); + err = format_line(&wline, &width, NULL, NULL, line, 0, + view->ncols, 0, 0); if (err) { free(line); return err;