commit cc3ce05962c0e173176dd8fa1a545daded616853 from: Stefan Sperling date: Mon May 29 09:35:01 2023 UTC rework how reference labels are rendered in the tog log view Draw reference labels and log message as separate strings. The previous code contained calculations mixing variables which represent an amount of wide characters in a string vs the display width of the string. We can avoid such nonsense by keeping the strings separate, though we have to be a bit careful about keeping horizontal scrolling intact. Also fix a bug where we failed to account for reference labels while setting view->maxx which made the $ key not scroll far enough. ok op@ commit - 50f6148a8cb54672795a89ce089488e86f584a0e commit + cc3ce05962c0e173176dd8fa1a545daded616853 blob - d61d75ad690d0df4ae45b27ab6108711ef2113d9 blob + 64550af73ca34b53669e898b8d6008418d6a3c20 --- tog/tog.c +++ tog/tog.c @@ -2406,11 +2406,10 @@ draw_commit(struct tog_view *view, struct got_commit_o char *refs_str = NULL; char *logmsg0 = NULL, *logmsg = NULL; char *author = NULL; - wchar_t *wlogmsg = NULL, *wauthor = NULL; - int author_width, logmsg_width; - size_t wrefstr_len = 0; + wchar_t *wrefstr = NULL, *wlogmsg = NULL, *wauthor = NULL; + int author_width, refstr_width, logmsg_width; char *newline, *line = NULL; - int col, limit, scrollx; + int col, limit, scrollx, logmsg_x; const int avail = view->ncols; struct tm tm; time_t committer_time; @@ -2496,57 +2495,70 @@ draw_commit(struct tog_view *view, struct got_commit_o if (newline) *newline = '\0'; + limit = avail - col; + if (view->child && !view_is_hsplit_top(view) && limit > 0) + limit--; /* for the border */ + /* Prepend reference labels to log message if possible .*/ refs = got_reflist_object_id_map_lookup(tog_refs_idmap, id); err = build_refs_str(&refs_str, refs, id, s->repo); if (err) goto done; if (refs_str) { - char *newlogmsg; - wchar_t *ws; + char *rs; - /* - * The length of this wide-char sub-string will be - * needed later for colorization. - */ - err = mbs2ws(&ws, &wrefstr_len, refs_str); - if (err) - goto done; - free(ws); - - wrefstr_len += 2; /* account for '[' and ']' */ - - if (asprintf(&newlogmsg, "[%s] %s", refs_str, logmsg) == -1) { + if (asprintf(&rs, "[%s]", refs_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } - - free(logmsg0); - logmsg0 = newlogmsg; - logmsg = logmsg0; - } - - limit = avail - col; - if (view->child && !view_is_hsplit_top(view) && limit > 0) - limit--; /* for the border */ - err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, view->x, - limit, col, 1); - if (err) - goto done; - if (wrefstr_len > 0 && scrollx < wrefstr_len) { + err = format_line(&wrefstr, &refstr_width, + &scrollx, rs, view->x, limit, col, 1); + free(rs); + if (err) + goto done; tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); - waddnwstr(view->window, &wlogmsg[scrollx], - MIN(logmsg_width, wrefstr_len - scrollx)); + waddwstr(view->window, &wrefstr[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); - if (col + MIN(logmsg_width, wrefstr_len - scrollx) < avail) - waddwstr(view->window, &wlogmsg[wrefstr_len]); + col += MAX(refstr_width, 0); + if (col > avail) + goto done; + + if (col < avail) { + waddch(view->window, ' '); + col++; + } + + if (refstr_width > 0) + logmsg_x = 0; + else { + int unscrolled_refstr_width; + size_t len = wcslen(wrefstr); + + /* + * No need to check for -1 return value here since + * unprintables have been replaced by span_wline(). + */ + unscrolled_refstr_width = wcswidth(wrefstr, len); + unscrolled_refstr_width += 1; /* trailing space */ + logmsg_x = view->x - unscrolled_refstr_width; + } + + limit = avail - col; + if (view->child && !view_is_hsplit_top(view) && limit > 0) + limit--; /* for the border */ } else - waddwstr(view->window, &wlogmsg[scrollx]); + logmsg_x = view->x; + + err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, logmsg_x, + limit, col, 1); + if (err) + goto done; + waddwstr(view->window, &wlogmsg[scrollx]); col += MAX(logmsg_width, 0); while (col < avail) { waddch(view->window, ' '); @@ -2555,6 +2567,7 @@ draw_commit(struct tog_view *view, struct got_commit_o done: free(logmsg0); free(wlogmsg); + free(wrefstr); free(refs_str); free(author); free(wauthor); @@ -2761,19 +2774,19 @@ draw_commits(struct tog_view *view) struct commit_queue_entry *entry = s->selected_entry; int limit = view->nlines; int width; - int ncommits, author_cols = 4; + int ncommits, author_cols = 4, refstr_cols; char *id_str = NULL, *header = NULL, *ncommits_str = NULL; char *refs_str = NULL; wchar_t *wline; struct tog_color *tc; static const size_t date_display_cols = 12; + struct got_reflist_head *refs; if (view_is_hsplit_top(view)) --limit; /* account for border */ if (s->selected_entry && !(view->searching && view->search_next_done == 0)) { - struct got_reflist_head *refs; err = got_object_id_str(&id_str, s->selected_entry->id); if (err) return err; @@ -2887,6 +2900,21 @@ draw_commits(struct tog_view *view) free(author); if (err) goto done; + refs = got_reflist_object_id_map_lookup(tog_refs_idmap, + entry->id); + err = build_refs_str(&refs_str, refs, entry->id, s->repo); + if (err) + goto done; + if (refs_str) { + wchar_t *ws; + err = format_line(&ws, &width, NULL, refs_str, + 0, INT_MAX, date_display_cols + author_cols, 0); + free(ws); + if (err) + goto done; + refstr_cols = width + 3; /* account for [ ] + space */ + } else + refstr_cols = 0; err = got_object_commit_get_logmsg(&msg0, c); if (err) goto done; @@ -2896,10 +2924,10 @@ draw_commits(struct tog_view *view) if ((eol = strchr(msg, '\n'))) *eol = '\0'; err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX, - date_display_cols + author_cols, 0); + date_display_cols + author_cols + refstr_cols, 0); if (err) goto done; - view->maxx = MAX(view->maxx, width); + view->maxx = MAX(view->maxx, width + refstr_cols); free(msg0); free(wmsg); ncommits++;