Commit: patch 9.2.1003: popup: border is not shown when the popup does not fit

1 view
Skip to first unread message

Christian Brabandt

unread,
Aug 25, 2026, 3:30:21 PM (2 days ago) Aug 25
to vim...@googlegroups.com
patch 9.2.1003: popup: border is not shown when the popup does not fit

Commit: https://github.com/vim/vim/commit/bad7c5a77d3ec33e5e7129a7785495337b2db7d4
Author: Hirohito Higashi <h.eas...@gmail.com>
Date: Tue Aug 25 19:26:04 2026 +0000

patch 9.2.1003: popup: border is not shown when the popup does not fit

Problem: A popup with a border loses part of the border when it does
not fit on the screen: the right border is missing when a
scrollbar is added, and the left border is missing when "pos"
is right aligned and "fixed" is set (Mao-Yining).
Solution: Reserve a column for a scrollbar that is added after the width
and the position were computed. For a right aligned popup
with "fixed", scroll the text instead of moving the border off
the screen (Hirohito Higashi).

fixes: #21128
closes: #21145

Co-Authored-By: Claude Opus 5 (1M context) <nor...@anthropic.com>
Signed-off-by: Hirohito Higashi <h.eas...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/popupwin.c b/src/popupwin.c
index d44e845ee..9c5d6e4df 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -1568,9 +1568,8 @@ popup_height(win_T *wp)
int
popup_width(win_T *wp)
{
- // w_leftcol is how many columns of the core are left of the screen
// w_popup_rightoff is how many columns of the core are right of the screen
- return wp->w_width + wp->w_leftcol
+ return wp->w_width
+ popup_extra_width(wp)
+ wp->w_popup_rightoff;
}
@@ -2766,13 +2765,10 @@ popup_adjust_position(win_T *wp)
wp->w_wincol = leftoff;
else if (wp->w_popup_fixed)
{
- // "col" specifies the right edge, but popup doesn't fit, skip some
- // columns when displaying the window, minus left border and
- // padding.
- if (-leftoff > left_extra)
- wp->w_leftcol = -leftoff - left_extra;
+ // "col" specifies the right edge, but the popup doesn't fit.
+ // Scroll the text instead of moving the border off the screen.
+ wp->w_leftcol = -leftoff;
wp->w_width -= wp->w_leftcol;
- wp->w_popup_leftoff = -leftoff;
if (wp->w_width < 0)
wp->w_width = 0;
}
@@ -2882,6 +2878,10 @@ popup_adjust_position(win_T *wp)
wp->w_has_scrollbar = true;
if (width_with_scrollbar > 0)
wp->w_width = width_with_scrollbar;
+ else
+ // The width and the position were computed without the
+ // scrollbar, reserve a column for it.
+ ++extra_width;
}
}

