Using the yegappan/lsp plugin, popups leave stray chars when scrollbar is being hidden:
Introduced in
~/prj/vim $ git bisect good
4d0c57e15fd74fb9464178a06cb27acaa14081f7 is the first bad commit
commit 4d0c57e15fd74fb9464178a06cb27acaa14081f7 (tag: v9.2.0112)
Author: Yasuhiro Matsumoto <matt...@gmail.com>
Date: Thu Mar 5 20:33:40 2026 +0000
patch 9.2.0112: popup: windows flicker when updating text
Problem: popup: windows flicker when updating text
Solution: Only refresh the popup mask if the position or size changed,
manually set the window redraw type instead of using
redraw_win_later() to avoid triggering a full screen redraw.
Handle opacity 100 correctly. Keep "firstline" sticky when
setting options (Yasuhiro Matsumoto).
related: #19510
closes: #19559
Signed-off-by: Yasuhiro Matsumoto <matt...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>
src/popupwin.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
src/screen.c | 2 +-
src/version.c | 2 ++
3 files changed, 57 insertions(+), 6 deletions(-)
@mattn fyi
Popup shouldn't have stray chars on the right hand side if scroll bar is hidden
9.2.413
debian13, bash
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.![]()
repro steps:
vim --cleanvim9script
popup_create(repeat(["hello world", "world hello", "vim is a text editor"], 10), {
maxheight: 10,
minheight: 10,
minwidth: 30,
border: [1, 1, 1, 1],
filter: (id, key) => {
if key == "\<esc>"
popup_close(id)
else
popup_settext(id, ["should be no stray border"])
endif
return true
}
})
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.![]()
Thanks for the bisect. I figured out two things, separately:
popup_adjust_position() doesn't check w_has_scrollbar, so when popup_settext() shrinks the buffer enough that the scrollbar disappears, the cell that held the old border / scrollbar never gets repainted.org_wincol != w_wincol), because for a centered popup losing the scrollbar shifts wincol by 1. But the centering math is integer-divided, so whether wincol actually shifts depends on the parity of Columns. My terminal happened to be even-width, where it does shift, so the bug was hidden.w_has_scrollbarpopup_adjust_position() decides whether to refresh the popup mask by comparing a fixed set of fields:
if (org_winrow != wp->w_winrow || org_wincol != wp->w_wincol || org_leftcol != wp->w_leftcol || org_leftoff != wp->w_popup_leftoff || org_width != wp->w_width || org_height != wp->w_height) { redraw_win_later(wp, UPD_NOT_VALID); ... popup_mask_refresh = TRUE; }
wp->w_width is the popup's inner content width — it doesn't include the scrollbar column. So when the scrollbar goes away, wp->w_has_scrollbar flips true → false while none of the tracked fields change, and the mask refresh is skipped.
Pre-9.2.0112 this happened to work because f_popup_settext() called redraw_win_later(UPD_NOT_VALID), which propagated must_redraw globally and forced may_update_popup_mask() anyway. The flicker fix dropped that global propagation in favor of a popup-local redraw, exposing the gap.
For a centered popup, w_wincol is computed as:
wp->w_wincol = firstwin->w_wincol + (Columns - wp->w_width - extra_width) / 2;
Losing the scrollbar drops extra_width by 1, so wincol becomes either (Columns - 33) / 2 or (Columns - 32) / 2. With integer truncation, whether the value actually shifts depends on the parity of Columns:
Columns |
wincol BEFORE | wincol AFTER | shifted? | stray? |
|---|---|---|---|---|
| 80 (even) | 23 | 24 | yes | no (saved by org_wincol != w_wincol) |
| 81 (odd) | 24 | 24 | no | yes |
| 82 (even) | 24 | 25 | yes | no |
| 83 (odd) | 25 | 25 | no | yes |
My local terminal was at an even width, so the centered repro silently looked correct on my side. A pos: 'topleft' popup with explicit line/col reproduces unconditionally because w_wincol is anchored — that's how I caught it.
Add w_has_scrollbar to the change detection. PR coming.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.![]()