diff --git a/src/ui/window.c b/src/ui/window.c index f0ec5bbb..0f6e2780 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -67,6 +67,20 @@ _win_ensure_pad_capacity(ProfWin* window, WINDOW* win, int lines_needed) } } } + +// upper-bound estimate of rows a message body occupies (hard newlines + soft-wrap), to reserve pad space before printing so a tall message isn't clipped (a clipped height desyncs the scroll offset) +static int +_win_estimated_lines(WINDOW* win, const char* const message, int indent, int pad_indent) +{ + int usable = MAX(1, getmaxx(win) - (indent + pad_indent)); + int newlines = 0; + for (const char* p = message; *p; p++) { + if (*p == '\n') { + newlines++; + } + } + return newlines + utf8_display_len(message) / usable + 2; +} static const char* LOADING_MESSAGE = "Loading older messages…"; static const char* CONS_WIN_TITLE = "CProof. Type /help for help information."; static const char* XML_WIN_TITLE = "XML Console"; @@ -2001,7 +2015,7 @@ _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)); + _win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win) + _win_estimated_lines(window->layout->win, message + offset, indent, pad_indent)); if (prefs_get_boolean(PREF_WRAP)) { _win_print_wrapped(window->layout->win, message + offset, indent, pad_indent);