@@ -7881,7 +7881,7 @@ update_popups(void (*win_update)(win_T *wp))
if (do_padding && cl.eff_padding[1] > 0)
{
int pad_col_start = wincol + wp->w_popup_border[3]
- + wp->w_popup_padding[3] + wp->w_width + wp->w_leftcol;
+ + wp->w_popup_padding[3] + wp->w_width;
int pad_col_end = pad_col_start + wp->w_popup_padding[1];

if (screen_opacity_popup != NULL && saved_screen.lines != NULL)
diff --git a/src/testdir/dumps/Test_popupwin_border_edge_1.dump b/src/testdir/dumps/Test_popupwin_border_edge_1.dump
new file mode 100644
index 000000000..47092e031
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_border_edge_1.dump
@@ -0,0 +1,16 @@
+>1+0&#ffffff0| @43
+|2| @43
+|3| @43
+|4| @43
+|5| @43
+|6| @43
+|7| @29|╔+0#0000001#ffd7ff255|═@11|╗
+|8+0#0000000#ffffff0| @29|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#0000001|║+0#0000001#ffd7ff255
+|9+0#0000000#ffffff0| @29|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#0000001|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0|0| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#0000001|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0@1| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#0000001|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0|2| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#0000001|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0|3| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0|4| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255
+|1+0#0000000#ffffff0|5| @28|║+0#0000001#ffd7ff255| |a@8| | +0#0000000#a8a8a8255|║+0#0000001#ffd7ff255
+| +0#0000000#ffffff0@26|1|,|1| |╚+0#0000001#ffd7ff255|═@11|╝
diff --git a/src/testdir/dumps/Test_popupwin_border_edge_2.dump b/src/testdir/dumps/Test_popupwin_border_edge_2.dump
new file mode 100644
index 000000000..ade1b5ceb
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_border_edge_2.dump
@@ -0,0 +1,16 @@
+>1+0&#ffffff0| @43
+|2| @43
+|3| @43
+|4| @43
+|5| @43
+|6| @43
+|7| @43
+|╔+0#0000001#ffd7ff255|═@27|╗| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f| |║| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |g|h|i|j|a|b|c|d|e|f|g|h|i|j| @12|║| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f| |║| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |g|h|i|j|a|b|c|d|e|f|g|h|i|j| @12|║| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f|g|h|i|j|a|b|c|d|e|f| |║| +0#0000000#ffffff0@14
+|║+0#0000001#ffd7ff255| |g|h|i|j|a|b|c|d|e|f|g|h|i|j| @12|║| +0#0000000#ffffff0@14
+|╚+0#0000001#ffd7ff255|═@27|╝| +0#0000000#ffffff0@14
+|:| @25|1|,|1| @10|T|o|p|
diff --git a/src/testdir/dumps/Test_popupwin_mask_4.dump b/src/testdir/dumps/Test_popupwin_mask_4.dump
index 0cf44d2c2..fe624c1b4 100644
--- a/src/testdir/dumps/Test_popupwin_mask_4.dump
+++ b/src/testdir/dumps/Test_popupwin_mask_4.dump
@@ -1,13 +1,13 @@
>1+0&#ffffff0|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-| +0&#e0e0e08@11|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|o+0&#e0e0e08|m|e| |5+0&#ffffff0|6|7|t+0&#e0e0e08| @3|1+0&#ffffff0@1|2|1|3|x+0#0000001#ffd7ff255@8|8+0#0000000#ffffff0|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|1|2|t+0&#e0e0e08|h|5+0&#ffffff0|6|7|l+0&#e0e0e08|i|n|e| |1+0&#ffffff0@1|2|1|3|y+0#0000001#ffd7ff255@8|8+0#0000000#ffffff0|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|1| +0&#e0e0e08@10|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+| +0&#e0e0e08|m|e| |t|e|7+0&#ffffff0|8|9| +0&#e0e0e08@2|1+0&#ffffff0@1|2|1|3|x+0#0000001#ffd7ff255@8|8+0#0000000#ffffff0|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+| +0&#e0e0e08|2+0&#ffffff0|3|4|e+0&#e0e0e08|r|7+0&#ffffff0|8|9|n+0&#e0e0e08|e| |1+0&#ffffff0@1|2|1|3|y+0#0000001#ffd7ff255@8|8+0#0000000#ffffff0|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
| +0&#e0e0e08@6|8+0&#ffffff0|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
|1|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|═+0#0000001#ffd7ff255@10|X|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-| +0#0000001#ffd7ff255|2+0#0000000#ffffff0|3|4| +0#0000001#ffd7ff255@6|║|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|t+0#0000001#ffd7ff255|2+0#0000000#ffffff0|3|4|e+0#0000001#ffd7ff255| |l|i|n|e| |║|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-| +0#0000001#ffd7ff255@6|8+0#0000000#ffffff0|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|═+0#0000001#ffd7ff255@4|6+0#0000000#ffffff0|7|8|9|═+0#0000001#ffd7ff255@1|╝|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|1|2|═+0#0000001#ffd7ff255@8|X|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|║+0#0000001#ffd7ff255| @4|7+0#0000000#ffffff0|8|9| +0#0000001#ffd7ff255@1|║|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|║+0#0000001#ffd7ff255| |o|n|e| |7+0#0000000#ffffff0|8|9|e+0#0000001#ffd7ff255| |║|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|║+0#0000001#ffd7ff255| @5|8+0#0000000#ffffff0|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|╚+0#0000001#ffd7ff255|═|3+0#0000000#ffffff0|4|5|6|7|8|9|═+0#0000001#ffd7ff255@1|╝|1+0#0000000#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
|1|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
|:| @55|1|,|1| @10|T|o|p|
diff --git a/src/testdir/dumps/Test_popupwin_mask_5.dump b/src/testdir/dumps/Test_popupwin_mask_5.dump
index 63ba30dea..1b8b7435a 100644
--- a/src/testdir/dumps/Test_popupwin_mask_5.dump
+++ b/src/testdir/dumps/Test_popupwin_mask_5.dump
@@ -7,7 +7,7 @@
|1|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
|1|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|2|7|2|8|2|9|3|0|3|1|3|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
|1|2|3|4|5|6|7|8|9|1|0|1@2|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|2|6|═+0#0000001#ffd7ff255@13|X|4+0#0000000#ffffff0|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-| +0&#e0e0e08@11|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| @4|2+0#0000000#ffffff0|9|3| +0#0000001#ffd7ff255@6|║|4+0#0000000#ffffff0|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|o+0&#e0e0e08|m|e| |5+0&#ffffff0|6|7|t+0&#e0e0e08| @3|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| |j|u|s|t|2+0#0000000#ffffff0|9|3|e+0#0000001#ffd7ff255| |l|i|n|e| |║|4+0#0000000#ffffff0|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
-|1|2|t+0&#e0e0e08|h|5+0&#ffffff0|6|7|l+0&#e0e0e08|i|n|e| |1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| @10|3+0#0000000#ffffff0|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+|1| +0&#e0e0e08@10|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| @4|2+0#0000000#ffffff0|9|3| +0#0000001#ffd7ff255@6|║|4+0#0000000#ffffff0|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+| +0&#e0e0e08|m|e| |t|e|7+0&#ffffff0|8|9| +0&#e0e0e08@2|1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| |j|u|s|t|2+0#0000000#ffffff0|9|3|e+0#0000001#ffd7ff255| |l|i|n|e| |║|4+0#0000000#ffffff0|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
+| +0&#e0e0e08|2+0&#ffffff0|3|4|e+0&#e0e0e08|r|7+0&#ffffff0|8|9|n+0&#e0e0e08|e| |1+0&#ffffff0@1|2|1|3|1|4|1|5|1|6|1|7|1|8|1|9|2|0|2|1|2@2|3|2|4|2|5|║+0#0000001#ffd7ff255| @10|3+0#0000000#ffffff0|2|3@2|4|3|5|3|6|3|7|3|8|3|9|4|0|4|1|4|2
| +0&#e0e0e08@6| +0&#ffffff0@33|╚+0#0000001#ffd7ff255|═| +0#0000000#ffffff0@2|═+0#0000001#ffd7ff255@4| +0#0000000#ffffff0@3|═+0#0000001#ffd7ff255@1|╝|,+0#0000000#ffffff0|1| @10|T|o|p|
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 4ee44ffba..b9d50e44a 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -2309,6 +2309,36 @@ func Test_adjust_left_past_screen_width()
%bwipe!
endfunc

+func Test_popupwin_border_at_screen_edge()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, range(1, 20))
+ func ShowScrollbarPopup()
+ call popup_clear()
+ call popup_create(map(range(12), {-> repeat('a', 9)}), #{
+ \ pos: 'botleft', line: 5, col: 33, fixed: v:true,
+ \ maxwidth: 80, padding: [0, 1, 0, 1], border: []})
+ endfunc
+ func ShowRightAlignedPopup()
+ call popup_clear()
+ call popup_create(map(range(6), {-> repeat('abcdefghij', 4)}), #{
+ \ pos: 'botright', line: 15, col: 30, fixed: v:true,
+ \ maxwidth: 80, padding: [0, 1, 0, 1], border: []})
+ endfunc
+ call ShowScrollbarPopup()
+ END
+ call writefile(lines, 'XtestPopupBorderEdge', 'D')
+ let buf = RunVimInTerminal('-S XtestPopupBorderEdge', #{rows: 16, cols: 45})
+ call VerifyScreenDump(buf, 'Test_popupwin_border_edge_1', {})
+
+ call term_sendkeys(buf, ":call ShowRightAlignedPopup()\<CR>")
+ call term_sendkeys(buf, ":\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_border_edge_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_popup_moved()
new
call test_override('char_avail', 1)
diff --git a/src/version.c b/src/version.c
index 4636427d3..38d66cf17 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1003,
/**/
1002,
/**/
Reply all
Reply to author
Forward
0 new messages