From: Hirohito Higashi Date: Thu, 2 Jul 2026 17:59:24 +0000 (+0000) Subject: patch 9.2.0765: popup: opacity popup over a terminal is not cleared when moved X-Git-Tag: v9.2.0765^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8819c1514003dbe9488d8526d5517860f0be9a1d;p=thirdparty%2Fvim.git patch 9.2.0765: popup: opacity popup over a terminal is not cleared when moved Problem: A semi-transparent (opacity) popup shown over a terminal window leaves its old cells on screen when it is moved or its text changes, and typing in the terminal makes them accumulate. Only a full redraw (CTRL-L) clears them. Solution: When redrawing the background under an opacity popup, force a full repaint of an underlying terminal window so the blend uses the terminal's true background instead of stale, already-blended cells. fixes: #20679 closes: #20688 Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/src/popupwin.c b/src/popupwin.c index 849849f827..96fa7895a1 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -6132,7 +6132,7 @@ redraw_win_under_opacity_popup(win_T *wp) // Check across the full width of the popup to find all underlying // windows (e.g., when the popup spans a vertical split). for (col = wp->w_wincol; - col < wp->w_wincol + width && col < screen_Columns; ++col) + col < wp->w_wincol + width && col < screen_Columns; ++col) { int line_cp = r; int col_cp = col; @@ -6146,10 +6146,21 @@ redraw_win_under_opacity_popup(win_T *wp) { linenr_T lnum; - (void)mouse_comp_pos(twp, &line_cp, &col_cp, &lnum, NULL); - // Called from inside update_screen(); raising must_redraw - // would loop the outer redraw indefinitely. - redraw_win_range_now(twp, lnum, lnum); +#ifdef FEAT_TERMINAL + // A terminal only repaints vterm-damaged rows; force a + // full repaint so the opacity blend sees the true + // background, not stale blended cells. + if (term_do_update_window(twp)) + twp->w_redr_type = UPD_NOT_VALID; + else +#endif + { + (void)mouse_comp_pos(twp, &line_cp, &col_cp, &lnum, + NULL); + // Called from inside update_screen(); raising + // must_redraw would loop the outer redraw indefinitely. + redraw_win_range_now(twp, lnum, lnum); + } } else if (line_cp == twp->w_height) // Status bar line: mark for redraw to prevent diff --git a/src/testdir/dumps/Test_popupwin_opacity_term_move_1.dump b/src/testdir/dumps/Test_popupwin_opacity_term_move_1.dump new file mode 100644 index 0000000000..46714d08b0 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_opacity_term_move_1.dump @@ -0,0 +1,12 @@ +|v+0&#ffffff0|i|m|>| > @69 +@75 +@75 +@75 +@9|A+0#0000001#ffffff255|B|C| +0#0000000#ffffff0@62 +@75 +@75 +@75 +@75 +@75 +@75 +@75 diff --git a/src/testdir/dumps/Test_popupwin_opacity_term_move_2.dump b/src/testdir/dumps/Test_popupwin_opacity_term_move_2.dump new file mode 100644 index 0000000000..9a9b0f5b25 --- /dev/null +++ b/src/testdir/dumps/Test_popupwin_opacity_term_move_2.dump @@ -0,0 +1,12 @@ +|v+0&#ffffff0|i|m|>| > @69 +@75 +@75 +@75 +@12|X+0#0000001#ffffff255|Y|Z| +0#0000000#ffffff0@59 +@75 +@75 +@75 +@75 +@75 +@75 +|:|c|a|l@1| |M|o|v|e|I|t|(|)| @60 diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 79f8dac39b..5e4bc5221f 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -5315,6 +5315,43 @@ func Test_popup_opacity_settext_no_leftover() call StopVimInTerminal(buf) endfunc +func Test_popup_opacity_terminal_move_no_leftover() + CheckScreendump + CheckFeature terminal + CheckUnix + + " A semi-transparent popup over a terminal used to leave the old popup + " cells behind when it moved. + let lines =<< trim END + set shell=/bin/sh noruler + unlet $PROMPT_COMMAND + let $PS1 = 'vim> ' + terminal ++curwin + call popup_create('ABC', + \ #{line: 5, col: 10, highlight: 'None', opacity: 30}) + func MoveIt() + let id = popup_list()[0] + call popup_settext(id, 'XYZ') + call popup_setoptions(id, #{col: popup_getpos(id).col + 3}) + endfunc + END + call writefile(lines, 'XtestPopupOpacityTermMove', 'D') + let buf = RunVimInTerminal('-S XtestPopupOpacityTermMove', + \ #{rows: 12, wait_for_ruler: 0}) + call WaitForAssert({-> assert_match('ABC', term_getline(buf, 5))}) + call VerifyScreenDump(buf, 'Test_popupwin_opacity_term_move_1', {}) + + " Move the popup and change its text: the old "ABC" cells must be cleared. + call term_sendkeys(buf, "\:call MoveIt()\") + call WaitForAssert({-> assert_match('XYZ', term_getline(buf, 5))}) + call VerifyScreenDump(buf, 'Test_popupwin_opacity_term_move_2', {}) + + " clean up + call term_sendkeys(buf, "\:qa!\") + call WaitForAssert({-> assert_equal("finished", term_getstatus(buf))}) + exe buf .. 'bwipe!' +endfunc + func Test_popup_opacity_terminal_no_freeze() CheckFeature terminal CheckUnix diff --git a/src/version.c b/src/version.c index 09f4dc2c47..dd14dedba2 100644 --- a/src/version.c +++ b/src/version.c @@ -759,6 +759,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 765, /**/ 764, /**/