fix(ui): reserve pad height per message to prevent multi-line clip and scroll desync
All checks were successful
CI Code / Check spelling (pull_request) Successful in 16s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Code Coverage (pull_request) Successful in 3m28s
CI Code / Linux (debian) (pull_request) Successful in 4m44s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m57s
CI Code / Linux (arch) (pull_request) Successful in 6m49s
All checks were successful
CI Code / Check spelling (pull_request) Successful in 16s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Code Coverage (pull_request) Successful in 3m28s
CI Code / Linux (debian) (pull_request) Successful in 4m44s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m57s
CI Code / Linux (arch) (pull_request) Successful in 6m49s
A tall multi-line message printed near the bottom of the ncurses pad was clipped because _win_print_internal grew the pad from the current cursor only (_win_ensure_pad_capacity(getcury)), not the height of the message about to be printed. The clipped message's captured height (e.g. 1 row for a 49-row message) was wrong while win_redraw later rendered it in full; the resulting buffer->lines / y_start_pos mismatch desynced the page-up scroll anchor, producing a ~one-page jump when scrolling past such messages from history.
Estimate the rendered height (hard newlines + soft-wrap over the usable width) and reserve that many rows before printing, so the message is never clipped and its captured height matches the redraw. All print paths go through _win_print_internal, so incoming/outgoing/history are covered.
Regression from the upstream sync (72f4f186d), which replaced the fixed-size pad with the dynamic _win_ensure_pad_capacity model.
This commit is contained in:
@@ -2001,7 +2001,19 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
|
||||
}
|
||||
}
|
||||
|
||||
_win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win));
|
||||
// reserve pad rows for this message's full height so a tall message isn't clipped at the pad bottom (a clipped height desyncs the scroll offset)
|
||||
int usable = getmaxx(window->layout->win) - (indent + pad_indent);
|
||||
if (usable < 1) {
|
||||
usable = 1;
|
||||
}
|
||||
int msg_nl = 0;
|
||||
for (const char* mp = message + offset; *mp; mp++) {
|
||||
if (*mp == '\n') {
|
||||
msg_nl++;
|
||||
}
|
||||
}
|
||||
int est_lines = msg_nl + (int)(utf8_display_len(message + offset) / usable) + 2;
|
||||
_win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win) + est_lines);
|
||||
|
||||
if (prefs_get_boolean(PREF_WRAP)) {
|
||||
_win_print_wrapped(window->layout->win, message + offset, indent, pad_indent);
|
||||
|
||||
Reference in New Issue
Block a user